diff --git a/.changelog/5407.bugfix.md b/.changelog/5407.bugfix.md new file mode 100644 index 00000000000..655ad300a42 --- /dev/null +++ b/.changelog/5407.bugfix.md @@ -0,0 +1 @@ +Fix stuck `control status` on runtime nodes before initialization diff --git a/go/oasis-node/cmd/node/node_control.go b/go/oasis-node/cmd/node/node_control.go index 44385e0a521..ce655bec45b 100644 --- a/go/oasis-node/cmd/node/node_control.go +++ b/go/oasis-node/cmd/node/node_control.go @@ -332,12 +332,13 @@ func (n *Node) getRuntimeStatus(ctx context.Context) (map[common.Namespace]contr } // Fetch provisioner type. - _, provisioner, err := rt.Host(ctx) + _, provisioner, err := rt.Host() switch { case err != nil: n.logger.Error("failed to fetch host configuration", "err", err, ) + status.Provisioner = "pending" case provisioner != nil: status.Provisioner = provisioner.Name() default: diff --git a/go/oasis-test-runner/scenario/e2e/byzantine_beacon_vrf.go b/go/oasis-test-runner/scenario/e2e/byzantine_beacon_vrf.go index d610dad5c19..cd10a5f4d69 100644 --- a/go/oasis-test-runner/scenario/e2e/byzantine_beacon_vrf.go +++ b/go/oasis-test-runner/scenario/e2e/byzantine_beacon_vrf.go @@ -51,7 +51,7 @@ type byzantineVRFBeaconImpl struct { func (sc *byzantineVRFBeaconImpl) Clone() scenario.Scenario { return &byzantineVRFBeaconImpl{ - Scenario: sc.Scenario.Clone(), + Scenario: *sc.Scenario.Clone().(*Scenario), extraArgs: sc.extraArgs, identitySeed: sc.identitySeed, } diff --git a/go/oasis-test-runner/scenario/e2e/change_reward_schedule.go b/go/oasis-test-runner/scenario/e2e/change_reward_schedule.go index a350e3cef84..6952bc1fb77 100644 --- a/go/oasis-test-runner/scenario/e2e/change_reward_schedule.go +++ b/go/oasis-test-runner/scenario/e2e/change_reward_schedule.go @@ -57,7 +57,7 @@ func newChangeRewardScheduleImpl(name string, parameters *api.ChangeParametersPr func (sc *changeRewardScheduleImpl) Clone() scenario.Scenario { return &changeRewardScheduleImpl{ - Scenario: sc.Scenario.Clone(), + Scenario: *sc.Scenario.Clone().(*Scenario), parameters: sc.parameters, currentEpoch: sc.currentEpoch, entityNonce: sc.entityNonce, diff --git a/go/oasis-test-runner/scenario/e2e/consensus_parameter_upgrade.go b/go/oasis-test-runner/scenario/e2e/consensus_parameter_upgrade.go index acb97b7cb71..2e03eebcfab 100644 --- a/go/oasis-test-runner/scenario/e2e/consensus_parameter_upgrade.go +++ b/go/oasis-test-runner/scenario/e2e/consensus_parameter_upgrade.go @@ -235,7 +235,7 @@ func newConsensusParameterUpgradeImpl(name string, parameters *api.ChangeParamet func (sc *consensusParameterUpgradeImpl) Clone() scenario.Scenario { return &consensusParameterUpgradeImpl{ - Scenario: sc.Scenario.Clone(), + Scenario: *sc.Scenario.Clone().(*Scenario), parameters: sc.parameters, upgradeChecker: sc.upgradeChecker, currentEpoch: sc.currentEpoch, diff --git a/go/oasis-test-runner/scenario/e2e/consensus_state_sync.go b/go/oasis-test-runner/scenario/e2e/consensus_state_sync.go index 1f4b8d71ebb..e9a007309cf 100644 --- a/go/oasis-test-runner/scenario/e2e/consensus_state_sync.go +++ b/go/oasis-test-runner/scenario/e2e/consensus_state_sync.go @@ -23,7 +23,7 @@ type consensusStateSyncImpl struct { func (sc *consensusStateSyncImpl) Clone() scenario.Scenario { return &consensusStateSyncImpl{ - Scenario: sc.Scenario.Clone(), + Scenario: *sc.Scenario.Clone().(*Scenario), } } diff --git a/go/oasis-test-runner/scenario/e2e/debond.go b/go/oasis-test-runner/scenario/e2e/debond.go index 4184632b8e1..7a0a74e80fc 100644 --- a/go/oasis-test-runner/scenario/e2e/debond.go +++ b/go/oasis-test-runner/scenario/e2e/debond.go @@ -23,7 +23,7 @@ type debondImpl struct { func (s *debondImpl) Clone() scenario.Scenario { return &debondImpl{ - Scenario: s.Scenario.Clone(), + Scenario: *s.Scenario.Clone().(*Scenario), } } diff --git a/go/oasis-test-runner/scenario/e2e/early_query.go b/go/oasis-test-runner/scenario/e2e/early_query.go deleted file mode 100644 index fa78020aa71..00000000000 --- a/go/oasis-test-runner/scenario/e2e/early_query.go +++ /dev/null @@ -1,109 +0,0 @@ -package e2e - -import ( - "context" - "errors" - "fmt" - "time" - - consensus "github.com/oasisprotocol/oasis-core/go/consensus/api" - "github.com/oasisprotocol/oasis-core/go/oasis-test-runner/env" - "github.com/oasisprotocol/oasis-core/go/oasis-test-runner/oasis" - "github.com/oasisprotocol/oasis-core/go/oasis-test-runner/scenario" -) - -var ( - // EarlyQuery is the early query scenario where we query a validator node before the network - // has started and there are no committed blocks. - EarlyQuery scenario.Scenario = &earlyQueryImpl{ - Scenario: *NewScenario("early-query"), - } - - // EarlyQueryInitHeight is the same as EarlyQuery scenario but with an initial height set. - EarlyQueryInitHeight scenario.Scenario = &earlyQueryImpl{ - Scenario: *NewScenario("early-query/init-height"), - initialHeight: 42, - } -) - -type earlyQueryImpl struct { - Scenario - - initialHeight int64 -} - -func (sc *earlyQueryImpl) Clone() scenario.Scenario { - return &earlyQueryImpl{ - Scenario: sc.Scenario.Clone(), - initialHeight: sc.initialHeight, - } -} - -func (sc *earlyQueryImpl) Fixture() (*oasis.NetworkFixture, error) { - f, err := sc.Scenario.Fixture() - if err != nil { - return nil, err - } - - f.Network.SetInsecureBeacon() - - // Set initial height. - f.Network.InitialHeight = sc.initialHeight - - // Only one validator should actually start to prevent the network from committing any blocks. - f.Validators[1].NoAutoStart = true - f.Validators[2].NoAutoStart = true - - return f, nil -} - -func (sc *earlyQueryImpl) Run(ctx context.Context, _ *env.Env) error { - // Start the network. - var err error - if err = sc.Net.Start(); err != nil { - return err - } - - // Perform some queries. - cs := sc.Net.Controller().Consensus - ctx, cancel := context.WithTimeout(ctx, 1*time.Second) - defer cancel() - - // StateToGenesis. - _, err = cs.StateToGenesis(ctx, consensus.HeightLatest) - if !errors.Is(err, consensus.ErrNoCommittedBlocks) { - return fmt.Errorf("StateToGenesis query should fail with ErrNoCommittedBlocks (got: %s)", err) - } - // GetBlock. - _, err = cs.GetBlock(ctx, consensus.HeightLatest) - if !errors.Is(err, consensus.ErrNoCommittedBlocks) { - return fmt.Errorf("GetBlock query should fail with ErrNoCommittedBlocks (got: %s)", err) - } - // GetTransactions. - _, err = cs.GetTransactions(ctx, consensus.HeightLatest) - if !errors.Is(err, consensus.ErrNoCommittedBlocks) { - return fmt.Errorf("GetTransactions query should fail with ErrNoCommittedBlocks (got: %s)", err) - } - // GetTransactionsWithResults. - _, err = cs.GetTransactionsWithResults(ctx, consensus.HeightLatest) - if !errors.Is(err, consensus.ErrNoCommittedBlocks) { - return fmt.Errorf("GetTransactionsWithResults query should fail with ErrNoCommittedBlocks (got: %s)", err) - } - - // GetStatus. - status, err := sc.Net.Controller().GetStatus(ctx) - if err != nil { - return fmt.Errorf("failed to get status for node: %w", err) - } - if status.Consensus.Status != consensus.StatusStateSyncing { - return fmt.Errorf("node reports as ready before chain is initialized") - } - if status.Consensus.LatestHeight != 0 { - return fmt.Errorf("node reports non-zero latest height before chain is initialized") - } - if !status.Consensus.IsValidator { - return fmt.Errorf("node does not report itself to be a validator at genesis") - } - - return nil -} diff --git a/go/oasis-test-runner/scenario/e2e/gas_fees_staking.go b/go/oasis-test-runner/scenario/e2e/gas_fees_staking.go index 2ebdee812c8..b5a90cf50e2 100644 --- a/go/oasis-test-runner/scenario/e2e/gas_fees_staking.go +++ b/go/oasis-test-runner/scenario/e2e/gas_fees_staking.go @@ -51,7 +51,7 @@ type gasFeesImpl struct { func (sc *gasFeesImpl) Clone() scenario.Scenario { return &gasFeesImpl{ - Scenario: sc.Scenario.Clone(), + Scenario: *sc.Scenario.Clone().(*Scenario), dumpRestore: sc.dumpRestore, } } diff --git a/go/oasis-test-runner/scenario/e2e/genesis_file.go b/go/oasis-test-runner/scenario/e2e/genesis_file.go index 12147127974..a6ed7e97164 100644 --- a/go/oasis-test-runner/scenario/e2e/genesis_file.go +++ b/go/oasis-test-runner/scenario/e2e/genesis_file.go @@ -42,7 +42,7 @@ type genesisFileImpl struct { func (s *genesisFileImpl) Clone() scenario.Scenario { return &genesisFileImpl{ - Scenario: s.Scenario.Clone(), + Scenario: *s.Scenario.Clone().(*Scenario), } } diff --git a/go/oasis-test-runner/scenario/e2e/identity_cli.go b/go/oasis-test-runner/scenario/e2e/identity_cli.go index b108c7f2811..90082dcd828 100644 --- a/go/oasis-test-runner/scenario/e2e/identity_cli.go +++ b/go/oasis-test-runner/scenario/e2e/identity_cli.go @@ -26,7 +26,7 @@ type identityCLIImpl struct { func (sc *identityCLIImpl) Clone() scenario.Scenario { return &identityCLIImpl{ - Scenario: sc.Scenario.Clone(), + Scenario: *sc.Scenario.Clone().(*Scenario), dataDir: sc.dataDir, } } diff --git a/go/oasis-test-runner/scenario/e2e/min_transact_balance.go b/go/oasis-test-runner/scenario/e2e/min_transact_balance.go index 7f41361d6f7..0a753b05904 100644 --- a/go/oasis-test-runner/scenario/e2e/min_transact_balance.go +++ b/go/oasis-test-runner/scenario/e2e/min_transact_balance.go @@ -82,7 +82,7 @@ func (mtb *minTransactBalanceImpl) getAccountAndCheckNonce(ctx context.Context, func (mtb *minTransactBalanceImpl) Clone() scenario.Scenario { return &minTransactBalanceImpl{ - Scenario: mtb.Scenario.Clone(), + Scenario: *mtb.Scenario.Clone().(*Scenario), } } diff --git a/go/oasis-test-runner/scenario/e2e/multiple_seeds.go b/go/oasis-test-runner/scenario/e2e/multiple_seeds.go index ab826c73904..4bec95c52a4 100644 --- a/go/oasis-test-runner/scenario/e2e/multiple_seeds.go +++ b/go/oasis-test-runner/scenario/e2e/multiple_seeds.go @@ -39,7 +39,7 @@ func (sc *multipleSeeds) Fixture() (*oasis.NetworkFixture, error) { func (sc *multipleSeeds) Clone() scenario.Scenario { return &multipleSeeds{ - Scenario: sc.Scenario.Clone(), + Scenario: *sc.Scenario.Clone().(*Scenario), } } diff --git a/go/oasis-test-runner/scenario/e2e/runtime/early_query.go b/go/oasis-test-runner/scenario/e2e/runtime/early_query.go new file mode 100644 index 00000000000..975b6753672 --- /dev/null +++ b/go/oasis-test-runner/scenario/e2e/runtime/early_query.go @@ -0,0 +1,152 @@ +package runtime + +import ( + "context" + "errors" + "fmt" + "time" + + consensus "github.com/oasisprotocol/oasis-core/go/consensus/api" + "github.com/oasisprotocol/oasis-core/go/oasis-test-runner/env" + "github.com/oasisprotocol/oasis-core/go/oasis-test-runner/oasis" + "github.com/oasisprotocol/oasis-core/go/oasis-test-runner/scenario" + "github.com/oasisprotocol/oasis-core/go/oasis-test-runner/scenario/e2e" +) + +var ( + // EarlyQuery is the early query scenario where we query a validator node before the network + // has started and there are no committed blocks. + EarlyQuery scenario.Scenario = &earlyQueryImpl{ + Scenario: e2e.NewScenario("early-query"), + } + + // EarlyQueryInitHeight is the same as EarlyQuery scenario but with an initial height set. + EarlyQueryInitHeight scenario.Scenario = &earlyQueryImpl{ + Scenario: e2e.NewScenario("early-query/init-height"), + initialHeight: 42, + } + + // EarlyQueryRuntime is the early query scenario where we query a runtime node. + EarlyQueryRuntime scenario.Scenario = &earlyQueryImpl{ + Scenario: NewScenario("early-query", nil), + runtime: true, + } +) + +type earlyQueryImpl struct { + scenario.Scenario + + runtime bool + initialHeight int64 +} + +func (sc *earlyQueryImpl) Clone() scenario.Scenario { + return &earlyQueryImpl{ + Scenario: sc.Scenario.Clone(), + runtime: sc.runtime, + initialHeight: sc.initialHeight, + } +} + +func (sc *earlyQueryImpl) Fixture() (*oasis.NetworkFixture, error) { + f, err := sc.Scenario.Fixture() + if err != nil { + return nil, err + } + + f.Network.SetInsecureBeacon() + + // Set initial height. + f.Network.InitialHeight = sc.initialHeight + + // Only one validator should actually start to prevent the network from committing any blocks. + f.Validators[1].NoAutoStart = true + f.Validators[2].NoAutoStart = true + + return f, nil +} + +func (sc *earlyQueryImpl) Run(ctx context.Context, _ *env.Env) error { + // Start the network. + var err error + if err = sc.Network().Start(); err != nil { + return err + } + + var ctrl *oasis.Controller + switch sc.runtime { + case false: + ctrl = sc.Network().Controller() + case true: + // Use the compute worker node in the runtime scenario. + ctrl, err = oasis.NewController(sc.Network().ComputeWorkers()[0].SocketPath()) + if err != nil { + return fmt.Errorf("failed to create controller for compute node: %w", err) + } + + } + + // Perform consensus queries. + ctx, cancel := context.WithTimeout(ctx, 10*time.Second) + defer cancel() + + // StateToGenesis. + _, err = ctrl.Consensus.StateToGenesis(ctx, consensus.HeightLatest) + if !errors.Is(err, consensus.ErrNoCommittedBlocks) { + return fmt.Errorf("StateToGenesis query should fail with ErrNoCommittedBlocks (got: %s)", err) + } + // GetBlock. + _, err = ctrl.Consensus.GetBlock(ctx, consensus.HeightLatest) + if !errors.Is(err, consensus.ErrNoCommittedBlocks) { + return fmt.Errorf("GetBlock query should fail with ErrNoCommittedBlocks (got: %s)", err) + } + // GetTransactions. + _, err = ctrl.Consensus.GetTransactions(ctx, consensus.HeightLatest) + if !errors.Is(err, consensus.ErrNoCommittedBlocks) { + return fmt.Errorf("GetTransactions query should fail with ErrNoCommittedBlocks (got: %s)", err) + } + // GetTransactionsWithResults. + _, err = ctrl.Consensus.GetTransactionsWithResults(ctx, consensus.HeightLatest) + if !errors.Is(err, consensus.ErrNoCommittedBlocks) { + return fmt.Errorf("GetTransactionsWithResults query should fail with ErrNoCommittedBlocks (got: %s)", err) + } + + switch sc.runtime { + case false: + // GetStatus on validator. + status, err := ctrl.GetStatus(ctx) + if err != nil { + return fmt.Errorf("failed to get status for node: %w", err) + } + if status.Consensus.Status != consensus.StatusStateSyncing { + return fmt.Errorf("node reports as ready before chain is initialized") + } + if status.Consensus.LatestHeight != 0 { + return fmt.Errorf("node reports non-zero latest height before chain is initialized") + } + if !status.Consensus.IsValidator { + return fmt.Errorf("node does not report itself to be a validator at genesis") + } + case true: + // GetStatus on a compute node. + status, err := ctrl.GetStatus(ctx) + if err != nil { + return fmt.Errorf("failed to get status for compute node: %w", err) + } + fmt.Println(status) + if status.Consensus.Status != consensus.StatusStateSyncing { + return fmt.Errorf("node reports as ready before chain is initialized") + } + if status.Consensus.LatestHeight != 0 { + return fmt.Errorf("node reports non-zero latest height before chain is initialized") + } + if status.Consensus.IsValidator { + return fmt.Errorf("compute node does report itself to be a validator at genesis") + } + if len(status.Runtimes) < 1 { + return fmt.Errorf("compute node status does not contain any runtimes") + } + } + + return nil +} diff --git a/go/oasis-test-runner/scenario/e2e/runtime/scenario.go b/go/oasis-test-runner/scenario/e2e/runtime/scenario.go index 8daf6034beb..34870718627 100644 --- a/go/oasis-test-runner/scenario/e2e/runtime/scenario.go +++ b/go/oasis-test-runner/scenario/e2e/runtime/scenario.go @@ -110,7 +110,7 @@ func (sc *Scenario) Clone() scenario.Scenario { testClient = sc.TestClient.Clone() } return &Scenario{ - Scenario: sc.Scenario.Clone(), + Scenario: *sc.Scenario.Clone().(*e2e.Scenario), TestClient: testClient, debugNoRandomInitialEpoch: sc.debugNoRandomInitialEpoch, debugWeakAlphaOk: sc.debugWeakAlphaOk, @@ -362,6 +362,10 @@ func RegisterScenarios() error { TrustRootChangeFailsTest, // Archive node API test. ArchiveAPI, + // Early query tests. + EarlyQuery, + EarlyQueryInitHeight, + EarlyQueryRuntime, } { if err := cmd.Register(s); err != nil { return err diff --git a/go/oasis-test-runner/scenario/e2e/scenario.go b/go/oasis-test-runner/scenario/e2e/scenario.go index 516ba8cd6a5..d68cdc75249 100644 --- a/go/oasis-test-runner/scenario/e2e/scenario.go +++ b/go/oasis-test-runner/scenario/e2e/scenario.go @@ -2,6 +2,8 @@ package e2e import ( + "context" + flag "github.com/spf13/pflag" "github.com/oasisprotocol/oasis-core/go/common/logging" @@ -49,8 +51,8 @@ func NewScenario(name string) *Scenario { } // Clone implements scenario.Scenario. -func (sc *Scenario) Clone() Scenario { - return Scenario{ +func (sc *Scenario) Clone() scenario.Scenario { + return &Scenario{ Net: sc.Net, Flags: sc.Flags.Clone(), Logger: sc.Logger, @@ -63,6 +65,11 @@ func (sc *Scenario) Name() string { return sc.name } +// Network implements scenario.Scenario. +func (sc *Scenario) Network() *oasis.Network { + return sc.Net +} + // Parameters implements scenario.Scenario. func (sc *Scenario) Parameters() *env.ParameterFlagSet { return sc.Flags @@ -73,6 +80,11 @@ func (sc *Scenario) PreInit() error { return nil } +// Run implements scenario.Scenario. +func (sc *Scenario) Run(context.Context, *env.Env) error { + return nil +} + // Fixture implements scenario.Scenario. func (sc *Scenario) Fixture() (*oasis.NetworkFixture, error) { nodeBinary, _ := sc.Flags.GetString(cfgNodeBinary) @@ -129,9 +141,6 @@ func RegisterScenarios() error { NodeUpgradeCancel, // Debonding entries from genesis test. Debond, - // Early query test. - EarlyQuery, - EarlyQueryInitHeight, // Consensus state sync. ConsensusStateSync, // Multiple seeds test. diff --git a/go/oasis-test-runner/scenario/e2e/seed_api.go b/go/oasis-test-runner/scenario/e2e/seed_api.go index 77f848f8030..8343735e2f0 100644 --- a/go/oasis-test-runner/scenario/e2e/seed_api.go +++ b/go/oasis-test-runner/scenario/e2e/seed_api.go @@ -37,7 +37,7 @@ func (sc *seedAPI) Fixture() (*oasis.NetworkFixture, error) { func (sc *seedAPI) Clone() scenario.Scenario { return &seedAPI{ - Scenario: sc.Scenario.Clone(), + Scenario: *sc.Scenario.Clone().(*Scenario), } } diff --git a/go/oasis-test-runner/scenario/e2e/upgrade.go b/go/oasis-test-runner/scenario/e2e/upgrade.go index 6195f3602a1..287b43d88fa 100644 --- a/go/oasis-test-runner/scenario/e2e/upgrade.go +++ b/go/oasis-test-runner/scenario/e2e/upgrade.go @@ -225,7 +225,7 @@ func newNodeUpgradeImpl(handlerName upgrade.HandlerName, upgradeChecker upgradeC func (sc *nodeUpgradeImpl) Clone() scenario.Scenario { return &nodeUpgradeImpl{ - Scenario: sc.Scenario.Clone(), + Scenario: *sc.Scenario.Clone().(*Scenario), handlerName: sc.handlerName, upgradeChecker: sc.upgradeChecker, } diff --git a/go/oasis-test-runner/scenario/e2e/upgrade_cancel.go b/go/oasis-test-runner/scenario/e2e/upgrade_cancel.go index c64b8a4b23d..e33ad1267eb 100644 --- a/go/oasis-test-runner/scenario/e2e/upgrade_cancel.go +++ b/go/oasis-test-runner/scenario/e2e/upgrade_cancel.go @@ -42,7 +42,7 @@ func newNodeUpgradeCancelImpl() scenario.Scenario { func (sc *nodeUpgradeCancelImpl) Clone() scenario.Scenario { return &nodeUpgradeCancelImpl{ - Scenario: sc.Scenario.Clone(), + Scenario: *sc.Scenario.Clone().(*Scenario), } } diff --git a/go/oasis-test-runner/scenario/e2e/validator_equivocation.go b/go/oasis-test-runner/scenario/e2e/validator_equivocation.go index 2e0e052e810..1267496cd56 100644 --- a/go/oasis-test-runner/scenario/e2e/validator_equivocation.go +++ b/go/oasis-test-runner/scenario/e2e/validator_equivocation.go @@ -36,7 +36,7 @@ type validatorEquivocationImpl struct { func (sc *validatorEquivocationImpl) Clone() scenario.Scenario { return &validatorEquivocationImpl{ - Scenario: sc.Scenario.Clone(), + Scenario: *sc.Scenario.Clone().(*Scenario), } } diff --git a/go/oasis-test-runner/scenario/pluginsigner/pluginsigner.go b/go/oasis-test-runner/scenario/pluginsigner/pluginsigner.go index 49d2b7b9212..f2c5ca841e1 100644 --- a/go/oasis-test-runner/scenario/pluginsigner/pluginsigner.go +++ b/go/oasis-test-runner/scenario/pluginsigner/pluginsigner.go @@ -68,6 +68,10 @@ func (sc *pluginSignerImpl) Fixture() (*oasis.NetworkFixture, error) { return nil, nil } +func (sc *pluginSignerImpl) Network() *oasis.Network { + return nil +} + func (sc *pluginSignerImpl) Init(*env.Env, *oasis.Network) error { return nil } diff --git a/go/oasis-test-runner/scenario/remotesigner/remotesigner.go b/go/oasis-test-runner/scenario/remotesigner/remotesigner.go index e71db55ba1e..fcaf6b0ad45 100644 --- a/go/oasis-test-runner/scenario/remotesigner/remotesigner.go +++ b/go/oasis-test-runner/scenario/remotesigner/remotesigner.go @@ -67,6 +67,10 @@ func (sc *remoteSignerImpl) Fixture() (*oasis.NetworkFixture, error) { return nil, nil } +func (sc *remoteSignerImpl) Network() *oasis.Network { + return nil +} + func (sc *remoteSignerImpl) Init(*env.Env, *oasis.Network) error { return nil } diff --git a/go/oasis-test-runner/scenario/scenario.go b/go/oasis-test-runner/scenario/scenario.go index 42cb5d92829..541c463df86 100644 --- a/go/oasis-test-runner/scenario/scenario.go +++ b/go/oasis-test-runner/scenario/scenario.go @@ -38,6 +38,9 @@ type Scenario interface { // otherwise it will be nil. Init(childEnv *env.Env, net *oasis.Network) error + // Network returns the network used by this scenario. + Network() *oasis.Network + // Run runs the scenario. Run(ctx context.Context, childEnv *env.Env) error } diff --git a/go/runtime/registry/host.go b/go/runtime/registry/host.go index e05cbda2689..5346c225076 100644 --- a/go/runtime/registry/host.go +++ b/go/runtime/registry/host.go @@ -61,7 +61,13 @@ type RuntimeHostNode struct { // started automatically, you must call Start explicitly. func (n *RuntimeHostNode) ProvisionHostedRuntime(ctx context.Context) (host.RichRuntime, protocol.Notifier, error) { runtime := n.factory.GetRuntime() - cfgs, provisioner, err := runtime.Host(ctx) + + // Ensure registry descriptor is ready as it is required for obtaining Host configuration. + _, err := runtime.RegistryDescriptor(ctx) + if err != nil { + return nil, nil, fmt.Errorf("failed to wait for registry descriptor: %w", err) + } + cfgs, provisioner, err := runtime.Host() if err != nil { return nil, nil, fmt.Errorf("failed to get runtime host: %w", err) } diff --git a/go/runtime/registry/registry.go b/go/runtime/registry/registry.go index 3476bbd9f17..91b7115aa9c 100644 --- a/go/runtime/registry/registry.go +++ b/go/runtime/registry/registry.go @@ -107,7 +107,10 @@ type Runtime interface { HasHost() bool // Host returns the runtime host configuration and provisioner if configured. - Host(ctx context.Context) (map[version.Version]*runtimeHost.Config, runtimeHost.Provisioner, error) + // + // If the runtime is not yet registered an error is returned. Use `RegistryDescriptor` to + // wait for the runtime to be registered. + Host() (map[version.Version]*runtimeHost.Config, runtimeHost.Provisioner, error) // HostVersions returns a list of supported runtime versions. HostVersions() []version.Version @@ -240,19 +243,20 @@ func (r *runtime) HasHost() bool { return r.hostProvisioners != nil && r.hostConfig != nil } -func (r *runtime) Host(ctx context.Context) (map[version.Version]*runtimeHost.Config, runtimeHost.Provisioner, error) { +func (r *runtime) Host() (map[version.Version]*runtimeHost.Config, runtimeHost.Provisioner, error) { if r.hostProvisioners == nil || r.hostConfig == nil { return nil, nil, ErrRuntimeHostNotConfigured } - rt, err := r.RegistryDescriptor(ctx) - if err != nil { - return nil, nil, fmt.Errorf("failed to get runtime registry descriptor: %w", err) + r.RLock() + defer r.RUnlock() + if r.registryDescriptor == nil { + return nil, nil, fmt.Errorf("runtime not yet registered") } - provisioner, ok := r.hostProvisioners[rt.TEEHardware] + provisioner, ok := r.hostProvisioners[r.registryDescriptor.TEEHardware] if !ok { - return nil, nil, fmt.Errorf("no provisioner suitable for TEE hardware '%s'", rt.TEEHardware) + return nil, nil, fmt.Errorf("no provisioner suitable for TEE hardware '%s'", r.registryDescriptor.TEEHardware) } return r.hostConfig, provisioner, nil