Skip to content

Commit

Permalink
roothash/api: move Genesis.Blocks -> RuntimeStates
Browse files Browse the repository at this point in the history
  • Loading branch information
matevz committed Dec 20, 2019
1 parent 2785878 commit e1b122e
Show file tree
Hide file tree
Showing 22 changed files with 272 additions and 157 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

38 changes: 19 additions & 19 deletions go/consensus/tendermint/apps/roothash/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@ import (
"github.com/oasislabs/oasis-core/go/common/crypto/signature"
"github.com/oasislabs/oasis-core/go/consensus/tendermint/abci"
registryState "github.com/oasislabs/oasis-core/go/consensus/tendermint/apps/registry/state"
genesisApi "github.com/oasislabs/oasis-core/go/genesis/api"
roothash "github.com/oasislabs/oasis-core/go/roothash/api"
"github.com/oasislabs/oasis-core/go/roothash/api/block"
genesisAPI "github.com/oasislabs/oasis-core/go/genesis/api"
"github.com/oasislabs/oasis-core/go/registry/api"
roothashAPI "github.com/oasislabs/oasis-core/go/roothash/api"
storageAPI "github.com/oasislabs/oasis-core/go/storage/api"
)

func (app *rootHashApplication) InitChain(ctx *abci.Context, request types.RequestInitChain, doc *genesisApi.Document) error {
func (app *rootHashApplication) InitChain(ctx *abci.Context, request types.RequestInitChain, doc *genesisAPI.Document) error {
st := doc.RootHash

// The per-runtime roothash state is done primarily via DeliverTx, but
Expand All @@ -35,26 +36,25 @@ func (app *rootHashApplication) InitChain(ctx *abci.Context, request types.Reque
return nil
}

func (rq *rootHashQuerier) Genesis(ctx context.Context) (*roothash.Genesis, error) {
func (rq *rootHashQuerier) Genesis(ctx context.Context) (*roothashAPI.Genesis, error) {
runtimes := rq.state.Runtimes()

// Get per-runtime blocks.
blocks := make(map[signature.PublicKey]*block.Block)
// Get per-runtime states.
rtStates := make(map[signature.PublicKey]*api.RuntimeGenesis)
for _, rt := range runtimes {
blk := *rt.CurrentBlock
// Header should be a normal header for genesis.
blk.Header.HeaderType = block.Normal
// There should be no previous hash.
blk.Header.PreviousHash.Empty()
// No messages.
blk.Header.Messages = nil
// No storage signatures.
blk.Header.StorageSignatures = []signature.Signature{}
blocks[rt.Runtime.ID] = &blk
rtState := api.RuntimeGenesis{
StateRoot: rt.CurrentBlock.Header.StateRoot,
// State is always empty in Genesis regardless of StateRoot.
State: storageAPI.WriteLog{},
StorageReceipts: []signature.Signature{},
Round: rt.CurrentBlock.Header.Round,
}

rtStates[rt.Runtime.ID] = &rtState
}

genesis := &roothash.Genesis{
Blocks: blocks,
genesis := &roothashAPI.Genesis{
RuntimeStates: rtStates,
}
return genesis, nil
}
18 changes: 12 additions & 6 deletions go/consensus/tendermint/apps/roothash/roothash.go
Original file line number Diff line number Diff line change
Expand Up @@ -382,12 +382,18 @@ func (app *rootHashApplication) onNewRuntime(ctx *abci.Context, runtime *registr
}

// Create genesis block.
genesisBlock := genesis.Blocks[runtime.ID]
if genesisBlock == nil {
now := ctx.Now().Unix()
genesisBlock = block.NewGenesisBlock(runtime.ID, uint64(now))
if !runtime.Genesis.StateRoot.IsEmpty() {
genesisBlock.Header.StateRoot = runtime.Genesis.StateRoot
now := ctx.Now().Unix()
genesisBlock := block.NewGenesisBlock(runtime.ID, uint64(now))
// Fill the Header fields with Genesis runtime states, if this was called during InitChain().
genesisBlock.Header.Round = runtime.Genesis.Round
genesisBlock.Header.StateRoot = runtime.Genesis.StateRoot
genesisBlock.Header.StorageSignatures = runtime.Genesis.StorageReceipts
if ctx.IsInitChain() {
genesisRts := genesis.RuntimeStates[runtime.ID]
if genesisRts != nil {
genesisBlock.Header.Round = genesisRts.Round
genesisBlock.Header.StateRoot = genesisRts.StateRoot
genesisBlock.Header.StorageSignatures = runtime.Genesis.StorageReceipts
}
}

Expand Down
2 changes: 1 addition & 1 deletion go/genesis/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ func (d *Document) SanityCheck() error {
if err = d.Registry.SanityCheck(); err != nil {
return err
}
if err = d.RootHash.SanityCheck(); err != nil {
if err = d.RootHash.SanityCheck(true); err != nil {
return err
}
if err = d.Staking.SanityCheck(d.EpochTime.Base); err != nil {
Expand Down
118 changes: 59 additions & 59 deletions go/genesis/tests/tester.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ import (
keymanager "github.com/oasislabs/oasis-core/go/keymanager/api"
cmdFlags "github.com/oasislabs/oasis-core/go/oasis-node/cmd/common/flags"
registry "github.com/oasislabs/oasis-core/go/registry/api"
"github.com/oasislabs/oasis-core/go/roothash/api/block"
scheduler "github.com/oasislabs/oasis-core/go/scheduler/api"
staking "github.com/oasislabs/oasis-core/go/staking/api"
stakingTests "github.com/oasislabs/oasis-core/go/staking/tests/debug"
storage "github.com/oasislabs/oasis-core/go/storage/api"
)

var testDoc = &genesis.Document{
Expand Down Expand Up @@ -111,6 +111,7 @@ func TestGenesisSanityCheck(t *testing.T) {

// First, set up a few things we'll need in the tests below.
signer := memorySigner.NewTestSigner("genesis sanity checks signer")
signer2 := memorySigner.NewTestSigner("another genesis sanity checks signer")
validPK := signer.Public()

invalidPK := hex2pk("c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a")
Expand All @@ -119,6 +120,8 @@ func TestGenesisSanityCheck(t *testing.T) {

var emptyHash hash.Hash
emptyHash.Empty()
var nonEmptyHash hash.Hash
_ = nonEmptyHash.UnmarshalHex("1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef")

// Note that this test entity has no nodes by design, those will be added
// later by various tests.
Expand Down Expand Up @@ -234,73 +237,70 @@ func TestGenesisSanityCheck(t *testing.T) {

// Test roothash genesis checks.
d = *testDoc
d.RootHash.Blocks = make(map[signature.PublicKey]*block.Block)
d.RootHash.Blocks[validPK] = &block.Block{
Header: block.Header{
HeaderType: 123,
},
}
require.Error(d.SanityCheck(), "invalid block header should be rejected")

d = *testDoc
d.RootHash.Blocks = make(map[signature.PublicKey]*block.Block)
d.RootHash.Blocks[validPK] = &block.Block{
Header: block.Header{
HeaderType: block.Normal,
PreviousHash: hash.Hash{},
},
d.RootHash.RuntimeStates = make(map[signature.PublicKey]*registry.RuntimeGenesis)
d.RootHash.RuntimeStates[validPK] = &registry.RuntimeGenesis{
StateRoot: nonEmptyHash,
// Empty list of storage receipts.
StorageReceipts: []signature.Signature{},
}
require.Error(d.SanityCheck(), "invalid previous hash should be rejected")
require.Error(d.RootHash.SanityCheck(false), "empty StorageReceipts for StateRoot should be rejected")
require.NoError(d.RootHash.SanityCheck(true), "empty StorageReceipts for StateRoot should be ignored, if isGenesis=true")

d = *testDoc
d.RootHash.Blocks = make(map[signature.PublicKey]*block.Block)
d.RootHash.Blocks[validPK] = &block.Block{
Header: block.Header{
HeaderType: block.Normal,
PreviousHash: emptyHash,
Timestamp: uint64(time.Now().Unix() + 62*60),
},
d.RootHash.RuntimeStates = make(map[signature.PublicKey]*registry.RuntimeGenesis)
d.RootHash.RuntimeStates[validPK] = &registry.RuntimeGenesis{
StateRoot: nonEmptyHash,
// List with one empty (invalid) storage receipt.
StorageReceipts: []signature.Signature{signature.Signature{}},
}
require.Error(d.SanityCheck(), "invalid timestamp should be rejected")

d = *testDoc
sigCtx := signature.NewContext("genesis sanity check storage sig test")
sig, grr := signature.Sign(signer, sigCtx, []byte{1, 2, 3})
require.NoError(grr, "should be able to sign")
d.RootHash.Blocks = make(map[signature.PublicKey]*block.Block)
d.RootHash.Blocks[validPK] = &block.Block{
Header: block.Header{
HeaderType: block.Normal,
PreviousHash: emptyHash,
Timestamp: uint64(time.Now().Unix()),
StorageSignatures: []signature.Signature{*sig},
},
require.Error(d.RootHash.SanityCheck(false), "empty StorageReceipt for StateRoot should be rejected")
require.NoError(d.RootHash.SanityCheck(true), "empty StorageReceipt for StateRoot should be ignored, if isGenesis=true")

d = *testDoc
signature.SetChainContext("test: oasis-core tests")
stateRootSig, _ := signature.Sign(signer, storage.ReceiptSignatureContext, nonEmptyHash[:])
stateRootSig2, _ := signature.Sign(signer2, storage.ReceiptSignatureContext, nonEmptyHash[:])
wrongSig, _ := signature.Sign(signer, storage.ReceiptSignatureContext, []byte{1, 2, 3})
d.RootHash.RuntimeStates = make(map[signature.PublicKey]*registry.RuntimeGenesis)
d.RootHash.RuntimeStates[validPK] = &registry.RuntimeGenesis{
StateRoot: nonEmptyHash,
// Some non-empty signature, but not related to StateRoot.
StorageReceipts: []signature.Signature{*wrongSig, *stateRootSig, *stateRootSig2},
}
require.Error(d.SanityCheck(), "non-empty storage signature array should be rejected")
require.Error(d.RootHash.SanityCheck(false), "some incorrect StorageReceipt for StateRoot should be rejected")
require.NoError(d.RootHash.SanityCheck(true), "some incorrect StorageReceipt for StateRoot should be ignored, if isGenesis=true")

d = *testDoc
d.RootHash.Blocks = make(map[signature.PublicKey]*block.Block)
d.RootHash.Blocks[validPK] = &block.Block{
Header: block.Header{
HeaderType: block.Normal,
PreviousHash: emptyHash,
Timestamp: uint64(time.Now().Unix()),
StorageSignatures: []signature.Signature{},
Messages: []*block.Message{nil, nil, nil},
},
d.RootHash.RuntimeStates = make(map[signature.PublicKey]*registry.RuntimeGenesis)
d.RootHash.RuntimeStates[validPK] = &registry.RuntimeGenesis{
StateRoot: nonEmptyHash,
StorageReceipts: []signature.Signature{*stateRootSig, *stateRootSig2},
}
require.Error(d.SanityCheck(), "non-empty roothash message array should be rejected")

d = *testDoc
d.RootHash.Blocks = make(map[signature.PublicKey]*block.Block)
d.RootHash.Blocks[validPK] = &block.Block{
Header: block.Header{
HeaderType: block.Normal,
PreviousHash: emptyHash,
Timestamp: uint64(time.Now().Unix()),
},
require.NoError(d.RootHash.SanityCheck(false), "non-empty StateRoot with all correct StorageReceipts should pass")
require.NoError(d.RootHash.SanityCheck(true), "non-empty StateRoot with all correct StorageReceipts should pass, if isGenesis=true")

d = *testDoc
nonEmptyState := storage.WriteLog{storage.LogEntry{
Key: []byte{1, 2, 3},
Value: []byte{1, 2, 3},
}}
d.RootHash.RuntimeStates = make(map[signature.PublicKey]*registry.RuntimeGenesis)
d.RootHash.RuntimeStates[validPK] = &registry.RuntimeGenesis{
State: nonEmptyState,
StateRoot: nonEmptyHash,
StorageReceipts: []signature.Signature{*wrongSig, *stateRootSig, *stateRootSig2},
}
require.NoError(d.RootHash.SanityCheck(false), "non-empty StateRoot with non-empty State and some invalid StorageReceipt should pass")
require.NoError(d.RootHash.SanityCheck(true), "non-empty StateRoot with non-empty State and some invalid StorageReceipt should pass, if isGenesis=true")

d.RootHash.RuntimeStates = make(map[signature.PublicKey]*registry.RuntimeGenesis)
d.RootHash.RuntimeStates[validPK] = &registry.RuntimeGenesis{
State: nonEmptyState,
StateRoot: nonEmptyHash,
StorageReceipts: []signature.Signature{*stateRootSig, *stateRootSig2},
}
require.NoError(d.SanityCheck(), "well-formed block should pass")
require.NoError(d.RootHash.SanityCheck(false), "non-empty StateRoot with non-empty State and all valid StorageReceipts should pass")
require.NoError(d.RootHash.SanityCheck(true), "non-empty StateRoot with non-empty State and all valid StorageReceipts should pass, if isGenesis=true")

// Test registry genesis checks.
d = *testDoc
Expand Down
1 change: 1 addition & 0 deletions go/oasis-net-runner/fixtures/default.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ func NewDefaultFixture() (*oasis.NetworkFixture, error) {
},
Storage: registry.StorageParameters{GroupSize: 1},
GenesisState: viper.GetString(cfgRuntimeGenesisState),
GenesisRound: 0,
},
},
Validators: []oasis.ValidatorFixture{
Expand Down
27 changes: 12 additions & 15 deletions go/oasis-node/cmd/genesis/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ import (
cmdGrpc "github.com/oasislabs/oasis-core/go/oasis-node/cmd/common/grpc"
registry "github.com/oasislabs/oasis-core/go/registry/api"
roothash "github.com/oasislabs/oasis-core/go/roothash/api"
"github.com/oasislabs/oasis-core/go/roothash/api/block"
scheduler "github.com/oasislabs/oasis-core/go/scheduler/api"
staking "github.com/oasislabs/oasis-core/go/staking/api"
stakingTests "github.com/oasislabs/oasis-core/go/staking/tests/debug"
Expand Down Expand Up @@ -406,39 +405,37 @@ func AppendRegistryState(doc *genesis.Document, entities, runtimes, nodes []stri
// of exported roothash blocks.
func AppendRootHashState(doc *genesis.Document, exports []string, l *logging.Logger) error {
rootSt := roothash.Genesis{
Blocks: make(map[signature.PublicKey]*block.Block),
RuntimeStates: make(map[signature.PublicKey]*registry.RuntimeGenesis),
}

for _, v := range exports {
b, err := ioutil.ReadFile(v)
if err != nil {
l.Error("failed to load genesis roothash blocks",
l.Error("failed to load genesis roothash runtime states",
"err", err,
"filename", v,
)
return err
}

var blocks []*block.Block
if err = json.Unmarshal(b, &blocks); err != nil {
l.Error("failed to parse genesis roothash blocks",
var rtStates map[signature.PublicKey]*registry.RuntimeGenesis
if err = json.Unmarshal(b, &rtStates); err != nil {
l.Error("failed to parse genesis roothash runtime states",
"err", err,
"filename", v,
)
return err
}

for _, blk := range blocks {
var key signature.PublicKey
copy(key[:], blk.Header.Namespace[:])
if _, ok := rootSt.Blocks[key]; ok {
l.Error("duplicate genesis roothash block",
"runtime_id", blk.Header.Namespace,
"block", blk,
for key, rtg := range rtStates {
if _, ok := rootSt.RuntimeStates[key]; ok {
l.Error("duplicate genesis roothash runtime state",
"runtime_id", key,
"block", rtg,
)
return errors.New("duplicate genesis roothash block")
return errors.New("duplicate genesis roothash runtime states")
}
rootSt.Blocks[key] = blk
rootSt.RuntimeStates[key] = rtg
}
}

Expand Down
3 changes: 3 additions & 0 deletions go/oasis-node/cmd/registry/runtime/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ const (
CfgID = "runtime.id"
CfgTEEHardware = "runtime.tee_hardware"
CfgGenesisState = "runtime.genesis.state"
CfgGenesisRound = "runtime.genesis.round"
CfgKind = "runtime.kind"
CfgKeyManager = "runtime.keymanager"
cfgOutput = "runtime.genesis.file"
Expand Down Expand Up @@ -264,6 +265,7 @@ func runtimeFromFlags() (*registry.Runtime, signature.Signer, error) {

// TODO: Support root upload when registering.
gen := registry.RuntimeGenesis{}
gen.Round = viper.GetUint64(CfgGenesisRound)
switch state := viper.GetString(CfgGenesisState); state {
case "":
gen.StateRoot.Empty()
Expand Down Expand Up @@ -431,6 +433,7 @@ func init() {
runtimeFlags.String(CfgID, "", "Runtime ID")
runtimeFlags.String(CfgTEEHardware, "invalid", "Type of TEE hardware. Supported values are \"invalid\" and \"intel-sgx\"")
runtimeFlags.String(CfgGenesisState, "", "Runtime state at genesis")
runtimeFlags.Uint64(CfgGenesisRound, 0, "Runtime round at genesis")
runtimeFlags.String(CfgKeyManager, "", "Key Manager Runtime ID")
runtimeFlags.String(CfgKind, "compute", "Kind of runtime. Supported values are \"compute\" and \"keymanager\"")
runtimeFlags.String(CfgVersion, "", "Runtime version. Value is 64-bit hex e.g. 0x0000000100020003 for 1.2.3")
Expand Down
2 changes: 2 additions & 0 deletions go/oasis-test-runner/oasis/fixture.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ type RuntimeFixture struct {

Binary string `json:"binary"`
GenesisState string `json:"genesis_state"`
GenesisRound uint64 `json:"genesis_round"`

Compute registry.ComputeParameters `json:"compute"`
Merge registry.MergeParameters `json:"merge"`
Expand Down Expand Up @@ -198,6 +199,7 @@ func (f *RuntimeFixture) Create(netFixture *NetworkFixture, net *Network) (*Runt
Storage: f.Storage,
Binary: f.Binary,
GenesisState: f.GenesisState,
GenesisRound: f.GenesisRound,
Pruner: f.Pruner,
})
}
Expand Down
2 changes: 2 additions & 0 deletions go/oasis-test-runner/oasis/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ type RuntimeCfg struct { // nolint: maligned

Binary string
GenesisState string
GenesisRound uint64

Compute registry.ComputeParameters
Merge registry.MergeParameters
Expand Down Expand Up @@ -88,6 +89,7 @@ func (net *Network) NewRuntime(cfg *RuntimeCfg) (*Runtime, error) {
"--" + common.CfgDataDir, rtDir.String(),
"--" + cmdRegRt.CfgID, cfg.ID.String(),
"--" + cmdRegRt.CfgKind, cfg.Kind.String(),
"--" + cmdRegRt.CfgGenesisRound, strconv.FormatUint(cfg.GenesisRound, 10),
}
if cfg.Kind == registry.KindCompute {
args = append(args, []string{
Expand Down
1 change: 1 addition & 0 deletions go/oasis-test-runner/scenario/e2e/halt_restore.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ func (sc *haltRestoreImpl) Run(childEnv *env.Env) error {
if err != nil {
sc.logger.Error("scenario/e2e/halt_restore: failed getting genesis file provider",
"err", err,
"genesis_file", files[0],
)
return err
}
Expand Down
1 change: 1 addition & 0 deletions go/oasis-test-runner/scenario/e2e/registry_cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -663,6 +663,7 @@ func (r *registryCLIImpl) genRegisterRuntimeTx(childEnv *env.Env, runtime regist
"--" + cmdRegRt.CfgID, runtime.ID.String(),
"--" + cmdRegRt.CfgTEEHardware, runtime.TEEHardware.String(),
"--" + cmdRegRt.CfgGenesisState, genesisStateFile,
"--" + cmdRegRt.CfgGenesisRound, strconv.FormatUint(runtime.Genesis.Round, 10),
"--" + cmdRegRt.CfgKind, runtime.Kind.String(),
"--" + cmdRegRt.CfgVersion, runtime.Version.Version.String(),
"--" + cmdRegRt.CfgVersionEnclave, string(runtime.Version.TEE),
Expand Down
Loading

0 comments on commit e1b122e

Please sign in to comment.