From 3b936f387e4d10ab82ed656d53b24a8ea70ec014 Mon Sep 17 00:00:00 2001 From: Adrian Sutton Date: Tue, 19 May 2026 09:39:29 +1000 Subject: [PATCH 1/3] chore: remove rust/kona/tests/supervisor and the sysgo op-supervisor path The rust/kona/tests/supervisor packages are not invoked by any CI job (the kona test-e2e-sysgo matrix only runs node/common, node/reorgs and node/restart). They were the last consumer of the NewSimpleInterop/NewSingleChainInterop presets, which in turn were the last code path that booted op-supervisor as a service in devstack. With those tests gone: - Delete NewSimpleInterop / NewSingleChainInterop factories and the singleChainInteropFromRuntime / simpleInteropFromRuntime adapters. - Delete NewSimpleInteropRuntime{,WithConfig} / NewSingleChainInteropRuntime{,WithConfig} plus the startSupervisor, startOPSupervisor, startKonaSupervisor, OpSupervisor, KonaSupervisor, and Supervisor-interface chain. - Drop MultiChainRuntime.PrimarySupervisor and SingleChainInteropSupport.Supervisor (no setters/readers left). - Drop SingleChainInterop.Supervisor, the dsl.Supervisor wrapper, supervisorFrontend, newSupervisorFrontend, newPresetSupervisor, and the stack.Supervisor interface. - Move readJWTSecretFromPath and validateSimpleInteropPresetConfig to a small interop_helpers.go since they are still needed by the supernode runtime. --- op-devstack/dsl/check.go | 1 - op-devstack/dsl/supervisor.go | 164 ------- op-devstack/presets/interop.go | 21 - op-devstack/presets/interop_from_runtime.go | 146 ------- op-devstack/presets/option_validation.go | 13 - op-devstack/presets/rpc_frontends.go | 33 -- .../presets/superproofs_from_runtime.go | 2 - op-devstack/presets/sysgo_runtime.go | 11 - op-devstack/stack/supervisor.go | 13 - op-devstack/sysgo/interop_filter.go | 1 - op-devstack/sysgo/interop_helpers.go | 42 ++ .../sysgo/multichain_supervisor_runtime.go | 404 ------------------ op-devstack/sysgo/runtime_state.go | 4 +- op-devstack/sysgo/supervisor.go | 8 - op-devstack/sysgo/supervisor_kona.go | 99 ----- op-devstack/sysgo/supervisor_op.go | 80 ---- .../supervisor/l2reorg/init_exec_msg_test.go | 247 ----------- .../l2reorgAfterL1reorg/reorg_test.go | 162 ------- .../supervisor/pre_interop/helpers_test.go | 14 - .../tests/supervisor/pre_interop/post_test.go | 208 --------- .../tests/supervisor/pre_interop/pre_test.go | 109 ----- .../supervisor/presets/interop_minimal.go | 39 -- 22 files changed, 43 insertions(+), 1778 deletions(-) delete mode 100644 op-devstack/dsl/supervisor.go delete mode 100644 op-devstack/presets/interop_from_runtime.go delete mode 100644 op-devstack/stack/supervisor.go create mode 100644 op-devstack/sysgo/interop_helpers.go delete mode 100644 op-devstack/sysgo/multichain_supervisor_runtime.go delete mode 100644 op-devstack/sysgo/supervisor.go delete mode 100644 op-devstack/sysgo/supervisor_kona.go delete mode 100644 op-devstack/sysgo/supervisor_op.go delete mode 100644 rust/kona/tests/supervisor/l2reorg/init_exec_msg_test.go delete mode 100644 rust/kona/tests/supervisor/l2reorgAfterL1reorg/reorg_test.go delete mode 100644 rust/kona/tests/supervisor/pre_interop/helpers_test.go delete mode 100644 rust/kona/tests/supervisor/pre_interop/post_test.go delete mode 100644 rust/kona/tests/supervisor/pre_interop/pre_test.go delete mode 100644 rust/kona/tests/supervisor/presets/interop_minimal.go diff --git a/op-devstack/dsl/check.go b/op-devstack/dsl/check.go index 18d366ccf7d..1fed3af4fa1 100644 --- a/op-devstack/dsl/check.go +++ b/op-devstack/dsl/check.go @@ -36,7 +36,6 @@ type ChainBlockProvider interface { } var _ SyncStatusProvider = (*L2CLNode)(nil) -var _ SyncStatusProvider = (*Supervisor)(nil) // LaggedFn returns a lambda that checks the baseNode head with given safety level is lagged with the refNode chain sync status provider // Composable with other lambdas to wait in parallel diff --git a/op-devstack/dsl/supervisor.go b/op-devstack/dsl/supervisor.go deleted file mode 100644 index 015848d41f6..00000000000 --- a/op-devstack/dsl/supervisor.go +++ /dev/null @@ -1,164 +0,0 @@ -package dsl - -import ( - "context" - "errors" - "fmt" - "strings" - "time" - - "github.com/ethereum-optimism/optimism/op-devstack/stack" - "github.com/ethereum-optimism/optimism/op-service/eth" - "github.com/ethereum-optimism/optimism/op-service/retry" - "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/backend/status" - "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" - "github.com/ethereum/go-ethereum/common/hexutil" -) - -type Supervisor struct { - commonImpl - inner stack.Supervisor -} - -func NewSupervisor(inner stack.Supervisor) *Supervisor { - return &Supervisor{ - commonImpl: commonFromT(inner.T()), - inner: inner, - } -} - -func (s *Supervisor) String() string { - return s.inner.Name() -} - -func (s *Supervisor) Escape() stack.Supervisor { - return s.inner -} - -func (s *Supervisor) FetchSyncStatus() eth.SupervisorSyncStatus { - s.log.Debug("Fetching supervisor sync status") - ctx, cancel := context.WithTimeout(s.ctx, DefaultTimeout) - defer cancel() - syncStatus, err := retry.Do(ctx, 10, retry.Fixed(500*time.Millisecond), func() (eth.SupervisorSyncStatus, error) { - ctx, cancel := context.WithTimeout(s.ctx, 300*time.Millisecond) - defer cancel() - syncStatus, err := s.inner.QueryAPI().SyncStatus(ctx) - if errors.Is(err, status.ErrStatusTrackerNotReady) { - s.log.Debug("Sync status not ready from supervisor") - return syncStatus, err - } - // Check for L1 sync mismatch error and retry - if err != nil && strings.Contains(err.Error(), "min synced L1 mismatch") { - s.log.Debug("L1 sync mismatch, retrying", "error", err) - return syncStatus, err - } - return syncStatus, err - }) - s.require.NoError(err, "Failed to fetch sync status") - s.log.Info("Fetched supervisor sync status", - "minSyncedL1", syncStatus.MinSyncedL1, - "safeTimestamp", syncStatus.SafeTimestamp, - "finalizedTimestamp", syncStatus.FinalizedTimestamp) - return syncStatus -} - -func (s *Supervisor) SafeBlockID(chainID eth.ChainID) eth.BlockID { - return s.L2HeadBlockID(chainID, types.CrossSafe) -} - -// ChainSyncStatus satisfies that the supervisor can provide sync status per chain -func (s *Supervisor) ChainSyncStatus(chainID eth.ChainID, lvl types.SafetyLevel) eth.BlockID { - return s.L2HeadBlockID(chainID, lvl) -} - -// L2HeadBlockID fetches supervisor sync status and returns block id with given safety level -func (s *Supervisor) L2HeadBlockID(chainID eth.ChainID, lvl types.SafetyLevel) eth.BlockID { - supervisorSyncStatus := s.FetchSyncStatus() - supervisorChainSyncStatus, ok := supervisorSyncStatus.Chains[chainID] - s.require.True(ok, "chain id not found in supervisor sync status") - var blockID eth.BlockID - switch lvl { - case types.Finalized: - blockID = supervisorChainSyncStatus.Finalized - case types.CrossSafe: - blockID = supervisorChainSyncStatus.CrossSafe - case types.LocalSafe: - blockID = supervisorChainSyncStatus.LocalSafe - case types.CrossUnsafe: - blockID = supervisorChainSyncStatus.CrossUnsafe - case types.LocalUnsafe: - blockID = supervisorChainSyncStatus.LocalUnsafe.ID() - default: - s.require.NoError(errors.New("invalid safety level")) - } - return blockID -} - -// WaitForL2HeadToAdvance checks the supervisor view of L2CL chain head with given safety level advanced more than delta block number -func (s *Supervisor) WaitForL2HeadToAdvance(chainID eth.ChainID, delta uint64, lvl types.SafetyLevel, attempts int) { - chInitial := s.L2HeadBlockID(chainID, lvl) - target := chInitial.Number + delta - err := retry.Do0(s.ctx, attempts, &retry.FixedStrategy{Dur: 2 * time.Second}, - func() error { - chStatus := s.L2HeadBlockID(chainID, lvl) - s.log.Info("Supervisor view", - "chain", chainID, "label", lvl, "initial", chInitial.Number, "current", chStatus.Number, "target", target) - if chStatus.Number >= target { - s.log.Info("Supervisor view advanced", "chain", chainID, "label", lvl, "target", target) - return nil - } - return fmt.Errorf("expected head to advance: %s", lvl) - }) - s.require.NoError(err) -} - -func (s *Supervisor) WaitForL2HeadToAdvanceTo(chainID eth.ChainID, lvl types.SafetyLevel, blockID eth.BlockID) { - ctx, cancel := context.WithCancelCause(s.ctx) - defer cancel(nil) - err := retry.Do0(ctx, 5*60, &retry.FixedStrategy{Dur: 1 * time.Second}, func() error { - chStatus := s.L2HeadBlockID(chainID, lvl) - s.log.Info("Supervisor view", - "chain", chainID, "label", lvl, "current", chStatus.Number, "target", blockID.Number) - if chStatus.Number < blockID.Number { - return fmt.Errorf("expected %s head to advance to blockID: %v", lvl, blockID) - } else if chStatus.Number == blockID.Number && chStatus.Hash != blockID.Hash { - err := fmt.Errorf("supervisor %s head with blockID %v for chainID %s does not match target blockID: %v", lvl, chStatus, chainID, blockID) - cancel(err) - return err - } - return nil - }) - - // If we got a context.Canceled error, check if there's a more descriptive cause - if err != nil && errors.Is(err, context.Canceled) { - if cause := context.Cause(ctx); cause != nil && !errors.Is(cause, context.Canceled) { - // Log the original cause for better debugging - err = fmt.Errorf("supervisor wait failed: %w (original cause: %w)", err, cause) - } - } - - s.require.NoError(err) -} - -func (s *Supervisor) WaitForUnsafeHeadToAdvance(chainID eth.ChainID, delta uint64) { - attempts := int(delta + 3) // intentionally allow few more attempts for avoid flaking - s.WaitForL2HeadToAdvance(chainID, delta, types.LocalUnsafe, attempts) -} - -func (s *Supervisor) FetchSuperRootAtTimestamp(timestamp uint64) eth.SuperRootResponse { - response, err := s.inner.QueryAPI().SuperRootAtTimestamp(s.ctx, hexutil.Uint64(timestamp)) - s.require.NoError(err, "Unable to fetch super root at timestamp") - return response -} - -func (s *Supervisor) Start() { - lifecycle, ok := s.inner.(stack.Lifecycle) - s.require.Truef(ok, "supervisor %s is not lifecycle-controllable", s.inner.Name()) - lifecycle.Start() -} - -func (s *Supervisor) Stop() { - lifecycle, ok := s.inner.(stack.Lifecycle) - s.require.Truef(ok, "supervisor %s is not lifecycle-controllable", s.inner.Name()) - lifecycle.Stop() -} diff --git a/op-devstack/presets/interop.go b/op-devstack/presets/interop.go index a0da5b05a6b..00bfacba5cf 100644 --- a/op-devstack/presets/interop.go +++ b/op-devstack/presets/interop.go @@ -21,7 +21,6 @@ type SingleChainInterop struct { T devtest.T timeTravel *clock.AdvancingClock - Supervisor *dsl.Supervisor SuperRoots *dsl.Supernode TestSequencer *dsl.TestSequencer @@ -45,16 +44,6 @@ type SingleChainInterop struct { challengerConfig *challengerConfig.Config } -// NewSingleChainInterop creates a fresh SingleChainInterop target for the current test. -// -// The target is created from the single-chain interop runtime plus any additional preset options. -func NewSingleChainInterop(t devtest.T, opts ...Option) *SingleChainInterop { - presetCfg, presetOpts := collectSupportedPresetConfig(t, "NewSingleChainInterop", opts, singleChainInteropPresetSupportedOptionKinds) - out := singleChainInteropFromRuntime(t, sysgo.NewSingleChainInteropRuntimeWithConfig(t, presetCfg)) - presetOpts.applyPreset(out) - return out -} - func (s *SingleChainInterop) L2Networks() []*dsl.L2Network { return []*dsl.L2Network{ s.L2ChainA, @@ -139,16 +128,6 @@ func NewSingleChainInteropSuperRootAtGenesis(t devtest.T, opts ...Option) *Singl return singleChainInteropFromSupernodeProofsRuntime(t, sysgo.NewSingleChainSuperRootAtGenesisRuntimeWithConfig(t, presetCfg)) } -// NewSimpleInterop creates a fresh SimpleInterop target for the current test. -// -// The target is created from the interop runtime plus any additional preset options. -func NewSimpleInterop(t devtest.T, opts ...Option) *SimpleInterop { - presetCfg, presetOpts := collectSupportedPresetConfig(t, "NewSimpleInterop", opts, singleChainInteropPresetSupportedOptionKinds) - out := simpleInteropFromRuntime(t, sysgo.NewSimpleInteropRuntimeWithConfig(t, presetCfg)) - presetOpts.applyPreset(out) - return out -} - // WithSuggestedInteropActivationOffset suggests a hardfork time offset to use. // This is applied e.g. to the deployment if running against sysgo. func WithSuggestedInteropActivationOffset(offset uint64) Option { diff --git a/op-devstack/presets/interop_from_runtime.go b/op-devstack/presets/interop_from_runtime.go deleted file mode 100644 index fcb3602fb73..00000000000 --- a/op-devstack/presets/interop_from_runtime.go +++ /dev/null @@ -1,146 +0,0 @@ -package presets - -import ( - "github.com/ethereum-optimism/optimism/op-devstack/devtest" - "github.com/ethereum-optimism/optimism/op-devstack/dsl" - "github.com/ethereum-optimism/optimism/op-devstack/sysgo" -) - -func singleChainInteropFromRuntime(t devtest.T, runtime *sysgo.MultiChainRuntime) *SingleChainInterop { - chainA := runtime.Chains["l2a"] - t.Require().NotNil(chainA, "missing l2a interop chain") - l1ChainID := runtime.L1Network.ChainID() - l2ChainID := chainA.Network.ChainID() - - l1Network := newPresetL1Network(t, "l1", runtime.L1Network.ChainConfig()) - l1EL := newL1ELFrontend(t, "l1", l1ChainID, runtime.L1EL.UserRPC()) - l1CL := newL1CLFrontend(t, "l1", l1ChainID, runtime.L1CL.BeaconHTTPAddr(), runtime.L1CL.FakePoS()) - l1Network.AddL1ELNode(l1EL) - l1Network.AddL1CLNode(l1CL) - - l2Chain := newPresetL2Network( - t, - "l2a", - chainA.Network.ChainConfig(), - chainA.Network.RollupConfig(), - chainA.Network.Deployment(), - newKeyring(runtime.Keys, t.Require()), - l1Network, - ) - - l2EL := newL2ELFrontend( - t, - "sequencer", - l2ChainID, - chainA.EL.UserRPC(), - chainA.EL.EngineRPC(), - chainA.EL.JWTPath(), - chainA.Network.RollupConfig(), - chainA.EL, - ) - l2CL := newL2CLFrontend( - t, - "sequencer", - l2ChainID, - chainA.CL.UserRPC(), - chainA.CL, - ) - l2CL.attachEL(l2EL) - l2Batcher := newL2BatcherFrontend(t, "main", l2ChainID, chainA.Batcher.UserRPC()) - l2Chain.AddL2ELNode(l2EL) - l2Chain.AddL2CLNode(l2CL) - l2Chain.AddL2Batcher(l2Batcher) - - supervisor := newSupervisorFrontend(t, "1-primary", runtime.PrimarySupervisor.UserRPC(), runtime.PrimarySupervisor) - testSequencer := newTestSequencerFrontend( - t, - runtime.TestSequencer.Name, - runtime.TestSequencer.AdminRPC, - runtime.TestSequencer.ControlRPC, - runtime.TestSequencer.JWTSecret, - ) - l1ELDSL := dsl.NewL1ELNode(l1EL) - l1CLDSL := dsl.NewL1CLNode(l1CL) - l2ELDSL := dsl.NewL2ELNode(l2EL) - l2CLDSL := dsl.NewL2CLNode(l2CL) - - faucetAFrontend := newFaucetFrontendForChain(t, runtime.FaucetService, l2ChainID) - faucetL1Frontend := newFaucetFrontendForChain(t, runtime.FaucetService, l1ChainID) - out := &SingleChainInterop{ - Log: t.Logger(), - T: t, - timeTravel: runtime.TimeTravel, - Supervisor: dsl.NewSupervisor(supervisor), - SuperRoots: nil, - TestSequencer: dsl.NewTestSequencer(testSequencer), - L1Network: dsl.NewL1Network(l1Network, l1ELDSL, l1CLDSL), - L1EL: l1ELDSL, - L1CL: l1CLDSL, - L2ChainA: dsl.NewL2Network(l2Chain, l2ELDSL, l2CLDSL, l1ELDSL, nil, nil), - L2BatcherA: dsl.NewL2Batcher(l2Batcher), - L2ELA: l2ELDSL, - L2CLA: l2CLDSL, - Wallet: dsl.NewRandomHDWallet(t, 30), - FaucetA: dsl.NewFaucet(faucetAFrontend), - FaucetL1: dsl.NewFaucet(faucetL1Frontend), - challengerConfig: runtime.L2ChallengerConfig, - } - l1Network.AddFaucet(faucetL1Frontend) - l2Chain.AddFaucet(faucetAFrontend) - out.FunderL1 = dsl.NewFunder(out.Wallet, out.FaucetL1, out.L1EL) - out.FunderA = dsl.NewFunder(out.Wallet, out.FaucetA, out.L2ELA) - return out -} - -func simpleInteropFromRuntime(t devtest.T, runtime *sysgo.MultiChainRuntime) *SimpleInterop { - singleChain := singleChainInteropFromRuntime(t, runtime) - chainB := runtime.Chains["l2b"] - t.Require().NotNil(chainB, "missing l2b interop chain") - l2BChainID := chainB.Network.ChainID() - - l1Network, ok := singleChain.L1Network.Escape().(*presetL1Network) - t.Require().True(ok, "expected preset L1 network") - - l2B := newPresetL2Network( - t, - "l2b", - chainB.Network.ChainConfig(), - chainB.Network.RollupConfig(), - chainB.Network.Deployment(), - newKeyring(runtime.Keys, t.Require()), - l1Network, - ) - - l2BEL := newL2ELFrontend( - t, - "sequencer", - l2BChainID, - chainB.EL.UserRPC(), - chainB.EL.EngineRPC(), - chainB.EL.JWTPath(), - chainB.Network.RollupConfig(), - chainB.EL, - ) - l2BCL := newL2CLFrontend(t, "sequencer", l2BChainID, chainB.CL.UserRPC(), chainB.CL) - l2BCL.attachEL(l2BEL) - l2BBatcher := newL2BatcherFrontend(t, "main", l2BChainID, chainB.Batcher.UserRPC()) - l2B.AddL2ELNode(l2BEL) - l2B.AddL2CLNode(l2BCL) - l2B.AddL2Batcher(l2BBatcher) - - l2BELDSL := dsl.NewL2ELNode(l2BEL) - l2BCLDSL := dsl.NewL2CLNode(l2BCL) - - faucetBFrontend := newFaucetFrontendForChain(t, runtime.FaucetService, l2BChainID) - out := &SimpleInterop{ - SingleChainInterop: *singleChain, - L2ChainB: dsl.NewL2Network(l2B, l2BELDSL, l2BCLDSL, singleChain.L1EL, nil, nil), - L2BatcherB: dsl.NewL2Batcher(l2BBatcher), - L2ELB: l2BELDSL, - L2CLB: l2BCLDSL, - FaucetB: dsl.NewFaucet(faucetBFrontend), - } - l2B.AddFaucet(faucetBFrontend) - out.FunderB = dsl.NewFunder(out.Wallet, out.FaucetB, out.L2ELB) - return out -} diff --git a/op-devstack/presets/option_validation.go b/op-devstack/presets/option_validation.go index 7bca01a3c37..06a132c95aa 100644 --- a/op-devstack/presets/option_validation.go +++ b/op-devstack/presets/option_validation.go @@ -135,19 +135,6 @@ const minimalWithConductorsPresetSupportedOptionKinds = optionKindDeployer | const simpleWithSyncTesterPresetSupportedOptionKinds = minimalPresetSupportedOptionKinds | optionKindGlobalSyncTesterEL -const singleChainInteropPresetSupportedOptionKinds = optionKindDeployer | - optionKindBatcher | - optionKindProposer | - optionKindGlobalL2CL | - optionKindL1EL | - optionKindAddedGameType | - optionKindRespectedGameType | - optionKindTimeTravel | - optionKindMaxSequencingWindow | - optionKindRequireInteropNotAtGen | - optionKindAfterBuild | - optionKindProofValidation - const supernodeProofsPresetSupportedOptionKinds = optionKindDeployer | optionKindBatcher | optionKindL1EL | diff --git a/op-devstack/presets/rpc_frontends.go b/op-devstack/presets/rpc_frontends.go index 85d43b2eac5..629502b95a6 100644 --- a/op-devstack/presets/rpc_frontends.go +++ b/op-devstack/presets/rpc_frontends.go @@ -429,39 +429,6 @@ func (r *rollupBoostFrontend) Stop() { r.lifecycle.Stop() } -type supervisorFrontend struct { - presetCommon - api apis.SupervisorAPI - lifecycle stack.Lifecycle -} - -var _ stack.Supervisor = (*supervisorFrontend)(nil) - -func newPresetSupervisor(t devtest.T, name string, rpcCl opclient.RPC) *supervisorFrontend { - return &supervisorFrontend{ - presetCommon: newPresetCommon(t, name), - api: sources.NewSupervisorClient(rpcCl), - } -} - -func (r *supervisorFrontend) AdminAPI() apis.SupervisorAdminAPI { - return r.api -} - -func (r *supervisorFrontend) QueryAPI() apis.SupervisorQueryAPI { - return r.api -} - -func (r *supervisorFrontend) Start() { - r.require().NotNil(r.lifecycle, "supervisor %s is not lifecycle-controllable", r.Name()) - r.lifecycle.Start() -} - -func (r *supervisorFrontend) Stop() { - r.require().NotNil(r.lifecycle, "supervisor %s is not lifecycle-controllable", r.Name()) - r.lifecycle.Stop() -} - type supernodeFrontend struct { presetCommon api apis.SupernodeQueryAPI diff --git a/op-devstack/presets/superproofs_from_runtime.go b/op-devstack/presets/superproofs_from_runtime.go index aef7eaab625..e08bcf6ab15 100644 --- a/op-devstack/presets/superproofs_from_runtime.go +++ b/op-devstack/presets/superproofs_from_runtime.go @@ -38,7 +38,6 @@ func simpleInteropFromSupernodeProofsRuntime(t devtest.T, runtime *sysgo.MultiCh Log: t.Logger(), T: t, timeTravel: runtime.TimeTravel, - Supervisor: nil, SuperRoots: dsl.NewSupernodeWithTestControl(supernodeFrontend, runtime.Supernode), TestSequencer: dsl.NewTestSequencer(testSequencer), L1Network: twoL2.L1Network, @@ -133,7 +132,6 @@ func singleChainInteropFromSupernodeProofsRuntime(t devtest.T, runtime *sysgo.Mu Log: t.Logger(), T: t, timeTravel: runtime.TimeTravel, - Supervisor: nil, SuperRoots: dsl.NewSupernodeWithTestControl(supernodeFrontend, runtime.Supernode), TestSequencer: dsl.NewTestSequencer(testSequencer), L1Network: dsl.NewL1Network(l1Network, l1ELDSL, l1CLDSL), diff --git a/op-devstack/presets/sysgo_runtime.go b/op-devstack/presets/sysgo_runtime.go index 9dee4db2fd7..58f30f8a370 100644 --- a/op-devstack/presets/sysgo_runtime.go +++ b/op-devstack/presets/sysgo_runtime.go @@ -122,17 +122,6 @@ func newRollupBoostFrontend(t devtest.T, name string, chainID eth.ChainID, userR return rollupBoost } -func newSupervisorFrontend(t devtest.T, name string, userRPC string, lifecycle ...stack.Lifecycle) *supervisorFrontend { - rpcCl, err := client.NewRPC(t.Ctx(), t.Logger(), userRPC, client.WithLazyDial()) - t.Require().NoError(err) - t.Cleanup(rpcCl.Close) - supervisor := newPresetSupervisor(t, name, rpcCl) - if len(lifecycle) > 0 { - supervisor.lifecycle = lifecycle[0] - } - return supervisor -} - func newSupernodeFrontend(t devtest.T, name string, userRPC string) *supernodeFrontend { rpcCl, err := client.NewRPC(t.Ctx(), t.Logger(), userRPC, client.WithLazyDial()) t.Require().NoError(err) diff --git a/op-devstack/stack/supervisor.go b/op-devstack/stack/supervisor.go deleted file mode 100644 index 8ca5f458439..00000000000 --- a/op-devstack/stack/supervisor.go +++ /dev/null @@ -1,13 +0,0 @@ -package stack - -import ( - "github.com/ethereum-optimism/optimism/op-service/apis" -) - -// Supervisor is an interop service, used to cross-verify messages between chains. -type Supervisor interface { - Common - - AdminAPI() apis.SupervisorAdminAPI - QueryAPI() apis.SupervisorQueryAPI -} diff --git a/op-devstack/sysgo/interop_filter.go b/op-devstack/sysgo/interop_filter.go index c22d9dfa5f6..c23f239d45e 100644 --- a/op-devstack/sysgo/interop_filter.go +++ b/op-devstack/sysgo/interop_filter.go @@ -14,7 +14,6 @@ import ( ) // InteropFilter wraps an in-process op-interop-filter service for devstack. -// Follows the same pattern as OpSupervisor (supervisor_op.go). type InteropFilter struct { mu sync.Mutex name string diff --git a/op-devstack/sysgo/interop_helpers.go b/op-devstack/sysgo/interop_helpers.go new file mode 100644 index 00000000000..775a0350c3b --- /dev/null +++ b/op-devstack/sysgo/interop_helpers.go @@ -0,0 +1,42 @@ +package sysgo + +import ( + "os" + "strings" + + "github.com/ethereum/go-ethereum/common/hexutil" + + "github.com/ethereum-optimism/optimism/op-devstack/devtest" +) + +func validateSimpleInteropPresetConfig(t devtest.T, cfg PresetConfig, l2Nets ...*L2Network) { + require := t.Require() + if cfg.MaxSequencingWindow != nil { + for _, l2Net := range l2Nets { + require.LessOrEqualf( + l2Net.rollupCfg.SeqWindowSize, + *cfg.MaxSequencingWindow, + "sequencing window of chain %s must fit in max sequencing window size", + l2Net.ChainID(), + ) + } + } + if cfg.RequireInteropNotAtGen { + for _, l2Net := range l2Nets { + interopTime := l2Net.genesis.Config.InteropTime + require.NotNilf(interopTime, "chain %s must have interop", l2Net.ChainID()) + require.NotZerof(*interopTime, "chain %s interop must not be at genesis", l2Net.ChainID()) + } + } +} + +func readJWTSecretFromPath(t devtest.T, jwtPath string) [32]byte { + content, err := os.ReadFile(jwtPath) + t.Require().NoError(err, "failed to read jwt path %s", jwtPath) + raw, err := hexutil.Decode(strings.TrimSpace(string(content))) + t.Require().NoError(err, "failed to decode jwt secret from %s", jwtPath) + t.Require().Len(raw, 32, "invalid jwt secret length from %s", jwtPath) + var secret [32]byte + copy(secret[:], raw) + return secret +} diff --git a/op-devstack/sysgo/multichain_supervisor_runtime.go b/op-devstack/sysgo/multichain_supervisor_runtime.go deleted file mode 100644 index 9ea22183f9a..00000000000 --- a/op-devstack/sysgo/multichain_supervisor_runtime.go +++ /dev/null @@ -1,404 +0,0 @@ -package sysgo - -import ( - "encoding/json" - "os" - "path/filepath" - "strings" - "time" - - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/log" - - "github.com/ethereum-optimism/optimism/op-chain-ops/devkeys" - "github.com/ethereum-optimism/optimism/op-core/devfeatures" - "github.com/ethereum-optimism/optimism/op-devstack/devtest" - "github.com/ethereum-optimism/optimism/op-devstack/shared/rustbin" - "github.com/ethereum-optimism/optimism/op-node/rollup" - "github.com/ethereum-optimism/optimism/op-service/client" - "github.com/ethereum-optimism/optimism/op-service/clock" - "github.com/ethereum-optimism/optimism/op-service/dial" - "github.com/ethereum-optimism/optimism/op-service/eth" - oplog "github.com/ethereum-optimism/optimism/op-service/log" - opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics" - "github.com/ethereum-optimism/optimism/op-service/oppprof" - "github.com/ethereum-optimism/optimism/op-service/retry" - oprpc "github.com/ethereum-optimism/optimism/op-service/rpc" - supervisorConfig "github.com/ethereum-optimism/optimism/op-supervisor/config" - "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/backend/depset" - "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/backend/syncnode" -) - -func NewSingleChainInteropRuntime(t devtest.T) *MultiChainRuntime { - return NewSingleChainInteropRuntimeWithConfig(t, PresetConfig{}) -} - -func NewSingleChainInteropRuntimeWithConfig(t devtest.T, cfg PresetConfig) *MultiChainRuntime { - require := t.Require() - - keys, err := devkeys.NewMnemonicDevKeys(devkeys.TestMnemonic) - require.NoError(err, "failed to derive dev keys from mnemonic") - - cfg.DeployerOptions = append([]DeployerOption{ - WithDevFeatureEnabled(devfeatures.OptimismPortalInteropFlag), - }, cfg.DeployerOptions...) - migration, l1Net, l2Net, depSet, fullCfgSet := buildSingleChainWorldWithInteropAndState(t, keys, true, cfg.LocalContractArtifactsPath, cfg.DeployerOptions...) - validateSimpleInteropPresetConfig(t, cfg, l2Net) - - jwtPath, jwtSecret := writeJWTSecret(t) - l1Clock := clock.SystemClock - var timeTravelClock *clock.AdvancingClock - if cfg.EnableTimeTravel { - timeTravelClock = clock.NewAdvancingClock(100 * time.Millisecond) - l1Clock = timeTravelClock - } - l1EL, l1CL := startInProcessL1WithClockConfig(t, l1Net, jwtPath, l1Clock, cfg) - supervisor := startSupervisor(t, "1-primary", l1EL, fullCfgSet, map[eth.ChainID]*rollup.Config{ - l2Net.ChainID(): l2Net.rollupCfg, - }) - - l2EL := startL2ELNodeWithSupervisor(t, l2Net, jwtPath, jwtSecret, "sequencer", NewELNodeIdentity(0), supervisor.UserRPC()) - l2CL := startL2CLNode(t, keys, l1Net, l2Net, l1EL, l1CL, l2EL, jwtSecret, l2CLNodeStartConfig{ - Key: "sequencer", - IsSequencer: true, - NoDiscovery: true, - EnableReqResp: true, - UseReqResp: true, - IndexingMode: true, - DependencySet: depSet, - L2FollowSource: "", - L2CLOptions: cfg.GlobalL2CLOptions, - }) - connectManagedL2CLToSupervisor(t, supervisor, l2CL) - - l2Batcher := startMinimalBatcher(t, keys, l2Net, l1EL, l2CL, l2EL, cfg.BatcherOptions...) - l2Proposer := startMinimalProposer(t, keys, l2Net, l1EL, l2CL, cfg.ProposerOptions...) - applyMinimalGameTypeOptions(t, keys, l1Net, l2Net, l1EL, cfg.AddedGameTypes, cfg.RespectedGameTypes) - testSequencer := startTestSequencer(t, keys, jwtPath, jwtSecret, l1Net, l1EL, l1CL, l2EL, l2Net, l2CL) - faucetService := startFaucets(t, keys, l1Net.ChainID(), l2Net.ChainID(), l1EL.UserRPC(), l2EL.UserRPC()) - - chainA := &MultiChainNodeRuntime{ - Name: "l2a", - Network: l2Net, - EL: l2EL, - CL: l2CL, - Batcher: l2Batcher, - Proposer: l2Proposer, - } - - return &MultiChainRuntime{ - Keys: keys, - FullConfigSet: fullCfgSet, - DependencySet: depSet, - Migration: migration, - L1Network: l1Net, - L1EL: l1EL, - L1CL: l1CL, - Chains: map[string]*MultiChainNodeRuntime{"l2a": chainA}, - PrimarySupervisor: supervisor, - FaucetService: faucetService, - TimeTravel: timeTravelClock, - TestSequencer: newTestSequencerRuntime(testSequencer, "dev"), - } -} - -func NewSimpleInteropRuntime(t devtest.T) *MultiChainRuntime { - return NewSimpleInteropRuntimeWithConfig(t, PresetConfig{}) -} - -func NewSimpleInteropRuntimeWithConfig(t devtest.T, cfg PresetConfig) *MultiChainRuntime { - require := t.Require() - - keys, err := devkeys.NewMnemonicDevKeys(devkeys.TestMnemonic) - require.NoError(err, "failed to derive dev keys from mnemonic") - - cfg.DeployerOptions = append([]DeployerOption{ - WithDevFeatureEnabled(devfeatures.OptimismPortalInteropFlag), - }, cfg.DeployerOptions...) - migration, l1Net, l2ANet, l2BNet, fullCfgSet := buildTwoL2WorldWithState(t, keys, true, cfg.LocalContractArtifactsPath, cfg.DeployerOptions...) - validateSimpleInteropPresetConfig(t, cfg, l2ANet, l2BNet) - depSet := fullCfgSet.DependencySet - - jwtPath, jwtSecret := writeJWTSecret(t) - l1Clock := clock.SystemClock - var timeTravelClock *clock.AdvancingClock - if cfg.EnableTimeTravel { - timeTravelClock = clock.NewAdvancingClock(100 * time.Millisecond) - l1Clock = timeTravelClock - } - l1EL, l1CL := startInProcessL1WithClockConfig(t, l1Net, jwtPath, l1Clock, cfg) - supervisor := startSupervisor(t, "1-primary", l1EL, fullCfgSet, map[eth.ChainID]*rollup.Config{ - l2ANet.ChainID(): l2ANet.rollupCfg, - l2BNet.ChainID(): l2BNet.rollupCfg, - }) - - l2AEL := startL2ELNodeWithSupervisor(t, l2ANet, jwtPath, jwtSecret, "sequencer", NewELNodeIdentity(0), supervisor.UserRPC()) - l2BEL := startL2ELNodeWithSupervisor(t, l2BNet, jwtPath, jwtSecret, "sequencer", NewELNodeIdentity(0), supervisor.UserRPC()) - l2ACL := startL2CLNode(t, keys, l1Net, l2ANet, l1EL, l1CL, l2AEL, jwtSecret, l2CLNodeStartConfig{ - Key: "sequencer", - IsSequencer: true, - NoDiscovery: true, - EnableReqResp: true, - UseReqResp: true, - IndexingMode: true, - DependencySet: depSet, - L2FollowSource: "", - L2CLOptions: cfg.GlobalL2CLOptions, - }) - l2BCL := startL2CLNode(t, keys, l1Net, l2BNet, l1EL, l1CL, l2BEL, jwtSecret, l2CLNodeStartConfig{ - Key: "sequencer", - IsSequencer: true, - NoDiscovery: true, - EnableReqResp: true, - UseReqResp: true, - IndexingMode: true, - DependencySet: depSet, - L2FollowSource: "", - L2CLOptions: cfg.GlobalL2CLOptions, - }) - connectManagedL2CLToSupervisor(t, supervisor, l2ACL) - connectManagedL2CLToSupervisor(t, supervisor, l2BCL) - - l2ABatcher := startMinimalBatcher(t, keys, l2ANet, l1EL, l2ACL, l2AEL, cfg.BatcherOptions...) - l2AProposer := startMinimalProposer(t, keys, l2ANet, l1EL, l2ACL, cfg.ProposerOptions...) - l2BBatcher := startMinimalBatcher(t, keys, l2BNet, l1EL, l2BCL, l2BEL, cfg.BatcherOptions...) - l2BProposer := startMinimalProposer(t, keys, l2BNet, l1EL, l2BCL, cfg.ProposerOptions...) - testSequencer := startTestSequencer(t, keys, jwtPath, jwtSecret, l1Net, l1EL, l1CL, l2AEL, l2ANet, l2ACL) - faucetService := startFaucetsForRPCs(t, keys, map[eth.ChainID]string{ - l1Net.ChainID(): l1EL.UserRPC(), - l2ANet.ChainID(): l2AEL.UserRPC(), - l2BNet.ChainID(): l2BEL.UserRPC(), - }) - - return &MultiChainRuntime{ - Keys: keys, - FullConfigSet: fullCfgSet, - DependencySet: depSet, - Migration: migration, - L1Network: l1Net, - L1EL: l1EL, - L1CL: l1CL, - Chains: map[string]*MultiChainNodeRuntime{ - "l2a": { - Name: "l2a", - Network: l2ANet, - EL: l2AEL, - CL: l2ACL, - Batcher: l2ABatcher, - Proposer: l2AProposer, - }, - "l2b": { - Name: "l2b", - Network: l2BNet, - EL: l2BEL, - CL: l2BCL, - Batcher: l2BBatcher, - Proposer: l2BProposer, - }, - }, - PrimarySupervisor: supervisor, - FaucetService: faucetService, - TimeTravel: timeTravelClock, - TestSequencer: newTestSequencerRuntime(testSequencer, "dev"), - } -} - -func validateSimpleInteropPresetConfig(t devtest.T, cfg PresetConfig, l2Nets ...*L2Network) { - require := t.Require() - if cfg.MaxSequencingWindow != nil { - for _, l2Net := range l2Nets { - require.LessOrEqualf( - l2Net.rollupCfg.SeqWindowSize, - *cfg.MaxSequencingWindow, - "sequencing window of chain %s must fit in max sequencing window size", - l2Net.ChainID(), - ) - } - } - if cfg.RequireInteropNotAtGen { - for _, l2Net := range l2Nets { - interopTime := l2Net.genesis.Config.InteropTime - require.NotNilf(interopTime, "chain %s must have interop", l2Net.ChainID()) - require.NotZerof(*interopTime, "chain %s interop must not be at genesis", l2Net.ChainID()) - } - } -} - -func startSupervisor( - t devtest.T, - supervisorName string, - l1EL *L1Geth, - fullCfgSet depset.FullConfigSetMerged, - rollupCfgs map[eth.ChainID]*rollup.Config, -) Supervisor { - switch os.Getenv("DEVSTACK_SUPERVISOR_KIND") { - case "kona": - return startKonaSupervisor(t, supervisorName, l1EL, fullCfgSet, rollupCfgs) - default: - return startOPSupervisor(t, supervisorName, l1EL, fullCfgSet) - } -} - -func startOPSupervisor( - t devtest.T, - supervisorName string, - l1EL *L1Geth, - fullCfgSet depset.FullConfigSetMerged, -) *OpSupervisor { - cfg := &supervisorConfig.Config{ - MetricsConfig: opmetrics.CLIConfig{ - Enabled: false, - }, - PprofConfig: oppprof.CLIConfig{ - ListenEnabled: false, - }, - LogConfig: oplog.CLIConfig{ - Level: log.LevelDebug, - Format: oplog.FormatText, - }, - RPC: oprpc.CLIConfig{ - ListenAddr: "127.0.0.1", - ListenPort: 0, - EnableAdmin: true, - }, - SyncSources: &syncnode.CLISyncNodes{}, - L1RPC: l1EL.UserRPC(), - Datadir: t.TempDir(), - Version: "dev", - FullConfigSetSource: fullCfgSet, - MockRun: false, - SynchronousProcessors: false, - DatadirSyncEndpoint: "", - } - supervisorNode := &OpSupervisor{ - name: supervisorName, - userRPC: "", - cfg: cfg, - p: t, - logger: t.Logger().New("component", "supervisor"), - service: nil, - } - supervisorNode.Start() - t.Cleanup(supervisorNode.Stop) - return supervisorNode -} - -func startKonaSupervisor( - t devtest.T, - supervisorName string, - l1EL *L1Geth, - fullCfgSet depset.FullConfigSetMerged, - rollupCfgs map[eth.ChainID]*rollup.Config, -) *KonaSupervisor { - require := t.Require() - - cfgDir := t.TempDir() - depSetJSON, err := json.Marshal(fullCfgSet.DependencySet) - require.NoError(err, "failed to marshal dependency set") - depSetCfgPath := filepath.Join(cfgDir, "depset.json") - require.NoError(os.WriteFile(depSetCfgPath, depSetJSON, 0o644)) - - rollupCfgPath := filepath.Join(cfgDir, "rollup-config-*.json") - for chainID, cfg := range rollupCfgs { - rollupData, err := json.Marshal(cfg) - require.NoError(err, "failed to marshal rollup config for chain %s", chainID) - filePath := filepath.Join(cfgDir, "rollup-config-"+chainID.String()+".json") - require.NoError(os.WriteFile(filePath, rollupData, 0o644)) - } - - execPath, err := rustbin.Spec{ - SrcDir: "rust/kona", - Package: "kona-supervisor", - Binary: "kona-supervisor", - }.EnsureExists(t.Ctx(), t.Logger()) - require.NoError(err, "prepare kona-supervisor binary") - require.NotEmpty(execPath, "kona-supervisor binary path resolved") - - envVars := []string{ - "RPC_ADDR=127.0.0.1", - "DATADIR=" + t.TempDir(), - "DEPENDENCY_SET=" + depSetCfgPath, - "ROLLUP_CONFIG_PATHS=" + rollupCfgPath, - "L1_RPC=" + l1EL.UserRPC(), - "RPC_ENABLE_ADMIN=true", - "L2_CONSENSUS_NODES=", - "L2_CONSENSUS_JWT_SECRET=", - "KONA_LOG_LEVEL=3", - "KONA_LOG_STDOUT_FORMAT=json", - } - - konaSupervisor := &KonaSupervisor{ - name: supervisorName, - userRPC: "", - execPath: execPath, - args: []string{}, - env: envVars, - p: t, - } - konaSupervisor.Start() - t.Cleanup(konaSupervisor.Stop) - return konaSupervisor -} - -func connectManagedL2CLToSupervisor(t devtest.T, supervisor Supervisor, l2CL L2CLNode) { - interopEndpoint, secret := l2CL.InteropRPC() - supClient, err := dial.DialSupervisorClientWithTimeout(t.Ctx(), t.Logger(), supervisor.UserRPC(), client.WithLazyDial()) - t.Require().NoError(err) - t.Cleanup(supClient.Close) - - err = retry.Do0(t.Ctx(), 10, retry.Exponential(), func() error { - return supClient.AddL2RPC(t.Ctx(), interopEndpoint, secret) - }) - t.Require().NoErrorf(err, "must connect CL node %s to supervisor %s", l2CL, supervisorIDString(supervisor)) -} - -func supervisorIDString(supervisor Supervisor) string { - switch s := supervisor.(type) { - case *OpSupervisor: - return s.name - case *KonaSupervisor: - return s.name - default: - return "" - } -} - -func startL2ELNodeWithSupervisor( - t devtest.T, - l2Net *L2Network, - jwtPath string, - jwtSecret [32]byte, - key string, - identity *ELNodeIdentity, - supervisorRPC string, -) L2ELNode { - cfg := DefaultL2ELConfig() - cfg.P2PAddr = "127.0.0.1" - cfg.P2PPort = identity.Port - cfg.P2PNodeKeyHex = identity.KeyHex() - - l2EL := &OpGeth{ - name: key, - p: t, - logger: t.Logger().New("component", "l2el-"+key), - l2Net: l2Net, - jwtPath: jwtPath, - jwtSecret: jwtSecret, - supervisorRPC: supervisorRPC, - cfg: cfg, - } - l2EL.Start() - t.Cleanup(l2EL.Stop) - return l2EL -} - -func readJWTSecretFromPath(t devtest.T, jwtPath string) [32]byte { - content, err := os.ReadFile(jwtPath) - t.Require().NoError(err, "failed to read jwt path %s", jwtPath) - raw, err := hexutil.Decode(strings.TrimSpace(string(content))) - t.Require().NoError(err, "failed to decode jwt secret from %s", jwtPath) - t.Require().Len(raw, 32, "invalid jwt secret length from %s", jwtPath) - var secret [32]byte - copy(secret[:], raw) - return secret -} diff --git a/op-devstack/sysgo/runtime_state.go b/op-devstack/sysgo/runtime_state.go index 60d7d8b49b4..9527efe6224 100644 --- a/op-devstack/sysgo/runtime_state.go +++ b/op-devstack/sysgo/runtime_state.go @@ -62,7 +62,6 @@ type SingleChainInteropSupport struct { Migration *interopMigrationState FullConfigSet depset.FullConfigSetMerged DependencySet depset.DependencySet - Supervisor Supervisor } type SingleChainRuntime struct { @@ -143,8 +142,7 @@ type MultiChainRuntime struct { Chains map[string]*MultiChainNodeRuntime - PrimarySupervisor Supervisor - Supernode *SuperNode + Supernode *SuperNode FaucetService *faucet.Service TimeTravel *clock.AdvancingClock diff --git a/op-devstack/sysgo/supervisor.go b/op-devstack/sysgo/supervisor.go deleted file mode 100644 index 62f5cc9bca6..00000000000 --- a/op-devstack/sysgo/supervisor.go +++ /dev/null @@ -1,8 +0,0 @@ -package sysgo - -import "github.com/ethereum-optimism/optimism/op-devstack/stack" - -type Supervisor interface { - stack.Lifecycle - UserRPC() string -} diff --git a/op-devstack/sysgo/supervisor_kona.go b/op-devstack/sysgo/supervisor_kona.go deleted file mode 100644 index 463ce416903..00000000000 --- a/op-devstack/sysgo/supervisor_kona.go +++ /dev/null @@ -1,99 +0,0 @@ -package sysgo - -import ( - "sync" - - "github.com/ethereum-optimism/optimism/op-devstack/devtest" - "github.com/ethereum-optimism/optimism/op-devstack/stack" - "github.com/ethereum-optimism/optimism/op-service/logpipe" - "github.com/ethereum-optimism/optimism/op-service/tasks" - "github.com/ethereum-optimism/optimism/op-service/testutils/tcpproxy" - "github.com/ethereum/go-ethereum/log" -) - -type KonaSupervisor struct { - mu sync.Mutex - - name string - userRPC string - - userProxy *tcpproxy.Proxy - - execPath string - args []string - // Each entry is of the form "key=value". - env []string - - p devtest.CommonT - - sub *SubProcess -} - -var _ stack.Lifecycle = (*KonaSupervisor)(nil) - -func (s *KonaSupervisor) UserRPC() string { - return s.userRPC -} - -func (s *KonaSupervisor) Start() { - s.mu.Lock() - defer s.mu.Unlock() - if s.sub != nil { - s.p.Logger().Warn("Kona-supervisor already started") - return - } - - // Create a proxy for the user RPC, - // so other services can connect, and stay connected, across restarts. - if s.userProxy == nil { - s.userProxy = tcpproxy.New(s.p.Logger()) - s.p.Require().NoError(s.userProxy.Start()) - s.p.Cleanup(func() { - s.userProxy.Close() - }) - s.userRPC = "http://" + s.userProxy.Addr() - } - - // Create the sub-process. - // We pipe sub-process logs to the test-logger. - // And inspect them along the way, to get the RPC server address. - logOut := logpipe.ToLoggerWithMinLevel(s.p.Logger().New("src", "stdout"), log.LevelWarn) - logErr := logpipe.ToLoggerWithMinLevel(s.p.Logger().New("src", "stderr"), log.LevelWarn) - userRPC := make(chan string, 1) - onLogEntry := func(e logpipe.LogEntry) { - switch e.LogMessage() { - case "RPC server bound to address": - userRPC <- "http://" + e.FieldValue("addr").(string) - } - } - stdOutLogs := logpipe.LogCallback(func(line []byte) { - e := logpipe.ParseRustStructuredLogs(line) - logOut(e) - onLogEntry(e) - }) - stdErrLogs := logpipe.LogCallback(func(line []byte) { - e := logpipe.ParseRustStructuredLogs(line) - logErr(e) - }) - - s.sub = NewSubProcess(s.p, stdOutLogs, stdErrLogs) - err := s.sub.Start(s.execPath, s.args, s.env) - s.p.Require().NoError(err, "Must start") - - var userRPCAddr string - s.p.Require().NoError(tasks.Await(s.p.Ctx(), userRPC, &userRPCAddr), "need user RPC") - - s.userProxy.SetUpstream(ProxyAddr(s.p.Require(), userRPCAddr)) -} - -func (s *KonaSupervisor) Stop() { - s.mu.Lock() - defer s.mu.Unlock() - if s.sub == nil { - s.p.Logger().Warn("kona-supervisor already stopped") - return - } - err := s.sub.Stop(true) - s.p.Require().NoError(err, "Must stop") - s.sub = nil -} diff --git a/op-devstack/sysgo/supervisor_op.go b/op-devstack/sysgo/supervisor_op.go deleted file mode 100644 index dffdd8216b7..00000000000 --- a/op-devstack/sysgo/supervisor_op.go +++ /dev/null @@ -1,80 +0,0 @@ -package sysgo - -import ( - "context" - "sync" - - "github.com/ethereum-optimism/optimism/op-devstack/stack" - "github.com/ethereum-optimism/optimism/op-service/testutils/tcpproxy" - - "github.com/ethereum-optimism/optimism/op-devstack/devtest" - "github.com/ethereum/go-ethereum/log" - - supervisorConfig "github.com/ethereum-optimism/optimism/op-supervisor/config" - "github.com/ethereum-optimism/optimism/op-supervisor/supervisor" -) - -type OpSupervisor struct { - mu sync.Mutex - - name string - userRPC string - - cfg *supervisorConfig.Config - p devtest.CommonT - logger log.Logger - - service *supervisor.SupervisorService - - proxy *tcpproxy.Proxy -} - -var _ stack.Lifecycle = (*OpSupervisor)(nil) - -func (s *OpSupervisor) UserRPC() string { - return s.userRPC -} - -func (s *OpSupervisor) Start() { - s.mu.Lock() - defer s.mu.Unlock() - if s.service != nil { - s.logger.Warn("Supervisor already started") - return - } - - if s.proxy == nil { - s.proxy = tcpproxy.New(s.logger.New("proxy", "supervisor")) - s.p.Require().NoError(s.proxy.Start()) - s.p.Cleanup(func() { - s.proxy.Close() - }) - s.userRPC = "http://" + s.proxy.Addr() - } - - super, err := supervisor.SupervisorFromConfig(context.Background(), s.cfg, s.logger) - s.p.Require().NoError(err) - - s.service = super - s.logger.Info("Starting supervisor") - err = super.Start(context.Background()) - s.p.Require().NoError(err, "supervisor failed to start") - s.logger.Info("Started supervisor") - s.proxy.SetUpstream(ProxyAddr(s.p.Require(), super.RPC())) -} - -func (s *OpSupervisor) Stop() { - s.mu.Lock() - defer s.mu.Unlock() - if s.service == nil { - s.logger.Warn("Supervisor already stopped") - return - } - ctx, cancel := context.WithCancel(context.Background()) - cancel() // force-quit - s.logger.Info("Closing supervisor") - closeErr := s.service.Stop(ctx) - s.logger.Info("Closed supervisor", "err", closeErr) - - s.service = nil -} diff --git a/rust/kona/tests/supervisor/l2reorg/init_exec_msg_test.go b/rust/kona/tests/supervisor/l2reorg/init_exec_msg_test.go deleted file mode 100644 index 235f3060235..00000000000 --- a/rust/kona/tests/supervisor/l2reorg/init_exec_msg_test.go +++ /dev/null @@ -1,247 +0,0 @@ -package l2reorg - -import ( - "math/rand" - "testing" - "time" - - "github.com/ethereum-optimism/optimism/op-acceptance-tests/tests/interop" - "github.com/ethereum-optimism/optimism/op-core/predeploys" - "github.com/ethereum-optimism/optimism/op-devstack/devtest" - "github.com/ethereum-optimism/optimism/op-devstack/dsl" - "github.com/ethereum-optimism/optimism/op-devstack/presets" - "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait" - "github.com/ethereum-optimism/optimism/op-service/bigs" - "github.com/ethereum-optimism/optimism/op-service/eth" - "github.com/ethereum-optimism/optimism/op-service/txintent" - "github.com/ethereum-optimism/optimism/op-service/txintent/bindings" - "github.com/ethereum-optimism/optimism/op-service/txplan" - "github.com/ethereum-optimism/optimism/op-test-sequencer/sequencer/seqtypes" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/stretchr/testify/require" -) - -// Acceptance Test: https://github.com/ethereum-optimism/optimism/blob/develop/op-acceptance-tests/tests/interop/reorgs/init_exec_msg_test.go#L25 -func TestReorgInitExecMsg(gt *testing.T) { - t := devtest.SerialT(gt) - ctx := t.Ctx() - - sys := presets.NewSimpleInterop(t) - l := sys.Log - - ia := sys.TestSequencer.Escape().ControlAPI(sys.L2ChainA.ChainID()) - - // three EOAs for triggering the init and exec interop txs, as well as a simple transfer tx - alice := sys.FunderA.NewFundedEOA(eth.OneHundredthEther) - bob := sys.FunderB.NewFundedEOA(eth.OneHundredthEther) - cathrine := sys.FunderA.NewFundedEOA(eth.OneHundredthEther) - - sys.L1Network.WaitForBlock() - sys.L2ChainA.WaitForBlock() - - // stop batchers on chain A and on chain B - sys.L2BatcherA.Stop() - sys.L2BatcherB.Stop() - - // deploy event logger on chain A - var eventLoggerAddress common.Address - { - tx := txplan.NewPlannedTx(txplan.Combine( - alice.Plan(), - txplan.WithData(common.FromHex(bindings.EventloggerBin)), - )) - res, err := tx.Included.Eval(ctx) - require.NoError(t, err) - - eventLoggerAddress = res.ContractAddress - l.Info("deployed EventLogger", "chainID", tx.ChainID.Value(), "address", eventLoggerAddress) - } - - sys.L1Network.WaitForBlock() - - var initTrigger *txintent.InitTrigger - // prepare init trigger (i.e. what logs to emit on chain A) - { - rng := rand.New(rand.NewSource(time.Now().UnixNano())) - nTopics := 3 - lenData := 10 - initTrigger = interop.RandomInitTrigger(rng, eventLoggerAddress, nTopics, lenData) - - l.Info("created init trigger", "address", eventLoggerAddress, "topics", nTopics, "lenData", lenData) - } - - // wait for chain B to catch up to chain A if necessary - sys.L2ChainB.CatchUpTo(sys.L2ChainA) - - var initTx *txintent.IntentTx[*txintent.InitTrigger, *txintent.InteropOutput] - var initReceipt *types.Receipt - // prepare and include initiating message on chain A - { - initTx = txintent.NewIntent[*txintent.InitTrigger, *txintent.InteropOutput](alice.Plan()) - initTx.Content.Set(initTrigger) - var err error - initReceipt, err = initTx.PlannedTx.Included.Eval(ctx) - require.NoError(t, err) - - l.Info("initiating message included", "chain", sys.L2ChainA.ChainID(), "block_number", initReceipt.BlockNumber, "block_hash", initReceipt.BlockHash, "now", time.Now().Unix()) - } - - // stop sequencer on chain A so that we later force a reorg/removal of the init msg - sys.L2CLA.StopSequencer() - - // at least one block between the init tx on chain A and the exec tx on chain B - sys.L2ChainB.WaitForBlock() - - var execTx *txintent.IntentTx[*txintent.ExecTrigger, *txintent.InteropOutput] - var execReceipt *types.Receipt - // prepare and include executing message on chain B - { - execTx = txintent.NewIntent[*txintent.ExecTrigger, *txintent.InteropOutput](bob.Plan()) - execTx.Content.DependOn(&initTx.Result) - // single event in tx so index is 0. ExecuteIndexed returns a lambda to transform InteropOutput to a new ExecTrigger - execTx.Content.Fn(txintent.ExecuteIndexed(predeploys.CrossL2InboxAddr, &initTx.Result, 0)) - var err error - execReceipt, err = execTx.PlannedTx.Included.Eval(ctx) - require.NoError(t, err) - require.Equal(t, 1, len(execReceipt.Logs)) - - l.Info("executing message included", "chain", sys.L2ChainB.ChainID(), "block_number", execReceipt.BlockNumber, "block_hash", execReceipt.BlockHash, "now", time.Now().Unix()) - } - - // record divergence block numbers and original refs for future validation checks - var divergenceBlockNumber_A, divergenceBlockNumber_B uint64 - var originalRef_A, originalRef_B eth.L2BlockRef - - // sequence a conflicting block with a simple transfer tx, based on the parent of the parent of the unsafe head - { - var err error - divergenceBlockNumber_B = bigs.Uint64Strict(execReceipt.BlockNumber) - originalRef_B, err = sys.L2ELB.Escape().L2EthClient().L2BlockRefByHash(ctx, execReceipt.BlockHash) - require.NoError(t, err, "Expected to be able to call L2BlockRefByHash API, but got error") - - headToReorgA := initReceipt.BlockHash - headToReorgARef, err := sys.L2ELA.Escape().L2EthClient().L2BlockRefByHash(ctx, headToReorgA) - require.NoError(t, err, "Expected to be able to call L2BlockRefByHash API, but got error") - - divergenceBlockNumber_A = headToReorgARef.Number - originalRef_A = headToReorgARef - - parentOfHeadToReorgA := headToReorgARef.ParentID() - parentsL1Origin, err := sys.L2ELA.Escape().L2EthClient().L2BlockRefByHash(ctx, parentOfHeadToReorgA.Hash) - require.NoError(t, err, "Expected to be able to call L2BlockRefByHash API, but got error") - - nextL1Origin := parentsL1Origin.L1Origin.Number + 1 - l1Origin, err := sys.L1EL.EthClient().InfoByNumber(ctx, nextL1Origin) - require.NoError(t, err, "Expected to get block number %v from L1 execution client", nextL1Origin) - l1OriginHash := l1Origin.Hash() - - l.Info("Sequencing a conflicting block", "chain", sys.L2ChainA.ChainID(), "newL1Origin", eth.ToBlockID(l1Origin), "headToReorgA", headToReorgARef, "parent", parentOfHeadToReorgA, "parent_l1_origin", parentsL1Origin.L1Origin) - - err = ia.New(ctx, seqtypes.BuildOpts{ - Parent: parentOfHeadToReorgA.Hash, - L1Origin: &l1OriginHash, - }) - require.NoError(t, err, "Expected to be able to create a new block job for sequencing on op-test-sequencer, but got error") - - // include simple transfer tx in opened block - { - to := cathrine.PlanTransfer(alice.Address(), eth.OneGWei) - opt := txplan.Combine(to) - ptx := txplan.NewPlannedTx(opt) - signed_tx, err := ptx.Signed.Eval(ctx) - require.NoError(t, err, "Expected to be able to evaluate a planned transaction on op-test-sequencer, but got error") - txdata, err := signed_tx.MarshalBinary() - require.NoError(t, err, "Expected to be able to marshal a signed transaction on op-test-sequencer, but got error") - - err = ia.IncludeTx(ctx, txdata) - require.NoError(t, err, "Expected to be able to include a signed transaction on op-test-sequencer, but got error") - } - - err = ia.Next(ctx) - require.NoError(t, err, "Expected to be able to call Next() after New() on op-test-sequencer, but got error") - } - - // sequence a second block with op-test-sequencer - { - unsafe := sys.L2ELA.BlockRefByLabel(eth.Unsafe) - l.Info("Current unsafe ref", "unsafeHead", unsafe) - err := ia.New(ctx, seqtypes.BuildOpts{ - Parent: unsafe.Hash, - L1Origin: nil, - }) - require.NoError(t, err, "Expected to be able to create a new block job for sequencing on op-test-sequencer, but got error") - - err = ia.Next(ctx) - require.NoError(t, err, "Expected to be able to call Next() after New() on op-test-sequencer, but got error") - } - - // continue sequencing with op-node - sys.L2CLA.StartSequencer() - - // start batchers on chain A and on chain B - sys.L2BatcherA.Start() - sys.L2BatcherB.Start() - - // wait and confirm reorgs on chain A and B - dsl.CheckAll(t, - sys.L2ELA.ReorgExactFn(eth.L2BlockRef{ - Number: divergenceBlockNumber_A, - Hash: originalRef_A.Hash, - ParentHash: originalRef_A.ParentID().Hash, - }, 30), - sys.L2ELB.ReorgExactFn(eth.L2BlockRef{ - Number: divergenceBlockNumber_B, - Hash: originalRef_B.Hash, - ParentHash: originalRef_B.ParentID().Hash, - }, 30), - ) - - // executing tx should eventually be no longer confirmed on chain B - require.Eventually(t, func() bool { - receipt, err := sys.L2ELB.Escape().EthClient().TransactionReceipt(ctx, execReceipt.TxHash) - if err == nil || err.Error() != "not found" { // want to get "not found" error - return false - } - if receipt != nil { // want to get nil receipt - return false - } - return true - }, 60*time.Second, 3*time.Second, "Expected for the executing tx to be removed from chain B") - - err := wait.For(ctx, 5*time.Second, func() (bool, error) { - safeL2Head_supervisor_A := sys.Supervisor.SafeBlockID(sys.L2ChainA.ChainID()).Hash - safeL2Head_supervisor_B := sys.Supervisor.SafeBlockID(sys.L2ChainB.ChainID()).Hash - safeL2Head_sequencer_A := sys.L2CLA.SafeL2BlockRef() - safeL2Head_sequencer_B := sys.L2CLB.SafeL2BlockRef() - - if safeL2Head_sequencer_A.Number < divergenceBlockNumber_A { - l.Info("Safe ref number is still behind divergence block A number", "divergence", divergenceBlockNumber_A, "safe", safeL2Head_sequencer_A.Number) - return false, nil - } - - if safeL2Head_sequencer_B.Number < divergenceBlockNumber_B { - l.Info("Safe ref number is still behind divergence block B number", "divergence", divergenceBlockNumber_B, "safe", safeL2Head_sequencer_B.Number) - return false, nil - } - - if safeL2Head_sequencer_A.Hash.Cmp(safeL2Head_supervisor_A) != 0 { - l.Info("Safe ref still not the same on supervisor and sequencer A", "supervisor", safeL2Head_supervisor_A, "sequencer", safeL2Head_sequencer_A.Hash) - return false, nil - } - - if safeL2Head_sequencer_B.Hash.Cmp(safeL2Head_supervisor_B) != 0 { - l.Info("Safe ref still not the same on supervisor and sequencer B", "supervisor", safeL2Head_supervisor_B, "sequencer", safeL2Head_sequencer_B.Hash) - return false, nil - } - - l.Info("Safe ref the same across supervisor and sequencers", - "supervisor_A", safeL2Head_supervisor_A, - "sequencer_A", safeL2Head_sequencer_A.Hash, - "supervisor_B", safeL2Head_supervisor_B, - "sequencer_B", safeL2Head_sequencer_B.Hash) - - return true, nil - }) - require.NoError(t, err, "Expected to get same safe ref on both supervisor and sequencer eventually") -} diff --git a/rust/kona/tests/supervisor/l2reorgAfterL1reorg/reorg_test.go b/rust/kona/tests/supervisor/l2reorgAfterL1reorg/reorg_test.go deleted file mode 100644 index f253f5c81c2..00000000000 --- a/rust/kona/tests/supervisor/l2reorgAfterL1reorg/reorg_test.go +++ /dev/null @@ -1,162 +0,0 @@ -package sysgo - -import ( - "testing" - "time" - - "github.com/ethereum-optimism/optimism/op-devstack/devtest" - "github.com/ethereum-optimism/optimism/op-devstack/presets" - "github.com/ethereum-optimism/optimism/op-service/apis" - "github.com/ethereum-optimism/optimism/op-service/eth" - "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" - "github.com/ethereum-optimism/optimism/op-test-sequencer/sequencer/seqtypes" - spresets "github.com/ethereum-optimism/optimism/rust/kona/tests/supervisor/presets" - "github.com/ethereum/go-ethereum/common" - "github.com/stretchr/testify/require" -) - -type checksFunc func(t devtest.T, sys *presets.SimpleInterop) - -func TestL2ReorgAfterL1Reorg(gt *testing.T) { - gt.Run("unsafe reorg", func(gt *testing.T) { - var crossSafeRef, localSafeRef, unsafeRef eth.BlockID - pre := func(t devtest.T, sys *presets.SimpleInterop) { - ss := sys.Supervisor.FetchSyncStatus() - crossSafeRef = ss.Chains[sys.L2ChainA.ChainID()].CrossSafe - localSafeRef = ss.Chains[sys.L2ChainA.ChainID()].LocalSafe - unsafeRef = ss.Chains[sys.L2ChainA.ChainID()].LocalUnsafe.ID() - } - post := func(t devtest.T, sys *presets.SimpleInterop) { - require.True(t, sys.L2ELA.IsCanonical(crossSafeRef), "Previous cross-safe block should still be canonical") - require.True(t, sys.L2ELA.IsCanonical(localSafeRef), "Previous local-safe block should still be canonical") - require.False(t, sys.L2ELA.IsCanonical(unsafeRef), "Previous unsafe block should have been reorged") - } - testL2ReorgAfterL1Reorg(gt, 3, pre, post) - }) - - gt.Run("unsafe, local-safe, cross-unsafe, cross-safe reorgs", func(gt *testing.T) { - var crossSafeRef, crossUnsafeRef, localSafeRef, unsafeRef eth.BlockID - pre := func(t devtest.T, sys *presets.SimpleInterop) { - ss := sys.Supervisor.FetchSyncStatus() - crossUnsafeRef = ss.Chains[sys.L2ChainA.ChainID()].CrossUnsafe - crossSafeRef = ss.Chains[sys.L2ChainA.ChainID()].CrossSafe - localSafeRef = ss.Chains[sys.L2ChainA.ChainID()].LocalSafe - unsafeRef = ss.Chains[sys.L2ChainA.ChainID()].LocalUnsafe.ID() - } - post := func(t devtest.T, sys *presets.SimpleInterop) { - require.False(t, sys.L2ELA.IsCanonical(crossSafeRef), "Previous cross-safe block should have been reorged") - require.False(t, sys.L2ELA.IsCanonical(crossUnsafeRef), "Previous cross-unsafe block should have been reorged") - require.False(t, sys.L2ELA.IsCanonical(localSafeRef), "Previous local-safe block should have been reorged") - require.False(t, sys.L2ELA.IsCanonical(unsafeRef), "Previous unsafe block should have been reorged") - } - testL2ReorgAfterL1Reorg(gt, 10, pre, post) - }) -} - -// testL2ReorgAfterL1Reorg tests that the L2 chain reorgs after an L1 reorg, and takes n, number of blocks to reorg, as parameter -// for unsafe reorgs - n must be at least >= confDepth, which is 2 in our test deployments -// for cross-safe reorgs - n must be at least >= safe distance, which is 10 in our test deployments (set in -// op-e2e/e2eutils/geth/geth.go when initialising FakePoS) -// pre- and post-checks are sanity checks to ensure that the blocks we expected to be reorged were indeed reorged or not -func testL2ReorgAfterL1Reorg(gt *testing.T, n int, preChecks, postChecks checksFunc) { - t := devtest.SerialT(gt) - ctx := t.Ctx() - - sys := spresets.NewSimpleInteropMinimal(t) - ts := sys.TestSequencer.Escape().ControlAPI(sys.L1Network.ChainID()) - - sys.L1Network.WaitForBlock() - - sys.L1CL.Stop() - - // sequence a few L1 and L2 blocks - for range n + 1 { - sequenceL1Block(t, ts, common.Hash{}) - - sys.L2ChainA.WaitForBlock() - sys.L2ChainA.WaitForBlock() - } - - // select a divergence block to reorg from - var divergence eth.L1BlockRef - { - tip := sys.L1EL.BlockRefByLabel(eth.Unsafe) - require.Greater(t, tip.Number, uint64(n), "n is larger than L1 tip, cannot reorg out block number `tip-n`") - - divergence = sys.L1EL.BlockRefByNumber(tip.Number - uint64(n)) - } - - // print the chains before sequencing an alternative L1 block - sys.L2ChainA.PrintChain() - sys.L1Network.PrintChain() - - // pre reorg trigger validations and checks - preChecks(t, sys) - - tipL2_preReorg := sys.L2ELA.BlockRefByLabel(eth.Unsafe) - - // reorg the L1 chain -- sequence an alternative L1 block from divergence block parent - sequenceL1Block(t, ts, divergence.ParentHash) - - // continue building on the alternative L1 chain - sys.L1CL.Start() - - // confirm L1 reorged - sys.L1EL.ReorgTriggered(divergence, 5) - - // wait until L2 chain A cross-safe ref caught up to where it was before the reorg - sys.L2CLA.Reached(types.CrossSafe, tipL2_preReorg.Number, 50) - - // test that latest chain A unsafe is not referencing a reorged L1 block (through the L1Origin field) - require.Eventually(t, func() bool { - unsafe := sys.L2ELA.BlockRefByLabel(eth.Unsafe) - - block, err := sys.L1EL.Escape().EthClient().InfoByNumber(ctx, unsafe.L1Origin.Number) - if err != nil { - sys.Log.Warn("failed to get L1 block info by number", "number", unsafe.L1Origin.Number, "err", err) - return false - } - - sys.Log.Info("current unsafe ref", "tip", unsafe, "tip_origin", unsafe.L1Origin, "l1blk", eth.InfoToL1BlockRef(block)) - - // print the chains so we have information to debug if the test fails - sys.L2ChainA.PrintChain() - sys.L1Network.PrintChain() - - return block.Hash() == unsafe.L1Origin.Hash - }, 120*time.Second, 7*time.Second, "L1 block origin hash should match hash of block on L1 at that number. If not, it means there was a reorg, and L2 blocks L1Origin field is referencing a reorged block.") - - // confirm all L1Origin fields point to canonical blocks - require.Eventually(t, func() bool { - ref := sys.L2ELA.BlockRefByLabel(eth.Unsafe) - var err error - - // wait until L2 chains' L1Origin points to a L1 block after the one that was reorged - if ref.L1Origin.Number < divergence.Number { - return false - } - - sys.Log.Info("L2 chain progressed, pointing to newer L1 block", "ref", ref, "ref_origin", ref.L1Origin, "divergence", divergence) - - for i := ref.Number; i > 0 && ref.L1Origin.Number >= divergence.Number; i-- { - ref, err = sys.L2ELA.Escape().L2EthClient().L2BlockRefByNumber(ctx, i) - if err != nil { - return false - } - - if !sys.L1EL.IsCanonical(ref.L1Origin) { - return false - } - } - - return true - }, 120*time.Second, 5*time.Second, "all L1Origin fields should point to canonical L1 blocks") - - // post reorg test validations and checks - postChecks(t, sys) -} - -func sequenceL1Block(t devtest.T, ts apis.TestSequencerControlAPI, parent common.Hash) { - require.NoError(t, ts.New(t.Ctx(), seqtypes.BuildOpts{Parent: parent})) - require.NoError(t, ts.Next(t.Ctx())) -} diff --git a/rust/kona/tests/supervisor/pre_interop/helpers_test.go b/rust/kona/tests/supervisor/pre_interop/helpers_test.go deleted file mode 100644 index 9b93b79fb13..00000000000 --- a/rust/kona/tests/supervisor/pre_interop/helpers_test.go +++ /dev/null @@ -1,14 +0,0 @@ -package preinterop - -import ( - "github.com/ethereum-optimism/optimism/op-devstack/devtest" - "github.com/ethereum-optimism/optimism/op-devstack/presets" - spresets "github.com/ethereum-optimism/optimism/rust/kona/tests/supervisor/presets" -) - -func newMinimalPreInterop(t devtest.T) *presets.SimpleInterop { - return spresets.NewSimpleInteropMinimal(t, - spresets.WithSuggestedInteropActivationOffset(30), - spresets.WithInteropNotAtGenesis(), - ) -} diff --git a/rust/kona/tests/supervisor/pre_interop/post_test.go b/rust/kona/tests/supervisor/pre_interop/post_test.go deleted file mode 100644 index 04424557756..00000000000 --- a/rust/kona/tests/supervisor/pre_interop/post_test.go +++ /dev/null @@ -1,208 +0,0 @@ -package preinterop - -import ( - "math/rand" - "testing" - "time" - - "github.com/ethereum-optimism/optimism/op-acceptance-tests/tests/interop" - "github.com/ethereum-optimism/optimism/op-chain-ops/genesis" - "github.com/ethereum-optimism/optimism/op-core/forks" - "github.com/ethereum-optimism/optimism/op-core/predeploys" - "github.com/ethereum-optimism/optimism/op-devstack/devtest" - "github.com/ethereum-optimism/optimism/op-devstack/dsl" - "github.com/ethereum-optimism/optimism/op-devstack/presets" - "github.com/ethereum-optimism/optimism/op-service/eth" - stypes "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" - "github.com/ethereum/go-ethereum/common" -) - -func testSupervisorActivationBlock(t devtest.T, sys *presets.SimpleInterop, net *dsl.L2Network, activationBlock eth.BlockID) { - require := t.Require() - - // wait for some time to ensure the interop activation block is become cross-safe - t.Logger().Info("Waiting for interop activation block to be cross-safe") - sys.Supervisor.WaitForL2HeadToAdvanceTo(net.ChainID(), stypes.CrossSafe, activationBlock) - - interopTime := net.Escape().ChainConfig().InteropTime - pre := net.LatestBlockBeforeTimestamp(t, *interopTime) - require.NotNil(pre, "Pre-interop block should be found before interop time") - - // make sure pre-interop block is parent of activation block - require.Equal(pre.Number, activationBlock.Number-1, "Activation block should be one after pre-interop block") - - // fetching the source for the pre-interop block should return the error - // this is to make sure that we only store the blocks after interop - _, err := sys.Supervisor.Escape().QueryAPI().CrossDerivedToSource(t.Ctx(), net.ChainID(), pre.ID()) - require.Error(err, "CrossDerivedToSource should error before interop") - - // fetch the source for the activation block - derivedFrom, err := sys.Supervisor.Escape().QueryAPI().CrossDerivedToSource(t.Ctx(), net.ChainID(), activationBlock) - require.NoError(err, "CrossDerivedToSource should not error after interop") - require.NotNil(derivedFrom, "CrossDerivedToSource should return a valid source block") -} - -// Acceptance Test: https://github.com/ethereum-optimism/optimism/blob/develop/op-acceptance-tests/tests/interop/upgrade/post_test.go -// test case modified to check the correctness of the supervisor activation block as well -func TestPostInbox(gt *testing.T) { - t := devtest.ParallelT(gt) - sys := newMinimalPreInterop(t) - devtest.RunParallel(t, sys.L2Networks(), func(t devtest.T, net *dsl.L2Network) { - require := t.Require() - activationBlock := net.AwaitActivation(t, forks.Interop) - - el := net.PrimaryEL() - implAddrBytes, err := el.EthClient().GetStorageAt(t.Ctx(), predeploys.CrossL2InboxAddr, - genesis.ImplementationSlot, activationBlock.Hash.String()) - require.NoError(err) - implAddr := common.BytesToAddress(implAddrBytes[:]) - require.NotEqual(common.Address{}, implAddr) - code, err := el.EthClient().CodeAtHash(t.Ctx(), implAddr, activationBlock.Hash) - require.NoError(err) - require.NotEmpty(code) - - testSupervisorActivationBlock(t, sys, net, activationBlock) - }) -} - -// Acceptance Test: https://github.com/ethereum-optimism/optimism/blob/develop/op-acceptance-tests/tests/interop/upgrade/post_test.go -func TestPostInteropUpgradeComprehensive(gt *testing.T) { - t := devtest.ParallelT(gt) - sys := newMinimalPreInterop(t) - require := t.Require() - logger := t.Logger() - - // Wait for networks to be online by waiting for blocks - sys.L1Network.WaitForBlock() - sys.L2ChainA.WaitForBlock() - sys.L2ChainB.WaitForBlock() - - // Get interop activation time - interopTime := sys.L2ChainA.Escape().ChainConfig().InteropTime - require.NotNil(interopTime, "InteropTime must be set") - - logger.Info("Starting comprehensive post-interop upgrade tests", "interopTime", *interopTime) - - // 1. Check that anchor block of supervisor matches the activation block - logger.Info("Checking supervisor anchor block matches activation block") - testSupervisorAnchorBlock(t, sys) - - // 2. Check that the supervisor has safety progression for each level - logger.Info("Checking supervisor safety progression") - testSupervisorSafetyProgression(t, sys) - - // 3. Confirms that interop message can be included - logger.Info("Testing interop message inclusion") - testInteropMessageInclusion(t, sys) - - logger.Info("All comprehensive post-interop upgrade tests completed successfully") -} - -// testSupervisorAnchorBlock checks that the supervisor's anchor block has been set and matches the upgrade timestamp -func testSupervisorAnchorBlock(t devtest.T, sys *presets.SimpleInterop) { - logger := t.Logger() - - // Use the DSL helper for anchor block validation - logger.Info("Testing supervisor anchor block functionality") - - // Phase 1: Wait for L2 chains to reach interop activation time - logger.Info("Phase 1: Waiting for L2 chains to reach interop activation time") - - devtest.RunParallel(t, sys.L2Networks(), func(t devtest.T, net *dsl.L2Network) { - - // Gate test to not time out before upgrade happens - forkTimestamp := net.Escape().ChainConfig().InteropTime - t.Gate().NotNil(forkTimestamp, "Must have fork configured") - t.Gate().Greater(*forkTimestamp, uint64(0), "Must not start fork at genesis") - upgradeTime := time.Unix(int64(*forkTimestamp), 0) - if deadline, hasDeadline := t.Deadline(); hasDeadline { - t.Gate().True(upgradeTime.Before(deadline), "test must not time out before upgrade happens") - } - - activationBlock := net.AwaitActivation(t, forks.Interop) - sys.Supervisor.WaitForL2HeadToAdvanceTo(net.ChainID(), stypes.CrossSafe, activationBlock) - - logger.Info("Validating anchor block timing", - "chainID", net.ChainID(), - "derivedBlockNumber", activationBlock.Number, - "interopTime", *forkTimestamp) - }) - - logger.Info("Supervisor anchor block validation completed successfully") -} - -// testSupervisorSafetyProgression checks that supervisor has safety progression for each level -func testSupervisorSafetyProgression(t devtest.T, sys *presets.SimpleInterop) { - logger := t.Logger() - logger.Info("Testing supervisor safety progression") - - delta := uint64(3) // Minimum blocks of progression expected - dsl.CheckAll(t, - sys.L2CLA.AdvancedFn(stypes.LocalUnsafe, delta, 30), - sys.L2CLB.AdvancedFn(stypes.LocalUnsafe, delta, 30), - - sys.L2CLA.AdvancedFn(stypes.LocalSafe, delta, 30), - sys.L2CLB.AdvancedFn(stypes.LocalSafe, delta, 30), - - sys.L2CLA.AdvancedFn(stypes.CrossUnsafe, delta, 30), - sys.L2CLB.AdvancedFn(stypes.CrossUnsafe, delta, 30), - - sys.L2CLA.AdvancedFn(stypes.CrossSafe, delta, 60), - sys.L2CLB.AdvancedFn(stypes.CrossSafe, delta, 60), - ) - - logger.Info("Supervisor safety progression validation completed successfully") -} - -// testInteropMessageInclusion confirms that interop messages can be included post-upgrade -func testInteropMessageInclusion(t devtest.T, sys *presets.SimpleInterop) { - logger := t.Logger() - logger.Info("Starting interop message inclusion test") - - // Phase 1: Setup test accounts and contracts - alice, bob, eventLoggerAddress := setupInteropTestEnvironment(sys) - - // Phase 2: Send init message on chain A - rng := rand.New(rand.NewSource(1234)) - initMsg := alice.SendInitMessage(interop.RandomInitTrigger(rng, eventLoggerAddress, rng.Intn(5), rng.Intn(30))) - - // Make sure supervisor indexes block which includes init message - sys.Supervisor.WaitForUnsafeHeadToAdvance(alice.ChainID(), 2) - - // Single event in tx so index is 0 - execMsg := bob.SendExecMessage(initMsg) - - // Phase 5: Verify cross-safe progression - verifyInteropMessagesProgression(t, sys, initMsg, execMsg) - - logger.Info("Interop message inclusion test completed successfully") -} - -// setupInteropTestEnvironment creates test accounts and deploys necessary contracts -func setupInteropTestEnvironment(sys *presets.SimpleInterop) (alice, bob *dsl.EOA, eventLoggerAddress common.Address) { - - // Create EOAs for interop messaging - alice = sys.FunderA.NewFundedEOA(eth.OneHundredthEther) - bob = sys.FunderB.NewFundedEOA(eth.OneHundredthEther) - - // Deploy event logger contract on chain A - eventLoggerAddress = alice.DeployEventLogger() - - // Wait for chains to catch up - sys.L2ChainB.CatchUpTo(sys.L2ChainA) - - return alice, bob, eventLoggerAddress -} - -// verifyInteropMessagesProgression verifies cross-safe progression for both init and exec messages -func verifyInteropMessagesProgression(t devtest.T, sys *presets.SimpleInterop, initMsg *dsl.InitMessage, execMsg *dsl.ExecMessage) { - logger := t.Logger() - - // Verify cross-safe progression for both messages - dsl.CheckAll(t, - sys.L2CLA.ReachedRefFn(stypes.CrossSafe, initMsg.BlockID(), 60), - sys.L2CLB.ReachedRefFn(stypes.CrossSafe, execMsg.BlockID(), 60), - ) - - logger.Info("Cross-safe progression verified for both init and exec messages") -} diff --git a/rust/kona/tests/supervisor/pre_interop/pre_test.go b/rust/kona/tests/supervisor/pre_interop/pre_test.go deleted file mode 100644 index 869c62e7279..00000000000 --- a/rust/kona/tests/supervisor/pre_interop/pre_test.go +++ /dev/null @@ -1,109 +0,0 @@ -package preinterop - -import ( - "math/rand" - "testing" - "time" - - "github.com/ethereum/go-ethereum/common" - - "github.com/ethereum-optimism/optimism/op-acceptance-tests/tests/interop" - "github.com/ethereum-optimism/optimism/op-chain-ops/genesis" - "github.com/ethereum-optimism/optimism/op-core/predeploys" - "github.com/ethereum-optimism/optimism/op-devstack/devtest" - "github.com/ethereum-optimism/optimism/op-devstack/dsl" - "github.com/ethereum-optimism/optimism/op-service/eth" - "github.com/ethereum-optimism/optimism/op-service/txintent" - stypes "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" -) - -// Acceptance Test: https://github.com/ethereum-optimism/optimism/blob/develop/op-acceptance-tests/tests/interop/upgrade/pre_test.go -func TestPreNoInbox(gt *testing.T) { - t := devtest.ParallelT(gt) - sys := newMinimalPreInterop(t) - require := t.Require() - - t.Logger().Info("Starting") - - devtest.RunParallel(t, sys.L2Networks(), func(t devtest.T, net *dsl.L2Network) { - interopTime := net.Escape().ChainConfig().InteropTime - t.Require().NotNil(interopTime) - pre := net.LatestBlockBeforeTimestamp(t, *interopTime) - el := net.PrimaryEL() - codeAddr := common.HexToAddress("0xC0D3C0d3C0D3C0d3c0d3c0D3c0D3C0d3C0D30022") - implCode, err := el.EthClient().CodeAtHash(t.Ctx(), codeAddr, pre.Hash) - require.NoError(err) - require.Len(implCode, 0, "needs to be empty") - implAddrBytes, err := el.EthClient().GetStorageAt(t.Ctx(), predeploys.CrossL2InboxAddr, - genesis.ImplementationSlot, pre.Hash.String()) - require.NoError(err) - require.Equal(common.Address{}, common.BytesToAddress(implAddrBytes[:])) - }) - - // try access the sync-status of the supervisor, assert that the sync-status returns the expected error - devtest.RunParallel(t, sys.L2Networks(), func(t devtest.T, net *dsl.L2Network) { - interopTime := net.Escape().ChainConfig().InteropTime - - _, err := sys.Supervisor.Escape().QueryAPI().SyncStatus(t.Ctx()) - require.ErrorContains(err, "supervisor status tracker not ready") - - // confirm we are still pre-interop - require.False(net.IsActivated(*interopTime)) - t.Logger().Info("Timestamps", "interopTime", *interopTime, "now", time.Now().Unix()) - }) - - var initMsg *dsl.InitMessage - // try interop before the upgrade, confirm that messages do not get included - { - // two EOAs for triggering the init and exec interop txs - alice := sys.FunderA.NewFundedEOA(eth.OneHundredthEther) - bob := sys.FunderB.NewFundedEOA(eth.OneHundredthEther) - - interopTimeA := sys.L2ChainA.Escape().ChainConfig().InteropTime - interopTimeB := sys.L2ChainB.Escape().ChainConfig().InteropTime - - eventLoggerAddress := alice.DeployEventLogger() - - // wait for chain B to catch up to chain A if necessary - sys.L2ChainB.CatchUpTo(sys.L2ChainA) - - // send initiating message on chain A - rng := rand.New(rand.NewSource(time.Now().UnixNano())) - initMsg = alice.SendInitMessage(interop.RandomInitTrigger(rng, eventLoggerAddress, rng.Intn(3), rng.Intn(10))) - - // at least one block between the init tx on chain A and the exec tx on chain B - sys.L2ChainB.WaitForBlock() - - // send executing message on chain B and confirm we got an error - execTx := txintent.NewIntent[*txintent.ExecTrigger, *txintent.InteropOutput](bob.Plan()) - execTx.Content.DependOn(&initMsg.Tx.Result) - execTx.Content.Fn(txintent.ExecuteIndexed(predeploys.CrossL2InboxAddr, &initMsg.Tx.Result, 0)) - execReceipt, err := execTx.PlannedTx.Included.Eval(sys.T.Ctx()) - require.ErrorContains(err, "implementation not initialized", "error did not contain expected string") - require.Nil(execReceipt) - - t.Logger().Info("initReceipt", "blocknum", initMsg.Receipt.BlockNumber, "txhash", initMsg.Receipt.TxHash) - - // confirm we are still pre-interop - require.False(sys.L2ChainA.IsActivated(*interopTimeA)) - require.False(sys.L2ChainB.IsActivated(*interopTimeB)) - t.Logger().Info("Timestamps", "interopTimeA", *interopTimeA, "interopTimeB", *interopTimeB, "now", time.Now().Unix()) - } - - // check that log events from a block before activation, when converted into an access-list, fail the check-access-list RPC check - { - ctx := sys.T.Ctx() - - execTrigger, err := txintent.ExecuteIndexed(predeploys.CrossL2InboxAddr, &initMsg.Tx.Result, 0)(ctx) - require.NoError(err) - - ed := stypes.ExecutingDescriptor{Timestamp: uint64(time.Now().Unix())} - accessEntries := []stypes.Access{execTrigger.Msg.Access()} - accessList := stypes.EncodeAccessList(accessEntries) - - err = sys.Supervisor.Escape().QueryAPI().CheckAccessList(ctx, accessList, stypes.CrossSafe, ed) - require.ErrorContains(err, "conflicting data") - } - - t.Logger().Info("Done") -} diff --git a/rust/kona/tests/supervisor/presets/interop_minimal.go b/rust/kona/tests/supervisor/presets/interop_minimal.go deleted file mode 100644 index 0d5ad7e09fa..00000000000 --- a/rust/kona/tests/supervisor/presets/interop_minimal.go +++ /dev/null @@ -1,39 +0,0 @@ -package presets - -import ( - "os" - "path/filepath" - - "github.com/ethereum-optimism/optimism/op-chain-ops/devkeys" - "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/artifacts" - "github.com/ethereum-optimism/optimism/op-devstack/devtest" - oppresets "github.com/ethereum-optimism/optimism/op-devstack/presets" - "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/intentbuilder" -) - -func NewSimpleInteropMinimal(t devtest.T, opts ...oppresets.Option) *oppresets.SimpleInterop { - artifactsPath := os.Getenv("OP_DEPLOYER_ARTIFACTS") - if artifactsPath == "" { - panic("OP_DEPLOYER_ARTIFACTS is not set") - } - contractArtifacts := artifacts.MustNewFileLocator(filepath.Join(artifactsPath, "src")) - - baseOpts := []oppresets.Option{ - oppresets.WithDeployerOptions( - func(_ devtest.T, _ devkeys.Keys, builder intentbuilder.Builder) { - builder.WithL1ContractsLocator(contractArtifacts) - builder.WithL2ContractsLocator(contractArtifacts) - }, - ), - } - baseOpts = append(baseOpts, opts...) - return oppresets.NewSimpleInterop(t, baseOpts...) -} - -func WithSuggestedInteropActivationOffset(offset uint64) oppresets.Option { - return oppresets.WithSuggestedInteropActivationOffset(offset) -} - -func WithInteropNotAtGenesis() oppresets.Option { - return oppresets.WithInteropNotAtGenesis() -} From ac00a0b677124b6946230c832180d343c0128d01 Mon Sep 17 00:00:00 2001 From: Adrian Sutton Date: Tue, 19 May 2026 09:50:50 +1000 Subject: [PATCH 2/3] chore(devstack): rename SupernodeProofs interop factories to drop suffix Now that 'interop' implies supernode-backed by default, the NewSimpleInteropSupernodeProofs / NewSingleChainInteropSupernodeProofs names carried redundant suffixes. Rename them to NewSimpleInterop and NewSingleChainInterop, matching the surviving struct names. The Isthmus and SuperRootAtGenesis variants keep their distinguishing suffixes since they configure non-default fork activations. --- .../interop_fault_proofs_test.go | 2 +- .../tests/interop/proofs/challenger_test.go | 8 +++--- .../tests/interop/proofs/fpp/fpp_test.go | 4 +-- .../tests/interop/proofs/proposer_test.go | 2 +- .../serial/interop_fault_proofs_test.go | 26 +++++++++---------- .../proofs/withdrawal/withdrawal_test.go | 2 +- .../super_dispute_game_via_upgrade_test.go | 2 +- .../upgrade-singlechain/crossl2inbox_test.go | 2 +- op-devstack/presets/interop.go | 12 ++++----- 9 files changed, 30 insertions(+), 30 deletions(-) diff --git a/op-acceptance-tests/tests/interop/proofs-singlechain/interop_fault_proofs_test.go b/op-acceptance-tests/tests/interop/proofs-singlechain/interop_fault_proofs_test.go index 551bd5661d7..0d8faa8db4e 100644 --- a/op-acceptance-tests/tests/interop/proofs-singlechain/interop_fault_proofs_test.go +++ b/op-acceptance-tests/tests/interop/proofs-singlechain/interop_fault_proofs_test.go @@ -10,6 +10,6 @@ import ( func TestInteropSingleChainFaultProofs(gt *testing.T) { t := devtest.SerialT(gt) - sys := presets.NewSingleChainInteropSupernodeProofs(t) + sys := presets.NewSingleChainInterop(t) sfp.RunSingleChainSuperFaultProofSmokeTest(t, sys) } diff --git a/op-acceptance-tests/tests/interop/proofs/challenger_test.go b/op-acceptance-tests/tests/interop/proofs/challenger_test.go index 94ef07bba02..f4a96843656 100644 --- a/op-acceptance-tests/tests/interop/proofs/challenger_test.go +++ b/op-acceptance-tests/tests/interop/proofs/challenger_test.go @@ -16,7 +16,7 @@ import ( func TestChallengerPlaysGame(gt *testing.T) { t := devtest.ParallelT(gt) - sys := presets.NewSimpleInteropSupernodeProofs(t, presets.WithoutHonestProposer()) + sys := presets.NewSimpleInterop(t, presets.WithoutHonestProposer()) dsl.CheckAll(t, sys.L2CLA.AdvancedFn(types.CrossSafe, 1, 30), sys.L2CLB.AdvancedFn(types.CrossSafe, 1, 30), @@ -38,7 +38,7 @@ func TestChallengerPlaysGame(gt *testing.T) { func TestChallengerRespondsToMultipleInvalidClaims(gt *testing.T) { t := devtest.ParallelT(gt) - sys := presets.NewSimpleInteropSupernodeProofs(t, presets.WithoutHonestProposer()) + sys := presets.NewSimpleInterop(t, presets.WithoutHonestProposer()) dsl.CheckAll(t, sys.L2CLA.AdvancedFn(types.CrossSafe, 1, 30), sys.L2CLB.AdvancedFn(types.CrossSafe, 1, 30), @@ -61,7 +61,7 @@ func TestChallengerRespondsToMultipleInvalidClaims(gt *testing.T) { func TestChallengerRespondsToMultipleInvalidClaimsEOA(gt *testing.T) { t := devtest.ParallelT(gt) - sys := presets.NewSimpleInteropSupernodeProofs(t, presets.WithoutHonestProposer()) + sys := presets.NewSimpleInterop(t, presets.WithoutHonestProposer()) dsl.CheckAll(t, sys.L2CLA.AdvancedFn(types.CrossSafe, 1, 30), sys.L2CLB.AdvancedFn(types.CrossSafe, 1, 30), @@ -87,7 +87,7 @@ func TestChallengerRespondsToMultipleInvalidClaimsEOA(gt *testing.T) { func TestChallengerCountersPreGenesisGame(gt *testing.T) { t := devtest.SerialT(gt) - sys := presets.NewSimpleInteropSupernodeProofs( + sys := presets.NewSimpleInterop( t, presets.WithPreGenesisSuperGame( eth.Bytes32(common.HexToHash("0x1111000000000000000000000000000000000000000000000000000000000000")), diff --git a/op-acceptance-tests/tests/interop/proofs/fpp/fpp_test.go b/op-acceptance-tests/tests/interop/proofs/fpp/fpp_test.go index 661a5e134c6..184a94092bd 100644 --- a/op-acceptance-tests/tests/interop/proofs/fpp/fpp_test.go +++ b/op-acceptance-tests/tests/interop/proofs/fpp/fpp_test.go @@ -10,7 +10,7 @@ import ( func TestFPP(gt *testing.T) { t := devtest.ParallelT(gt) - sys := presets.NewSimpleInteropSupernodeProofs(t) + sys := presets.NewSimpleInterop(t) startTimestamp := max(sys.L2ChainA.Escape().RollupConfig().TimestampForBlock(1), sys.L2ChainB.Escape().RollupConfig().TimestampForBlock(1)) endTimestamp := sys.L2ChainA.Escape().RollupConfig().TimestampForBlock(5) @@ -22,7 +22,7 @@ func TestFPP(gt *testing.T) { func TestNextSuperRootNotFound(gt *testing.T) { t := devtest.ParallelT(gt) - sys := presets.NewSimpleInteropSupernodeProofs(t) + sys := presets.NewSimpleInterop(t) blockTime := sys.L2ChainA.Escape().RollupConfig().BlockTime // Need to setup situation where the next super root is not found but the next block is safe on the first chain, but not safe on the second. diff --git a/op-acceptance-tests/tests/interop/proofs/proposer_test.go b/op-acceptance-tests/tests/interop/proofs/proposer_test.go index 3da5286bca8..c4806c3b361 100644 --- a/op-acceptance-tests/tests/interop/proofs/proposer_test.go +++ b/op-acceptance-tests/tests/interop/proofs/proposer_test.go @@ -9,7 +9,7 @@ import ( func TestProposer(gt *testing.T) { t := devtest.ParallelT(gt) - sys := presets.NewSimpleInteropSupernodeProofs(t) + sys := presets.NewSimpleInterop(t) dgf := sys.DisputeGameFactory() diff --git a/op-acceptance-tests/tests/interop/proofs/serial/interop_fault_proofs_test.go b/op-acceptance-tests/tests/interop/proofs/serial/interop_fault_proofs_test.go index 0098024ec1b..05812a8cc8d 100644 --- a/op-acceptance-tests/tests/interop/proofs/serial/interop_fault_proofs_test.go +++ b/op-acceptance-tests/tests/interop/proofs/serial/interop_fault_proofs_test.go @@ -12,13 +12,13 @@ import ( func TestInteropFaultProofs(gt *testing.T) { t := devtest.ParallelT(gt) - sys := presets.NewSimpleInteropSupernodeProofs(t) + sys := presets.NewSimpleInterop(t) sfp.RunSuperFaultProofTest(t, sys) } func TestInteropFaultProofs_PreForkActivation(gt *testing.T) { t := devtest.SerialT(gt) - sys := presets.NewSimpleInteropSupernodeProofs(t, presets.WithSuggestedInteropActivationOffset(365*24*60*60)) + sys := presets.NewSimpleInterop(t, presets.WithSuggestedInteropActivationOffset(365*24*60*60)) sfp.RunPreForkActivationTest(t, sys) } @@ -26,7 +26,7 @@ func TestInteropFaultProofs_ActivationBoundary(gt *testing.T) { t := devtest.SerialT(gt) // Set interop activation ~6s (3 blocks) after genesis. A small offset keeps // the fork reachable within CI timeouts while still having pre-interop blocks. - sys := presets.NewSimpleInteropSupernodeProofs(t, + sys := presets.NewSimpleInterop(t, presets.WithSuggestedInteropActivationOffset(6), ) sfp.RunInteropActivationBoundaryTest(t, sys) @@ -34,19 +34,19 @@ func TestInteropFaultProofs_ActivationBoundary(gt *testing.T) { func TestInteropFaultProofs_ConsolidateValidCrossChainMessage(gt *testing.T) { t := devtest.ParallelT(gt) - sys := presets.NewSimpleInteropSupernodeProofs(t) + sys := presets.NewSimpleInterop(t) sfp.RunConsolidateValidCrossChainMessageTest(t, sys) } func TestInteropFaultProofs_DepositMessage(gt *testing.T) { t := devtest.SerialT(gt) - sys := presets.NewSimpleInteropSupernodeProofs(t) + sys := presets.NewSimpleInterop(t) sfp.RunDepositMessageTest(t, sys) } func TestInteropFaultProofs_VariedBlockTimes(gt *testing.T) { t := devtest.SerialT(gt) - sys := presets.NewSimpleInteropSupernodeProofs( + sys := presets.NewSimpleInterop( t, presets.WithL2BlockTimes(map[eth.ChainID]uint64{ sysgo.DefaultL2AID: 1, @@ -58,7 +58,7 @@ func TestInteropFaultProofs_VariedBlockTimes(gt *testing.T) { func TestInteropFaultProofs_VariedBlockTimes_FasterChainB(gt *testing.T) { t := devtest.SerialT(gt) - sys := presets.NewSimpleInteropSupernodeProofs( + sys := presets.NewSimpleInterop( t, presets.WithL2BlockTimes(map[eth.ChainID]uint64{ sysgo.DefaultL2AID: 2, @@ -70,7 +70,7 @@ func TestInteropFaultProofs_VariedBlockTimes_FasterChainB(gt *testing.T) { func TestInteropFaultProofs_InvalidBlock(gt *testing.T) { t := devtest.SerialT(gt) - sys := presets.NewSimpleInteropSupernodeProofs(t) + sys := presets.NewSimpleInterop(t) sfp.RunInvalidBlockTest(t, sys) } @@ -78,7 +78,7 @@ func TestInteropFaultProofs_IntraBlock(gt *testing.T) { for _, tc := range sfp.IntraBlockCases() { gt.Run(tc.Name, func(gt *testing.T) { t := devtest.SerialT(gt) - sys := presets.NewSimpleInteropSupernodeProofs(t) + sys := presets.NewSimpleInterop(t) sfp.RunIntraBlockConsolidationTest(t, sys, tc) }) } @@ -86,26 +86,26 @@ func TestInteropFaultProofs_IntraBlock(gt *testing.T) { func TestInteropFaultProofs_DepositMessage_InvalidExecution(gt *testing.T) { t := devtest.SerialT(gt) - sys := presets.NewSimpleInteropSupernodeProofs(t) + sys := presets.NewSimpleInterop(t) sfp.RunDepositMessageInvalidExecutionTest(t, sys) } func TestInteropFaultProofs_SuperrootOptimisticPairing(gt *testing.T) { t := devtest.SerialT(gt) - sys := presets.NewSimpleInteropSupernodeProofs(t) + sys := presets.NewSimpleInterop(t) sfp.RunOptimisticPairingTest(t, sys, true) } func TestInteropFaultProofs_SuperrootOptimisticPairing_NoReplacement(gt *testing.T) { t := devtest.SerialT(gt) - sys := presets.NewSimpleInteropSupernodeProofs(t) + sys := presets.NewSimpleInterop(t) sfp.RunOptimisticPairingTest(t, sys, false) } func TestInteropFaultProofs_MessageExpiry(gt *testing.T) { t := devtest.SerialT(gt) const messageExpiryWindow = uint64(12) // 12 seconds for fast test - sys := presets.NewSimpleInteropSupernodeProofs(t, + sys := presets.NewSimpleInterop(t, presets.WithMessageExpiryWindow(messageExpiryWindow), ) sfp.RunMessageExpiryTest(t, sys, messageExpiryWindow) diff --git a/op-acceptance-tests/tests/interop/proofs/withdrawal/withdrawal_test.go b/op-acceptance-tests/tests/interop/proofs/withdrawal/withdrawal_test.go index e6422e94f28..e43c5c2cbfb 100644 --- a/op-acceptance-tests/tests/interop/proofs/withdrawal/withdrawal_test.go +++ b/op-acceptance-tests/tests/interop/proofs/withdrawal/withdrawal_test.go @@ -11,7 +11,7 @@ import ( func TestSuperRootWithdrawal(gt *testing.T) { t := devtest.ParallelT(gt) - sys := presets.NewSimpleInteropSupernodeProofs(t, presets.WithTimeTravelEnabled()) + sys := presets.NewSimpleInterop(t, presets.WithTimeTravelEnabled()) sys.L1Network.WaitForOnline() initialL1Balance := eth.HalfEther diff --git a/op-acceptance-tests/tests/interop/super-via-upgrade/super_dispute_game_via_upgrade_test.go b/op-acceptance-tests/tests/interop/super-via-upgrade/super_dispute_game_via_upgrade_test.go index 56b5bc01ffc..3cb9979bb4f 100644 --- a/op-acceptance-tests/tests/interop/super-via-upgrade/super_dispute_game_via_upgrade_test.go +++ b/op-acceptance-tests/tests/interop/super-via-upgrade/super_dispute_game_via_upgrade_test.go @@ -12,7 +12,7 @@ import ( // the permissionless super games and makes SUPER_CANNON_KONA the respected type. func TestSuperRootGamesInstalledViaOPCMUpgrade(gt *testing.T) { t := devtest.SerialT(gt) - sys := presets.NewSingleChainInteropSupernodeProofs(t) + sys := presets.NewSingleChainInterop(t) sys.StandardBridge(sys.L2ChainA).VerifyRespectedGameType(gameTypes.SuperCannonKonaGameType) sys.DisputeGameFactory().VerifyGameImplPresent(gameTypes.SuperCannonKonaGameType) diff --git a/op-acceptance-tests/tests/interop/upgrade-singlechain/crossl2inbox_test.go b/op-acceptance-tests/tests/interop/upgrade-singlechain/crossl2inbox_test.go index 52dd14b1b5e..40fc9d0b238 100644 --- a/op-acceptance-tests/tests/interop/upgrade-singlechain/crossl2inbox_test.go +++ b/op-acceptance-tests/tests/interop/upgrade-singlechain/crossl2inbox_test.go @@ -18,7 +18,7 @@ import ( func TestPostInbox(gt *testing.T) { t := devtest.ParallelT(gt) offset := uint64(30) - sys := presets.NewSingleChainInteropSupernodeProofs(t, presets.WithDeployerOptions( + sys := presets.NewSingleChainInterop(t, presets.WithDeployerOptions( func(p devtest.T, keys devkeys.Keys, builder intentbuilder.Builder) { for _, l2Cfg := range builder.L2s() { l2Cfg.WithForkAtOffset(forks.Interop, &offset) diff --git a/op-devstack/presets/interop.go b/op-devstack/presets/interop.go index 00bfacba5cf..107d2cdac91 100644 --- a/op-devstack/presets/interop.go +++ b/op-devstack/presets/interop.go @@ -90,17 +90,17 @@ func (s *SingleChainInterop) StandardBridge(l2Chain *dsl.L2Network) *dsl.Standar return dsl.NewStandardBridge(s.T, l2Chain, s.L1EL) } -// NewSimpleInteropSupernodeProofs creates a fresh SimpleInterop target for the current +// NewSimpleInterop creates a fresh SimpleInterop target for the current // test using the super-root proofs system backed by op-supernode. -func NewSimpleInteropSupernodeProofs(t devtest.T, opts ...Option) *SimpleInterop { - presetCfg, _ := collectSupportedPresetConfig(t, "NewSimpleInteropSupernodeProofs", opts, twoL2SupernodeProofsPresetSupportedOptionKinds) +func NewSimpleInterop(t devtest.T, opts ...Option) *SimpleInterop { + presetCfg, _ := collectSupportedPresetConfig(t, "NewSimpleInterop", opts, twoL2SupernodeProofsPresetSupportedOptionKinds) return simpleInteropFromSupernodeProofsRuntime(t, sysgo.NewTwoL2SupernodeProofsRuntimeWithConfig(t, true, presetCfg)) } -// NewSingleChainInteropSupernodeProofs creates a fresh SingleChainInterop target for the +// NewSingleChainInterop creates a fresh SingleChainInterop target for the // current test using the single-chain super-root proofs system backed by op-supernode. -func NewSingleChainInteropSupernodeProofs(t devtest.T, opts ...Option) *SingleChainInterop { - presetCfg, _ := collectSupportedPresetConfig(t, "NewSingleChainInteropSupernodeProofs", opts, supernodeProofsPresetSupportedOptionKinds) +func NewSingleChainInterop(t devtest.T, opts ...Option) *SingleChainInterop { + presetCfg, _ := collectSupportedPresetConfig(t, "NewSingleChainInterop", opts, supernodeProofsPresetSupportedOptionKinds) return singleChainInteropFromSupernodeProofsRuntime(t, sysgo.NewSingleChainSupernodeProofsRuntimeWithConfig(t, true, presetCfg)) } From b7ad11f9b61d9bfc64f7580fa11110aa37d4bbb8 Mon Sep 17 00:00:00 2001 From: Adrian Sutton Date: Tue, 19 May 2026 10:08:40 +1000 Subject: [PATCH 3/3] chore: drop unused buildTwoL2WorldWithState --- op-devstack/sysgo/world.go | 50 -------------------------------------- 1 file changed, 50 deletions(-) diff --git a/op-devstack/sysgo/world.go b/op-devstack/sysgo/world.go index 4cc9c5ebd13..557c2a43056 100644 --- a/op-devstack/sysgo/world.go +++ b/op-devstack/sysgo/world.go @@ -103,53 +103,3 @@ func buildSingleChainWorldWithInteropAndState(t devtest.T, keys devkeys.Keys, in } return newInteropMigrationState(wb), l1Net, l2Net, depSet, wb.outFullCfgSet } - -func buildTwoL2WorldWithState(t devtest.T, keys devkeys.Keys, interopAtGenesis bool, localContractArtifactsPath string, deployerOpts ...DeployerOption) (*interopMigrationState, *L1Network, *L2Network, *L2Network, depset.FullConfigSetMerged) { - wb := newWorldBuilder(t, keys) - applyConfigLocalContractSources(t, keys, wb.builder, localContractArtifactsPath) - applyConfigCommons(t, keys, DefaultL1ID, wb.builder) - applyConfigPrefundedL2(t, keys, DefaultL1ID, DefaultL2AID, wb.builder) - applyConfigPrefundedL2(t, keys, DefaultL1ID, DefaultL2BID, wb.builder) - if interopAtGenesis { - applyConfigInteropAtGenesis(wb.builder) - } - applyConfigDeployerOptions(t, keys, wb.builder, deployerOpts) - wb.Build() - - l1ID := eth.ChainIDFromUInt64(wb.output.AppliedIntent.L1ChainID) - l1Net := &L1Network{ - name: "l1", - chainID: l1ID, - genesis: wb.outL1Genesis, - blockTime: 6, - } - - l2ANet, ok := wb.outL2Genesis[DefaultL2AID] - t.Require().True(ok, "missing L2A genesis") - l2BNet, ok := wb.outL2Genesis[DefaultL2BID] - t.Require().True(ok, "missing L2B genesis") - - l2A := &L2Network{ - name: "l2a", - chainID: DefaultL2AID, - l1ChainID: l1ID, - genesis: l2ANet, - rollupCfg: wb.outL2RollupCfg[DefaultL2AID], - deployment: wb.outL2Deployment[DefaultL2AID], - opcmImpl: wb.output.ImplementationsDeployment.OpcmV2Impl, - mipsImpl: wb.output.ImplementationsDeployment.MipsImpl, - keys: keys, - } - l2B := &L2Network{ - name: "l2b", - chainID: DefaultL2BID, - l1ChainID: l1ID, - genesis: l2BNet, - rollupCfg: wb.outL2RollupCfg[DefaultL2BID], - deployment: wb.outL2Deployment[DefaultL2BID], - opcmImpl: wb.output.ImplementationsDeployment.OpcmV2Impl, - mipsImpl: wb.output.ImplementationsDeployment.MipsImpl, - keys: keys, - } - return newInteropMigrationState(wb), l1Net, l2A, l2B, wb.outFullCfgSet -}