diff --git a/op-acceptance-tests/tests/base/conductor/leadership_transfer_test.go b/op-acceptance-tests/tests/base/conductor/leadership_transfer_test.go index 7e61b8931e7..985d9760c28 100644 --- a/op-acceptance-tests/tests/base/conductor/leadership_transfer_test.go +++ b/op-acceptance-tests/tests/base/conductor/leadership_transfer_test.go @@ -50,7 +50,7 @@ func TestConductorLeadershipTransfer(gt *testing.T) { idToConductor := make(map[string]conductorWithInfo) for _, conductor := range conductors { - conductorId := strings.TrimPrefix(conductor.String(), stack.ConductorKind.String()+"-") + conductorId := strings.TrimPrefix(conductor.String(), stack.KindConductor.String()+"-") idToConductor[conductorId] = conductorWithInfo{conductor, consensus.ServerInfo{}} } for _, memberInfo := range membership.Servers { diff --git a/op-acceptance-tests/tests/batcher/init_test.go b/op-acceptance-tests/tests/batcher/init_test.go index 1a86b3b9589..a7f4e665550 100644 --- a/op-acceptance-tests/tests/batcher/init_test.go +++ b/op-acceptance-tests/tests/batcher/init_test.go @@ -17,7 +17,7 @@ func TestMain(m *testing.M) { presets.WithCompatibleTypes(compat.SysGo), presets.WithNoDiscovery(), presets.WithTimeTravel(), - stack.MakeCommon(sysgo.WithBatcherOption(func(id stack.L2BatcherID, cfg *bss.CLIConfig) { + stack.MakeCommon(sysgo.WithBatcherOption(func(id stack.ComponentID, cfg *bss.CLIConfig) { cfg.Stopped = true // set the blob max size to 40_000 bytes for test purposes diff --git a/op-acceptance-tests/tests/batcher/throttling/init_test.go b/op-acceptance-tests/tests/batcher/throttling/init_test.go index 7bc65344ef9..f27364fe952 100644 --- a/op-acceptance-tests/tests/batcher/throttling/init_test.go +++ b/op-acceptance-tests/tests/batcher/throttling/init_test.go @@ -18,7 +18,7 @@ func TestMain(m *testing.M) { presets.DoMain(m, presets.WithMinimal(), presets.WithCompatibleTypes(compat.SysGo), - stack.MakeCommon(sysgo.WithBatcherOption(func(id stack.L2BatcherID, cfg *bss.CLIConfig) { + stack.MakeCommon(sysgo.WithBatcherOption(func(id stack.ComponentID, cfg *bss.CLIConfig) { // Enable throttling with step controller for predictable behavior cfg.ThrottleConfig.LowerThreshold = 99 // > 0 enables the throttling loop. cfg.ThrottleConfig.UpperThreshold = 100 diff --git a/op-acceptance-tests/tests/depreqres/reqressyncdisabled/clsync/init_test.go b/op-acceptance-tests/tests/depreqres/reqressyncdisabled/clsync/init_test.go index 6163f1cc02e..1463cb3bbea 100644 --- a/op-acceptance-tests/tests/depreqres/reqressyncdisabled/clsync/init_test.go +++ b/op-acceptance-tests/tests/depreqres/reqressyncdisabled/clsync/init_test.go @@ -16,7 +16,7 @@ func TestMain(m *testing.M) { presets.WithCompatibleTypes(compat.SysGo), presets.WithReqRespSyncDisabled(), presets.WithNoDiscovery(), - stack.MakeCommon(sysgo.WithBatcherOption(func(id stack.L2BatcherID, cfg *bss.CLIConfig) { + stack.MakeCommon(sysgo.WithBatcherOption(func(id stack.ComponentID, cfg *bss.CLIConfig) { cfg.Stopped = true })), ) diff --git a/op-acceptance-tests/tests/depreqres/reqressyncdisabled/divergence/divergence_test.go b/op-acceptance-tests/tests/depreqres/reqressyncdisabled/divergence/divergence_test.go index ba866b76383..48c4b5d2f99 100644 --- a/op-acceptance-tests/tests/depreqres/reqressyncdisabled/divergence/divergence_test.go +++ b/op-acceptance-tests/tests/depreqres/reqressyncdisabled/divergence/divergence_test.go @@ -21,7 +21,7 @@ func TestMain(m *testing.M) { presets.WithExecutionLayerSyncOnVerifiers(), presets.WithReqRespSyncDisabled(), presets.WithNoDiscovery(), - stack.MakeCommon(sysgo.WithBatcherOption(func(id stack.L2BatcherID, cfg *bss.CLIConfig) { + stack.MakeCommon(sysgo.WithBatcherOption(func(id stack.ComponentID, cfg *bss.CLIConfig) { cfg.Stopped = true })), ) diff --git a/op-acceptance-tests/tests/depreqres/reqressyncdisabled/elsync/init_test.go b/op-acceptance-tests/tests/depreqres/reqressyncdisabled/elsync/init_test.go index 867ffcec2c5..47899a6ab83 100644 --- a/op-acceptance-tests/tests/depreqres/reqressyncdisabled/elsync/init_test.go +++ b/op-acceptance-tests/tests/depreqres/reqressyncdisabled/elsync/init_test.go @@ -16,7 +16,7 @@ func TestMain(m *testing.M) { presets.WithCompatibleTypes(compat.SysGo), presets.WithReqRespSyncDisabled(), presets.WithNoDiscovery(), - stack.MakeCommon(sysgo.WithBatcherOption(func(id stack.L2BatcherID, cfg *bss.CLIConfig) { + stack.MakeCommon(sysgo.WithBatcherOption(func(id stack.ComponentID, cfg *bss.CLIConfig) { cfg.Stopped = true })), ) diff --git a/op-acceptance-tests/tests/depreqres/reqressyncdisabled/init_test.go b/op-acceptance-tests/tests/depreqres/reqressyncdisabled/init_test.go index 10fe7cec718..41bc97589e3 100644 --- a/op-acceptance-tests/tests/depreqres/reqressyncdisabled/init_test.go +++ b/op-acceptance-tests/tests/depreqres/reqressyncdisabled/init_test.go @@ -16,7 +16,7 @@ func TestMain(m *testing.M) { presets.WithCompatibleTypes(compat.SysGo), presets.WithReqRespSyncDisabled(), presets.WithNoDiscovery(), - stack.MakeCommon(sysgo.WithBatcherOption(func(id stack.L2BatcherID, cfg *bss.CLIConfig) { + stack.MakeCommon(sysgo.WithBatcherOption(func(id stack.ComponentID, cfg *bss.CLIConfig) { cfg.Stopped = true })), ) diff --git a/op-acceptance-tests/tests/depreqres/syncmodereqressync/clsync/init_test.go b/op-acceptance-tests/tests/depreqres/syncmodereqressync/clsync/init_test.go index 51dd93bfa3b..b7a96209aa3 100644 --- a/op-acceptance-tests/tests/depreqres/syncmodereqressync/clsync/init_test.go +++ b/op-acceptance-tests/tests/depreqres/syncmodereqressync/clsync/init_test.go @@ -16,7 +16,7 @@ func TestMain(m *testing.M) { presets.WithCompatibleTypes(compat.SysGo), presets.WithSyncModeReqRespSync(), presets.WithNoDiscovery(), - stack.MakeCommon(sysgo.WithBatcherOption(func(id stack.L2BatcherID, cfg *bss.CLIConfig) { + stack.MakeCommon(sysgo.WithBatcherOption(func(id stack.ComponentID, cfg *bss.CLIConfig) { cfg.Stopped = true })), ) diff --git a/op-acceptance-tests/tests/depreqres/syncmodereqressync/elsync/init_test.go b/op-acceptance-tests/tests/depreqres/syncmodereqressync/elsync/init_test.go index 311ed9f8a33..b35036a13c4 100644 --- a/op-acceptance-tests/tests/depreqres/syncmodereqressync/elsync/init_test.go +++ b/op-acceptance-tests/tests/depreqres/syncmodereqressync/elsync/init_test.go @@ -16,7 +16,7 @@ func TestMain(m *testing.M) { presets.WithCompatibleTypes(compat.SysGo), presets.WithSyncModeReqRespSync(), presets.WithNoDiscovery(), - stack.MakeCommon(sysgo.WithBatcherOption(func(id stack.L2BatcherID, cfg *bss.CLIConfig) { + stack.MakeCommon(sysgo.WithBatcherOption(func(id stack.ComponentID, cfg *bss.CLIConfig) { cfg.Stopped = true })), ) diff --git a/op-acceptance-tests/tests/fusaka/init_test.go b/op-acceptance-tests/tests/fusaka/init_test.go index 509d28a5886..61b00b94cb0 100644 --- a/op-acceptance-tests/tests/fusaka/init_test.go +++ b/op-acceptance-tests/tests/fusaka/init_test.go @@ -24,7 +24,7 @@ func TestMain(m *testing.M) { sysgo.WithForkAtL1Offset(forks.Osaka, 0), sysgo.WithForkAtL1Offset(forks.BPO1, 1), ), - sysgo.WithBatcherOption(func(_ stack.L2BatcherID, cfg *batcher.CLIConfig) { + sysgo.WithBatcherOption(func(_ stack.ComponentID, cfg *batcher.CLIConfig) { cfg.DataAvailabilityType = flags.BlobsType cfg.TxMgrConfig.CellProofTime = 0 // Force cell proofs to be used }), diff --git a/op-acceptance-tests/tests/interop/seqwindow/init_test.go b/op-acceptance-tests/tests/interop/seqwindow/init_test.go index 1be339ff3e1..b4110b7123f 100644 --- a/op-acceptance-tests/tests/interop/seqwindow/init_test.go +++ b/op-acceptance-tests/tests/interop/seqwindow/init_test.go @@ -16,7 +16,7 @@ func TestMain(m *testing.M) { // Short enough that we can run the test, // long enough that the batcher can still submit something before we make things expire. presets.WithSequencingWindow(10, 30), - stack.MakeCommon(sysgo.WithBatcherOption(func(id stack.L2BatcherID, cfg *bss.CLIConfig) { + stack.MakeCommon(sysgo.WithBatcherOption(func(id stack.ComponentID, cfg *bss.CLIConfig) { // Span-batches during recovery don't appear to align well with the starting-point. // It can be off by ~6 L2 blocks, possibly due to off-by-one // in L1 block sync considerations in batcher stop or start. diff --git a/op-acceptance-tests/tests/interop/sync/multisupervisor_interop/init_test.go b/op-acceptance-tests/tests/interop/sync/multisupervisor_interop/init_test.go index 6f052d88b4d..5c198171bd9 100644 --- a/op-acceptance-tests/tests/interop/sync/multisupervisor_interop/init_test.go +++ b/op-acceptance-tests/tests/interop/sync/multisupervisor_interop/init_test.go @@ -13,7 +13,7 @@ import ( func TestMain(m *testing.M) { presets.DoMain(m, presets.WithMultiSupervisorInterop(), presets.WithLogFilter(logfilter.DefaultMute( - stack.KindSelector(stack.SupervisorKind).And(logfilter.Level(log.LevelInfo)).Show(), + stack.KindSelector(stack.KindSupervisor).And(logfilter.Level(log.LevelInfo)).Show(), logfilter.Level(log.LevelError).Show(), ))) } diff --git a/op-acceptance-tests/tests/sync/clsync/gap_clp2p/init_test.go b/op-acceptance-tests/tests/sync/clsync/gap_clp2p/init_test.go index 5da44bdcd94..40343a01fa6 100644 --- a/op-acceptance-tests/tests/sync/clsync/gap_clp2p/init_test.go +++ b/op-acceptance-tests/tests/sync/clsync/gap_clp2p/init_test.go @@ -14,7 +14,7 @@ func TestMain(m *testing.M) { // No ELP2P, CLP2P to control the supply of unsafe payload to the CL presets.DoMain(m, presets.WithSingleChainMultiNodeWithoutP2P(), presets.WithCompatibleTypes(compat.SysGo), - stack.MakeCommon(sysgo.WithBatcherOption(func(id stack.L2BatcherID, cfg *bss.CLIConfig) { + stack.MakeCommon(sysgo.WithBatcherOption(func(id stack.ComponentID, cfg *bss.CLIConfig) { // For stopping derivation, not to advance safe heads cfg.Stopped = true })), diff --git a/op-acceptance-tests/tests/sync/elsync/gap_clp2p/init_test.go b/op-acceptance-tests/tests/sync/elsync/gap_clp2p/init_test.go index 75dffe931e0..83745675957 100644 --- a/op-acceptance-tests/tests/sync/elsync/gap_clp2p/init_test.go +++ b/op-acceptance-tests/tests/sync/elsync/gap_clp2p/init_test.go @@ -15,7 +15,7 @@ func TestMain(m *testing.M) { presets.DoMain(m, presets.WithSingleChainMultiNodeWithoutP2P(), presets.WithExecutionLayerSyncOnVerifiers(), presets.WithCompatibleTypes(compat.SysGo), - stack.MakeCommon(sysgo.WithBatcherOption(func(id stack.L2BatcherID, cfg *bss.CLIConfig) { + stack.MakeCommon(sysgo.WithBatcherOption(func(id stack.ComponentID, cfg *bss.CLIConfig) { // For stopping derivation, not to advance safe heads cfg.Stopped = true })), diff --git a/op-acceptance-tests/tests/sync/elsync/gap_elp2p/init_test.go b/op-acceptance-tests/tests/sync/elsync/gap_elp2p/init_test.go index 280fdd55ad5..43dec397475 100644 --- a/op-acceptance-tests/tests/sync/elsync/gap_elp2p/init_test.go +++ b/op-acceptance-tests/tests/sync/elsync/gap_elp2p/init_test.go @@ -14,7 +14,7 @@ func TestMain(m *testing.M) { // No ELP2P, CLP2P to control the supply of unsafe payload to the CL presets.DoMain(m, presets.WithSingleChainMultiNodeWithoutP2P(), presets.WithCompatibleTypes(compat.SysGo), - stack.MakeCommon(sysgo.WithBatcherOption(func(id stack.L2BatcherID, cfg *bss.CLIConfig) { + stack.MakeCommon(sysgo.WithBatcherOption(func(id stack.ComponentID, cfg *bss.CLIConfig) { // For stopping derivation, not to advance safe heads cfg.Stopped = true })), diff --git a/op-acceptance-tests/tests/sync/manual/init_test.go b/op-acceptance-tests/tests/sync/manual/init_test.go index ac448c396b4..a3c8bdff18d 100644 --- a/op-acceptance-tests/tests/sync/manual/init_test.go +++ b/op-acceptance-tests/tests/sync/manual/init_test.go @@ -14,7 +14,7 @@ func TestMain(m *testing.M) { // No ELP2P, CLP2P to control the supply of unsafe payload to the CL presets.DoMain(m, presets.WithSingleChainMultiNodeWithoutP2P(), presets.WithCompatibleTypes(compat.SysGo), - stack.MakeCommon(sysgo.WithBatcherOption(func(id stack.L2BatcherID, cfg *bss.CLIConfig) { + stack.MakeCommon(sysgo.WithBatcherOption(func(id stack.ComponentID, cfg *bss.CLIConfig) { // For stopping derivation, not to advance safe heads cfg.Stopped = true })), diff --git a/op-acceptance-tests/tests/sync_tester/sync_tester_elsync_multi/init_test.go b/op-acceptance-tests/tests/sync_tester/sync_tester_elsync_multi/init_test.go index 18563be5dfd..6b4a82e8ddc 100644 --- a/op-acceptance-tests/tests/sync_tester/sync_tester_elsync_multi/init_test.go +++ b/op-acceptance-tests/tests/sync_tester/sync_tester_elsync_multi/init_test.go @@ -16,7 +16,7 @@ func TestMain(m *testing.M) { presets.WithSimpleWithSyncTester(), presets.WithELSyncActive(), presets.WithCompatibleTypes(compat.SysGo), - stack.MakeCommon(sysgo.WithBatcherOption(func(id stack.L2BatcherID, cfg *bss.CLIConfig) { + stack.MakeCommon(sysgo.WithBatcherOption(func(id stack.ComponentID, cfg *bss.CLIConfig) { // For stopping derivation, not to advance safe heads cfg.Stopped = true })), diff --git a/op-acceptance-tests/tests/sync_tester/sync_tester_hfs/init_test.go b/op-acceptance-tests/tests/sync_tester/sync_tester_hfs/init_test.go index 80c210859c4..f01e0f67815 100644 --- a/op-acceptance-tests/tests/sync_tester/sync_tester_hfs/init_test.go +++ b/op-acceptance-tests/tests/sync_tester/sync_tester_hfs/init_test.go @@ -17,7 +17,7 @@ func TestMain(m *testing.M) { presets.WithCompatibleTypes(compat.SysGo), presets.WithHardforkSequentialActivation(forks.Bedrock, forks.Jovian, 6), presets.WithNoDiscovery(), - stack.MakeCommon(sysgo.WithBatcherOption(func(id stack.L2BatcherID, cfg *bss.CLIConfig) { + stack.MakeCommon(sysgo.WithBatcherOption(func(id stack.ComponentID, cfg *bss.CLIConfig) { // For supporting pre-delta batches cfg.BatchType = derive.SingularBatchType // For supporting pre-Fjord batches diff --git a/op-devstack/dsl/l2_cl.go b/op-devstack/dsl/l2_cl.go index dc04bbe7974..bfd4f562015 100644 --- a/op-devstack/dsl/l2_cl.go +++ b/op-devstack/dsl/l2_cl.go @@ -32,7 +32,7 @@ func NewL2CLNode(inner stack.L2CLNode, control stack.ControlPlane) *L2CLNode { } } -func (cl *L2CLNode) ID() stack.L2CLNodeID { +func (cl *L2CLNode) ID() stack.ComponentID { return cl.inner.ID() } diff --git a/op-devstack/dsl/l2_el.go b/op-devstack/dsl/l2_el.go index b7c856ce636..e26a7e93bb6 100644 --- a/op-devstack/dsl/l2_el.go +++ b/op-devstack/dsl/l2_el.go @@ -45,7 +45,7 @@ func (el *L2ELNode) Escape() stack.L2ELNode { return el.inner } -func (el *L2ELNode) ID() stack.L2ELNodeID { +func (el *L2ELNode) ID() stack.ComponentID { return el.inner.ID() } diff --git a/op-devstack/example/init_test.go b/op-devstack/example/init_test.go index 4efb1541bb3..79c83311d0e 100644 --- a/op-devstack/example/init_test.go +++ b/op-devstack/example/init_test.go @@ -16,9 +16,9 @@ func TestMain(m *testing.M) { // Logging can be adjusted with filters globally presets.WithPkgLogFilter( logfilter.DefaultShow( // Random configuration - stack.KindSelector(stack.L2ProposerKind).Mute(), - stack.KindSelector(stack.L2BatcherKind).And(logfilter.Level(log.LevelError)).Show(), - stack.KindSelector(stack.L2CLNodeKind).Mute(), + stack.KindSelector(stack.KindL2Proposer).Mute(), + stack.KindSelector(stack.KindL2Batcher).And(logfilter.Level(log.LevelError)).Show(), + stack.KindSelector(stack.KindL2CLNode).Mute(), ), // E.g. allow test interactions through while keeping background resource logs quiet ), diff --git a/op-devstack/presets/cl_config.go b/op-devstack/presets/cl_config.go index 3760cb3ab9a..2e2fbc51687 100644 --- a/op-devstack/presets/cl_config.go +++ b/op-devstack/presets/cl_config.go @@ -10,7 +10,7 @@ import ( func WithExecutionLayerSyncOnVerifiers() stack.CommonOption { return stack.MakeCommon( sysgo.WithGlobalL2CLOption(sysgo.L2CLOptionFn( - func(_ devtest.P, id stack.L2CLNodeID, cfg *sysgo.L2CLConfig) { + func(_ devtest.P, id stack.ComponentID, cfg *sysgo.L2CLConfig) { cfg.VerifierSyncMode = sync.ELSync }))) } @@ -18,7 +18,7 @@ func WithExecutionLayerSyncOnVerifiers() stack.CommonOption { func WithConsensusLayerSync() stack.CommonOption { return stack.MakeCommon( sysgo.WithGlobalL2CLOption(sysgo.L2CLOptionFn( - func(_ devtest.P, id stack.L2CLNodeID, cfg *sysgo.L2CLConfig) { + func(_ devtest.P, id stack.ComponentID, cfg *sysgo.L2CLConfig) { cfg.SequencerSyncMode = sync.CLSync cfg.VerifierSyncMode = sync.CLSync }))) @@ -27,7 +27,7 @@ func WithConsensusLayerSync() stack.CommonOption { func WithSafeDBEnabled() stack.CommonOption { return stack.MakeCommon( sysgo.WithGlobalL2CLOption(sysgo.L2CLOptionFn( - func(p devtest.P, id stack.L2CLNodeID, cfg *sysgo.L2CLConfig) { + func(p devtest.P, id stack.ComponentID, cfg *sysgo.L2CLConfig) { cfg.SafeDBPath = p.TempDir() }))) } @@ -35,7 +35,7 @@ func WithSafeDBEnabled() stack.CommonOption { func WithReqRespSyncDisabled() stack.CommonOption { return stack.MakeCommon( sysgo.WithGlobalL2CLOption(sysgo.L2CLOptionFn( - func(_ devtest.P, id stack.L2CLNodeID, cfg *sysgo.L2CLConfig) { + func(_ devtest.P, id stack.ComponentID, cfg *sysgo.L2CLConfig) { cfg.EnableReqRespSync = false cfg.UseReqRespSync = false }))) @@ -44,7 +44,7 @@ func WithReqRespSyncDisabled() stack.CommonOption { func WithSyncModeReqRespSync() stack.CommonOption { return stack.MakeCommon( sysgo.WithGlobalL2CLOption(sysgo.L2CLOptionFn( - func(_ devtest.P, id stack.L2CLNodeID, cfg *sysgo.L2CLConfig) { + func(_ devtest.P, id stack.ComponentID, cfg *sysgo.L2CLConfig) { cfg.UseReqRespSync = true }))) } @@ -52,7 +52,7 @@ func WithSyncModeReqRespSync() stack.CommonOption { func WithNoDiscovery() stack.CommonOption { return stack.MakeCommon( sysgo.WithGlobalL2CLOption(sysgo.L2CLOptionFn( - func(_ devtest.P, id stack.L2CLNodeID, cfg *sysgo.L2CLConfig) { + func(_ devtest.P, id stack.ComponentID, cfg *sysgo.L2CLConfig) { cfg.NoDiscovery = true }))) } diff --git a/op-devstack/presets/minimal_with_conductors.go b/op-devstack/presets/minimal_with_conductors.go index fee4f025240..4275b6705dc 100644 --- a/op-devstack/presets/minimal_with_conductors.go +++ b/op-devstack/presets/minimal_with_conductors.go @@ -14,7 +14,7 @@ import ( type MinimalWithConductors struct { *Minimal - ConductorSets map[stack.L2NetworkID]dsl.ConductorSet + ConductorSets map[stack.ComponentID]dsl.ConductorSet } // TODO(#16418): shift this to a different sysgo constructor once the sysgo implementation supports conductors @@ -34,7 +34,7 @@ func NewMinimalWithConductors(t devtest.T) *MinimalWithConductors { orch := Orchestrator() orch.Hydrate(system) chains := system.L2Networks() - conductorSets := make(map[stack.L2NetworkID]dsl.ConductorSet) + conductorSets := make(map[stack.ComponentID]dsl.ConductorSet) for _, chain := range chains { chainMatcher := match.L2ChainById(chain.ID()) l2 := system.L2Network(match.Assume(t, chainMatcher)) diff --git a/op-devstack/presets/op_rbuilder_rules.go b/op-devstack/presets/op_rbuilder_rules.go index 5942d82f67f..5ee7d12a669 100644 --- a/op-devstack/presets/op_rbuilder_rules.go +++ b/op-devstack/presets/op_rbuilder_rules.go @@ -13,7 +13,7 @@ import ( func WithOPRBuilderRules(ruleContent string, refreshInterval uint64) stack.CommonOption { return stack.MakeCommon( sysgo.WithGlobalOPRBuilderNodeOption(sysgo.OPRBuilderNodeOptionFn( - func(p devtest.P, id stack.OPRBuilderNodeID, cfg *sysgo.OPRBuilderNodeConfig) { + func(p devtest.P, id stack.ComponentID, cfg *sysgo.OPRBuilderNodeConfig) { cfg.RulesEnabled = true // Create a fixed directory for rules config rulesDir := filepath.Join(os.TempDir(), "rules") diff --git a/op-devstack/presets/proof.go b/op-devstack/presets/proof.go index 0a2d3d30e2c..90ed0e2e3d6 100644 --- a/op-devstack/presets/proof.go +++ b/op-devstack/presets/proof.go @@ -75,7 +75,7 @@ func RequireRespectedGameType(gameType gameTypes.GameType) stack.CommonOption { func WithProposerGameType(gameType gameTypes.GameType) stack.CommonOption { return stack.Combine( stack.MakeCommon( - sysgo.WithProposerOption(func(id stack.L2ProposerID, cfg *ps.CLIConfig) { + sysgo.WithProposerOption(func(id stack.ComponentID, cfg *ps.CLIConfig) { cfg.DisputeGameType = uint32(gameType) }))) } diff --git a/op-devstack/presets/singlechain_multinode.go b/op-devstack/presets/singlechain_multinode.go index e51ca6ea8a1..61210c34bdf 100644 --- a/op-devstack/presets/singlechain_multinode.go +++ b/op-devstack/presets/singlechain_multinode.go @@ -40,12 +40,12 @@ func NewSingleChainMultiNodeWithoutCheck(t devtest.T) *SingleChainMultiNode { verifierCL := l2.L2CLNode(match.Assume(t, match.And( match.Not(match.WithSequencerActive(t.Ctx())), - match.Not[stack.L2CLNodeID, stack.L2CLNode](minimal.L2CL.ID()), + match.Not(stack.ByID[stack.L2CLNode](minimal.L2CL.ID())), ))) verifierEL := l2.L2ELNode(match.Assume(t, match.And( match.EngineFor(verifierCL), - match.Not[stack.L2ELNodeID, stack.L2ELNode](minimal.L2EL.ID())))) + match.Not(stack.ByID[stack.L2ELNode](minimal.L2EL.ID()))))) preset := &SingleChainMultiNode{ Minimal: *minimal, L2ELB: dsl.NewL2ELNode(verifierEL, orch.ControlPlane()), @@ -73,12 +73,12 @@ func NewSingleChainMultiNodeWithTestSeq(t devtest.T) *SingleChainMultiNodeWithTe verifierCL := l2.L2CLNode(match.Assume(t, match.And( match.Not(match.WithSequencerActive(t.Ctx())), - match.Not[stack.L2CLNodeID, stack.L2CLNode](minimal.L2CL.ID()), + match.Not(stack.ByID[stack.L2CLNode](minimal.L2CL.ID())), ))) verifierEL := l2.L2ELNode(match.Assume(t, match.And( match.EngineFor(verifierCL), - match.Not[stack.L2ELNodeID, stack.L2ELNode](minimal.L2EL.ID())))) + match.Not(stack.ByID[stack.L2ELNode](minimal.L2EL.ID()))))) preset := &SingleChainMultiNode{ Minimal: *minimal, L2ELB: dsl.NewL2ELNode(verifierEL, orch.ControlPlane()), diff --git a/op-devstack/presets/singlechain_twoverifiers.go b/op-devstack/presets/singlechain_twoverifiers.go index 898af17b4bc..5b3fa9312f6 100644 --- a/op-devstack/presets/singlechain_twoverifiers.go +++ b/op-devstack/presets/singlechain_twoverifiers.go @@ -27,13 +27,13 @@ func NewSingleChainTwoVerifiersWithoutCheck(t devtest.T) *SingleChainTwoVerifier verifierCL := l2.L2CLNode(match.Assume(t, match.And( match.Not(match.WithSequencerActive(t.Ctx())), - match.Not[stack.L2CLNodeID, stack.L2CLNode](singleChainMultiNode.L2CL.ID()), - match.Not[stack.L2CLNodeID, stack.L2CLNode](singleChainMultiNode.L2CLB.ID()), + match.Not(stack.ByID[stack.L2CLNode](singleChainMultiNode.L2CL.ID())), + match.Not(stack.ByID[stack.L2CLNode](singleChainMultiNode.L2CLB.ID())), ))) verifierEL := l2.L2ELNode(match.Assume(t, match.And( - match.Not[stack.L2ELNodeID, stack.L2ELNode](singleChainMultiNode.L2EL.ID()), - match.Not[stack.L2ELNodeID, stack.L2ELNode](singleChainMultiNode.L2ELB.ID()), + match.Not(stack.ByID[stack.L2ELNode](singleChainMultiNode.L2EL.ID())), + match.Not(stack.ByID[stack.L2ELNode](singleChainMultiNode.L2ELB.ID())), ))) preset := &SingleChainTwoVerifiers{ SingleChainMultiNode: *singleChainMultiNode, diff --git a/op-devstack/presets/sync_tester_config.go b/op-devstack/presets/sync_tester_config.go index 08220e38e93..b97a32cbb23 100644 --- a/op-devstack/presets/sync_tester_config.go +++ b/op-devstack/presets/sync_tester_config.go @@ -10,7 +10,7 @@ import ( func WithSyncTesterELInitialState(fcu eth.FCUState) stack.CommonOption { return stack.MakeCommon( sysgo.WithGlobalSyncTesterELOption(sysgo.SyncTesterELOptionFn( - func(_ devtest.P, id stack.L2ELNodeID, cfg *sysgo.SyncTesterELConfig) { + func(_ devtest.P, id stack.ComponentID, cfg *sysgo.SyncTesterELConfig) { cfg.FCUState = fcu }))) } @@ -18,7 +18,7 @@ func WithSyncTesterELInitialState(fcu eth.FCUState) stack.CommonOption { func WithELSyncActive() stack.CommonOption { return stack.MakeCommon( sysgo.WithGlobalSyncTesterELOption(sysgo.SyncTesterELOptionFn( - func(_ devtest.P, id stack.L2ELNodeID, cfg *sysgo.SyncTesterELConfig) { + func(_ devtest.P, id stack.ComponentID, cfg *sysgo.SyncTesterELConfig) { cfg.ELSyncActive = true }))) } diff --git a/op-devstack/presets/twol2_follow_l2.go b/op-devstack/presets/twol2_follow_l2.go index 2c725c4908d..2ed3a11ed0a 100644 --- a/op-devstack/presets/twol2_follow_l2.go +++ b/op-devstack/presets/twol2_follow_l2.go @@ -41,17 +41,17 @@ func NewTwoL2SupernodeFollowL2(t devtest.T, delaySeconds uint64) *TwoL2Supernode followerELBID := stack.NewL2ELNodeID("follower", l2b.ID().ChainID()) followerCLBID := stack.NewL2CLNodeID("follower", l2b.ID().ChainID()) - followerELA := l2a.L2ELNode(match.MatchElemFn[stack.L2ELNodeID, stack.L2ELNode](func(elem stack.L2ELNode) bool { + followerELA := l2a.L2ELNode(match.MatchElemFn[stack.L2ELNode](func(elem stack.L2ELNode) bool { return elem.ID() == followerELAID })) - followerCLA := l2a.L2CLNode(match.MatchElemFn[stack.L2CLNodeID, stack.L2CLNode](func(elem stack.L2CLNode) bool { + followerCLA := l2a.L2CLNode(match.MatchElemFn[stack.L2CLNode](func(elem stack.L2CLNode) bool { return elem.ID() == followerCLAID })) - followerELB := l2b.L2ELNode(match.MatchElemFn[stack.L2ELNodeID, stack.L2ELNode](func(elem stack.L2ELNode) bool { + followerELB := l2b.L2ELNode(match.MatchElemFn[stack.L2ELNode](func(elem stack.L2ELNode) bool { return elem.ID() == followerELBID })) - followerCLB := l2b.L2CLNode(match.MatchElemFn[stack.L2CLNodeID, stack.L2CLNode](func(elem stack.L2CLNode) bool { + followerCLB := l2b.L2CLNode(match.MatchElemFn[stack.L2CLNode](func(elem stack.L2CLNode) bool { return elem.ID() == followerCLBID })) diff --git a/op-devstack/shim/cluster.go b/op-devstack/shim/cluster.go index 8dadaf4e069..41e2cb3eea8 100644 --- a/op-devstack/shim/cluster.go +++ b/op-devstack/shim/cluster.go @@ -9,14 +9,14 @@ import ( type ClusterConfig struct { CommonConfig DependencySet depset.DependencySet - ID stack.ClusterID + ID stack.ComponentID } // presetCluster implements Cluster with preset values type presetCluster struct { commonImpl depSet depset.DependencySet - id stack.ClusterID + id stack.ComponentID } var _ stack.Cluster = (*presetCluster)(nil) @@ -30,7 +30,7 @@ func NewCluster(cfg ClusterConfig) stack.Cluster { } } -func (p *presetCluster) ID() stack.ClusterID { +func (p *presetCluster) ID() stack.ComponentID { return p.id } diff --git a/op-devstack/shim/conductor.go b/op-devstack/shim/conductor.go index e16072d775b..4151241ab96 100644 --- a/op-devstack/shim/conductor.go +++ b/op-devstack/shim/conductor.go @@ -9,13 +9,13 @@ import ( type ConductorConfig struct { CommonConfig - ID stack.ConductorID + ID stack.ComponentID Client *rpc.Client } type rpcConductor struct { commonImpl - id stack.ConductorID + id stack.ComponentID client *rpc.Client api conductorRpc.API @@ -32,7 +32,7 @@ func NewConductor(cfg ConductorConfig) stack.Conductor { } } -func (r *rpcConductor) ID() stack.ConductorID { +func (r *rpcConductor) ID() stack.ComponentID { return r.id } diff --git a/op-devstack/shim/faucet.go b/op-devstack/shim/faucet.go index aaaedec7f93..80f6d8858c0 100644 --- a/op-devstack/shim/faucet.go +++ b/op-devstack/shim/faucet.go @@ -9,7 +9,7 @@ import ( type FaucetConfig struct { CommonConfig - ID stack.FaucetID + ID stack.ComponentID Client client.RPC } @@ -18,7 +18,7 @@ type FaucetConfig struct { // This deconflicts funding requests by parallel tests from the same funding account. type presetFaucet struct { commonImpl - id stack.FaucetID + id stack.ComponentID faucetClient *sources.FaucetClient } @@ -33,7 +33,7 @@ func NewFaucet(cfg FaucetConfig) stack.Faucet { } } -func (p *presetFaucet) ID() stack.FaucetID { +func (p *presetFaucet) ID() stack.ComponentID { return p.id } diff --git a/op-devstack/shim/fb_ws_client.go b/op-devstack/shim/fb_ws_client.go index b9275497a6e..5397c49ee9e 100644 --- a/op-devstack/shim/fb_ws_client.go +++ b/op-devstack/shim/fb_ws_client.go @@ -9,14 +9,14 @@ import ( type FlashblocksWSClientConfig struct { CommonConfig - ID stack.FlashblocksWSClientID + ID stack.ComponentID WsUrl string WsHeaders http.Header } type flashblocksWSClient struct { commonImpl - id stack.FlashblocksWSClientID + id stack.ComponentID wsUrl string wsHeaders http.Header } @@ -33,7 +33,7 @@ func NewFlashblocksWSClient(cfg FlashblocksWSClientConfig) stack.FlashblocksWSCl } } -func (r *flashblocksWSClient) ID() stack.FlashblocksWSClientID { +func (r *flashblocksWSClient) ID() stack.ComponentID { return r.id } diff --git a/op-devstack/shim/l1_cl.go b/op-devstack/shim/l1_cl.go index a8a65d8214f..a518166d94c 100644 --- a/op-devstack/shim/l1_cl.go +++ b/op-devstack/shim/l1_cl.go @@ -9,13 +9,13 @@ import ( type L1CLNodeConfig struct { CommonConfig - ID stack.L1CLNodeID + ID stack.ComponentID Client client.HTTP } type rpcL1CLNode struct { commonImpl - id stack.L1CLNodeID + id stack.ComponentID client apis.BeaconClient } @@ -30,7 +30,7 @@ func NewL1CLNode(cfg L1CLNodeConfig) stack.L1CLNode { } } -func (r *rpcL1CLNode) ID() stack.L1CLNodeID { +func (r *rpcL1CLNode) ID() stack.ComponentID { return r.id } diff --git a/op-devstack/shim/l1_el.go b/op-devstack/shim/l1_el.go index 03a0eb3a453..005c7e18298 100644 --- a/op-devstack/shim/l1_el.go +++ b/op-devstack/shim/l1_el.go @@ -7,12 +7,12 @@ import ( type L1ELNodeConfig struct { ELNodeConfig - ID stack.L1ELNodeID + ID stack.ComponentID } type rpcL1ELNode struct { rpcELNode - id stack.L1ELNodeID + id stack.ComponentID } var _ stack.L1ELNode = (*rpcL1ELNode)(nil) @@ -26,6 +26,6 @@ func NewL1ELNode(cfg L1ELNodeConfig) stack.L1ELNode { } } -func (r *rpcL1ELNode) ID() stack.L1ELNodeID { +func (r *rpcL1ELNode) ID() stack.ComponentID { return r.id } diff --git a/op-devstack/shim/l1_network.go b/op-devstack/shim/l1_network.go index 78ceae0d98d..60c45430b13 100644 --- a/op-devstack/shim/l1_network.go +++ b/op-devstack/shim/l1_network.go @@ -5,20 +5,16 @@ import ( "github.com/ethereum-optimism/optimism/op-devstack/stack" "github.com/ethereum-optimism/optimism/op-service/eth" - "github.com/ethereum-optimism/optimism/op-service/locks" ) type L1NetworkConfig struct { NetworkConfig - ID stack.L1NetworkID + ID stack.ComponentID } type presetL1Network struct { presetNetwork - id stack.L1NetworkID - - els locks.RWMap[stack.L1ELNodeID, stack.L1ELNode] - cls locks.RWMap[stack.L1CLNodeID, stack.L1CLNode] + id stack.ComponentID } var _ stack.ExtensibleL1Network = (*presetL1Network)(nil) @@ -32,12 +28,19 @@ func NewL1Network(cfg L1NetworkConfig) stack.ExtensibleL1Network { } } -func (p *presetL1Network) ID() stack.L1NetworkID { +func (p *presetL1Network) ID() stack.ComponentID { return p.id } func (p *presetL1Network) L1ELNode(m stack.L1ELMatcher) stack.L1ELNode { - v, ok := findMatch(m, p.els.Get, p.L1ELNodes) + getter := func(id stack.ComponentID) (stack.L1ELNode, bool) { + v, ok := p.registry.Get(id) + if !ok { + return nil, false + } + return v.(stack.L1ELNode), true + } + v, ok := findMatch(m, getter, p.L1ELNodes) p.require().True(ok, "must find L1 EL %s", m) return v } @@ -45,13 +48,20 @@ func (p *presetL1Network) L1ELNode(m stack.L1ELMatcher) stack.L1ELNode { func (p *presetL1Network) AddL1ELNode(v stack.L1ELNode) { id := v.ID() p.require().Equal(p.chainID, id.ChainID(), "l1 EL node %s must be on chain %s", id, p.chainID) - p.require().True(p.els.SetIfMissing(id, v), "l1 EL node %s must not already exist", id) - // Also register in unified registry - p.registry.Register(stack.ConvertL1ELNodeID(id).ComponentID, v) + _, exists := p.registry.Get(id) + p.require().False(exists, "l1 EL node %s must not already exist", id) + p.registry.Register(id, v) } func (p *presetL1Network) L1CLNode(m stack.L1CLMatcher) stack.L1CLNode { - v, ok := findMatch(m, p.cls.Get, p.L1CLNodes) + getter := func(id stack.ComponentID) (stack.L1CLNode, bool) { + v, ok := p.registry.Get(id) + if !ok { + return nil, false + } + return v.(stack.L1CLNode), true + } + v, ok := findMatch(m, getter, p.L1CLNodes) p.require().True(ok, "must find L1 CL %s", m) return v } @@ -59,23 +69,37 @@ func (p *presetL1Network) L1CLNode(m stack.L1CLMatcher) stack.L1CLNode { func (p *presetL1Network) AddL1CLNode(v stack.L1CLNode) { id := v.ID() p.require().Equal(p.chainID, id.ChainID(), "l1 CL node %s must be on chain %s", id, p.chainID) - p.require().True(p.cls.SetIfMissing(id, v), "l1 CL node %s must not already exist", id) - // Also register in unified registry - p.registry.Register(stack.ConvertL1CLNodeID(id).ComponentID, v) + _, exists := p.registry.Get(id) + p.require().False(exists, "l1 CL node %s must not already exist", id) + p.registry.Register(id, v) } -func (p *presetL1Network) L1ELNodeIDs() []stack.L1ELNodeID { - return stack.SortL1ELNodeIDs(p.els.Keys()) +func (p *presetL1Network) L1ELNodeIDs() []stack.ComponentID { + return sortByID(p.registry.IDsByKind(stack.KindL1ELNode)) } func (p *presetL1Network) L1ELNodes() []stack.L1ELNode { - return stack.SortL1ELNodes(p.els.Values()) + ids := p.registry.IDsByKind(stack.KindL1ELNode) + result := make([]stack.L1ELNode, 0, len(ids)) + for _, id := range ids { + if v, ok := p.registry.Get(id); ok { + result = append(result, v.(stack.L1ELNode)) + } + } + return sortByIDFunc(result) } -func (p *presetL1Network) L1CLNodeIDs() []stack.L1CLNodeID { - return stack.SortL1CLNodeIDs(p.cls.Keys()) +func (p *presetL1Network) L1CLNodeIDs() []stack.ComponentID { + return sortByID(p.registry.IDsByKind(stack.KindL1CLNode)) } func (p *presetL1Network) L1CLNodes() []stack.L1CLNode { - return stack.SortL1CLNodes(p.cls.Values()) + ids := p.registry.IDsByKind(stack.KindL1CLNode) + result := make([]stack.L1CLNode, 0, len(ids)) + for _, id := range ids { + if v, ok := p.registry.Get(id); ok { + result = append(result, v.(stack.L1CLNode)) + } + } + return sortByIDFunc(result) } diff --git a/op-devstack/shim/l2_batcher.go b/op-devstack/shim/l2_batcher.go index e75adad72b6..4e3e785af42 100644 --- a/op-devstack/shim/l2_batcher.go +++ b/op-devstack/shim/l2_batcher.go @@ -9,13 +9,13 @@ import ( type L2BatcherConfig struct { CommonConfig - ID stack.L2BatcherID + ID stack.ComponentID Client client.RPC } type rpcL2Batcher struct { commonImpl - id stack.L2BatcherID + id stack.ComponentID client *sources.BatcherAdminClient } @@ -30,7 +30,7 @@ func NewL2Batcher(cfg L2BatcherConfig) stack.L2Batcher { } } -func (r *rpcL2Batcher) ID() stack.L2BatcherID { +func (r *rpcL2Batcher) ID() stack.ComponentID { return r.id } diff --git a/op-devstack/shim/l2_challenger.go b/op-devstack/shim/l2_challenger.go index a5fe76f431a..65f360503da 100644 --- a/op-devstack/shim/l2_challenger.go +++ b/op-devstack/shim/l2_challenger.go @@ -7,13 +7,13 @@ import ( type L2ChallengerConfig struct { CommonConfig - ID stack.L2ChallengerID + ID stack.ComponentID Config *config.Config } type rpcL2Challenger struct { commonImpl - id stack.L2ChallengerID + id stack.ComponentID config *config.Config } @@ -32,6 +32,6 @@ func NewL2Challenger(cfg L2ChallengerConfig) stack.L2Challenger { } } -func (r *rpcL2Challenger) ID() stack.L2ChallengerID { +func (r *rpcL2Challenger) ID() stack.ComponentID { return r.id } diff --git a/op-devstack/shim/l2_cl.go b/op-devstack/shim/l2_cl.go index 1421c54f229..a1a490ed73e 100644 --- a/op-devstack/shim/l2_cl.go +++ b/op-devstack/shim/l2_cl.go @@ -11,7 +11,7 @@ import ( type L2CLNodeConfig struct { CommonConfig - ID stack.L2CLNodeID + ID stack.ComponentID Client client.RPC UserRPC string @@ -22,13 +22,13 @@ type L2CLNodeConfig struct { type rpcL2CLNode struct { commonImpl - id stack.L2CLNodeID + id stack.ComponentID client client.RPC rollupClient apis.RollupClient p2pClient apis.P2PClient - els locks.RWMap[stack.L2ELNodeID, stack.L2ELNode] - rollupBoostNodes locks.RWMap[stack.RollupBoostNodeID, stack.RollupBoostNode] - oprbuilderNodes locks.RWMap[stack.OPRBuilderNodeID, stack.OPRBuilderNode] + els locks.RWMap[stack.ComponentID, stack.L2ELNode] + rollupBoostNodes locks.RWMap[stack.ComponentID, stack.RollupBoostNode] + oprbuilderNodes locks.RWMap[stack.ComponentID, stack.OPRBuilderNode] userRPC string @@ -60,7 +60,7 @@ func (r *rpcL2CLNode) ClientRPC() client.RPC { return r.client } -func (r *rpcL2CLNode) ID() stack.L2CLNodeID { +func (r *rpcL2CLNode) ID() stack.ComponentID { return r.id } @@ -85,7 +85,7 @@ func (r *rpcL2CLNode) LinkOPRBuilderNode(oprb stack.OPRBuilderNode) { } func (r *rpcL2CLNode) ELs() []stack.L2ELNode { - return stack.SortL2ELNodes(r.els.Values()) + return sortByIDFunc(r.els.Values()) } func (r *rpcL2CLNode) ELClient() apis.EthClient { @@ -101,11 +101,11 @@ func (r *rpcL2CLNode) ELClient() apis.EthClient { } func (r *rpcL2CLNode) RollupBoostNodes() []stack.RollupBoostNode { - return stack.SortRollupBoostNodes(r.rollupBoostNodes.Values()) + return sortByIDFunc(r.rollupBoostNodes.Values()) } func (r *rpcL2CLNode) OPRBuilderNodes() []stack.OPRBuilderNode { - return stack.SortOPRBuilderNodes(r.oprbuilderNodes.Values()) + return sortByIDFunc(r.oprbuilderNodes.Values()) } func (r *rpcL2CLNode) UserRPC() string { diff --git a/op-devstack/shim/l2_el.go b/op-devstack/shim/l2_el.go index 1739647c215..4bd7e41a826 100644 --- a/op-devstack/shim/l2_el.go +++ b/op-devstack/shim/l2_el.go @@ -14,7 +14,7 @@ type L2ELNodeConfig struct { ELNodeConfig EngineClient client.RPC RollupCfg *rollup.Config - ID stack.L2ELNodeID + ID stack.ComponentID } type rpcL2ELNode struct { @@ -22,7 +22,7 @@ type rpcL2ELNode struct { l2Client *sources.L2Client l2EngineClient *sources.EngineClient - id stack.L2ELNodeID + id stack.ComponentID } var _ stack.L2ELNode = (*rpcL2ELNode)(nil) @@ -47,7 +47,7 @@ func NewL2ELNode(cfg L2ELNodeConfig) stack.L2ELNode { } } -func (r *rpcL2ELNode) ID() stack.L2ELNodeID { +func (r *rpcL2ELNode) ID() stack.ComponentID { return r.id } diff --git a/op-devstack/shim/l2_network.go b/op-devstack/shim/l2_network.go index 3631747298b..86128c95434 100644 --- a/op-devstack/shim/l2_network.go +++ b/op-devstack/shim/l2_network.go @@ -6,12 +6,11 @@ import ( "github.com/ethereum-optimism/optimism/op-devstack/stack" "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-service/eth" - "github.com/ethereum-optimism/optimism/op-service/locks" ) type L2NetworkConfig struct { NetworkConfig - ID stack.L2NetworkID + ID stack.ComponentID RollupConfig *rollup.Config Deployment stack.L2Deployment Keys stack.Keys @@ -23,7 +22,7 @@ type L2NetworkConfig struct { type presetL2Network struct { presetNetwork - id stack.L2NetworkID + id stack.ComponentID rollupCfg *rollup.Config deployment stack.L2Deployment @@ -32,17 +31,6 @@ type presetL2Network struct { superchain stack.Superchain l1 stack.L1Network cluster stack.Cluster - - batchers locks.RWMap[stack.L2BatcherID, stack.L2Batcher] - proposers locks.RWMap[stack.L2ProposerID, stack.L2Proposer] - challengers locks.RWMap[stack.L2ChallengerID, stack.L2Challenger] - - els locks.RWMap[stack.L2ELNodeID, stack.L2ELNode] - cls locks.RWMap[stack.L2CLNodeID, stack.L2CLNode] - - conductors locks.RWMap[stack.ConductorID, stack.Conductor] - rollupBoostNodes locks.RWMap[stack.RollupBoostNodeID, stack.RollupBoostNode] - oprBuilderNodes locks.RWMap[stack.OPRBuilderNodeID, stack.OPRBuilderNode] } var _ stack.L2Network = (*presetL2Network)(nil) @@ -65,7 +53,7 @@ func NewL2Network(cfg L2NetworkConfig) stack.ExtensibleL2Network { } } -func (p *presetL2Network) ID() stack.L2NetworkID { +func (p *presetL2Network) ID() stack.ComponentID { return p.id } @@ -100,7 +88,14 @@ func (p *presetL2Network) Cluster() stack.Cluster { } func (p *presetL2Network) L2Batcher(m stack.L2BatcherMatcher) stack.L2Batcher { - v, ok := findMatch(m, p.batchers.Get, p.L2Batchers) + getter := func(id stack.ComponentID) (stack.L2Batcher, bool) { + v, ok := p.registry.Get(id) + if !ok { + return nil, false + } + return v.(stack.L2Batcher), true + } + v, ok := findMatch(m, getter, p.L2Batchers) p.require().True(ok, "must find L2 batcher %s", m) return v } @@ -108,26 +103,40 @@ func (p *presetL2Network) L2Batcher(m stack.L2BatcherMatcher) stack.L2Batcher { func (p *presetL2Network) AddL2Batcher(v stack.L2Batcher) { id := v.ID() p.require().Equal(p.chainID, id.ChainID(), "l2 batcher %s must be on chain %s", id, p.chainID) - p.require().True(p.batchers.SetIfMissing(id, v), "l2 batcher %s must not already exist", id) - // Also register in unified registry - p.registry.Register(stack.ConvertL2BatcherID(id).ComponentID, v) + _, exists := p.registry.Get(id) + p.require().False(exists, "l2 batcher %s must not already exist", id) + p.registry.Register(id, v) } func (p *presetL2Network) Conductor(m stack.ConductorMatcher) stack.Conductor { - v, ok := findMatch(m, p.conductors.Get, p.Conductors) + getter := func(id stack.ComponentID) (stack.Conductor, bool) { + v, ok := p.registry.Get(id) + if !ok { + return nil, false + } + return v.(stack.Conductor), true + } + v, ok := findMatch(m, getter, p.Conductors) p.require().True(ok, "must find L2 conductor %s", m) return v } func (p *presetL2Network) AddConductor(v stack.Conductor) { id := v.ID() - p.require().True(p.conductors.SetIfMissing(id, v), "conductor %s must not already exist", id) - // Also register in unified registry - p.registry.Register(stack.ConvertConductorID(id).ComponentID, v) + _, exists := p.registry.Get(id) + p.require().False(exists, "conductor %s must not already exist", id) + p.registry.Register(id, v) } func (p *presetL2Network) L2Proposer(m stack.L2ProposerMatcher) stack.L2Proposer { - v, ok := findMatch(m, p.proposers.Get, p.L2Proposers) + getter := func(id stack.ComponentID) (stack.L2Proposer, bool) { + v, ok := p.registry.Get(id) + if !ok { + return nil, false + } + return v.(stack.L2Proposer), true + } + v, ok := findMatch(m, getter, p.L2Proposers) p.require().True(ok, "must find L2 proposer %s", m) return v } @@ -135,26 +144,40 @@ func (p *presetL2Network) L2Proposer(m stack.L2ProposerMatcher) stack.L2Proposer func (p *presetL2Network) AddL2Proposer(v stack.L2Proposer) { id := v.ID() p.require().Equal(p.chainID, id.ChainID(), "l2 proposer %s must be on chain %s", id, p.chainID) - p.require().True(p.proposers.SetIfMissing(id, v), "l2 proposer %s must not already exist", id) - // Also register in unified registry - p.registry.Register(stack.ConvertL2ProposerID(id).ComponentID, v) + _, exists := p.registry.Get(id) + p.require().False(exists, "l2 proposer %s must not already exist", id) + p.registry.Register(id, v) } func (p *presetL2Network) L2Challenger(m stack.L2ChallengerMatcher) stack.L2Challenger { - v, ok := findMatch(m, p.challengers.Get, p.L2Challengers) + getter := func(id stack.ComponentID) (stack.L2Challenger, bool) { + v, ok := p.registry.Get(id) + if !ok { + return nil, false + } + return v.(stack.L2Challenger), true + } + v, ok := findMatch(m, getter, p.L2Challengers) p.require().True(ok, "must find L2 challenger %s", m) return v } func (p *presetL2Network) AddL2Challenger(v stack.L2Challenger) { id := v.ID() - p.require().True(p.challengers.SetIfMissing(id, v), "l2 challenger %s must not already exist", id) - // Also register in unified registry - p.registry.Register(stack.ConvertL2ChallengerID(id).ComponentID, v) + _, exists := p.registry.Get(id) + p.require().False(exists, "l2 challenger %s must not already exist", id) + p.registry.Register(id, v) } func (p *presetL2Network) L2CLNode(m stack.L2CLMatcher) stack.L2CLNode { - v, ok := findMatch(m, p.cls.Get, p.L2CLNodes) + getter := func(id stack.ComponentID) (stack.L2CLNode, bool) { + v, ok := p.registry.Get(id) + if !ok { + return nil, false + } + return v.(stack.L2CLNode), true + } + v, ok := findMatch(m, getter, p.L2CLNodes) p.require().True(ok, "must find L2 CL %s", m) return v } @@ -162,13 +185,20 @@ func (p *presetL2Network) L2CLNode(m stack.L2CLMatcher) stack.L2CLNode { func (p *presetL2Network) AddL2CLNode(v stack.L2CLNode) { id := v.ID() p.require().Equal(p.chainID, id.ChainID(), "l2 CL node %s must be on chain %s", id, p.chainID) - p.require().True(p.cls.SetIfMissing(id, v), "l2 CL node %s must not already exist", id) - // Also register in unified registry - p.registry.Register(stack.ConvertL2CLNodeID(id).ComponentID, v) + _, exists := p.registry.Get(id) + p.require().False(exists, "l2 CL node %s must not already exist", id) + p.registry.Register(id, v) } func (p *presetL2Network) L2ELNode(m stack.L2ELMatcher) stack.L2ELNode { - v, ok := findMatch(m, p.els.Get, p.L2ELNodes) + getter := func(id stack.ComponentID) (stack.L2ELNode, bool) { + v, ok := p.registry.Get(id) + if !ok { + return nil, false + } + return v.(stack.L2ELNode), true + } + v, ok := findMatch(m, getter, p.L2ELNodes) p.require().True(ok, "must find L2 EL %s", m) return v } @@ -176,85 +206,155 @@ func (p *presetL2Network) L2ELNode(m stack.L2ELMatcher) stack.L2ELNode { func (p *presetL2Network) AddL2ELNode(v stack.L2ELNode) { id := v.ID() p.require().Equal(p.chainID, id.ChainID(), "l2 EL node %s must be on chain %s", id, p.chainID) - p.require().True(p.els.SetIfMissing(id, v), "l2 EL node %s must not already exist", id) - // Also register in unified registry - p.registry.Register(stack.ConvertL2ELNodeID(id).ComponentID, v) + _, exists := p.registry.Get(id) + p.require().False(exists, "l2 EL node %s must not already exist", id) + p.registry.Register(id, v) } -func (p *presetL2Network) L2BatcherIDs() []stack.L2BatcherID { - return stack.SortL2BatcherIDs(p.batchers.Keys()) +func (p *presetL2Network) L2BatcherIDs() []stack.ComponentID { + return sortByID(p.registry.IDsByKind(stack.KindL2Batcher)) } func (p *presetL2Network) L2Batchers() []stack.L2Batcher { - return stack.SortL2Batchers(p.batchers.Values()) + ids := p.registry.IDsByKind(stack.KindL2Batcher) + result := make([]stack.L2Batcher, 0, len(ids)) + for _, id := range ids { + if v, ok := p.registry.Get(id); ok { + result = append(result, v.(stack.L2Batcher)) + } + } + return sortByIDFunc(result) } -func (p *presetL2Network) L2ProposerIDs() []stack.L2ProposerID { - return stack.SortL2ProposerIDs(p.proposers.Keys()) +func (p *presetL2Network) L2ProposerIDs() []stack.ComponentID { + return sortByID(p.registry.IDsByKind(stack.KindL2Proposer)) } func (p *presetL2Network) L2Proposers() []stack.L2Proposer { - return stack.SortL2Proposers(p.proposers.Values()) + ids := p.registry.IDsByKind(stack.KindL2Proposer) + result := make([]stack.L2Proposer, 0, len(ids)) + for _, id := range ids { + if v, ok := p.registry.Get(id); ok { + result = append(result, v.(stack.L2Proposer)) + } + } + return sortByIDFunc(result) } -func (p *presetL2Network) L2ChallengerIDs() []stack.L2ChallengerID { - return stack.SortL2ChallengerIDs(p.challengers.Keys()) +func (p *presetL2Network) L2ChallengerIDs() []stack.ComponentID { + return sortByID(p.registry.IDsByKind(stack.KindL2Challenger)) } func (p *presetL2Network) L2Challengers() []stack.L2Challenger { - return stack.SortL2Challengers(p.challengers.Values()) + ids := p.registry.IDsByKind(stack.KindL2Challenger) + result := make([]stack.L2Challenger, 0, len(ids)) + for _, id := range ids { + if v, ok := p.registry.Get(id); ok { + result = append(result, v.(stack.L2Challenger)) + } + } + return sortByIDFunc(result) } func (p *presetL2Network) Conductors() []stack.Conductor { - return stack.SortConductors(p.conductors.Values()) + ids := p.registry.IDsByKind(stack.KindConductor) + result := make([]stack.Conductor, 0, len(ids)) + for _, id := range ids { + if v, ok := p.registry.Get(id); ok { + result = append(result, v.(stack.Conductor)) + } + } + return sortByIDFunc(result) } -func (p *presetL2Network) L2CLNodeIDs() []stack.L2CLNodeID { - return stack.SortL2CLNodeIDs(p.cls.Keys()) +func (p *presetL2Network) L2CLNodeIDs() []stack.ComponentID { + return sortByID(p.registry.IDsByKind(stack.KindL2CLNode)) } func (p *presetL2Network) L2CLNodes() []stack.L2CLNode { - return stack.SortL2CLNodes(p.cls.Values()) + ids := p.registry.IDsByKind(stack.KindL2CLNode) + result := make([]stack.L2CLNode, 0, len(ids)) + for _, id := range ids { + if v, ok := p.registry.Get(id); ok { + result = append(result, v.(stack.L2CLNode)) + } + } + return sortByIDFunc(result) } -func (p *presetL2Network) L2ELNodeIDs() []stack.L2ELNodeID { - return stack.SortL2ELNodeIDs(p.els.Keys()) +func (p *presetL2Network) L2ELNodeIDs() []stack.ComponentID { + return sortByID(p.registry.IDsByKind(stack.KindL2ELNode)) } func (p *presetL2Network) L2ELNodes() []stack.L2ELNode { - return stack.SortL2ELNodes(p.els.Values()) + ids := p.registry.IDsByKind(stack.KindL2ELNode) + result := make([]stack.L2ELNode, 0, len(ids)) + for _, id := range ids { + if v, ok := p.registry.Get(id); ok { + result = append(result, v.(stack.L2ELNode)) + } + } + return sortByIDFunc(result) } func (p *presetL2Network) RollupBoostNodes() []stack.RollupBoostNode { - return stack.SortRollupBoostNodes(p.rollupBoostNodes.Values()) + ids := p.registry.IDsByKind(stack.KindRollupBoostNode) + result := make([]stack.RollupBoostNode, 0, len(ids)) + for _, id := range ids { + if v, ok := p.registry.Get(id); ok { + result = append(result, v.(stack.RollupBoostNode)) + } + } + return sortByIDFunc(result) } func (p *presetL2Network) OPRBuilderNodes() []stack.OPRBuilderNode { - return stack.SortOPRBuilderNodes(p.oprBuilderNodes.Values()) + ids := p.registry.IDsByKind(stack.KindOPRBuilderNode) + result := make([]stack.OPRBuilderNode, 0, len(ids)) + for _, id := range ids { + if v, ok := p.registry.Get(id); ok { + result = append(result, v.(stack.OPRBuilderNode)) + } + } + return sortByIDFunc(result) } func (p *presetL2Network) AddRollupBoostNode(v stack.RollupBoostNode) { id := v.ID() - p.require().True(p.rollupBoostNodes.SetIfMissing(id, v), "rollup boost node %s must not already exist", id) - // Also register in unified registry - p.registry.Register(stack.ConvertRollupBoostNodeID(id).ComponentID, v) + _, exists := p.registry.Get(id) + p.require().False(exists, "rollup boost node %s must not already exist", id) + p.registry.Register(id, v) } func (p *presetL2Network) AddOPRBuilderNode(v stack.OPRBuilderNode) { id := v.ID() - p.require().True(p.oprBuilderNodes.SetIfMissing(id, v), "OPR builder node %s must not already exist", id) - // Also register in unified registry - p.registry.Register(stack.ConvertOPRBuilderNodeID(id).ComponentID, v) + _, exists := p.registry.Get(id) + p.require().False(exists, "OPR builder node %s must not already exist", id) + p.registry.Register(id, v) } func (p *presetL2Network) OPRBuilderNode(m stack.OPRBuilderNodeMatcher) stack.OPRBuilderNode { - v, ok := findMatch(m, p.oprBuilderNodes.Get, p.OPRBuilderNodes) + getter := func(id stack.ComponentID) (stack.OPRBuilderNode, bool) { + v, ok := p.registry.Get(id) + if !ok { + return nil, false + } + return v.(stack.OPRBuilderNode), true + } + v, ok := findMatch(m, getter, p.OPRBuilderNodes) p.require().True(ok, "must find OPR builder node %s", m) return v } func (p *presetL2Network) RollupBoostNode(m stack.RollupBoostNodeMatcher) stack.RollupBoostNode { - v, ok := findMatch(m, p.rollupBoostNodes.Get, p.RollupBoostNodes) + getter := func(id stack.ComponentID) (stack.RollupBoostNode, bool) { + v, ok := p.registry.Get(id) + if !ok { + return nil, false + } + return v.(stack.RollupBoostNode), true + } + v, ok := findMatch(m, getter, p.RollupBoostNodes) p.require().True(ok, "must find rollup boost node %s", m) return v } diff --git a/op-devstack/shim/l2_proposer.go b/op-devstack/shim/l2_proposer.go index 530ab3c73ac..190cf3a450e 100644 --- a/op-devstack/shim/l2_proposer.go +++ b/op-devstack/shim/l2_proposer.go @@ -7,13 +7,13 @@ import ( type L2ProposerConfig struct { CommonConfig - ID stack.L2ProposerID + ID stack.ComponentID Client client.RPC } type rpcL2Proposer struct { commonImpl - id stack.L2ProposerID + id stack.ComponentID client client.RPC } @@ -28,6 +28,6 @@ func NewL2Proposer(cfg L2ProposerConfig) stack.L2Proposer { } } -func (r *rpcL2Proposer) ID() stack.L2ProposerID { +func (r *rpcL2Proposer) ID() stack.ComponentID { return r.id } diff --git a/op-devstack/shim/matcher.go b/op-devstack/shim/matcher.go index b5e65c5facb..d8ce976fae5 100644 --- a/op-devstack/shim/matcher.go +++ b/op-devstack/shim/matcher.go @@ -1,16 +1,19 @@ package shim import ( + "slices" + "sort" + "github.com/ethereum-optimism/optimism/op-devstack/stack" ) -// findMatch checks if the matcher is an ID for direct lookup. If not, then it will search the list of values for a matching element. +// findMatch checks if the matcher is an ID wrapper for direct lookup. If not, then it will search the list of values for a matching element. // If multiple elements match, the first found is returned. // The values function is used to lazy-fetch values in sorted order, such that the search is deterministic. -func findMatch[I comparable, E stack.Identifiable[I]](m stack.Matcher[I, E], getValue func(I) (E, bool), values func() []E) (out E, found bool) { - id, ok := m.(I) - if ok { - return getValue(id) +func findMatch[E stack.Identifiable](m stack.Matcher[E], getValue func(stack.ComponentID) (E, bool), values func() []E) (out E, found bool) { + // Check for idMatcher wrapper (created by stack.ByID) + if idm, ok := m.(interface{ ID() stack.ComponentID }); ok { + return getValue(idm.ID()) } got := m.Match(values()) if len(got) == 0 { @@ -18,3 +21,21 @@ func findMatch[I comparable, E stack.Identifiable[I]](m stack.Matcher[I, E], get } return got[0], true } + +// sortByID sorts a slice of ComponentIDs. +func sortByID(ids []stack.ComponentID) []stack.ComponentID { + out := slices.Clone(ids) + sort.Slice(out, func(i, j int) bool { + return out[i].Less(out[j]) + }) + return out +} + +// sortByIDFunc sorts a slice of elements by extracting their ID. +func sortByIDFunc[T stack.Identifiable](elems []T) []T { + out := slices.Clone(elems) + sort.Slice(out, func(i, j int) bool { + return out[i].ID().Less(out[j].ID()) + }) + return out +} diff --git a/op-devstack/shim/network.go b/op-devstack/shim/network.go index c90ac2b6efe..d6652f4828d 100644 --- a/op-devstack/shim/network.go +++ b/op-devstack/shim/network.go @@ -5,7 +5,6 @@ import ( "github.com/ethereum-optimism/optimism/op-devstack/stack" "github.com/ethereum-optimism/optimism/op-service/eth" - "github.com/ethereum-optimism/optimism/op-service/locks" ) type NetworkConfig struct { @@ -20,11 +19,6 @@ type presetNetwork struct { // Unified component registry for generic access registry *stack.Registry - - // Legacy typed maps - kept for backward compatibility during migration - // These will be removed once all callers migrate to generic access - faucets locks.RWMap[stack.FaucetID, stack.Faucet] - syncTesters locks.RWMap[stack.SyncTesterID, stack.SyncTester] } var _ stack.Network = (*presetNetwork)(nil) @@ -68,16 +62,30 @@ func (p *presetNetwork) ChainConfig() *params.ChainConfig { return p.chainCfg } -func (p *presetNetwork) FaucetIDs() []stack.FaucetID { - return stack.SortFaucetIDs(p.faucets.Keys()) +func (p *presetNetwork) FaucetIDs() []stack.ComponentID { + return sortByID(p.registry.IDsByKind(stack.KindFaucet)) } func (p *presetNetwork) Faucets() []stack.Faucet { - return stack.SortFaucets(p.faucets.Values()) + ids := p.registry.IDsByKind(stack.KindFaucet) + result := make([]stack.Faucet, 0, len(ids)) + for _, id := range ids { + if v, ok := p.registry.Get(id); ok { + result = append(result, v.(stack.Faucet)) + } + } + return sortByIDFunc(result) } func (p *presetNetwork) Faucet(m stack.FaucetMatcher) stack.Faucet { - v, ok := findMatch(m, p.faucets.Get, p.Faucets) + getter := func(id stack.ComponentID) (stack.Faucet, bool) { + v, ok := p.registry.Get(id) + if !ok { + return nil, false + } + return v.(stack.Faucet), true + } + v, ok := findMatch(m, getter, p.Faucets) p.require().True(ok, "must find faucet %s", m) return v } @@ -85,21 +93,35 @@ func (p *presetNetwork) Faucet(m stack.FaucetMatcher) stack.Faucet { func (p *presetNetwork) AddFaucet(v stack.Faucet) { id := v.ID() p.require().Equal(p.chainID, id.ChainID(), "faucet %s must be on chain %s", id, p.chainID) - p.require().True(p.faucets.SetIfMissing(id, v), "faucet %s must not already exist", id) - // Also register in unified registry - p.registry.Register(stack.ConvertFaucetID(id).ComponentID, v) + _, exists := p.registry.Get(id) + p.require().False(exists, "faucet %s must not already exist", id) + p.registry.Register(id, v) } -func (p *presetNetwork) SyncTesterIDs() []stack.SyncTesterID { - return stack.SortSyncTesterIDs(p.syncTesters.Keys()) +func (p *presetNetwork) SyncTesterIDs() []stack.ComponentID { + return sortByID(p.registry.IDsByKind(stack.KindSyncTester)) } func (p *presetNetwork) SyncTesters() []stack.SyncTester { - return stack.SortSyncTesters(p.syncTesters.Values()) + ids := p.registry.IDsByKind(stack.KindSyncTester) + result := make([]stack.SyncTester, 0, len(ids)) + for _, id := range ids { + if v, ok := p.registry.Get(id); ok { + result = append(result, v.(stack.SyncTester)) + } + } + return sortByIDFunc(result) } func (p *presetNetwork) SyncTester(m stack.SyncTesterMatcher) stack.SyncTester { - v, ok := findMatch(m, p.syncTesters.Get, p.SyncTesters) + getter := func(id stack.ComponentID) (stack.SyncTester, bool) { + v, ok := p.registry.Get(id) + if !ok { + return nil, false + } + return v.(stack.SyncTester), true + } + v, ok := findMatch(m, getter, p.SyncTesters) p.require().True(ok, "must find sync tester %s", m) return v } @@ -107,7 +129,7 @@ func (p *presetNetwork) SyncTester(m stack.SyncTesterMatcher) stack.SyncTester { func (p *presetNetwork) AddSyncTester(v stack.SyncTester) { id := v.ID() p.require().Equal(p.chainID, id.ChainID(), "sync tester %s must be on chain %s", id, p.chainID) - p.require().True(p.syncTesters.SetIfMissing(id, v), "sync tester %s must not already exist", id) - // Also register in unified registry - p.registry.Register(stack.ConvertSyncTesterID(id).ComponentID, v) + _, exists := p.registry.Get(id) + p.require().False(exists, "sync tester %s must not already exist", id) + p.registry.Register(id, v) } diff --git a/op-devstack/shim/op_rbuilder.go b/op-devstack/shim/op_rbuilder.go index a1fca59679f..4b5c8216e4f 100644 --- a/op-devstack/shim/op_rbuilder.go +++ b/op-devstack/shim/op_rbuilder.go @@ -13,13 +13,13 @@ import ( type OPRBuilderNodeConfig struct { ELNodeConfig RollupCfg *rollup.Config - ID stack.OPRBuilderNodeID + ID stack.ComponentID FlashblocksClient *opclient.WSClient } type OPRBuilderNode struct { rpcELNode - id stack.OPRBuilderNodeID + id stack.ComponentID engineClient *sources.EngineClient flashblocksClient *opclient.WSClient } @@ -41,7 +41,7 @@ func NewOPRBuilderNode(cfg OPRBuilderNodeConfig) *OPRBuilderNode { } } -func (r *OPRBuilderNode) ID() stack.OPRBuilderNodeID { +func (r *OPRBuilderNode) ID() stack.ComponentID { return r.id } diff --git a/op-devstack/shim/rollup_boost.go b/op-devstack/shim/rollup_boost.go index be4fa4ef6e7..9ef83957942 100644 --- a/op-devstack/shim/rollup_boost.go +++ b/op-devstack/shim/rollup_boost.go @@ -13,7 +13,7 @@ import ( type RollupBoostNodeConfig struct { ELNodeConfig RollupCfg *rollup.Config - ID stack.RollupBoostNodeID + ID stack.ComponentID FlashblocksClient *opclient.WSClient } @@ -21,7 +21,7 @@ type RollupBoostNode struct { rpcELNode engineClient *sources.EngineClient - id stack.RollupBoostNodeID + id stack.ComponentID flashblocksClient *opclient.WSClient } @@ -43,7 +43,7 @@ func NewRollupBoostNode(cfg RollupBoostNodeConfig) *RollupBoostNode { } } -func (r *RollupBoostNode) ID() stack.RollupBoostNodeID { +func (r *RollupBoostNode) ID() stack.ComponentID { return r.id } diff --git a/op-devstack/shim/superchain.go b/op-devstack/shim/superchain.go index 1920fb52955..8e651c09a6b 100644 --- a/op-devstack/shim/superchain.go +++ b/op-devstack/shim/superchain.go @@ -6,13 +6,13 @@ import ( type SuperchainConfig struct { CommonConfig - ID stack.SuperchainID + ID stack.ComponentID Deployment stack.SuperchainDeployment } type presetSuperchain struct { commonImpl - id stack.SuperchainID + id stack.ComponentID deployment stack.SuperchainDeployment } @@ -27,7 +27,7 @@ func NewSuperchain(cfg SuperchainConfig) stack.Superchain { } } -func (p *presetSuperchain) ID() stack.SuperchainID { +func (p *presetSuperchain) ID() stack.ComponentID { return p.id } diff --git a/op-devstack/shim/supervisor.go b/op-devstack/shim/supervisor.go index ec5d4c06941..2a91406ec02 100644 --- a/op-devstack/shim/supervisor.go +++ b/op-devstack/shim/supervisor.go @@ -9,13 +9,13 @@ import ( type SupervisorConfig struct { CommonConfig - ID stack.SupervisorID + ID stack.ComponentID Client client.RPC } type rpcSupervisor struct { commonImpl - id stack.SupervisorID + id stack.ComponentID client client.RPC api apis.SupervisorAPI @@ -33,7 +33,7 @@ func NewSupervisor(cfg SupervisorConfig) stack.Supervisor { } } -func (r *rpcSupervisor) ID() stack.SupervisorID { +func (r *rpcSupervisor) ID() stack.ComponentID { return r.id } diff --git a/op-devstack/shim/sync_tester.go b/op-devstack/shim/sync_tester.go index 460169e148f..d86862374f0 100644 --- a/op-devstack/shim/sync_tester.go +++ b/op-devstack/shim/sync_tester.go @@ -12,7 +12,7 @@ import ( type SyncTesterConfig struct { CommonConfig - ID stack.SyncTesterID + ID stack.ComponentID Addr string Client client.RPC } @@ -20,7 +20,7 @@ type SyncTesterConfig struct { // presetSyncTester wraps around a syncTester-service, type presetSyncTester struct { commonImpl - id stack.SyncTesterID + id stack.ComponentID // Endpoint for initializing RPC Client per session addr string // RPC Client initialized without session @@ -39,7 +39,7 @@ func NewSyncTester(cfg SyncTesterConfig) stack.SyncTester { } } -func (p *presetSyncTester) ID() stack.SyncTesterID { +func (p *presetSyncTester) ID() stack.ComponentID { return p.id } diff --git a/op-devstack/shim/system.go b/op-devstack/shim/system.go index 71996c5beb0..3523e4e9485 100644 --- a/op-devstack/shim/system.go +++ b/op-devstack/shim/system.go @@ -24,22 +24,7 @@ type presetSystem struct { // Unified component registry for generic access registry *stack.Registry - // Legacy typed maps - kept for backward compatibility during migration - superchains locks.RWMap[stack.SuperchainID, stack.Superchain] - clusters locks.RWMap[stack.ClusterID, stack.Cluster] - - // tracks L1 networks by L1NetworkID (a typed eth.ChainID) - l1Networks locks.RWMap[stack.L1NetworkID, stack.L1Network] - // tracks L2 networks by L2NetworkID (a typed eth.ChainID) - l2Networks locks.RWMap[stack.L2NetworkID, stack.L2Network] - - // tracks all networks, and ensures there are no networks with the same eth.ChainID - networks locks.RWMap[eth.ChainID, stack.Network] - - supervisors locks.RWMap[stack.SupervisorID, stack.Supervisor] - supernodes locks.RWMap[stack.SupernodeID, stack.Supernode] - sequencers locks.RWMap[stack.TestSequencerID, stack.TestSequencer] - syncTesters locks.RWMap[stack.SyncTesterID, stack.SyncTester] + supernodes locks.RWMap[stack.ComponentID, stack.Supernode] } var _ stack.ExtensibleSystem = (*presetSystem)(nil) @@ -74,78 +59,131 @@ func (p *presetSystem) ComponentIDs(kind stack.ComponentKind) []stack.ComponentI } func (p *presetSystem) Superchain(m stack.SuperchainMatcher) stack.Superchain { - v, ok := findMatch(m, p.superchains.Get, p.Superchains) + getter := func(id stack.ComponentID) (stack.Superchain, bool) { + v, ok := p.registry.Get(id) + if !ok { + return nil, false + } + return v.(stack.Superchain), true + } + v, ok := findMatch(m, getter, p.Superchains) p.require().True(ok, "must find superchain %s", m) return v } func (p *presetSystem) AddSuperchain(v stack.Superchain) { - p.require().True(p.superchains.SetIfMissing(v.ID(), v), "superchain %s must not already exist", v.ID()) - // Also register in unified registry - p.registry.Register(stack.ConvertSuperchainID(v.ID()).ComponentID, v) + id := v.ID() + _, exists := p.registry.Get(id) + p.require().False(exists, "superchain %s must not already exist", id) + p.registry.Register(id, v) } func (p *presetSystem) Cluster(m stack.ClusterMatcher) stack.Cluster { - v, ok := findMatch(m, p.clusters.Get, p.Clusters) + getter := func(id stack.ComponentID) (stack.Cluster, bool) { + v, ok := p.registry.Get(id) + if !ok { + return nil, false + } + return v.(stack.Cluster), true + } + v, ok := findMatch(m, getter, p.Clusters) p.require().True(ok, "must find cluster %s", m) return v } func (p *presetSystem) AddCluster(v stack.Cluster) { - p.require().True(p.clusters.SetIfMissing(v.ID(), v), "cluster %s must not already exist", v.ID()) - // Also register in unified registry - p.registry.Register(stack.ConvertClusterID(v.ID()).ComponentID, v) + id := v.ID() + _, exists := p.registry.Get(id) + p.require().False(exists, "cluster %s must not already exist", id) + p.registry.Register(id, v) +} + +// networkExistsByChainID checks if any network (L1 or L2) exists with the given chain ID +func (p *presetSystem) networkExistsByChainID(chainID eth.ChainID) bool { + l1ID := stack.NewL1NetworkID(chainID) + if _, ok := p.registry.Get(l1ID); ok { + return true + } + l2ID := stack.NewL2NetworkID(chainID) + if _, ok := p.registry.Get(l2ID); ok { + return true + } + return false } func (p *presetSystem) Network(id eth.ChainID) stack.Network { - if l1Net, ok := p.l1Networks.Get(stack.L1NetworkID(id)); ok { - return l1Net + l1ID := stack.NewL1NetworkID(id) + if l1Net, ok := p.registry.Get(l1ID); ok { + return l1Net.(stack.L1Network) } - if l2Net, ok := p.l2Networks.Get(stack.L2NetworkID(id)); ok { - return l2Net + l2ID := stack.NewL2NetworkID(id) + if l2Net, ok := p.registry.Get(l2ID); ok { + return l2Net.(stack.L2Network) } p.t.FailNow() return nil } func (p *presetSystem) L1Network(m stack.L1NetworkMatcher) stack.L1Network { - v, ok := findMatch(m, p.l1Networks.Get, p.L1Networks) + getter := func(id stack.ComponentID) (stack.L1Network, bool) { + v, ok := p.registry.Get(id) + if !ok { + return nil, false + } + return v.(stack.L1Network), true + } + v, ok := findMatch(m, getter, p.L1Networks) p.require().True(ok, "must find l1 network %s", m) return v } func (p *presetSystem) AddL1Network(v stack.L1Network) { id := v.ID() - p.require().True(p.networks.SetIfMissing(id.ChainID(), v), "chain with id %s must not already exist", id.ChainID()) - p.require().True(p.l1Networks.SetIfMissing(id, v), "L1 chain %s must not already exist", id) - // Also register in unified registry - p.registry.Register(stack.ConvertL1NetworkID(id).ComponentID, v) + p.require().False(p.networkExistsByChainID(id.ChainID()), "chain with id %s must not already exist", id.ChainID()) + _, exists := p.registry.Get(id) + p.require().False(exists, "L1 chain %s must not already exist", id) + p.registry.Register(id, v) } func (p *presetSystem) L2Network(m stack.L2NetworkMatcher) stack.L2Network { - v, ok := findMatch(m, p.l2Networks.Get, p.L2Networks) + getter := func(id stack.ComponentID) (stack.L2Network, bool) { + v, ok := p.registry.Get(id) + if !ok { + return nil, false + } + return v.(stack.L2Network), true + } + v, ok := findMatch(m, getter, p.L2Networks) p.require().True(ok, "must find l2 network %s", m) return v } func (p *presetSystem) AddL2Network(v stack.L2Network) { id := v.ID() - p.require().True(p.networks.SetIfMissing(id.ChainID(), v), "chain with id %s must not already exist", id.ChainID()) - p.require().True(p.l2Networks.SetIfMissing(id, v), "L2 chain %s must not already exist", id) - // Also register in unified registry - p.registry.Register(stack.ConvertL2NetworkID(id).ComponentID, v) + p.require().False(p.networkExistsByChainID(id.ChainID()), "chain with id %s must not already exist", id.ChainID()) + _, exists := p.registry.Get(id) + p.require().False(exists, "L2 chain %s must not already exist", id) + p.registry.Register(id, v) } func (p *presetSystem) Supervisor(m stack.SupervisorMatcher) stack.Supervisor { - v, ok := findMatch(m, p.supervisors.Get, p.Supervisors) + getter := func(id stack.ComponentID) (stack.Supervisor, bool) { + v, ok := p.registry.Get(id) + if !ok { + return nil, false + } + return v.(stack.Supervisor), true + } + v, ok := findMatch(m, getter, p.Supervisors) p.require().True(ok, "must find supervisor %s", m) return v } func (p *presetSystem) AddSupervisor(v stack.Supervisor) { - p.require().True(p.supervisors.SetIfMissing(v.ID(), v), "supervisor %s must not already exist", v.ID()) - // Also register in unified registry - p.registry.Register(stack.ConvertSupervisorID(v.ID()).ComponentID, v) + id := v.ID() + _, exists := p.registry.Get(id) + p.require().False(exists, "supervisor %s must not already exist", id) + p.registry.Register(id, v) } func (p *presetSystem) Supernode(m stack.SupernodeMatcher) stack.Supernode { @@ -159,61 +197,105 @@ func (p *presetSystem) AddSupernode(v stack.Supernode) { } func (p *presetSystem) TestSequencer(m stack.TestSequencerMatcher) stack.TestSequencer { - v, ok := findMatch(m, p.sequencers.Get, p.TestSequencers) + getter := func(id stack.ComponentID) (stack.TestSequencer, bool) { + v, ok := p.registry.Get(id) + if !ok { + return nil, false + } + return v.(stack.TestSequencer), true + } + v, ok := findMatch(m, getter, p.TestSequencers) p.require().True(ok, "must find sequencer %s", m) return v } func (p *presetSystem) AddTestSequencer(v stack.TestSequencer) { - p.require().True(p.sequencers.SetIfMissing(v.ID(), v), "sequencer %s must not already exist", v.ID()) - // Also register in unified registry - p.registry.Register(stack.ConvertTestSequencerID(v.ID()).ComponentID, v) + id := v.ID() + _, exists := p.registry.Get(id) + p.require().False(exists, "sequencer %s must not already exist", id) + p.registry.Register(id, v) } func (p *presetSystem) AddSyncTester(v stack.SyncTester) { - p.require().True(p.syncTesters.SetIfMissing(v.ID(), v), "sync tester %s must not already exist", v.ID()) - // Also register in unified registry - p.registry.Register(stack.ConvertSyncTesterID(v.ID()).ComponentID, v) + id := v.ID() + _, exists := p.registry.Get(id) + p.require().False(exists, "sync tester %s must not already exist", id) + p.registry.Register(id, v) } -func (p *presetSystem) SuperchainIDs() []stack.SuperchainID { - return stack.SortSuperchainIDs(p.superchains.Keys()) +func (p *presetSystem) SuperchainIDs() []stack.ComponentID { + return sortByID(p.registry.IDsByKind(stack.KindSuperchain)) } func (p *presetSystem) Superchains() []stack.Superchain { - return stack.SortSuperchains(p.superchains.Values()) + ids := p.registry.IDsByKind(stack.KindSuperchain) + result := make([]stack.Superchain, 0, len(ids)) + for _, id := range ids { + if v, ok := p.registry.Get(id); ok { + result = append(result, v.(stack.Superchain)) + } + } + return sortByIDFunc(result) } -func (p *presetSystem) ClusterIDs() []stack.ClusterID { - return stack.SortClusterIDs(p.clusters.Keys()) +func (p *presetSystem) ClusterIDs() []stack.ComponentID { + return sortByID(p.registry.IDsByKind(stack.KindCluster)) } func (p *presetSystem) Clusters() []stack.Cluster { - return stack.SortClusters(p.clusters.Values()) + ids := p.registry.IDsByKind(stack.KindCluster) + result := make([]stack.Cluster, 0, len(ids)) + for _, id := range ids { + if v, ok := p.registry.Get(id); ok { + result = append(result, v.(stack.Cluster)) + } + } + return sortByIDFunc(result) } -func (p *presetSystem) L1NetworkIDs() []stack.L1NetworkID { - return stack.SortL1NetworkIDs(p.l1Networks.Keys()) +func (p *presetSystem) L1NetworkIDs() []stack.ComponentID { + return sortByID(p.registry.IDsByKind(stack.KindL1Network)) } func (p *presetSystem) L1Networks() []stack.L1Network { - return stack.SortL1Networks(p.l1Networks.Values()) + ids := p.registry.IDsByKind(stack.KindL1Network) + result := make([]stack.L1Network, 0, len(ids)) + for _, id := range ids { + if v, ok := p.registry.Get(id); ok { + result = append(result, v.(stack.L1Network)) + } + } + return sortByIDFunc(result) } -func (p *presetSystem) L2NetworkIDs() []stack.L2NetworkID { - return stack.SortL2NetworkIDs(p.l2Networks.Keys()) +func (p *presetSystem) L2NetworkIDs() []stack.ComponentID { + return sortByID(p.registry.IDsByKind(stack.KindL2Network)) } func (p *presetSystem) L2Networks() []stack.L2Network { - return stack.SortL2Networks(p.l2Networks.Values()) + ids := p.registry.IDsByKind(stack.KindL2Network) + result := make([]stack.L2Network, 0, len(ids)) + for _, id := range ids { + if v, ok := p.registry.Get(id); ok { + result = append(result, v.(stack.L2Network)) + } + } + return sortByIDFunc(result) } -func (p *presetSystem) SupervisorIDs() []stack.SupervisorID { - return stack.SortSupervisorIDs(p.supervisors.Keys()) +func (p *presetSystem) SupervisorIDs() []stack.ComponentID { + return sortByID(p.registry.IDsByKind(stack.KindSupervisor)) } func (p *presetSystem) Supervisors() []stack.Supervisor { - return stack.SortSupervisors(p.supervisors.Values()) + ids := p.registry.IDsByKind(stack.KindSupervisor) + result := make([]stack.Supervisor, 0, len(ids)) + for _, id := range ids { + if v, ok := p.registry.Get(id); ok { + result = append(result, v.(stack.Supervisor)) + } + } + return sortByIDFunc(result) } func (p *presetSystem) Supernodes() []stack.Supernode { @@ -221,7 +303,14 @@ func (p *presetSystem) Supernodes() []stack.Supernode { } func (p *presetSystem) TestSequencers() []stack.TestSequencer { - return stack.SortTestSequencers(p.sequencers.Values()) + ids := p.registry.IDsByKind(stack.KindTestSequencer) + result := make([]stack.TestSequencer, 0, len(ids)) + for _, id := range ids { + if v, ok := p.registry.Get(id); ok { + result = append(result, v.(stack.TestSequencer)) + } + } + return sortByIDFunc(result) } func (p *presetSystem) SetTimeTravelClock(cl stack.TimeTravelClock) { diff --git a/op-devstack/shim/test_sequencer.go b/op-devstack/shim/test_sequencer.go index 6f045efccc7..5edb519c6f8 100644 --- a/op-devstack/shim/test_sequencer.go +++ b/op-devstack/shim/test_sequencer.go @@ -10,14 +10,14 @@ import ( type TestSequencerConfig struct { CommonConfig - ID stack.TestSequencerID + ID stack.ComponentID Client client.RPC ControlClients map[eth.ChainID]client.RPC } type rpcTestSequencer struct { commonImpl - id stack.TestSequencerID + id stack.ComponentID client client.RPC api apis.TestSequencerAPI @@ -42,7 +42,7 @@ func NewTestSequencer(cfg TestSequencerConfig) stack.TestSequencer { return s } -func (r *rpcTestSequencer) ID() stack.TestSequencerID { +func (r *rpcTestSequencer) ID() stack.ComponentID { return r.id } diff --git a/op-devstack/stack/capabilities.go b/op-devstack/stack/capabilities.go deleted file mode 100644 index 7075fa0eabf..00000000000 --- a/op-devstack/stack/capabilities.go +++ /dev/null @@ -1,134 +0,0 @@ -package stack - -import ( - "github.com/ethereum-optimism/optimism/op-service/apis" - "github.com/ethereum-optimism/optimism/op-service/eth" -) - -// Capability interfaces define shared behaviors across component types. -// These enable polymorphic operations without requiring components to -// implement interfaces with incompatible ID() method signatures. -// -// For example, RollupBoostNode and OPRBuilderNode both provide L2 EL -// functionality but can't implement L2ELNode because their ID() methods -// return different types. The L2ELCapable interface captures the shared -// L2 EL behavior, allowing code to work with any L2 EL-like component. - -// L2ELCapable is implemented by any component that provides L2 execution layer functionality. -// This includes L2ELNode, RollupBoostNode, and OPRBuilderNode. -// -// Components implementing this interface can: -// - Execute L2 transactions -// - Provide engine API access for consensus layer integration -type L2ELCapable interface { - L2EthClient() apis.L2EthClient - L2EngineClient() apis.EngineClient - ELNode -} - -// L2ELCapableKinds returns all ComponentKinds that implement L2ELCapable. -func L2ELCapableKinds() []ComponentKind { - return []ComponentKind{ - KindL2ELNode, - KindRollupBoostNode, - KindOPRBuilderNode, - } -} - -// L1ELCapable is implemented by any component that provides L1 execution layer functionality. -type L1ELCapable interface { - ELNode -} - -// L1ELCapableKinds returns all ComponentKinds that implement L1ELCapable. -func L1ELCapableKinds() []ComponentKind { - return []ComponentKind{ - KindL1ELNode, - } -} - -// Verify that expected types implement capability interfaces. -// These are compile-time checks. -var ( - _ L2ELCapable = (L2ELNode)(nil) - _ L2ELCapable = (RollupBoostNode)(nil) - _ L2ELCapable = (OPRBuilderNode)(nil) -) - -// Registry helper functions for capability-based lookups. - -// RegistryFindByCapability returns all components that implement the given capability interface. -// This iterates over all components and performs a type assertion. -func RegistryFindByCapability[T any](r *Registry) []T { - var result []T - r.Range(func(id ComponentID, component any) bool { - if capable, ok := component.(T); ok { - result = append(result, capable) - } - return true - }) - return result -} - -// RegistryFindByCapabilityOnChain returns all components on a specific chain -// that implement the given capability interface. -func RegistryFindByCapabilityOnChain[T any](r *Registry, chainID eth.ChainID) []T { - var result []T - r.RangeByChainID(chainID, func(id ComponentID, component any) bool { - if capable, ok := component.(T); ok { - result = append(result, capable) - } - return true - }) - return result -} - -// RegistryFindByKinds returns all components of the specified kinds. -// This is useful when you know which kinds implement a capability. -func RegistryFindByKinds(r *Registry, kinds []ComponentKind) []any { - var result []any - for _, kind := range kinds { - result = append(result, r.GetByKind(kind)...) - } - return result -} - -// RegistryFindByKindsTyped returns all components of the specified kinds, -// cast to the expected type. Components that don't match are skipped. -func RegistryFindByKindsTyped[T any](r *Registry, kinds []ComponentKind) []T { - var result []T - for _, kind := range kinds { - for _, component := range r.GetByKind(kind) { - if typed, ok := component.(T); ok { - result = append(result, typed) - } - } - } - return result -} - -// FindL2ELCapable returns all L2 EL-capable components in the registry. -// This is a convenience function that finds L2ELNode, RollupBoostNode, and OPRBuilderNode. -func FindL2ELCapable(r *Registry) []L2ELCapable { - return RegistryFindByKindsTyped[L2ELCapable](r, L2ELCapableKinds()) -} - -// FindL2ELCapableOnChain returns all L2 EL-capable components on a specific chain. -func FindL2ELCapableOnChain(r *Registry, chainID eth.ChainID) []L2ELCapable { - return RegistryFindByCapabilityOnChain[L2ELCapable](r, chainID) -} - -// FindL2ELCapableByKey returns the first L2 EL-capable component with the given key and chainID. -// This enables the polymorphic lookup pattern where you want to find a node by key -// regardless of whether it's an L2ELNode, RollupBoostNode, or OPRBuilderNode. -func FindL2ELCapableByKey(r *Registry, key string, chainID eth.ChainID) (L2ELCapable, bool) { - for _, kind := range L2ELCapableKinds() { - id := NewComponentID(kind, key, chainID) - if component, ok := r.Get(id); ok { - if capable, ok := component.(L2ELCapable); ok { - return capable, true - } - } - } - return nil, false -} diff --git a/op-devstack/stack/capabilities_test.go b/op-devstack/stack/capabilities_test.go deleted file mode 100644 index b69758a0b9a..00000000000 --- a/op-devstack/stack/capabilities_test.go +++ /dev/null @@ -1,312 +0,0 @@ -package stack - -import ( - "testing" - "time" - - "github.com/ethereum-optimism/optimism/op-service/apis" - "github.com/ethereum-optimism/optimism/op-service/client" - "github.com/ethereum-optimism/optimism/op-service/eth" - "github.com/ethereum/go-ethereum/log" - "github.com/stretchr/testify/require" - - "github.com/ethereum-optimism/optimism/op-devstack/devtest" -) - -// Mock implementations for testing capabilities - -type mockELNode struct { - chainID eth.ChainID -} - -func (m *mockELNode) T() devtest.T { return nil } -func (m *mockELNode) Logger() log.Logger { return nil } -func (m *mockELNode) Label(key string) string { return "" } -func (m *mockELNode) SetLabel(key, value string) {} -func (m *mockELNode) ChainID() eth.ChainID { return m.chainID } -func (m *mockELNode) EthClient() apis.EthClient { return nil } -func (m *mockELNode) TransactionTimeout() time.Duration { return 0 } - -type mockL2ELNode struct { - mockELNode - id L2ELNodeID -} - -func (m *mockL2ELNode) ID() L2ELNodeID { return m.id } -func (m *mockL2ELNode) L2EthClient() apis.L2EthClient { return nil } -func (m *mockL2ELNode) L2EngineClient() apis.EngineClient { return nil } -func (m *mockL2ELNode) RegistryID() ComponentID { return ConvertL2ELNodeID(m.id).ComponentID } - -var _ L2ELNode = (*mockL2ELNode)(nil) -var _ L2ELCapable = (*mockL2ELNode)(nil) -var _ Registrable = (*mockL2ELNode)(nil) - -type mockRollupBoostNode struct { - mockELNode - id RollupBoostNodeID -} - -func (m *mockRollupBoostNode) ID() RollupBoostNodeID { return m.id } -func (m *mockRollupBoostNode) L2EthClient() apis.L2EthClient { return nil } -func (m *mockRollupBoostNode) L2EngineClient() apis.EngineClient { return nil } -func (m *mockRollupBoostNode) FlashblocksClient() *client.WSClient { return nil } -func (m *mockRollupBoostNode) RegistryID() ComponentID { - return ConvertRollupBoostNodeID(m.id).ComponentID -} - -var _ RollupBoostNode = (*mockRollupBoostNode)(nil) -var _ L2ELCapable = (*mockRollupBoostNode)(nil) -var _ Registrable = (*mockRollupBoostNode)(nil) - -type mockOPRBuilderNode struct { - mockELNode - id OPRBuilderNodeID -} - -func (m *mockOPRBuilderNode) ID() OPRBuilderNodeID { return m.id } -func (m *mockOPRBuilderNode) L2EthClient() apis.L2EthClient { return nil } -func (m *mockOPRBuilderNode) L2EngineClient() apis.EngineClient { return nil } -func (m *mockOPRBuilderNode) FlashblocksClient() *client.WSClient { return nil } -func (m *mockOPRBuilderNode) RegistryID() ComponentID { - return ConvertOPRBuilderNodeID(m.id).ComponentID -} - -var _ OPRBuilderNode = (*mockOPRBuilderNode)(nil) -var _ L2ELCapable = (*mockOPRBuilderNode)(nil) -var _ Registrable = (*mockOPRBuilderNode)(nil) - -func TestL2ELCapableKinds(t *testing.T) { - kinds := L2ELCapableKinds() - require.Len(t, kinds, 3) - require.Contains(t, kinds, KindL2ELNode) - require.Contains(t, kinds, KindRollupBoostNode) - require.Contains(t, kinds, KindOPRBuilderNode) -} - -func TestRegistryFindByCapability(t *testing.T) { - r := NewRegistry() - - chainID := eth.ChainIDFromUInt64(420) - - // Register different L2 EL-capable nodes - l2el := &mockL2ELNode{ - mockELNode: mockELNode{chainID: chainID}, - id: NewL2ELNodeID("sequencer", chainID), - } - rollupBoost := &mockRollupBoostNode{ - mockELNode: mockELNode{chainID: chainID}, - id: NewRollupBoostNodeID("boost", chainID), - } - oprBuilder := &mockOPRBuilderNode{ - mockELNode: mockELNode{chainID: chainID}, - id: NewOPRBuilderNodeID("builder", chainID), - } - - r.RegisterComponent(l2el) - r.RegisterComponent(rollupBoost) - r.RegisterComponent(oprBuilder) - - // Also register a non-L2EL component - r.Register(NewComponentID(KindL2Batcher, "batcher", chainID), "not-l2el-capable") - - // Find all L2ELCapable - capable := RegistryFindByCapability[L2ELCapable](r) - require.Len(t, capable, 3) -} - -func TestRegistryFindByCapabilityOnChain(t *testing.T) { - r := NewRegistry() - - chainID1 := eth.ChainIDFromUInt64(420) - chainID2 := eth.ChainIDFromUInt64(421) - - // Nodes on chain 420 - l2el1 := &mockL2ELNode{ - mockELNode: mockELNode{chainID: chainID1}, - id: NewL2ELNodeID("sequencer", chainID1), - } - rollupBoost1 := &mockRollupBoostNode{ - mockELNode: mockELNode{chainID: chainID1}, - id: NewRollupBoostNodeID("boost", chainID1), - } - - // Node on chain 421 - l2el2 := &mockL2ELNode{ - mockELNode: mockELNode{chainID: chainID2}, - id: NewL2ELNodeID("sequencer", chainID2), - } - - r.RegisterComponent(l2el1) - r.RegisterComponent(rollupBoost1) - r.RegisterComponent(l2el2) - - // Find on chain 420 - chain420 := RegistryFindByCapabilityOnChain[L2ELCapable](r, chainID1) - require.Len(t, chain420, 2) - - // Find on chain 421 - chain421 := RegistryFindByCapabilityOnChain[L2ELCapable](r, chainID2) - require.Len(t, chain421, 1) -} - -func TestFindL2ELCapable(t *testing.T) { - r := NewRegistry() - - chainID := eth.ChainIDFromUInt64(420) - - l2el := &mockL2ELNode{ - mockELNode: mockELNode{chainID: chainID}, - id: NewL2ELNodeID("sequencer", chainID), - } - rollupBoost := &mockRollupBoostNode{ - mockELNode: mockELNode{chainID: chainID}, - id: NewRollupBoostNodeID("boost", chainID), - } - - r.RegisterComponent(l2el) - r.RegisterComponent(rollupBoost) - - capable := FindL2ELCapable(r) - require.Len(t, capable, 2) -} - -func TestFindL2ELCapableOnChain(t *testing.T) { - r := NewRegistry() - - chainID1 := eth.ChainIDFromUInt64(420) - chainID2 := eth.ChainIDFromUInt64(421) - - l2el1 := &mockL2ELNode{ - mockELNode: mockELNode{chainID: chainID1}, - id: NewL2ELNodeID("sequencer", chainID1), - } - l2el2 := &mockL2ELNode{ - mockELNode: mockELNode{chainID: chainID2}, - id: NewL2ELNodeID("sequencer", chainID2), - } - - r.RegisterComponent(l2el1) - r.RegisterComponent(l2el2) - - chain420 := FindL2ELCapableOnChain(r, chainID1) - require.Len(t, chain420, 1) - require.Equal(t, chainID1, chain420[0].ChainID()) -} - -func TestFindL2ELCapableByKey(t *testing.T) { - r := NewRegistry() - - chainID := eth.ChainIDFromUInt64(420) - - // Register a RollupBoostNode with key "sequencer" - rollupBoost := &mockRollupBoostNode{ - mockELNode: mockELNode{chainID: chainID}, - id: NewRollupBoostNodeID("sequencer", chainID), - } - r.RegisterComponent(rollupBoost) - - // Should find it by key, even though it's not an L2ELNode - found, ok := FindL2ELCapableByKey(r, "sequencer", chainID) - require.True(t, ok) - require.NotNil(t, found) - require.Equal(t, chainID, found.ChainID()) - - // Should not find non-existent key - _, ok = FindL2ELCapableByKey(r, "nonexistent", chainID) - require.False(t, ok) -} - -func TestFindL2ELCapableByKey_PrefersL2ELNode(t *testing.T) { - r := NewRegistry() - - chainID := eth.ChainIDFromUInt64(420) - - // Register both L2ELNode and RollupBoostNode with same key - l2el := &mockL2ELNode{ - mockELNode: mockELNode{chainID: chainID}, - id: NewL2ELNodeID("sequencer", chainID), - } - rollupBoost := &mockRollupBoostNode{ - mockELNode: mockELNode{chainID: chainID}, - id: NewRollupBoostNodeID("sequencer", chainID), - } - - r.RegisterComponent(l2el) - r.RegisterComponent(rollupBoost) - - // Should find L2ELNode first (it's first in L2ELCapableKinds) - found, ok := FindL2ELCapableByKey(r, "sequencer", chainID) - require.True(t, ok) - // Verify it's the L2ELNode by checking it's the right mock type - _, isL2EL := found.(*mockL2ELNode) - require.True(t, isL2EL, "expected to find L2ELNode first") -} - -func TestRegistryFindByKindsTyped(t *testing.T) { - r := NewRegistry() - - chainID := eth.ChainIDFromUInt64(420) - - l2el := &mockL2ELNode{ - mockELNode: mockELNode{chainID: chainID}, - id: NewL2ELNodeID("sequencer", chainID), - } - rollupBoost := &mockRollupBoostNode{ - mockELNode: mockELNode{chainID: chainID}, - id: NewRollupBoostNodeID("boost", chainID), - } - - r.RegisterComponent(l2el) - r.RegisterComponent(rollupBoost) - - // Find only L2ELNode kind - l2els := RegistryFindByKindsTyped[L2ELCapable](r, []ComponentKind{KindL2ELNode}) - require.Len(t, l2els, 1) - - // Find both kinds - both := RegistryFindByKindsTyped[L2ELCapable](r, []ComponentKind{KindL2ELNode, KindRollupBoostNode}) - require.Len(t, both, 2) -} - -// TestPolymorphicLookupScenario demonstrates the polymorphic lookup use case -// that Phase 3 is designed to solve. -func TestPolymorphicLookupScenario(t *testing.T) { - r := NewRegistry() - - chainID := eth.ChainIDFromUInt64(420) - - // Scenario: A test wants to find an L2 EL node by key "sequencer" - // The actual node could be L2ELNode, RollupBoostNode, or OPRBuilderNode - // depending on the test configuration. - - // Configuration 1: Using RollupBoost - rollupBoost := &mockRollupBoostNode{ - mockELNode: mockELNode{chainID: chainID}, - id: NewRollupBoostNodeID("sequencer", chainID), - } - r.RegisterComponent(rollupBoost) - - // The polymorphic lookup finds the sequencer regardless of its concrete type - sequencer, ok := FindL2ELCapableByKey(r, "sequencer", chainID) - require.True(t, ok) - require.NotNil(t, sequencer) - - // Can use it as L2ELCapable - require.Equal(t, chainID, sequencer.ChainID()) - // Could call sequencer.L2EthClient(), sequencer.L2EngineClient(), etc. - - // Clear and try with OPRBuilder - r.Clear() - - oprBuilder := &mockOPRBuilderNode{ - mockELNode: mockELNode{chainID: chainID}, - id: NewOPRBuilderNodeID("sequencer", chainID), - } - r.RegisterComponent(oprBuilder) - - // Same lookup code works - sequencer, ok = FindL2ELCapableByKey(r, "sequencer", chainID) - require.True(t, ok) - require.NotNil(t, sequencer) - require.Equal(t, chainID, sequencer.ChainID()) -} diff --git a/op-devstack/stack/cluster.go b/op-devstack/stack/cluster.go index 09ae8ce557a..d1af1e22248 100644 --- a/op-devstack/stack/cluster.go +++ b/op-devstack/stack/cluster.go @@ -1,57 +1,14 @@ package stack import ( - "log/slog" - "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/backend/depset" ) -// ClusterID identifies a Cluster by name, is type-safe, and can be value-copied and used as map key. -type ClusterID genericID - -var _ GenericID = (*ClusterID)(nil) - -const ClusterKind Kind = "Cluster" - -func (id ClusterID) String() string { - return genericID(id).string(ClusterKind) -} - -func (id ClusterID) Kind() Kind { - return ClusterKind -} - -func (id ClusterID) LogValue() slog.Value { - return slog.StringValue(id.String()) -} - -func (id ClusterID) MarshalText() ([]byte, error) { - return genericID(id).marshalText(ClusterKind) -} - -func (id *ClusterID) UnmarshalText(data []byte) error { - return (*genericID)(id).unmarshalText(ClusterKind, data) -} - -func SortClusterIDs(ids []ClusterID) []ClusterID { - return copyAndSortCmp(ids) -} - -func SortClusters(elems []Cluster) []Cluster { - return copyAndSort(elems, lessElemOrdered[ClusterID, Cluster]) -} - -var _ ClusterMatcher = ClusterID("") - -func (id ClusterID) Match(elems []Cluster) []Cluster { - return findByID(id, elems) -} - // Cluster represents a set of chains that interop with each other. // This may include L1 chains (although potentially not two-way interop due to consensus-layer limitations). type Cluster interface { Common - ID() ClusterID + ID() ComponentID DependencySet() depset.DependencySet } diff --git a/op-devstack/stack/component_id.go b/op-devstack/stack/component_id.go index fdce22a6b17..ce87817a391 100644 --- a/op-devstack/stack/component_id.go +++ b/op-devstack/stack/component_id.go @@ -2,6 +2,7 @@ package stack import ( "bytes" + "errors" "fmt" "log/slog" @@ -13,6 +14,44 @@ import ( // This is used in serialization to make each ID unique and type-safe. type ComponentKind string +var _ slog.LogValuer = (*ComponentKind)(nil) + +// ChainIDProvider presents a type that provides a relevant ChainID. +type ChainIDProvider interface { + ChainID() eth.ChainID +} + +// KindProvider presents a type that provides a relevant ComponentKind. E.g. KindL2Batcher. +type KindProvider interface { + Kind() ComponentKind +} + +// Keyed presents a type that provides a relevant string key. E.g. a named superchain. +type Keyed interface { + Key() string +} + +const maxIDLength = 100 + +var errInvalidID = errors.New("invalid ID") + +func (k ComponentKind) LogValue() slog.Value { + return slog.StringValue(string(k)) +} + +func (k ComponentKind) String() string { + return string(k) +} + +func (k ComponentKind) MarshalText() ([]byte, error) { + return []byte(k), nil +} + +func (k *ComponentKind) UnmarshalText(data []byte) error { + *k = ComponentKind(data) + return nil +} + // All component kinds. These values are used in serialization and must remain stable. const ( KindL1ELNode ComponentKind = "L1ELNode" @@ -234,304 +273,110 @@ func (id ComponentID) Less(other ComponentID) bool { return id.chainID.Cmp(other.chainID) < 0 } -// KindMarker is implemented by marker types to associate them with their ComponentKind. -// This enables type-safe unmarshaling of ID[T] types. -type KindMarker interface { - componentKind() ComponentKind -} - -// ID is a type-safe wrapper around ComponentID. -// The type parameter T must implement KindMarker to enable unmarshaling. -// This prevents accidentally mixing up different ID types (e.g., L2BatcherID vs L2ELNodeID). -type ID[T KindMarker] struct { - ComponentID -} - -// Marker types for each component kind. -// Each marker implements KindMarker to associate it with the correct ComponentKind. -type ( - L1ELNodeMarker struct{} - L1CLNodeMarker struct{} - L1NetworkMarker struct{} - L2ELNodeMarker struct{} - L2CLNodeMarker struct{} - L2NetworkMarker struct{} - L2BatcherMarker struct{} - L2ProposerMarker struct{} - L2ChallengerMarker struct{} - RollupBoostNodeMarker struct{} - OPRBuilderNodeMarker struct{} - FaucetMarker struct{} - SyncTesterMarker struct{} - SupervisorMarker struct{} - ConductorMarker struct{} - ClusterMarker struct{} - SuperchainMarker struct{} - TestSequencerMarker struct{} - FlashblocksClientMarker struct{} -) - -// KindMarker implementations for all marker types. -func (L1ELNodeMarker) componentKind() ComponentKind { return KindL1ELNode } -func (L1CLNodeMarker) componentKind() ComponentKind { return KindL1CLNode } -func (L1NetworkMarker) componentKind() ComponentKind { return KindL1Network } -func (L2ELNodeMarker) componentKind() ComponentKind { return KindL2ELNode } -func (L2CLNodeMarker) componentKind() ComponentKind { return KindL2CLNode } -func (L2NetworkMarker) componentKind() ComponentKind { return KindL2Network } -func (L2BatcherMarker) componentKind() ComponentKind { return KindL2Batcher } -func (L2ProposerMarker) componentKind() ComponentKind { return KindL2Proposer } -func (L2ChallengerMarker) componentKind() ComponentKind { return KindL2Challenger } -func (RollupBoostNodeMarker) componentKind() ComponentKind { return KindRollupBoostNode } -func (OPRBuilderNodeMarker) componentKind() ComponentKind { return KindOPRBuilderNode } -func (FaucetMarker) componentKind() ComponentKind { return KindFaucet } -func (SyncTesterMarker) componentKind() ComponentKind { return KindSyncTester } -func (SupervisorMarker) componentKind() ComponentKind { return KindSupervisor } -func (ConductorMarker) componentKind() ComponentKind { return KindConductor } -func (ClusterMarker) componentKind() ComponentKind { return KindCluster } -func (SuperchainMarker) componentKind() ComponentKind { return KindSuperchain } -func (TestSequencerMarker) componentKind() ComponentKind { return KindTestSequencer } -func (FlashblocksClientMarker) componentKind() ComponentKind { return KindFlashblocksClient } - -// Type-safe ID type aliases using marker types. -// These maintain backward compatibility with existing code. -type ( - L1ELNodeID2 = ID[L1ELNodeMarker] - L1CLNodeID2 = ID[L1CLNodeMarker] - L1NetworkID2 = ID[L1NetworkMarker] - L2ELNodeID2 = ID[L2ELNodeMarker] - L2CLNodeID2 = ID[L2CLNodeMarker] - L2NetworkID2 = ID[L2NetworkMarker] - L2BatcherID2 = ID[L2BatcherMarker] - L2ProposerID2 = ID[L2ProposerMarker] - L2ChallengerID2 = ID[L2ChallengerMarker] - RollupBoostNodeID2 = ID[RollupBoostNodeMarker] - OPRBuilderNodeID2 = ID[OPRBuilderNodeMarker] - FaucetID2 = ID[FaucetMarker] - SyncTesterID2 = ID[SyncTesterMarker] - SupervisorID2 = ID[SupervisorMarker] - ConductorID2 = ID[ConductorMarker] - ClusterID2 = ID[ClusterMarker] - SuperchainID2 = ID[SuperchainMarker] - TestSequencerID2 = ID[TestSequencerMarker] - FlashblocksClientID2 = ID[FlashblocksClientMarker] -) - -// Type-safe constructors for each ID type. - -func NewL1ELNodeID2(key string, chainID eth.ChainID) L1ELNodeID2 { - return L1ELNodeID2{NewComponentID(KindL1ELNode, key, chainID)} -} - -func NewL1CLNodeID2(key string, chainID eth.ChainID) L1CLNodeID2 { - return L1CLNodeID2{NewComponentID(KindL1CLNode, key, chainID)} -} - -func NewL1NetworkID2(chainID eth.ChainID) L1NetworkID2 { - return L1NetworkID2{NewComponentIDChainOnly(KindL1Network, chainID)} +// idMatcher wraps ComponentID to implement Matcher[E] for any component type. +type idMatcher[E Identifiable] struct { + id ComponentID } -func NewL2ELNodeID2(key string, chainID eth.ChainID) L2ELNodeID2 { - return L2ELNodeID2{NewComponentID(KindL2ELNode, key, chainID)} -} - -func NewL2CLNodeID2(key string, chainID eth.ChainID) L2CLNodeID2 { - return L2CLNodeID2{NewComponentID(KindL2CLNode, key, chainID)} -} - -func NewL2NetworkID2(chainID eth.ChainID) L2NetworkID2 { - return L2NetworkID2{NewComponentIDChainOnly(KindL2Network, chainID)} -} - -func NewL2BatcherID2(key string, chainID eth.ChainID) L2BatcherID2 { - return L2BatcherID2{NewComponentID(KindL2Batcher, key, chainID)} -} - -func NewL2ProposerID2(key string, chainID eth.ChainID) L2ProposerID2 { - return L2ProposerID2{NewComponentID(KindL2Proposer, key, chainID)} -} - -func NewL2ChallengerID2(key string, chainID eth.ChainID) L2ChallengerID2 { - return L2ChallengerID2{NewComponentID(KindL2Challenger, key, chainID)} -} - -func NewRollupBoostNodeID2(key string, chainID eth.ChainID) RollupBoostNodeID2 { - return RollupBoostNodeID2{NewComponentID(KindRollupBoostNode, key, chainID)} -} - -func NewOPRBuilderNodeID2(key string, chainID eth.ChainID) OPRBuilderNodeID2 { - return OPRBuilderNodeID2{NewComponentID(KindOPRBuilderNode, key, chainID)} -} - -func NewFaucetID2(key string, chainID eth.ChainID) FaucetID2 { - return FaucetID2{NewComponentID(KindFaucet, key, chainID)} -} - -func NewSyncTesterID2(key string, chainID eth.ChainID) SyncTesterID2 { - return SyncTesterID2{NewComponentID(KindSyncTester, key, chainID)} -} - -func NewSupervisorID2(key string) SupervisorID2 { - return SupervisorID2{NewComponentIDKeyOnly(KindSupervisor, key)} -} - -func NewConductorID2(key string) ConductorID2 { - return ConductorID2{NewComponentIDKeyOnly(KindConductor, key)} -} - -func NewClusterID2(key string) ClusterID2 { - return ClusterID2{NewComponentIDKeyOnly(KindCluster, key)} -} - -func NewSuperchainID2(key string) SuperchainID2 { - return SuperchainID2{NewComponentIDKeyOnly(KindSuperchain, key)} -} - -func NewTestSequencerID2(key string) TestSequencerID2 { - return TestSequencerID2{NewComponentIDKeyOnly(KindTestSequencer, key)} -} - -func NewFlashblocksClientID2(key string, chainID eth.ChainID) FlashblocksClientID2 { - return FlashblocksClientID2{NewComponentID(KindFlashblocksClient, key, chainID)} -} - -// ID methods that delegate to ComponentID but preserve type safety. - -// Kind returns the ComponentKind for this ID type. -// Unlike ComponentID.Kind(), this works even on zero values. -func (id ID[T]) Kind() ComponentKind { - var marker T - return marker.componentKind() -} - -func (id ID[T]) String() string { - return id.ComponentID.String() -} - -func (id ID[T]) LogValue() slog.Value { - return id.ComponentID.LogValue() -} - -func (id ID[T]) MarshalText() ([]byte, error) { - return id.ComponentID.MarshalText() -} - -func (id *ID[T]) UnmarshalText(data []byte) error { - var marker T - return id.ComponentID.unmarshalTextWithKind(marker.componentKind(), data) +func (m idMatcher[E]) Match(elems []E) []E { + for i, elem := range elems { + if elem.ID() == m.id { + return elems[i : i+1] + } + } + return nil } -// Less compares two IDs of the same type for sorting. -func (id ID[T]) Less(other ID[T]) bool { - return id.ComponentID.Less(other.ComponentID) +func (m idMatcher[E]) String() string { + return m.id.String() } -// SortIDs sorts a slice of IDs of any type. -func SortIDs[T KindMarker](ids []ID[T]) []ID[T] { - return copyAndSort(ids, func(a, b ID[T]) bool { - return a.Less(b) - }) +// ID returns the ComponentID this matcher wraps. +// This is used by shim.findMatch for direct registry lookup. +func (m idMatcher[E]) ID() ComponentID { + return m.id } -// AsComponentID returns the underlying ComponentID. -// This is useful when you need to work with IDs in a type-erased context. -func (id ID[T]) AsComponentID() ComponentID { - return id.ComponentID +// ByID creates a matcher for a specific ComponentID. +// This allows using a ComponentID as a matcher for any component type. +func ByID[E Identifiable](id ComponentID) Matcher[E] { + return idMatcher[E]{id: id} } -// Conversion helpers between old and new ID systems. -// These enable incremental migration from the old ID types to the new unified system. +// Convenience constructors for each component kind. -// ConvertL2BatcherID converts an old L2BatcherID to the new system. -func ConvertL2BatcherID(old L2BatcherID) L2BatcherID2 { - return NewL2BatcherID2(old.Key(), old.ChainID()) +func NewL1ELNodeID(key string, chainID eth.ChainID) ComponentID { + return NewComponentID(KindL1ELNode, key, chainID) } -// ConvertL2ELNodeID converts an old L2ELNodeID to the new system. -func ConvertL2ELNodeID(old L2ELNodeID) L2ELNodeID2 { - return NewL2ELNodeID2(old.Key(), old.ChainID()) +func NewL1CLNodeID(key string, chainID eth.ChainID) ComponentID { + return NewComponentID(KindL1CLNode, key, chainID) } -// ConvertL2CLNodeID converts an old L2CLNodeID to the new system. -func ConvertL2CLNodeID(old L2CLNodeID) L2CLNodeID2 { - return NewL2CLNodeID2(old.Key(), old.ChainID()) +func NewL1NetworkID(chainID eth.ChainID) ComponentID { + return NewComponentIDChainOnly(KindL1Network, chainID) } -// ConvertL1ELNodeID converts an old L1ELNodeID to the new system. -func ConvertL1ELNodeID(old L1ELNodeID) L1ELNodeID2 { - return NewL1ELNodeID2(old.Key(), old.ChainID()) +func NewL2ELNodeID(key string, chainID eth.ChainID) ComponentID { + return NewComponentID(KindL2ELNode, key, chainID) } -// ConvertL1CLNodeID converts an old L1CLNodeID to the new system. -func ConvertL1CLNodeID(old L1CLNodeID) L1CLNodeID2 { - return NewL1CLNodeID2(old.Key(), old.ChainID()) +func NewL2CLNodeID(key string, chainID eth.ChainID) ComponentID { + return NewComponentID(KindL2CLNode, key, chainID) } -// ConvertL1NetworkID converts an old L1NetworkID to the new system. -func ConvertL1NetworkID(old L1NetworkID) L1NetworkID2 { - return NewL1NetworkID2(old.ChainID()) +func NewL2NetworkID(chainID eth.ChainID) ComponentID { + return NewComponentIDChainOnly(KindL2Network, chainID) } -// ConvertL2NetworkID converts an old L2NetworkID to the new system. -func ConvertL2NetworkID(old L2NetworkID) L2NetworkID2 { - return NewL2NetworkID2(old.ChainID()) +func NewL2BatcherID(key string, chainID eth.ChainID) ComponentID { + return NewComponentID(KindL2Batcher, key, chainID) } -// ConvertL2ProposerID converts an old L2ProposerID to the new system. -func ConvertL2ProposerID(old L2ProposerID) L2ProposerID2 { - return NewL2ProposerID2(old.Key(), old.ChainID()) +func NewL2ProposerID(key string, chainID eth.ChainID) ComponentID { + return NewComponentID(KindL2Proposer, key, chainID) } -// ConvertL2ChallengerID converts an old L2ChallengerID to the new system. -func ConvertL2ChallengerID(old L2ChallengerID) L2ChallengerID2 { - return NewL2ChallengerID2(old.Key(), old.ChainID()) +func NewL2ChallengerID(key string, chainID eth.ChainID) ComponentID { + return NewComponentID(KindL2Challenger, key, chainID) } -// ConvertRollupBoostNodeID converts an old RollupBoostNodeID to the new system. -func ConvertRollupBoostNodeID(old RollupBoostNodeID) RollupBoostNodeID2 { - return NewRollupBoostNodeID2(old.Key(), old.ChainID()) +func NewRollupBoostNodeID(key string, chainID eth.ChainID) ComponentID { + return NewComponentID(KindRollupBoostNode, key, chainID) } -// ConvertOPRBuilderNodeID converts an old OPRBuilderNodeID to the new system. -func ConvertOPRBuilderNodeID(old OPRBuilderNodeID) OPRBuilderNodeID2 { - return NewOPRBuilderNodeID2(old.Key(), old.ChainID()) +func NewOPRBuilderNodeID(key string, chainID eth.ChainID) ComponentID { + return NewComponentID(KindOPRBuilderNode, key, chainID) } -// ConvertFaucetID converts an old FaucetID to the new system. -func ConvertFaucetID(old FaucetID) FaucetID2 { - return NewFaucetID2(old.Key(), old.ChainID()) +func NewFaucetID(key string, chainID eth.ChainID) ComponentID { + return NewComponentID(KindFaucet, key, chainID) } -// ConvertSyncTesterID converts an old SyncTesterID to the new system. -func ConvertSyncTesterID(old SyncTesterID) SyncTesterID2 { - return NewSyncTesterID2(old.Key(), old.ChainID()) +func NewSyncTesterID(key string, chainID eth.ChainID) ComponentID { + return NewComponentID(KindSyncTester, key, chainID) } -// ConvertSupervisorID converts an old SupervisorID to the new system. -func ConvertSupervisorID(old SupervisorID) SupervisorID2 { - return NewSupervisorID2(string(old)) +func NewSupervisorID(key string) ComponentID { + return NewComponentIDKeyOnly(KindSupervisor, key) } -// ConvertConductorID converts an old ConductorID to the new system. -func ConvertConductorID(old ConductorID) ConductorID2 { - return NewConductorID2(string(old)) +func NewConductorID(key string) ComponentID { + return NewComponentIDKeyOnly(KindConductor, key) } -// ConvertClusterID converts an old ClusterID to the new system. -func ConvertClusterID(old ClusterID) ClusterID2 { - return NewClusterID2(string(old)) +func NewClusterID(key string) ComponentID { + return NewComponentIDKeyOnly(KindCluster, key) } -// ConvertSuperchainID converts an old SuperchainID to the new system. -func ConvertSuperchainID(old SuperchainID) SuperchainID2 { - return NewSuperchainID2(string(old)) +func NewSuperchainID(key string) ComponentID { + return NewComponentIDKeyOnly(KindSuperchain, key) } -// ConvertTestSequencerID converts an old TestSequencerID to the new system. -func ConvertTestSequencerID(old TestSequencerID) TestSequencerID2 { - return NewTestSequencerID2(string(old)) +func NewTestSequencerID(key string) ComponentID { + return NewComponentIDKeyOnly(KindTestSequencer, key) } -// ConvertFlashblocksClientID converts an old FlashblocksWSClientID to the new system. -func ConvertFlashblocksClientID(old FlashblocksWSClientID) FlashblocksClientID2 { - return NewFlashblocksClientID2(idWithChain(old).key, old.ChainID()) +func NewFlashblocksWSClientID(key string, chainID eth.ChainID) ComponentID { + return NewComponentID(KindFlashblocksClient, key, chainID) } diff --git a/op-devstack/stack/component_id_test.go b/op-devstack/stack/component_id_test.go index f581fcbabd4..97209c9e978 100644 --- a/op-devstack/stack/component_id_test.go +++ b/op-devstack/stack/component_id_test.go @@ -1,6 +1,7 @@ package stack import ( + "slices" "testing" "github.com/ethereum-optimism/optimism/op-service/eth" @@ -95,8 +96,8 @@ func TestID_TypeSafety(t *testing.T) { chainID := eth.ChainIDFromUInt64(420) // Create two different ID types with same key and chainID - batcherID := NewL2BatcherID2("mynode", chainID) - elNodeID := NewL2ELNodeID2("mynode", chainID) + batcherID := NewL2BatcherID("mynode", chainID) + elNodeID := NewL2ELNodeID("mynode", chainID) // They should have different kinds require.Equal(t, KindL2Batcher, batcherID.Kind()) @@ -106,21 +107,21 @@ func TestID_TypeSafety(t *testing.T) { require.Equal(t, "L2Batcher-mynode-420", batcherID.String()) require.Equal(t, "L2ELNode-mynode-420", elNodeID.String()) - // The underlying ComponentIDs should be different due to kind - require.NotEqual(t, batcherID.AsComponentID(), elNodeID.AsComponentID()) + // The IDs should be different due to kind + require.NotEqual(t, batcherID, elNodeID) } func TestID_MarshalRoundTrip(t *testing.T) { chainID := eth.ChainIDFromUInt64(420) - original := NewL2BatcherID2("mynode", chainID) + original := NewL2BatcherID("mynode", chainID) data, err := original.MarshalText() require.NoError(t, err) require.Equal(t, "L2Batcher-mynode-420", string(data)) - // Unmarshal into a zero value - Kind() should still work - var parsed L2BatcherID2 - require.Equal(t, KindL2Batcher, parsed.Kind()) // Works on zero value! + // Unmarshal into a ComponentID with kind preset + var parsed ComponentID + parsed.kind = KindL2Batcher // Must set kind before unmarshal err = parsed.UnmarshalText(data) require.NoError(t, err) @@ -128,8 +129,9 @@ func TestID_MarshalRoundTrip(t *testing.T) { } func TestID_UnmarshalKindMismatch(t *testing.T) { - // Try to unmarshal an L2ELNode ID into an L2Batcher ID - var batcherID L2BatcherID2 + // Try to unmarshal an L2ELNode ID into a ComponentID expecting L2Batcher + var batcherID ComponentID + batcherID.kind = KindL2Batcher err := batcherID.UnmarshalText([]byte("L2ELNode-mynode-420")) require.Error(t, err) require.Contains(t, err.Error(), "unexpected kind") @@ -137,7 +139,7 @@ func TestID_UnmarshalKindMismatch(t *testing.T) { func TestID_ChainOnlyTypes(t *testing.T) { chainID := eth.ChainIDFromUInt64(1) - networkID := NewL1NetworkID2(chainID) + networkID := NewL1NetworkID(chainID) require.Equal(t, KindL1Network, networkID.Kind()) require.Equal(t, chainID, networkID.ChainID()) @@ -146,14 +148,15 @@ func TestID_ChainOnlyTypes(t *testing.T) { data, err := networkID.MarshalText() require.NoError(t, err) - var parsed L1NetworkID2 + var parsed ComponentID + parsed.kind = KindL1Network // Must set kind before unmarshal err = parsed.UnmarshalText(data) require.NoError(t, err) require.Equal(t, networkID, parsed) } func TestID_KeyOnlyTypes(t *testing.T) { - supervisorID := NewSupervisorID2("mysupervisor") + supervisorID := NewSupervisorID("mysupervisor") require.Equal(t, KindSupervisor, supervisorID.Kind()) require.Equal(t, "mysupervisor", supervisorID.Key()) @@ -162,7 +165,8 @@ func TestID_KeyOnlyTypes(t *testing.T) { data, err := supervisorID.MarshalText() require.NoError(t, err) - var parsed SupervisorID2 + var parsed ComponentID + parsed.kind = KindSupervisor // Must set kind before unmarshal err = parsed.UnmarshalText(data) require.NoError(t, err) require.Equal(t, supervisorID, parsed) @@ -172,14 +176,24 @@ func TestID_Sorting(t *testing.T) { chainID1 := eth.ChainIDFromUInt64(100) chainID2 := eth.ChainIDFromUInt64(200) - ids := []L2BatcherID2{ - NewL2BatcherID2("charlie", chainID1), - NewL2BatcherID2("alice", chainID1), - NewL2BatcherID2("alice", chainID2), - NewL2BatcherID2("bob", chainID1), + ids := []ComponentID{ + NewL2BatcherID("charlie", chainID1), + NewL2BatcherID("alice", chainID1), + NewL2BatcherID("alice", chainID2), + NewL2BatcherID("bob", chainID1), } - sorted := SortIDs(ids) + // Sort using the ID's comparison + sorted := slices.Clone(ids) + slices.SortFunc(sorted, func(a, b ComponentID) int { + if a.Less(b) { + return -1 + } + if b.Less(a) { + return 1 + } + return 0 + }) // Should be sorted by key first, then by chainID require.Equal(t, "alice", sorted[0].Key()) @@ -194,10 +208,10 @@ func TestID_MapKey(t *testing.T) { chainID := eth.ChainIDFromUInt64(420) // IDs should work as map keys - m := make(map[L2BatcherID2]string) + m := make(map[ComponentID]string) - id1 := NewL2BatcherID2("node1", chainID) - id2 := NewL2BatcherID2("node2", chainID) + id1 := NewL2BatcherID("node1", chainID) + id2 := NewL2BatcherID("node2", chainID) m[id1] = "value1" m[id2] = "value2" @@ -206,7 +220,7 @@ func TestID_MapKey(t *testing.T) { require.Equal(t, "value2", m[id2]) // Same key+chainID should retrieve same value - id1Copy := NewL2BatcherID2("node1", chainID) + id1Copy := NewL2BatcherID("node1", chainID) require.Equal(t, "value1", m[id1Copy]) } @@ -219,25 +233,25 @@ func TestAllIDTypes(t *testing.T) { id interface{ Kind() ComponentKind } expected ComponentKind }{ - {"L1ELNode", NewL1ELNodeID2("node", chainID), KindL1ELNode}, - {"L1CLNode", NewL1CLNodeID2("node", chainID), KindL1CLNode}, - {"L1Network", NewL1NetworkID2(chainID), KindL1Network}, - {"L2ELNode", NewL2ELNodeID2("node", chainID), KindL2ELNode}, - {"L2CLNode", NewL2CLNodeID2("node", chainID), KindL2CLNode}, - {"L2Network", NewL2NetworkID2(chainID), KindL2Network}, - {"L2Batcher", NewL2BatcherID2("node", chainID), KindL2Batcher}, - {"L2Proposer", NewL2ProposerID2("node", chainID), KindL2Proposer}, - {"L2Challenger", NewL2ChallengerID2("node", chainID), KindL2Challenger}, - {"RollupBoostNode", NewRollupBoostNodeID2("node", chainID), KindRollupBoostNode}, - {"OPRBuilderNode", NewOPRBuilderNodeID2("node", chainID), KindOPRBuilderNode}, - {"Faucet", NewFaucetID2("node", chainID), KindFaucet}, - {"SyncTester", NewSyncTesterID2("node", chainID), KindSyncTester}, - {"Supervisor", NewSupervisorID2("node"), KindSupervisor}, - {"Conductor", NewConductorID2("node"), KindConductor}, - {"Cluster", NewClusterID2("node"), KindCluster}, - {"Superchain", NewSuperchainID2("node"), KindSuperchain}, - {"TestSequencer", NewTestSequencerID2("node"), KindTestSequencer}, - {"FlashblocksClient", NewFlashblocksClientID2("node", chainID), KindFlashblocksClient}, + {"L1ELNode", NewL1ELNodeID("node", chainID), KindL1ELNode}, + {"L1CLNode", NewL1CLNodeID("node", chainID), KindL1CLNode}, + {"L1Network", NewL1NetworkID(chainID), KindL1Network}, + {"L2ELNode", NewL2ELNodeID("node", chainID), KindL2ELNode}, + {"L2CLNode", NewL2CLNodeID("node", chainID), KindL2CLNode}, + {"L2Network", NewL2NetworkID(chainID), KindL2Network}, + {"L2Batcher", NewL2BatcherID("node", chainID), KindL2Batcher}, + {"L2Proposer", NewL2ProposerID("node", chainID), KindL2Proposer}, + {"L2Challenger", NewL2ChallengerID("node", chainID), KindL2Challenger}, + {"RollupBoostNode", NewRollupBoostNodeID("node", chainID), KindRollupBoostNode}, + {"OPRBuilderNode", NewOPRBuilderNodeID("node", chainID), KindOPRBuilderNode}, + {"Faucet", NewFaucetID("node", chainID), KindFaucet}, + {"SyncTester", NewSyncTesterID("node", chainID), KindSyncTester}, + {"Supervisor", NewSupervisorID("node"), KindSupervisor}, + {"Conductor", NewConductorID("node"), KindConductor}, + {"Cluster", NewClusterID("node"), KindCluster}, + {"Superchain", NewSuperchainID("node"), KindSuperchain}, + {"TestSequencer", NewTestSequencerID("node"), KindTestSequencer}, + {"FlashblocksClient", NewFlashblocksWSClientID("node", chainID), KindFlashblocksClient}, } for _, tt := range tests { @@ -258,11 +272,11 @@ func TestSerializationCompatibility(t *testing.T) { id interface{ MarshalText() ([]byte, error) } expected string }{ - {"L2Batcher", NewL2BatcherID2("mynode", chainID), "L2Batcher-mynode-420"}, - {"L2ELNode", NewL2ELNodeID2("mynode", chainID), "L2ELNode-mynode-420"}, - {"L1Network", NewL1NetworkID2(eth.ChainIDFromUInt64(1)), "L1Network-1"}, - {"Supervisor", NewSupervisorID2("mysupervisor"), "Supervisor-mysupervisor"}, - {"RollupBoostNode", NewRollupBoostNodeID2("boost", chainID), "RollupBoostNode-boost-420"}, + {"L2Batcher", NewL2BatcherID("mynode", chainID), "L2Batcher-mynode-420"}, + {"L2ELNode", NewL2ELNodeID("mynode", chainID), "L2ELNode-mynode-420"}, + {"L1Network", NewL1NetworkID(eth.ChainIDFromUInt64(1)), "L1Network-1"}, + {"Supervisor", NewSupervisorID("mysupervisor"), "Supervisor-mysupervisor"}, + {"RollupBoostNode", NewRollupBoostNodeID("boost", chainID), "RollupBoostNode-boost-420"}, } for _, tt := range tests { @@ -273,61 +287,3 @@ func TestSerializationCompatibility(t *testing.T) { }) } } - -// TestConversionHelpers verifies that conversion between old and new ID systems -// preserves all data correctly. -func TestConversionHelpers(t *testing.T) { - chainID := eth.ChainIDFromUInt64(420) - - t.Run("L2BatcherID", func(t *testing.T) { - old := NewL2BatcherID("mynode", chainID) - new := ConvertL2BatcherID(old) - require.Equal(t, KindL2Batcher, new.Kind()) - require.Equal(t, "mynode", new.Key()) - require.Equal(t, chainID, new.ChainID()) - require.Equal(t, old.String(), new.String()) - }) - - t.Run("L2ELNodeID", func(t *testing.T) { - old := NewL2ELNodeID("mynode", chainID) - new := ConvertL2ELNodeID(old) - require.Equal(t, KindL2ELNode, new.Kind()) - require.Equal(t, "mynode", new.Key()) - require.Equal(t, chainID, new.ChainID()) - require.Equal(t, old.String(), new.String()) - }) - - t.Run("L1NetworkID", func(t *testing.T) { - old := L1NetworkID(eth.ChainIDFromUInt64(1)) - new := ConvertL1NetworkID(old) - require.Equal(t, KindL1Network, new.Kind()) - require.Equal(t, eth.ChainIDFromUInt64(1), new.ChainID()) - require.Equal(t, old.String(), new.String()) - }) - - t.Run("SupervisorID", func(t *testing.T) { - old := SupervisorID("mysupervisor") - new := ConvertSupervisorID(old) - require.Equal(t, KindSupervisor, new.Kind()) - require.Equal(t, "mysupervisor", new.Key()) - require.Equal(t, old.String(), new.String()) - }) - - t.Run("RollupBoostNodeID", func(t *testing.T) { - old := NewRollupBoostNodeID("boost", chainID) - new := ConvertRollupBoostNodeID(old) - require.Equal(t, KindRollupBoostNode, new.Kind()) - require.Equal(t, "boost", new.Key()) - require.Equal(t, chainID, new.ChainID()) - require.Equal(t, old.String(), new.String()) - }) - - t.Run("FlashblocksWSClientID", func(t *testing.T) { - old := NewFlashblocksWSClientID("fbclient", chainID) - new := ConvertFlashblocksClientID(old) - require.Equal(t, KindFlashblocksClient, new.Kind()) - require.Equal(t, "fbclient", new.Key()) - require.Equal(t, chainID, new.ChainID()) - require.Equal(t, old.String(), new.String()) - }) -} diff --git a/op-devstack/stack/component_registry.go b/op-devstack/stack/component_registry.go index 8bb9c43d7b6..b1bf913383f 100644 --- a/op-devstack/stack/component_registry.go +++ b/op-devstack/stack/component_registry.go @@ -22,3 +22,222 @@ type ComponentRegistry interface { // Returns an empty slice if no components of that kind exist. ComponentIDs(kind ComponentKind) []ComponentID } + +// --- Free functions for typed component access --- +// These functions provide type-safe access to components without requiring +// type-specific methods on every container interface. + +// GetComponent returns a typed component from a registry by ID. +// Returns (component, true) if found and type matches, (nil/zero, false) otherwise. +func GetComponent[T any](r ComponentRegistry, id ComponentID) (T, bool) { + comp, ok := r.Component(id) + if !ok { + var zero T + return zero, false + } + typed, ok := comp.(T) + return typed, ok +} + +// GetComponentsByKind returns all components of a given kind, typed. +// Only components that match the expected type are returned. +func GetComponentsByKind[T any](r ComponentRegistry, kind ComponentKind) []T { + comps := r.Components(kind) + result := make([]T, 0, len(comps)) + for _, comp := range comps { + if typed, ok := comp.(T); ok { + result = append(result, typed) + } + } + return result +} + +// --- Typed getter free functions for L2Network components --- + +// GetL2BatcherByID returns an L2Batcher from a network by ID. +func GetL2BatcherByID(n L2Network, id ComponentID) (L2Batcher, bool) { + return GetComponent[L2Batcher](n, id) +} + +// GetL2ProposerByID returns an L2Proposer from a network by ID. +func GetL2ProposerByID(n L2Network, id ComponentID) (L2Proposer, bool) { + return GetComponent[L2Proposer](n, id) +} + +// GetL2ChallengerByID returns an L2Challenger from a network by ID. +func GetL2ChallengerByID(n L2Network, id ComponentID) (L2Challenger, bool) { + return GetComponent[L2Challenger](n, id) +} + +// GetL2CLNodeByID returns an L2CLNode from a network by ID. +func GetL2CLNodeByID(n L2Network, id ComponentID) (L2CLNode, bool) { + return GetComponent[L2CLNode](n, id) +} + +// GetL2ELNodeByID returns an L2ELNode from a network by ID. +func GetL2ELNodeByID(n L2Network, id ComponentID) (L2ELNode, bool) { + return GetComponent[L2ELNode](n, id) +} + +// GetConductorByID returns a Conductor from a network by ID. +func GetConductorByID(n L2Network, id ComponentID) (Conductor, bool) { + return GetComponent[Conductor](n, id) +} + +// GetRollupBoostNodeByID returns a RollupBoostNode from a network by ID. +func GetRollupBoostNodeByID(n L2Network, id ComponentID) (RollupBoostNode, bool) { + return GetComponent[RollupBoostNode](n, id) +} + +// GetOPRBuilderNodeByID returns an OPRBuilderNode from a network by ID. +func GetOPRBuilderNodeByID(n L2Network, id ComponentID) (OPRBuilderNode, bool) { + return GetComponent[OPRBuilderNode](n, id) +} + +// --- Typed getter free functions for L1Network components --- + +// GetL1ELNodeByID returns an L1ELNode from a network by ID. +func GetL1ELNodeByID(n L1Network, id ComponentID) (L1ELNode, bool) { + return GetComponent[L1ELNode](n, id) +} + +// GetL1CLNodeByID returns an L1CLNode from a network by ID. +func GetL1CLNodeByID(n L1Network, id ComponentID) (L1CLNode, bool) { + return GetComponent[L1CLNode](n, id) +} + +// --- Typed getter free functions for Network components (shared by L1 and L2) --- + +// GetFaucetByID returns a Faucet from a network by ID. +func GetFaucetByID(n Network, id ComponentID) (Faucet, bool) { + return GetComponent[Faucet](n, id) +} + +// GetSyncTesterByID returns a SyncTester from a network by ID. +func GetSyncTesterByID(n Network, id ComponentID) (SyncTester, bool) { + return GetComponent[SyncTester](n, id) +} + +// --- Typed getter free functions for System components --- + +// GetSuperchainByID returns a Superchain from a system by ID. +func GetSuperchainByID(s System, id ComponentID) (Superchain, bool) { + return GetComponent[Superchain](s, id) +} + +// GetClusterByID returns a Cluster from a system by ID. +func GetClusterByID(s System, id ComponentID) (Cluster, bool) { + return GetComponent[Cluster](s, id) +} + +// GetL1NetworkByID returns an L1Network from a system by ID. +func GetL1NetworkByID(s System, id ComponentID) (L1Network, bool) { + return GetComponent[L1Network](s, id) +} + +// GetL2NetworkByID returns an L2Network from a system by ID. +func GetL2NetworkByID(s System, id ComponentID) (L2Network, bool) { + return GetComponent[L2Network](s, id) +} + +// GetSupervisorByID returns a Supervisor from a system by ID. +func GetSupervisorByID(s System, id ComponentID) (Supervisor, bool) { + return GetComponent[Supervisor](s, id) +} + +// GetTestSequencerByID returns a TestSequencer from a system by ID. +func GetTestSequencerByID(s System, id ComponentID) (TestSequencer, bool) { + return GetComponent[TestSequencer](s, id) +} + +// --- List getter free functions --- + +// GetL2Batchers returns all L2Batchers from a network. +func GetL2Batchers(n L2Network) []L2Batcher { + return GetComponentsByKind[L2Batcher](n, KindL2Batcher) +} + +// GetL2Proposers returns all L2Proposers from a network. +func GetL2Proposers(n L2Network) []L2Proposer { + return GetComponentsByKind[L2Proposer](n, KindL2Proposer) +} + +// GetL2Challengers returns all L2Challengers from a network. +func GetL2Challengers(n L2Network) []L2Challenger { + return GetComponentsByKind[L2Challenger](n, KindL2Challenger) +} + +// GetL2CLNodes returns all L2CLNodes from a network. +func GetL2CLNodes(n L2Network) []L2CLNode { + return GetComponentsByKind[L2CLNode](n, KindL2CLNode) +} + +// GetL2ELNodes returns all L2ELNodes from a network. +func GetL2ELNodes(n L2Network) []L2ELNode { + return GetComponentsByKind[L2ELNode](n, KindL2ELNode) +} + +// GetConductors returns all Conductors from a network. +func GetConductors(n L2Network) []Conductor { + return GetComponentsByKind[Conductor](n, KindConductor) +} + +// GetRollupBoostNodes returns all RollupBoostNodes from a network. +func GetRollupBoostNodes(n L2Network) []RollupBoostNode { + return GetComponentsByKind[RollupBoostNode](n, KindRollupBoostNode) +} + +// GetOPRBuilderNodes returns all OPRBuilderNodes from a network. +func GetOPRBuilderNodes(n L2Network) []OPRBuilderNode { + return GetComponentsByKind[OPRBuilderNode](n, KindOPRBuilderNode) +} + +// GetL1ELNodes returns all L1ELNodes from a network. +func GetL1ELNodes(n L1Network) []L1ELNode { + return GetComponentsByKind[L1ELNode](n, KindL1ELNode) +} + +// GetL1CLNodes returns all L1CLNodes from a network. +func GetL1CLNodes(n L1Network) []L1CLNode { + return GetComponentsByKind[L1CLNode](n, KindL1CLNode) +} + +// GetFaucets returns all Faucets from a network. +func GetFaucets(n Network) []Faucet { + return GetComponentsByKind[Faucet](n, KindFaucet) +} + +// GetSyncTesters returns all SyncTesters from a network. +func GetSyncTesters(n Network) []SyncTester { + return GetComponentsByKind[SyncTester](n, KindSyncTester) +} + +// GetSuperchains returns all Superchains from a system. +func GetSuperchains(s System) []Superchain { + return GetComponentsByKind[Superchain](s, KindSuperchain) +} + +// GetClusters returns all Clusters from a system. +func GetClusters(s System) []Cluster { + return GetComponentsByKind[Cluster](s, KindCluster) +} + +// GetL1Networks returns all L1Networks from a system. +func GetL1Networks(s System) []L1Network { + return GetComponentsByKind[L1Network](s, KindL1Network) +} + +// GetL2Networks returns all L2Networks from a system. +func GetL2Networks(s System) []L2Network { + return GetComponentsByKind[L2Network](s, KindL2Network) +} + +// GetSupervisors returns all Supervisors from a system. +func GetSupervisors(s System) []Supervisor { + return GetComponentsByKind[Supervisor](s, KindSupervisor) +} + +// GetTestSequencers returns all TestSequencers from a system. +func GetTestSequencers(s System) []TestSequencer { + return GetComponentsByKind[TestSequencer](s, KindTestSequencer) +} diff --git a/op-devstack/stack/conductor.go b/op-devstack/stack/conductor.go index 951f4fd9ee2..7f5720cbfd0 100644 --- a/op-devstack/stack/conductor.go +++ b/op-devstack/stack/conductor.go @@ -4,39 +4,9 @@ import ( conductorRpc "github.com/ethereum-optimism/optimism/op-conductor/rpc" ) -type ConductorID genericID - -const ConductorKind Kind = "Conductor" - -func (id ConductorID) String() string { - return genericID(id).string(ConductorKind) -} - -func (id ConductorID) MarshalText() ([]byte, error) { - return genericID(id).marshalText(ConductorKind) -} - -func (id *ConductorID) UnmarshalText(data []byte) error { - return (*genericID)(id).unmarshalText(ConductorKind, data) -} - -func SortConductorIDs(ids []ConductorID) []ConductorID { - return copyAndSortCmp(ids) -} - -func SortConductors(elems []Conductor) []Conductor { - return copyAndSort(elems, lessElemOrdered[ConductorID, Conductor]) -} - -var _ ConductorMatcher = ConductorID("") - -func (id ConductorID) Match(elems []Conductor) []Conductor { - return findByID(id, elems) -} - type Conductor interface { Common - ID() ConductorID + ID() ComponentID RpcAPI() conductorRpc.API } diff --git a/op-devstack/stack/context.go b/op-devstack/stack/context.go index 5f7c070ceda..1ff61b0921b 100644 --- a/op-devstack/stack/context.go +++ b/op-devstack/stack/context.go @@ -9,20 +9,20 @@ import ( ) // ContextWithKind annotates the context with the given kind of service -func ContextWithKind(ctx context.Context, kind Kind) context.Context { +func ContextWithKind(ctx context.Context, kind ComponentKind) context.Context { return logfilter.AddLogAttrToContext(ctx, "kind", kind) } // KindFromContext extracts the kind from the context. -func KindFromContext(ctx context.Context) Kind { - v, _ := logfilter.ValueFromContext[Kind](ctx, "kind") +func KindFromContext(ctx context.Context) ComponentKind { + v, _ := logfilter.ValueFromContext[ComponentKind](ctx, "kind") return v } // KindSelector creates a log-filter that applies the given inner log-filter only if it matches the given kind. // For logs of the specified kind, it applies the inner filter. // For logs of other kinds, it returns false (filters them out). -func KindSelector(kind Kind) logfilter.Selector { +func KindSelector(kind ComponentKind) logfilter.Selector { return logfilter.Select("kind", kind) } @@ -48,7 +48,11 @@ func ChainIDSelector(chainID eth.ChainID) logfilter.Selector { // This also automatically attaches the chain ID and component kind to the context, if available from the ID. func ContextWithID(ctx context.Context, id slog.LogValuer) context.Context { if idWithChainID, ok := id.(ChainIDProvider); ok { - ctx = ContextWithChainID(ctx, idWithChainID.ChainID()) + chainID := idWithChainID.ChainID() + // Only set chain ID if it's non-zero (i.e., the ID type actually has a meaningful chain ID) + if chainID != (eth.ChainID{}) { + ctx = ContextWithChainID(ctx, chainID) + } } if idWithKind, ok := id.(KindProvider); ok { ctx = ContextWithKind(ctx, idWithKind.Kind()) diff --git a/op-devstack/stack/context_test.go b/op-devstack/stack/context_test.go index 885464767e4..8e28729bb38 100644 --- a/op-devstack/stack/context_test.go +++ b/op-devstack/stack/context_test.go @@ -22,28 +22,26 @@ func TestContext(t *testing.T) { require.Equal(t, chainB, ChainIDFromContext(ContextWithChainID(ContextWithChainID(ctx, chainA), chainB)), "priority") }) t.Run("kind", func(t *testing.T) { - require.Equal(t, Kind(""), KindFromContext(ctx), "none") - require.Equal(t, L2BatcherKind, KindFromContext(ContextWithKind(ctx, L2BatcherKind)), "lookup") - require.Equal(t, L2ProposerKind, KindFromContext(ContextWithKind(ContextWithKind(ctx, L2BatcherKind), L2ProposerKind)), "priority") + require.Equal(t, ComponentKind(""), KindFromContext(ctx), "none") + require.Equal(t, KindL2Batcher, KindFromContext(ContextWithKind(ctx, KindL2Batcher)), "lookup") + require.Equal(t, KindL2Proposer, KindFromContext(ContextWithKind(ContextWithKind(ctx, KindL2Batcher), KindL2Proposer)), "priority") }) t.Run("id", func(t *testing.T) { - require.Equal(t, L2BatcherID{}, IDFromContext[L2BatcherID](ctx), "none") - require.Equal(t, SuperchainID(""), IDFromContext[SuperchainID](ctx), "none") - id1 := L2BatcherID{ - key: "batcherA", - chainID: chainA, - } + require.Equal(t, ComponentID{}, IDFromContext[ComponentID](ctx), "none") + id1 := NewL2BatcherID("batcherA", chainA) ctx1 := ContextWithID(ctx, id1) - require.Equal(t, L2BatcherKind, KindFromContext(ctx1), "lookup kind") + require.Equal(t, KindL2Batcher, KindFromContext(ctx1), "lookup kind") require.Equal(t, chainA, ChainIDFromContext(ctx1), "lookup chainID") - require.Equal(t, id1, IDFromContext[L2BatcherID](ctx1), "lookup ID") + require.Equal(t, id1, IDFromContext[ComponentID](ctx1), "lookup ID") // now overlay another different kind of ID on top - id2 := SuperchainID("foobar") + id2 := NewSuperchainID("foobar") ctx2 := ContextWithID(ctx1, id2) - require.Equal(t, SuperchainKind, KindFromContext(ctx2), "lookup kind") + require.Equal(t, KindSuperchain, KindFromContext(ctx2), "lookup kind") require.Equal(t, chainA, ChainIDFromContext(ctx2), "chainID still preserved") - require.Equal(t, id2, IDFromContext[SuperchainID](ctx2), "lookup ID") - require.Equal(t, L2BatcherID{}, IDFromContext[L2BatcherID](ctx2), "batcher ID not available") + require.Equal(t, id2, IDFromContext[ComponentID](ctx2), "lookup ID - now shows superchain") + // With type aliases, IDFromContext returns the stored ComponentID regardless of "type" + // The Kind() method can be used to check the actual kind of ID + require.Equal(t, KindSuperchain, IDFromContext[ComponentID](ctx2).Kind(), "id kind check") }) } @@ -58,20 +56,17 @@ func TestLogFilter(t *testing.T) { require.Equal(t, tri.Undefined, fn(ContextWithChainID(ctx, chainB), log.LevelDebug), "different chain should be shown") }) t.Run("kind", func(t *testing.T) { - fn := KindSelector(L2BatcherKind).Mute() + fn := KindSelector(KindL2Batcher).Mute() require.Equal(t, tri.Undefined, fn(ctx, log.LevelDebug), "regular context should be false") - require.Equal(t, tri.False, fn(ContextWithKind(ctx, L2BatcherKind), log.LevelDebug), "detected kind should be muted") - require.Equal(t, tri.Undefined, fn(ContextWithKind(ctx, L2ProposerKind), log.LevelDebug), "different kind should be shown") + require.Equal(t, tri.False, fn(ContextWithKind(ctx, KindL2Batcher), log.LevelDebug), "detected kind should be muted") + require.Equal(t, tri.Undefined, fn(ContextWithKind(ctx, KindL2Proposer), log.LevelDebug), "different kind should be shown") }) t.Run("id", func(t *testing.T) { - id1 := L2BatcherID{ - key: "batcherA", - chainID: chainA, - } + id1 := NewL2BatcherID("batcherA", chainA) fn := IDSelector(id1).Mute() require.Equal(t, tri.Undefined, fn(ctx, log.LevelDebug), "regular context should be false") require.Equal(t, tri.False, fn(ContextWithID(ctx, id1), log.LevelDebug), "detected id should be muted") - id2 := SuperchainID("foobar") + id2 := NewSuperchainID("foobar") require.Equal(t, tri.Undefined, fn(ContextWithID(ctx, id2), log.LevelDebug), "different id should be shown") }) } diff --git a/op-devstack/stack/faucet.go b/op-devstack/stack/faucet.go index 16a869dcc95..fe590c798c5 100644 --- a/op-devstack/stack/faucet.go +++ b/op-devstack/stack/faucet.go @@ -1,74 +1,11 @@ package stack import ( - "log/slog" - "github.com/ethereum-optimism/optimism/op-service/apis" - "github.com/ethereum-optimism/optimism/op-service/eth" ) -// FaucetID identifies a Faucet by name and chainID, is type-safe, and can be value-copied and used as map key. -type FaucetID idWithChain - -var _ IDWithChain = (*FaucetID)(nil) - -const FaucetKind Kind = "Faucet" - -func NewFaucetID(key string, chainID eth.ChainID) FaucetID { - return FaucetID{ - key: key, - chainID: chainID, - } -} - -func (id FaucetID) String() string { - return idWithChain(id).string(FaucetKind) -} - -func (id FaucetID) ChainID() eth.ChainID { - return idWithChain(id).chainID -} - -func (id FaucetID) Kind() Kind { - return FaucetKind -} - -func (id FaucetID) Key() string { - return id.key -} - -func (id FaucetID) LogValue() slog.Value { - return slog.StringValue(id.String()) -} - -func (id FaucetID) MarshalText() ([]byte, error) { - return idWithChain(id).marshalText(FaucetKind) -} - -func (id *FaucetID) UnmarshalText(data []byte) error { - return (*idWithChain)(id).unmarshalText(FaucetKind, data) -} - -func SortFaucetIDs(ids []FaucetID) []FaucetID { - return copyAndSort(ids, func(a, b FaucetID) bool { - return lessIDWithChain(idWithChain(a), idWithChain(b)) - }) -} - -func SortFaucets(elems []Faucet) []Faucet { - return copyAndSort(elems, func(a, b Faucet) bool { - return lessIDWithChain(idWithChain(a.ID()), idWithChain(b.ID())) - }) -} - -var _ FaucetMatcher = FaucetID{} - -func (id FaucetID) Match(elems []Faucet) []Faucet { - return findByID(id, elems) -} - type Faucet interface { Common - ID() FaucetID + ID() ComponentID API() apis.Faucet } diff --git a/op-devstack/stack/fb_ws_client.go b/op-devstack/stack/fb_ws_client.go index 9da423dcbf3..54e2b95dae2 100644 --- a/op-devstack/stack/fb_ws_client.go +++ b/op-devstack/stack/fb_ws_client.go @@ -1,7 +1,6 @@ package stack import ( - "log/slog" "net/http" "github.com/ethereum-optimism/optimism/op-service/eth" @@ -10,54 +9,7 @@ import ( type FlashblocksWSClient interface { Common ChainID() eth.ChainID - ID() FlashblocksWSClientID + ID() ComponentID WsUrl() string WsHeaders() http.Header } - -type FlashblocksWSClientID idWithChain - -const FlashblocksWSClientKind Kind = "FlashblocksWSClient" - -func NewFlashblocksWSClientID(key string, chainID eth.ChainID) FlashblocksWSClientID { - return FlashblocksWSClientID{ - key: key, - chainID: chainID, - } -} - -func (id FlashblocksWSClientID) String() string { - return idWithChain(id).string(FlashblocksWSClientKind) -} - -func (id FlashblocksWSClientID) ChainID() eth.ChainID { - return idWithChain(id).chainID -} - -func (id FlashblocksWSClientID) MarshalText() ([]byte, error) { - return idWithChain(id).marshalText(FlashblocksWSClientKind) -} - -func (id FlashblocksWSClientID) LogValue() slog.Value { - return slog.StringValue(id.String()) -} - -func (id *FlashblocksWSClientID) UnmarshalText(data []byte) error { - return (*idWithChain)(id).unmarshalText(FlashblocksWSClientKind, data) -} - -func SortFlashblocksWSClientIDs(ids []FlashblocksWSClientID) []FlashblocksWSClientID { - return copyAndSort(ids, func(a, b FlashblocksWSClientID) bool { - return lessIDWithChain(idWithChain(a), idWithChain(b)) - }) -} - -func SortFlashblocksWSClients(elems []FlashblocksWSClient) []FlashblocksWSClient { - return copyAndSort(elems, func(a, b FlashblocksWSClient) bool { - return lessIDWithChain(idWithChain(a.ID()), idWithChain(b.ID())) - }) -} - -func (id FlashblocksWSClientID) Match(elems []FlashblocksWSClient) []FlashblocksWSClient { - return findByID(id, elems) -} diff --git a/op-devstack/stack/id.go b/op-devstack/stack/id.go deleted file mode 100644 index a871b535049..00000000000 --- a/op-devstack/stack/id.go +++ /dev/null @@ -1,217 +0,0 @@ -package stack - -import ( - "bytes" - "cmp" - "errors" - "fmt" - "log/slog" - "slices" - "sort" - - "github.com/ethereum-optimism/optimism/op-service/eth" -) - -// Kind represents a kind of component, this is used to make each ID unique, even when encoded as text. -type Kind string - -var _ slog.LogValuer = (*Kind)(nil) - -func (k Kind) LogValue() slog.Value { - return slog.StringValue(string(k)) -} - -func (k Kind) String() string { - return string(k) -} - -func (k Kind) MarshalText() ([]byte, error) { - return []byte(k), nil -} - -func (k *Kind) UnmarshalText(data []byte) error { - *k = Kind(data) - return nil -} - -// ChainIDProvider presents a type that provides a relevant ChainID. -type ChainIDProvider interface { - ChainID() eth.ChainID -} - -// KindProvider presents a type that provides a relevant Kind. E.g. an L2BatcherKind. -type KindProvider interface { - Kind() Kind -} - -// Keyed presents a type that provides a relevant string key. E.g. a named superchain. -type Keyed interface { - Key() string -} - -const maxIDLength = 100 - -var errInvalidID = errors.New("invalid ID") - -// Defined types based on idWithChain should implement this interface so they may be used as logging attributes. -type IDWithChain interface { - slog.LogValuer - ChainIDProvider - KindProvider - Keyed -} - -// idWithChain is comparable, can be copied, contains a chain-ID, -// and has type-safe text encoding/decoding to prevent accidental mixups. -type idWithChain struct { - key string - chainID eth.ChainID -} - -func (id idWithChain) string(kind Kind) string { - return fmt.Sprintf("%s-%s-%s", kind, id.key, id.chainID) -} - -func (id idWithChain) marshalText(kind Kind) ([]byte, error) { - k := string(id.key) - if len(k) > maxIDLength { - return nil, errInvalidID - } - k = fmt.Sprintf("%s-%s-%s", kind, k, id.chainID) - return []byte(k), nil -} - -func (id *idWithChain) unmarshalText(kind Kind, data []byte) error { - kindData, mainData, ok := bytes.Cut(data, []byte("-")) - if !ok { - return fmt.Errorf("expected kind-prefix, but id has none: %q", data) - } - if x := string(kindData); x != string(kind) { - return fmt.Errorf("id %q has unexpected kind %q, expected %q", string(data), x, kind) - } - before, after, ok := bytes.Cut(mainData, []byte("-")) - if !ok { - return fmt.Errorf("expected chain separator, but found none: %q", string(data)) - } - var chainID eth.ChainID - if err := chainID.UnmarshalText(after); err != nil { - return fmt.Errorf("failed to unmarshal chain part: %w", err) - } - if len(before) > maxIDLength { - return errInvalidID - } - id.key = string(before) - id.chainID = chainID - return nil -} - -// Defined types based on idOnlyChainID should implement this interface so they may be used as logging attributes. -type IDOnlyChainID interface { - slog.LogValuer - ChainIDProvider - KindProvider -} - -// idChainID is comparable, can be copied, contains only a chain-ID, -// and has type-safe text encoding/decoding to prevent accidental mixups. -type idOnlyChainID eth.ChainID - -func (id idOnlyChainID) string(kind Kind) string { - return fmt.Sprintf("%s-%s", kind, eth.ChainID(id)) -} - -func (id idOnlyChainID) marshalText(kind Kind) ([]byte, error) { - k := fmt.Sprintf("%s-%s", kind, eth.ChainID(id)) - return []byte(k), nil -} - -func (id *idOnlyChainID) unmarshalText(kind Kind, data []byte) error { - kindData, mainData, ok := bytes.Cut(data, []byte("-")) - if !ok { - return fmt.Errorf("expected kind-prefix, but id has none: %q", data) - } - if x := string(kindData); x != string(kind) { - return fmt.Errorf("id %q has unexpected kind %q, expected %q", string(data), x, kind) - } - var chainID eth.ChainID - if err := chainID.UnmarshalText(mainData); err != nil { - return fmt.Errorf("failed to unmarshal chain part: %w", err) - } - *id = idOnlyChainID(chainID) - return nil -} - -// Defined types based on genericID should implement this interface so they may be used as logging attributes. -type GenericID interface { - slog.LogValuer - KindProvider -} - -// genericID is comparable, can be copied, -// and has type-safe text encoding/decoding to prevent accidental mixups. -type genericID string - -func (id genericID) string(kind Kind) string { - return fmt.Sprintf("%s-%s", kind, string(id)) -} - -func (id genericID) marshalText(kind Kind) ([]byte, error) { - if len(id) > maxIDLength { - return nil, errInvalidID - } - return []byte(fmt.Sprintf("%s-%s", kind, string(id))), nil -} - -func (id *genericID) unmarshalText(kind Kind, data []byte) error { - kindData, mainData, ok := bytes.Cut(data, []byte("-")) - if !ok { - return fmt.Errorf("expected kind-prefix, but id has none: %q", data) - } - if x := string(kindData); x != string(kind) { - return fmt.Errorf("id %q has unexpected kind %q, expected %q", string(data), x, kind) - } - if len(mainData) > maxIDLength { - return errInvalidID - } - *id = genericID(mainData) - return nil -} - -// copyAndSort helps copy and sort a slice of objects with the given less function -func copyAndSort[V ~[]E, E any](vs V, lessFn func(a, b E) bool) V { - out := slices.Clone(vs) - sort.Slice(out, func(i, j int) bool { - a := out[i] - b := out[j] - return lessFn(a, b) - }) - return out -} - -// lessIDWithChain is a helper function to compare two idWithChain objects. -// It does not use generics, since idWithChain is a concrete type with struct fields and no accessor methods in the types that wrap this type. -func lessIDWithChain(a, b idWithChain) bool { - if a.key > b.key { - return false - } - if a.key == b.key { - return a.chainID.Cmp(b.chainID) < 0 - } - return true -} - -// lessIDOnlyChainID is a helper function to compare two idOnlyChainID objects. -func lessIDOnlyChainID(a, b idOnlyChainID) bool { - return eth.ChainID(a).Cmp(eth.ChainID(b)) < 0 -} - -func lessElemOrdered[I cmp.Ordered, E Identifiable[I]](a, b E) bool { - return a.ID() < b.ID() -} - -// copyAndSortCmp is a helper function to copy and sort a slice of elements that are already natively comparable. -func copyAndSortCmp[V ~[]E, E cmp.Ordered](vs V) V { - out := slices.Clone(vs) - slices.Sort(out) - return out -} diff --git a/op-devstack/stack/l1_cl.go b/op-devstack/stack/l1_cl.go index 7a3356f1674..a1e3ce3734a 100644 --- a/op-devstack/stack/l1_cl.go +++ b/op-devstack/stack/l1_cl.go @@ -1,77 +1,14 @@ package stack import ( - "log/slog" - "github.com/ethereum-optimism/optimism/op-service/apis" - "github.com/ethereum-optimism/optimism/op-service/eth" ) -// L1CLNodeID identifies a L1CLNode by name and chainID, is type-safe, and can be value-copied and used as map key. -type L1CLNodeID idWithChain - -var _ IDWithChain = (*L1CLNodeID)(nil) - -const L1CLNodeKind Kind = "L1CLNode" - -func NewL1CLNodeID(key string, chainID eth.ChainID) L1CLNodeID { - return L1CLNodeID{ - key: key, - chainID: chainID, - } -} - -func (id L1CLNodeID) String() string { - return idWithChain(id).string(L1CLNodeKind) -} - -func (id L1CLNodeID) Kind() Kind { - return L1CLNodeKind -} - -func (id L1CLNodeID) ChainID() eth.ChainID { - return id.chainID -} - -func (id L1CLNodeID) Key() string { - return id.key -} - -func (id L1CLNodeID) LogValue() slog.Value { - return slog.StringValue(id.String()) -} - -func (id L1CLNodeID) MarshalText() ([]byte, error) { - return idWithChain(id).marshalText(L1CLNodeKind) -} - -func (id *L1CLNodeID) UnmarshalText(data []byte) error { - return (*idWithChain)(id).unmarshalText(L1CLNodeKind, data) -} - -func SortL1CLNodeIDs(ids []L1CLNodeID) []L1CLNodeID { - return copyAndSort(ids, func(a, b L1CLNodeID) bool { - return lessIDWithChain(idWithChain(a), idWithChain(b)) - }) -} - -func SortL1CLNodes(elems []L1CLNode) []L1CLNode { - return copyAndSort(elems, func(a, b L1CLNode) bool { - return lessIDWithChain(idWithChain(a.ID()), idWithChain(b.ID())) - }) -} - -var _ L1CLMatcher = L1CLNodeID{} - -func (id L1CLNodeID) Match(elems []L1CLNode) []L1CLNode { - return findByID(id, elems) -} - // L1CLNode is a L1 ethereum consensus-layer node, aka Beacon node. // This node may not be a full beacon node, and instead run a mock L1 consensus node. type L1CLNode interface { Common - ID() L1CLNodeID + ID() ComponentID BeaconClient() apis.BeaconClient } diff --git a/op-devstack/stack/l1_el.go b/op-devstack/stack/l1_el.go index f51ee5075e7..ec65e6241dd 100644 --- a/op-devstack/stack/l1_el.go +++ b/op-devstack/stack/l1_el.go @@ -1,74 +1,8 @@ package stack -import ( - "log/slog" - - "github.com/ethereum-optimism/optimism/op-service/eth" -) - -// L1ELNodeID identifies a L1ELNode by name and chainID, is type-safe, and can be value-copied and used as map key. -type L1ELNodeID idWithChain - -var _ IDWithChain = (*L1ELNodeID)(nil) - -const L1ELNodeKind Kind = "L1ELNode" - -func NewL1ELNodeID(key string, chainID eth.ChainID) L1ELNodeID { - return L1ELNodeID{ - key: key, - chainID: chainID, - } -} - -func (id L1ELNodeID) String() string { - return idWithChain(id).string(L1ELNodeKind) -} - -func (id L1ELNodeID) ChainID() eth.ChainID { - return id.chainID -} - -func (id L1ELNodeID) Kind() Kind { - return L1ELNodeKind -} - -func (id L1ELNodeID) Key() string { - return id.key -} - -func (id L1ELNodeID) LogValue() slog.Value { - return slog.StringValue(id.String()) -} - -func (id L1ELNodeID) MarshalText() ([]byte, error) { - return idWithChain(id).marshalText(L1ELNodeKind) -} - -func (id *L1ELNodeID) UnmarshalText(data []byte) error { - return (*idWithChain)(id).unmarshalText(L1ELNodeKind, data) -} - -func SortL1ELNodeIDs(ids []L1ELNodeID) []L1ELNodeID { - return copyAndSort(ids, func(a, b L1ELNodeID) bool { - return lessIDWithChain(idWithChain(a), idWithChain(b)) - }) -} - -func SortL1ELNodes(elems []L1ELNode) []L1ELNode { - return copyAndSort(elems, func(a, b L1ELNode) bool { - return lessIDWithChain(idWithChain(a.ID()), idWithChain(b.ID())) - }) -} - -var _ L1ELMatcher = L1ELNodeID{} - -func (id L1ELNodeID) Match(elems []L1ELNode) []L1ELNode { - return findByID(id, elems) -} - // L1ELNode is a L1 ethereum execution-layer node type L1ELNode interface { - ID() L1ELNodeID + ID() ComponentID ELNode } diff --git a/op-devstack/stack/l1_network.go b/op-devstack/stack/l1_network.go index 10e09877f64..ce124772ef6 100644 --- a/op-devstack/stack/l1_network.go +++ b/op-devstack/stack/l1_network.go @@ -1,70 +1,15 @@ package stack -import ( - "log/slog" - - "github.com/ethereum-optimism/optimism/op-service/eth" -) - -// L1NetworkID identifies a L1Network by name and chainID, is type-safe, and can be value-copied and used as map key. -type L1NetworkID idOnlyChainID - -var _ IDOnlyChainID = (*L1NetworkID)(nil) - -const L1NetworkKind Kind = "L1Network" - -func (id L1NetworkID) Kind() Kind { - return L1NetworkKind -} - -func (id L1NetworkID) ChainID() eth.ChainID { - return eth.ChainID(id) -} - -func (id L1NetworkID) String() string { - return idOnlyChainID(id).string(L1NetworkKind) -} - -func (id L1NetworkID) LogValue() slog.Value { - return slog.StringValue(id.String()) -} - -func (id L1NetworkID) MarshalText() ([]byte, error) { - return idOnlyChainID(id).marshalText(L1NetworkKind) -} - -func (id *L1NetworkID) UnmarshalText(data []byte) error { - return (*idOnlyChainID)(id).unmarshalText(L1NetworkKind, data) -} - -func SortL1NetworkIDs(ids []L1NetworkID) []L1NetworkID { - return copyAndSort(ids, func(a, b L1NetworkID) bool { - return lessIDOnlyChainID(idOnlyChainID(a), idOnlyChainID(b)) - }) -} - -func SortL1Networks(elems []L1Network) []L1Network { - return copyAndSort(elems, func(a, b L1Network) bool { - return lessIDOnlyChainID(idOnlyChainID(a.ID()), idOnlyChainID(b.ID())) - }) -} - -var _ L1NetworkMatcher = L1NetworkID{} - -func (id L1NetworkID) Match(elems []L1Network) []L1Network { - return findByID(id, elems) -} - // L1Network represents a L1 chain, a collection of configuration and node resources. type L1Network interface { Network - ID() L1NetworkID + ID() ComponentID L1ELNode(m L1ELMatcher) L1ELNode L1CLNode(m L1CLMatcher) L1CLNode - L1ELNodeIDs() []L1ELNodeID - L1CLNodeIDs() []L1CLNodeID + L1ELNodeIDs() []ComponentID + L1CLNodeIDs() []ComponentID L1ELNodes() []L1ELNode L1CLNodes() []L1CLNode diff --git a/op-devstack/stack/l2_batcher.go b/op-devstack/stack/l2_batcher.go index 6978de7213d..04af9809428 100644 --- a/op-devstack/stack/l2_batcher.go +++ b/op-devstack/stack/l2_batcher.go @@ -1,75 +1,12 @@ package stack import ( - "log/slog" - "github.com/ethereum-optimism/optimism/op-service/apis" - "github.com/ethereum-optimism/optimism/op-service/eth" ) -// L2BatcherID identifies a L2Batcher by name and chainID, is type-safe, and can be value-copied and used as map key. -type L2BatcherID idWithChain - -var _ IDWithChain = (*L2BatcherID)(nil) - -const L2BatcherKind Kind = "L2Batcher" - -func NewL2BatcherID(key string, chainID eth.ChainID) L2BatcherID { - return L2BatcherID{ - key: key, - chainID: chainID, - } -} - -func (id L2BatcherID) String() string { - return idWithChain(id).string(L2BatcherKind) -} - -func (id L2BatcherID) ChainID() eth.ChainID { - return id.chainID -} - -func (id L2BatcherID) Kind() Kind { - return L2BatcherKind -} - -func (id L2BatcherID) Key() string { - return id.key -} - -func (id L2BatcherID) LogValue() slog.Value { - return slog.StringValue(id.String()) -} - -func (id L2BatcherID) MarshalText() ([]byte, error) { - return idWithChain(id).marshalText(L2BatcherKind) -} - -func (id *L2BatcherID) UnmarshalText(data []byte) error { - return (*idWithChain)(id).unmarshalText(L2BatcherKind, data) -} - -func SortL2BatcherIDs(ids []L2BatcherID) []L2BatcherID { - return copyAndSort(ids, func(a, b L2BatcherID) bool { - return lessIDWithChain(idWithChain(a), idWithChain(b)) - }) -} - -func SortL2Batchers(elems []L2Batcher) []L2Batcher { - return copyAndSort(elems, func(a, b L2Batcher) bool { - return lessIDWithChain(idWithChain(a.ID()), idWithChain(b.ID())) - }) -} - -var _ L2BatcherMatcher = L2BatcherID{} - -func (id L2BatcherID) Match(elems []L2Batcher) []L2Batcher { - return findByID(id, elems) -} - // L2Batcher represents an L2 batch-submission service, posting L2 data of an L2 to L1. type L2Batcher interface { Common - ID() L2BatcherID + ID() ComponentID ActivityAPI() apis.BatcherActivity } diff --git a/op-devstack/stack/l2_challenger.go b/op-devstack/stack/l2_challenger.go index c1caded6848..7d9f9d2dfc2 100644 --- a/op-devstack/stack/l2_challenger.go +++ b/op-devstack/stack/l2_challenger.go @@ -1,74 +1,11 @@ package stack import ( - "log/slog" - "github.com/ethereum-optimism/optimism/op-challenger/config" - "github.com/ethereum-optimism/optimism/op-service/eth" ) -// L2ChallengerID identifies a L2Challenger by name and chainID, is type-safe, and can be value-copied and used as map key. -type L2ChallengerID idWithChain - -var _ IDWithChain = (*L2ChallengerID)(nil) - -const L2ChallengerKind Kind = "L2Challenger" - -func NewL2ChallengerID(key string, chainID eth.ChainID) L2ChallengerID { - return L2ChallengerID{ - key: key, - chainID: chainID, - } -} - -func (id L2ChallengerID) String() string { - return idWithChain(id).string(L2ChallengerKind) -} - -func (id L2ChallengerID) ChainID() eth.ChainID { - return idWithChain(id).chainID -} - -func (id L2ChallengerID) Kind() Kind { - return L2ChallengerKind -} - -func (id L2ChallengerID) Key() string { - return id.key -} - -func (id L2ChallengerID) LogValue() slog.Value { - return slog.StringValue(id.String()) -} - -func (id L2ChallengerID) MarshalText() ([]byte, error) { - return idWithChain(id).marshalText(L2ChallengerKind) -} - -func (id *L2ChallengerID) UnmarshalText(data []byte) error { - return (*idWithChain)(id).unmarshalText(L2ChallengerKind, data) -} - -func SortL2ChallengerIDs(ids []L2ChallengerID) []L2ChallengerID { - return copyAndSort(ids, func(a, b L2ChallengerID) bool { - return lessIDWithChain(idWithChain(a), idWithChain(b)) - }) -} - -func SortL2Challengers(elems []L2Challenger) []L2Challenger { - return copyAndSort(elems, func(a, b L2Challenger) bool { - return lessIDWithChain(idWithChain(a.ID()), idWithChain(b.ID())) - }) -} - -var _ L2ChallengerMatcher = L2ChallengerID{} - -func (id L2ChallengerID) Match(elems []L2Challenger) []L2Challenger { - return findByID(id, elems) -} - type L2Challenger interface { Common - ID() L2ChallengerID + ID() ComponentID Config() *config.Config } diff --git a/op-devstack/stack/l2_cl.go b/op-devstack/stack/l2_cl.go index 8005cb3d28c..14d6d0695d4 100644 --- a/op-devstack/stack/l2_cl.go +++ b/op-devstack/stack/l2_cl.go @@ -1,77 +1,15 @@ package stack import ( - "log/slog" - "github.com/ethereum-optimism/optimism/op-service/apis" "github.com/ethereum-optimism/optimism/op-service/client" "github.com/ethereum-optimism/optimism/op-service/eth" ) -// L2CLNodeID identifies a L2CLNode by name and chainID, is type-safe, and can be value-copied and used as map key. -type L2CLNodeID idWithChain - -var _ IDWithChain = L2CLNodeID{} - -const L2CLNodeKind Kind = "L2CLNode" - -func NewL2CLNodeID(key string, chainID eth.ChainID) L2CLNodeID { - return L2CLNodeID{ - key: key, - chainID: chainID, - } -} - -func (id L2CLNodeID) String() string { - return idWithChain(id).string(L2CLNodeKind) -} - -func (id L2CLNodeID) ChainID() eth.ChainID { - return id.chainID -} - -func (id L2CLNodeID) Kind() Kind { - return L2CLNodeKind -} - -func (id L2CLNodeID) Key() string { - return id.key -} - -func (id L2CLNodeID) LogValue() slog.Value { - return slog.StringValue(id.String()) -} - -func (id L2CLNodeID) MarshalText() ([]byte, error) { - return idWithChain(id).marshalText(L2CLNodeKind) -} - -func (id *L2CLNodeID) UnmarshalText(data []byte) error { - return (*idWithChain)(id).unmarshalText(L2CLNodeKind, data) -} - -func SortL2CLNodeIDs(ids []L2CLNodeID) []L2CLNodeID { - return copyAndSort(ids, func(a, b L2CLNodeID) bool { - return lessIDWithChain(idWithChain(a), idWithChain(b)) - }) -} - -func SortL2CLNodes(elems []L2CLNode) []L2CLNode { - return copyAndSort(elems, func(a, b L2CLNode) bool { - return lessIDWithChain(idWithChain(a.ID()), idWithChain(b.ID())) - }) -} - -var _ L2CLMatcher = L2CLNodeID{} - -func (id L2CLNodeID) Match(elems []L2CLNode) []L2CLNode { - return findByID(id, elems) -} - // L2CLNode is a L2 ethereum consensus-layer node type L2CLNode interface { Common - ID() L2CLNodeID + ID() ComponentID ClientRPC() client.RPC RollupAPI() apis.RollupClient diff --git a/op-devstack/stack/l2_el.go b/op-devstack/stack/l2_el.go index 7b5e3e07815..4678cb084ec 100644 --- a/op-devstack/stack/l2_el.go +++ b/op-devstack/stack/l2_el.go @@ -1,75 +1,12 @@ package stack import ( - "log/slog" - "github.com/ethereum-optimism/optimism/op-service/apis" - "github.com/ethereum-optimism/optimism/op-service/eth" ) -// L2ELNodeID identifies a L2ELNode by name and chainID, is type-safe, and can be value-copied and used as map key. -type L2ELNodeID idWithChain - -var _ IDWithChain = (*L2ELNodeID)(nil) - -const L2ELNodeKind Kind = "L2ELNode" - -func NewL2ELNodeID(key string, chainID eth.ChainID) L2ELNodeID { - return L2ELNodeID{ - key: key, - chainID: chainID, - } -} - -func (id L2ELNodeID) String() string { - return idWithChain(id).string(L2ELNodeKind) -} - -func (id L2ELNodeID) ChainID() eth.ChainID { - return id.chainID -} - -func (id L2ELNodeID) Kind() Kind { - return L2ELNodeKind -} - -func (id L2ELNodeID) Key() string { - return id.key -} - -func (id L2ELNodeID) LogValue() slog.Value { - return slog.StringValue(id.String()) -} - -func (id L2ELNodeID) MarshalText() ([]byte, error) { - return idWithChain(id).marshalText(L2ELNodeKind) -} - -func (id *L2ELNodeID) UnmarshalText(data []byte) error { - return (*idWithChain)(id).unmarshalText(L2ELNodeKind, data) -} - -func SortL2ELNodeIDs(ids []L2ELNodeID) []L2ELNodeID { - return copyAndSort(ids, func(a, b L2ELNodeID) bool { - return lessIDWithChain(idWithChain(a), idWithChain(b)) - }) -} - -func SortL2ELNodes(elems []L2ELNode) []L2ELNode { - return copyAndSort(elems, func(a, b L2ELNode) bool { - return lessIDWithChain(idWithChain(a.ID()), idWithChain(b.ID())) - }) -} - -var _ L2ELMatcher = L2ELNodeID{} - -func (id L2ELNodeID) Match(elems []L2ELNode) []L2ELNode { - return findByID(id, elems) -} - // L2ELNode is a L2 ethereum execution-layer node type L2ELNode interface { - ID() L2ELNodeID + ID() ComponentID L2EthClient() apis.L2EthClient L2EngineClient() apis.EngineClient diff --git a/op-devstack/stack/l2_network.go b/op-devstack/stack/l2_network.go index d49f26750b6..7fb0f010b98 100644 --- a/op-devstack/stack/l2_network.go +++ b/op-devstack/stack/l2_network.go @@ -2,64 +2,13 @@ package stack import ( "crypto/ecdsa" - "log/slog" "github.com/ethereum/go-ethereum/common" "github.com/ethereum-optimism/optimism/op-chain-ops/devkeys" "github.com/ethereum-optimism/optimism/op-node/rollup" - "github.com/ethereum-optimism/optimism/op-service/eth" ) -// L2NetworkID identifies a L2Network by name and chainID, is type-safe, and can be value-copied and used as map key. -type L2NetworkID idOnlyChainID - -var _ IDOnlyChainID = (*L2NetworkID)(nil) - -const L2NetworkKind Kind = "L2Network" - -func (id L2NetworkID) ChainID() eth.ChainID { - return eth.ChainID(id) -} - -func (id L2NetworkID) Kind() Kind { - return L2NetworkKind -} - -func (id L2NetworkID) String() string { - return idOnlyChainID(id).string(L2NetworkKind) -} - -func (id L2NetworkID) LogValue() slog.Value { - return slog.StringValue(id.String()) -} - -func (id L2NetworkID) MarshalText() ([]byte, error) { - return idOnlyChainID(id).marshalText(L2NetworkKind) -} - -func (id *L2NetworkID) UnmarshalText(data []byte) error { - return (*idOnlyChainID)(id).unmarshalText(L2NetworkKind, data) -} - -func SortL2NetworkIDs(ids []L2NetworkID) []L2NetworkID { - return copyAndSort(ids, func(a, b L2NetworkID) bool { - return lessIDOnlyChainID(idOnlyChainID(a), idOnlyChainID(b)) - }) -} - -func SortL2Networks(elems []L2Network) []L2Network { - return copyAndSort(elems, func(a, b L2Network) bool { - return lessIDOnlyChainID(idOnlyChainID(a.ID()), idOnlyChainID(b.ID())) - }) -} - -var _ L2NetworkMatcher = L2NetworkID{} - -func (id L2NetworkID) Match(elems []L2Network) []L2Network { - return findByID(id, elems) -} - type L2Deployment interface { SystemConfigProxyAddr() common.Address DisputeGameFactoryProxyAddr() common.Address @@ -76,7 +25,7 @@ type Keys interface { // There is an extension-interface ExtensibleL2Network for adding new components to the chain. type L2Network interface { Network - ID() L2NetworkID + ID() ComponentID RollupConfig() *rollup.Config Deployment() L2Deployment Keys() Keys @@ -94,11 +43,11 @@ type L2Network interface { RollupBoostNode(m RollupBoostNodeMatcher) RollupBoostNode OPRBuilderNode(m OPRBuilderNodeMatcher) OPRBuilderNode - L2BatcherIDs() []L2BatcherID - L2ProposerIDs() []L2ProposerID - L2ChallengerIDs() []L2ChallengerID - L2CLNodeIDs() []L2CLNodeID - L2ELNodeIDs() []L2ELNodeID + L2BatcherIDs() []ComponentID + L2ProposerIDs() []ComponentID + L2ChallengerIDs() []ComponentID + L2CLNodeIDs() []ComponentID + L2ELNodeIDs() []ComponentID L2Batchers() []L2Batcher L2Proposers() []L2Proposer diff --git a/op-devstack/stack/l2_proposer.go b/op-devstack/stack/l2_proposer.go index 4109b5ed07f..71e8dbe58cc 100644 --- a/op-devstack/stack/l2_proposer.go +++ b/op-devstack/stack/l2_proposer.go @@ -1,73 +1,7 @@ package stack -import ( - "log/slog" - - "github.com/ethereum-optimism/optimism/op-service/eth" -) - -// L2ProposerID identifies a L2Proposer by name and chainID, is type-safe, and can be value-copied and used as map key. -type L2ProposerID idWithChain - -var _ IDWithChain = (*L2ProposerID)(nil) - -const L2ProposerKind Kind = "L2Proposer" - -func NewL2ProposerID(key string, chainID eth.ChainID) L2ProposerID { - return L2ProposerID{ - key: key, - chainID: chainID, - } -} - -func (id L2ProposerID) String() string { - return idWithChain(id).string(L2ProposerKind) -} - -func (id L2ProposerID) ChainID() eth.ChainID { - return idWithChain(id).chainID -} - -func (id L2ProposerID) Kind() Kind { - return L2ProposerKind -} - -func (id L2ProposerID) Key() string { - return id.key -} - -func (id L2ProposerID) LogValue() slog.Value { - return slog.StringValue(id.String()) -} - -func (id L2ProposerID) MarshalText() ([]byte, error) { - return idWithChain(id).marshalText(L2ProposerKind) -} - -func (id *L2ProposerID) UnmarshalText(data []byte) error { - return (*idWithChain)(id).unmarshalText(L2ProposerKind, data) -} - -func SortL2ProposerIDs(ids []L2ProposerID) []L2ProposerID { - return copyAndSort(ids, func(a, b L2ProposerID) bool { - return lessIDWithChain(idWithChain(a), idWithChain(b)) - }) -} - -func SortL2Proposers(elems []L2Proposer) []L2Proposer { - return copyAndSort(elems, func(a, b L2Proposer) bool { - return lessIDWithChain(idWithChain(a.ID()), idWithChain(b.ID())) - }) -} - -var _ L2ProposerMatcher = L2ProposerID{} - -func (id L2ProposerID) Match(elems []L2Proposer) []L2Proposer { - return findByID(id, elems) -} - // L2Proposer is a L2 output proposer, posting claims of L2 state to L1. type L2Proposer interface { Common - ID() L2ProposerID + ID() ComponentID } diff --git a/op-devstack/stack/match/archive.go b/op-devstack/stack/match/archive.go index 84f6a1eb142..dac4ca2febc 100644 --- a/op-devstack/stack/match/archive.go +++ b/op-devstack/stack/match/archive.go @@ -16,8 +16,8 @@ import ( // // Either assumption being false could result in false positives or false negatives. Note that // there is also a race condition where assumption (2) becomes true after the function returns. -func WithArchive(ctx context.Context) stack.Matcher[stack.L2ELNodeID, stack.L2ELNode] { - return MatchElemFn[stack.L2ELNodeID, stack.L2ELNode](func(elem stack.L2ELNode) bool { +func WithArchive(ctx context.Context) stack.Matcher[stack.L2ELNode] { + return MatchElemFn[stack.L2ELNode](func(elem stack.L2ELNode) bool { if _, err := elem.L2EthClient().BlockRefByNumber(ctx, 1); err != nil { // The devnet is fresh. This is almost guaranteed to be a devnet created by sysgo, // which always uses archive mode. diff --git a/op-devstack/stack/match/core.go b/op-devstack/stack/match/core.go index b1bf06a6e77..073d607fa5b 100644 --- a/op-devstack/stack/match/core.go +++ b/op-devstack/stack/match/core.go @@ -7,24 +7,23 @@ import ( ) // MatchFn implements stack.Matcher, checking all elements at once. -type MatchFn[I comparable, E stack.Identifiable[I]] func(elems []E) []E +type MatchFn[E stack.Identifiable] func(elems []E) []E -func (m MatchFn[I, E]) Match(elems []E) []E { +func (m MatchFn[E]) Match(elems []E) []E { return m(elems) } -func (m MatchFn[I, E]) String() string { - var id I +func (m MatchFn[E]) String() string { var x E - return fmt.Sprintf("MatchFn[%T, %T]", id, x) + return fmt.Sprintf("MatchFn[%T]", x) } -var _ stack.Matcher[stack.L2NetworkID, stack.L2Network] = MatchFn[stack.L2NetworkID, stack.L2Network](nil) +var _ stack.Matcher[stack.L2Network] = MatchFn[stack.L2Network](nil) // MatchElemFn implements stack.Matcher, checking one element at a time. -type MatchElemFn[I comparable, E stack.Identifiable[I]] func(elem E) bool +type MatchElemFn[E stack.Identifiable] func(elem E) bool -func (m MatchElemFn[I, E]) Match(elems []E) (out []E) { +func (m MatchElemFn[E]) Match(elems []E) (out []E) { for _, elem := range elems { if m(elem) { out = append(out, elem) @@ -33,10 +32,9 @@ func (m MatchElemFn[I, E]) Match(elems []E) (out []E) { return out } -func (m MatchElemFn[I, E]) String() string { - var id I +func (m MatchElemFn[E]) String() string { var x E - return fmt.Sprintf("MatchElemFn[%T, %T]", id, x) + return fmt.Sprintf("MatchElemFn[%T]", x) } -var _ stack.Matcher[stack.L2NetworkID, stack.L2Network] = MatchElemFn[stack.L2NetworkID, stack.L2Network](nil) +var _ stack.Matcher[stack.L2Network] = MatchElemFn[stack.L2Network](nil) diff --git a/op-devstack/stack/match/engine.go b/op-devstack/stack/match/engine.go index a9bd93413e6..a0eca09d00e 100644 --- a/op-devstack/stack/match/engine.go +++ b/op-devstack/stack/match/engine.go @@ -4,20 +4,22 @@ import ( "github.com/ethereum-optimism/optimism/op-devstack/stack" ) -func WithEngine(engine stack.L2ELNodeID) stack.Matcher[stack.L2CLNodeID, stack.L2CLNode] { - return MatchElemFn[stack.L2CLNodeID, stack.L2CLNode](func(elem stack.L2CLNode) bool { +func WithEngine(engine stack.ComponentID) stack.Matcher[stack.L2CLNode] { + return MatchElemFn[stack.L2CLNode](func(elem stack.L2CLNode) bool { for _, el := range elem.ELs() { if el.ID() == engine { return true } } - rbID := stack.RollupBoostNodeID(engine) + // Check RollupBoost nodes with matching key/chainID + rbID := stack.NewRollupBoostNodeID(engine.Key(), engine.ChainID()) for _, rb := range elem.RollupBoostNodes() { - if rb.ID().ChainID() == rbID.ChainID() { + if rb.ID() == rbID { return true } } - oprbID := stack.OPRBuilderNodeID(engine) + // Check OPRBuilder nodes with matching key/chainID + oprbID := stack.NewOPRBuilderNodeID(engine.Key(), engine.ChainID()) for _, oprb := range elem.OPRBuilderNodes() { if oprb.ID() == oprbID { return true @@ -27,20 +29,22 @@ func WithEngine(engine stack.L2ELNodeID) stack.Matcher[stack.L2CLNodeID, stack.L }) } -func EngineFor(cl stack.L2CLNode) stack.Matcher[stack.L2ELNodeID, stack.L2ELNode] { - return MatchElemFn[stack.L2ELNodeID, stack.L2ELNode](func(elem stack.L2ELNode) bool { +func EngineFor(cl stack.L2CLNode) stack.Matcher[stack.L2ELNode] { + return MatchElemFn[stack.L2ELNode](func(elem stack.L2ELNode) bool { for _, el := range cl.ELs() { if el.ID() == elem.ID() { return true } } - rbID := stack.RollupBoostNodeID(elem.ID()) + // Check RollupBoost nodes with matching key/chainID + rbID := stack.NewRollupBoostNodeID(elem.ID().Key(), elem.ID().ChainID()) for _, rb := range cl.RollupBoostNodes() { - if rb.ID().ChainID() == rbID.ChainID() { + if rb.ID() == rbID { return true } } - oprbID := stack.OPRBuilderNodeID(elem.ID()) + // Check OPRBuilder nodes with matching key/chainID + oprbID := stack.NewOPRBuilderNodeID(elem.ID().Key(), elem.ID().ChainID()) for _, oprb := range cl.OPRBuilderNodes() { if oprb.ID() == oprbID { return true diff --git a/op-devstack/stack/match/first.go b/op-devstack/stack/match/first.go index 085c47918b0..56af94e80ab 100644 --- a/op-devstack/stack/match/first.go +++ b/op-devstack/stack/match/first.go @@ -2,26 +2,26 @@ package match import "github.com/ethereum-optimism/optimism/op-devstack/stack" -var FirstL2EL = First[stack.L2ELNodeID, stack.L2ELNode]() -var FirstL2CL = First[stack.L2CLNodeID, stack.L2CLNode]() -var FirstL2Batcher = First[stack.L2BatcherID, stack.L2Batcher]() -var FirstL2Proposer = First[stack.L2ProposerID, stack.L2Proposer]() -var FirstL2Challenger = First[stack.L2ChallengerID, stack.L2Challenger]() +var FirstL2EL = First[stack.L2ELNode]() +var FirstL2CL = First[stack.L2CLNode]() +var FirstL2Batcher = First[stack.L2Batcher]() +var FirstL2Proposer = First[stack.L2Proposer]() +var FirstL2Challenger = First[stack.L2Challenger]() -var FirstTestSequencer = First[stack.TestSequencerID, stack.TestSequencer]() -var FirstSupervisor = First[stack.SupervisorID, stack.Supervisor]() -var FirstSupernode = First[stack.SupernodeID, stack.Supernode]() +var FirstTestSequencer = First[stack.TestSequencer]() +var FirstSupervisor = First[stack.Supervisor]() +var FirstSupernode = First[stack.Supernode]() -var FirstL1EL = First[stack.L1ELNodeID, stack.L1ELNode]() -var FirstL1CL = First[stack.L1CLNodeID, stack.L1CLNode]() +var FirstL1EL = First[stack.L1ELNode]() +var FirstL1CL = First[stack.L1CLNode]() -var FirstL1Network = First[stack.L1NetworkID, stack.L1Network]() -var FirstL2Network = First[stack.L2NetworkID, stack.L2Network]() -var FirstSuperchain = First[stack.SuperchainID, stack.Superchain]() -var FirstCluster = First[stack.ClusterID, stack.Cluster]() +var FirstL1Network = First[stack.L1Network]() +var FirstL2Network = First[stack.L2Network]() +var FirstSuperchain = First[stack.Superchain]() +var FirstCluster = First[stack.Cluster]() -var FirstFaucet = First[stack.FaucetID, stack.Faucet]() -var FirstSyncTester = First[stack.SyncTesterID, stack.SyncTester]() +var FirstFaucet = First[stack.Faucet]() +var FirstSyncTester = First[stack.SyncTester]() -var FirstOPRBuilderNode = First[stack.OPRBuilderNodeID, stack.OPRBuilderNode]() -var FirstRollupBoostNode = First[stack.RollupBoostNodeID, stack.RollupBoostNode]() +var FirstOPRBuilderNode = First[stack.OPRBuilderNode]() +var FirstRollupBoostNode = First[stack.RollupBoostNode]() diff --git a/op-devstack/stack/match/gate.go b/op-devstack/stack/match/gate.go index 7b5cc81055d..115fbc63dc0 100644 --- a/op-devstack/stack/match/gate.go +++ b/op-devstack/stack/match/gate.go @@ -7,24 +7,24 @@ import ( "github.com/ethereum-optimism/optimism/op-devstack/stack" ) -type assume[I comparable, E stack.Identifiable[I]] struct { +type assume[E stack.Identifiable] struct { t devtest.T - inner stack.Matcher[I, E] + inner stack.Matcher[E] } -func (a *assume[I, E]) Match(elems []E) []E { +func (a *assume[E]) Match(elems []E) []E { elems = a.inner.Match(elems) a.t.Gate().NotEmpty(elems, "must match something to continue, but matched nothing with %s", a.inner) return elems } -func (a *assume[I, E]) String() string { +func (a *assume[E]) String() string { return fmt.Sprintf("Assume(%s)", a.inner) } // Assume skips the test if no elements were matched with the inner matcher -func Assume[I comparable, E stack.Identifiable[I]](t devtest.T, inner stack.Matcher[I, E]) stack.Matcher[I, E] { - return &assume[I, E]{ +func Assume[E stack.Identifiable](t devtest.T, inner stack.Matcher[E]) stack.Matcher[E] { + return &assume[E]{ t: t, inner: inner, } diff --git a/op-devstack/stack/match/gate_test.go b/op-devstack/stack/match/gate_test.go index 34181bf36c1..61f26077f58 100644 --- a/op-devstack/stack/match/gate_test.go +++ b/op-devstack/stack/match/gate_test.go @@ -36,11 +36,11 @@ func (f *fakeTesting) Gate() *testreq.Assertions { } func TestAssume(t *testing.T) { - a := &testObject{id: "a"} - b := &testObject{id: "b"} + a := newTestObject("a") + b := newTestObject("b") fT := &fakeTesting{T: nil, g: &gateTesting{log: t.Logf}} - m := Assume(fT, First[testID, *testObject]()) + m := Assume(fT, First[*testObject]()) require.Equal(t, m.String(), "Assume(ByIndex(0))") require.Equal(t, []*testObject{a}, m.Match([]*testObject{a})) require.Equal(t, []*testObject{a}, m.Match([]*testObject{a, b})) diff --git a/op-devstack/stack/match/interop.go b/op-devstack/stack/match/interop.go index 298fa296cdb..1810debd764 100644 --- a/op-devstack/stack/match/interop.go +++ b/op-devstack/stack/match/interop.go @@ -3,12 +3,12 @@ package match import "github.com/ethereum-optimism/optimism/op-devstack/stack" // L2ChainA is an alias for the first L2 network. -var L2ChainA = First[stack.L2NetworkID, stack.L2Network]() +var L2ChainA = First[stack.L2Network]() // L2ChainB is an alias for the second L2 network. -var L2ChainB = Second[stack.L2NetworkID, stack.L2Network]() +var L2ChainB = Second[stack.L2Network]() // L2ChainById returns a matcher for the L2 network with the given ID. -func L2ChainById(id stack.L2NetworkID) stack.Matcher[stack.L2NetworkID, stack.L2Network] { - return byID[stack.L2NetworkID, stack.L2Network](id) +func L2ChainById(id stack.ComponentID) stack.Matcher[stack.L2Network] { + return byID[stack.L2Network](id) } diff --git a/op-devstack/stack/match/labels.go b/op-devstack/stack/match/labels.go index be32276b337..44ea4e09fc9 100644 --- a/op-devstack/stack/match/labels.go +++ b/op-devstack/stack/match/labels.go @@ -4,11 +4,11 @@ import ( "github.com/ethereum-optimism/optimism/op-devstack/stack" ) -func WithLabel[I comparable, E interface { - stack.Identifiable[I] +func WithLabel[E interface { + stack.Identifiable Label(key string) string -}](key, value string) stack.Matcher[I, E] { - return MatchElemFn[I, E](func(elem E) bool { +}](key, value string) stack.Matcher[E] { + return MatchElemFn[E](func(elem E) bool { return elem.Label(key) == value }) } @@ -30,7 +30,7 @@ const ( ) func (v Vendor) Match(elems []stack.L2ELNode) []stack.L2ELNode { - return WithLabel[stack.L2ELNodeID, stack.L2ELNode](LabelVendor, string(v)).Match(elems) + return WithLabel[stack.L2ELNode](LabelVendor, string(v)).Match(elems) } func (v Vendor) String() string { diff --git a/op-devstack/stack/match/second.go b/op-devstack/stack/match/second.go index 20e6c2a9607..c483f015c39 100644 --- a/op-devstack/stack/match/second.go +++ b/op-devstack/stack/match/second.go @@ -2,7 +2,7 @@ package match import "github.com/ethereum-optimism/optimism/op-devstack/stack" -var SecondL2EL = Second[stack.L2ELNodeID, stack.L2ELNode]() -var SecondL2CL = Second[stack.L2CLNodeID, stack.L2CLNode]() +var SecondL2EL = Second[stack.L2ELNode]() +var SecondL2CL = Second[stack.L2CLNode]() -var SecondSupervisor = Second[stack.SupervisorID, stack.Supervisor]() +var SecondSupervisor = Second[stack.Supervisor]() diff --git a/op-devstack/stack/match/sequencer.go b/op-devstack/stack/match/sequencer.go index ce2a17dd29b..49e6b3b25e0 100644 --- a/op-devstack/stack/match/sequencer.go +++ b/op-devstack/stack/match/sequencer.go @@ -7,8 +7,8 @@ import ( "github.com/ethereum-optimism/optimism/op-service/retry" ) -func WithSequencerActive(ctx context.Context) stack.Matcher[stack.L2CLNodeID, stack.L2CLNode] { - return MatchElemFn[stack.L2CLNodeID, stack.L2CLNode](func(elem stack.L2CLNode) bool { +func WithSequencerActive(ctx context.Context) stack.Matcher[stack.L2CLNode] { + return MatchElemFn[stack.L2CLNode](func(elem stack.L2CLNode) bool { sequencing, err := retry.Do(ctx, 10, retry.Exponential(), func() (bool, error) { return elem.RollupAPI().SequencerActive(ctx) }) diff --git a/op-devstack/stack/match/util.go b/op-devstack/stack/match/util.go index 680380df74b..97a3361dcaa 100644 --- a/op-devstack/stack/match/util.go +++ b/op-devstack/stack/match/util.go @@ -7,25 +7,25 @@ import ( "github.com/ethereum-optimism/optimism/op-devstack/stack" ) -func First[I comparable, E stack.Identifiable[I]]() stack.Matcher[I, E] { - return ByIndex[I, E](0) +func First[E stack.Identifiable]() stack.Matcher[E] { + return ByIndex[E](0) } -func Second[I comparable, E stack.Identifiable[I]]() stack.Matcher[I, E] { - return ByIndex[I, E](1) +func Second[E stack.Identifiable]() stack.Matcher[E] { + return ByIndex[E](1) } -func byID[I comparable, E stack.Identifiable[I]](id I) stack.Matcher[I, E] { - return MatchElemFn[I, E](func(elem E) bool { +func byID[E stack.Identifiable](id stack.ComponentID) stack.Matcher[E] { + return MatchElemFn[E](func(elem E) bool { return elem.ID() == id }) } -type byIndexMatcher[I comparable, E stack.Identifiable[I]] struct { +type byIndexMatcher[E stack.Identifiable] struct { index int } -func (ma byIndexMatcher[I, E]) Match(elems []E) []E { +func (ma byIndexMatcher[E]) Match(elems []E) []E { if ma.index < 0 { return nil } @@ -35,78 +35,78 @@ func (ma byIndexMatcher[I, E]) Match(elems []E) []E { return elems[ma.index : ma.index+1] } -func (ma byIndexMatcher[I, E]) String() string { +func (ma byIndexMatcher[E]) String() string { return fmt.Sprintf("ByIndex(%d)", ma.index) } // ByIndex matches element i (zero-indexed). -func ByIndex[I comparable, E stack.Identifiable[I]](index int) stack.Matcher[I, E] { - return byIndexMatcher[I, E]{index: index} +func ByIndex[E stack.Identifiable](index int) stack.Matcher[E] { + return byIndexMatcher[E]{index: index} } -type lastMatcher[I comparable, E stack.Identifiable[I]] struct{} +type lastMatcher[E stack.Identifiable] struct{} -func (ma lastMatcher[I, E]) Match(elems []E) []E { +func (ma lastMatcher[E]) Match(elems []E) []E { if len(elems) == 0 { return nil } return elems[len(elems)-1:] } -func (ma lastMatcher[I, E]) String() string { +func (ma lastMatcher[E]) String() string { return "Last" } // Last matches the last element. -func Last[I comparable, E stack.Identifiable[I]]() stack.Matcher[I, E] { - return lastMatcher[I, E]{} +func Last[E stack.Identifiable]() stack.Matcher[E] { + return lastMatcher[E]{} } -type onlyMatcher[I comparable, E stack.Identifiable[I]] struct{} +type onlyMatcher[E stack.Identifiable] struct{} -func (ma onlyMatcher[I, E]) Match(elems []E) []E { +func (ma onlyMatcher[E]) Match(elems []E) []E { if len(elems) != 1 { return nil } return elems } -func (ma onlyMatcher[I, E]) String() string { +func (ma onlyMatcher[E]) String() string { return "Only" } // Only matches the only value. If there are none, or more than one, then no value is matched. -func Only[I comparable, E stack.Identifiable[I]]() stack.Matcher[I, E] { - return onlyMatcher[I, E]{} +func Only[E stack.Identifiable]() stack.Matcher[E] { + return onlyMatcher[E]{} } -type andMatcher[I comparable, E stack.Identifiable[I]] struct { - inner []stack.Matcher[I, E] +type andMatcher[E stack.Identifiable] struct { + inner []stack.Matcher[E] } -func (ma andMatcher[I, E]) Match(elems []E) []E { +func (ma andMatcher[E]) Match(elems []E) []E { for _, matcher := range ma.inner { elems = matcher.Match(elems) } return elems } -func (ma andMatcher[I, E]) String() string { +func (ma andMatcher[E]) String() string { return fmt.Sprintf("And(%s)", joinStr(ma.inner)) } // And combines all the matchers, by running them all, narrowing down the set with each application. // If none are provided, all inputs are matched. -func And[I comparable, E stack.Identifiable[I]](matchers ...stack.Matcher[I, E]) stack.Matcher[I, E] { - return andMatcher[I, E]{inner: matchers} +func And[E stack.Identifiable](matchers ...stack.Matcher[E]) stack.Matcher[E] { + return andMatcher[E]{inner: matchers} } -type orMatcher[I comparable, E stack.Identifiable[I]] struct { - inner []stack.Matcher[I, E] +type orMatcher[E stack.Identifiable] struct { + inner []stack.Matcher[E] } -func (ma orMatcher[I, E]) Match(elems []E) []E { - seen := make(map[I]struct{}) +func (ma orMatcher[E]) Match(elems []E) []E { + seen := make(map[stack.ComponentID]struct{}) for _, matcher := range ma.inner { for _, elem := range matcher.Match(elems) { seen[elem.ID()] = struct{}{} @@ -122,7 +122,7 @@ func (ma orMatcher[I, E]) Match(elems []E) []E { return out } -func (ma orMatcher[I, E]) String() string { +func (ma orMatcher[E]) String() string { return fmt.Sprintf("Or(%s)", joinStr(ma.inner)) } @@ -139,16 +139,16 @@ func joinStr[V fmt.Stringer](elems []V) string { // Or returns each of the inputs that have a match with any of the matchers. // All inputs are applied to all matchers, even if matched previously. -func Or[I comparable, E stack.Identifiable[I]](matchers ...stack.Matcher[I, E]) stack.Matcher[I, E] { - return orMatcher[I, E]{inner: matchers} +func Or[E stack.Identifiable](matchers ...stack.Matcher[E]) stack.Matcher[E] { + return orMatcher[E]{inner: matchers} } -type notMatcher[I comparable, E stack.Identifiable[I]] struct { - inner stack.Matcher[I, E] +type notMatcher[E stack.Identifiable] struct { + inner stack.Matcher[E] } -func (ma notMatcher[I, E]) Match(elems []E) []E { - matched := make(map[I]struct{}) +func (ma notMatcher[E]) Match(elems []E) []E { + matched := make(map[stack.ComponentID]struct{}) for _, elem := range ma.inner.Match(elems) { matched[elem.ID()] = struct{}{} } @@ -161,11 +161,11 @@ func (ma notMatcher[I, E]) Match(elems []E) []E { return out } -func (ma notMatcher[I, E]) String() string { +func (ma notMatcher[E]) String() string { return fmt.Sprintf("Not(%s)", ma.inner) } // Not matches the elements that do not match the given matcher. -func Not[I comparable, E stack.Identifiable[I]](matcher stack.Matcher[I, E]) stack.Matcher[I, E] { - return notMatcher[I, E]{inner: matcher} +func Not[E stack.Identifiable](matcher stack.Matcher[E]) stack.Matcher[E] { + return notMatcher[E]{inner: matcher} } diff --git a/op-devstack/stack/match/util_test.go b/op-devstack/stack/match/util_test.go index 52f59260f4d..5080c6f5a99 100644 --- a/op-devstack/stack/match/util_test.go +++ b/op-devstack/stack/match/util_test.go @@ -8,26 +8,28 @@ import ( "github.com/ethereum-optimism/optimism/op-devstack/stack" ) -type testID string - type testObject struct { - id testID + id stack.ComponentID } -func (t *testObject) ID() testID { +func (t *testObject) ID() stack.ComponentID { return t.id } -var _ stack.Identifiable[testID] = (*testObject)(nil) +var _ stack.Identifiable = (*testObject)(nil) + +func newTestObject(key string) *testObject { + return &testObject{id: stack.NewComponentIDKeyOnly(stack.KindL2ELNode, key)} +} func TestUtils(t *testing.T) { - a := &testObject{id: "a"} - b := &testObject{id: "b"} - c := &testObject{id: "c"} - d := &testObject{id: "d"} + a := newTestObject("a") + b := newTestObject("b") + c := newTestObject("c") + d := newTestObject("d") t.Run("first", func(t *testing.T) { - m := First[testID, *testObject]() + m := First[*testObject]() require.Equal(t, m.String(), "ByIndex(0)") require.Equal(t, []*testObject{a}, m.Match([]*testObject{a, b, c, d})) require.Equal(t, []*testObject{b}, m.Match([]*testObject{b, a, c, d})) @@ -35,13 +37,13 @@ func TestUtils(t *testing.T) { require.Equal(t, []*testObject(nil), m.Match([]*testObject{})) }) t.Run("last", func(t *testing.T) { - m := Last[testID, *testObject]() + m := Last[*testObject]() require.Equal(t, m.String(), "Last") require.Equal(t, []*testObject{d}, m.Match([]*testObject{a, b, c, d})) require.Equal(t, []*testObject{c}, m.Match([]*testObject{b, a, c})) }) t.Run("only", func(t *testing.T) { - m := Only[testID, *testObject]() + m := Only[*testObject]() t.Log(m.String()) require.Equal(t, []*testObject(nil), m.Match([]*testObject{a, b, c, d})) require.Equal(t, []*testObject(nil), m.Match([]*testObject{a, b})) @@ -49,38 +51,38 @@ func TestUtils(t *testing.T) { require.Equal(t, []*testObject(nil), m.Match([]*testObject{})) }) t.Run("and", func(t *testing.T) { - m := And(First[testID, *testObject](), Second[testID, *testObject]()) + m := And(First[*testObject](), Second[*testObject]()) require.Equal(t, m.String(), "And(ByIndex(0), ByIndex(1))") require.Equal(t, []*testObject(nil), m.Match([]*testObject{a, b, c, d})) // narrowed down to single element with First require.Equal(t, []*testObject(nil), m.Match([]*testObject{a, a})) - m2 := And(Second[testID, *testObject](), First[testID, *testObject]()) + m2 := And(Second[*testObject](), First[*testObject]()) // Narrowed down to b, then select b as first require.Equal(t, []*testObject{b}, m2.Match([]*testObject{a, b})) }) t.Run("or", func(t *testing.T) { - m := Or(First[testID, *testObject](), Second[testID, *testObject]()) + m := Or(First[*testObject](), Second[*testObject]()) t.Log(m.String()) require.Equal(t, []*testObject{a, b}, m.Match([]*testObject{a, b, c, d})) }) t.Run("not", func(t *testing.T) { - m := Not(Or(First[testID, *testObject](), Second[testID, *testObject]())) + m := Not(Or(First[*testObject](), Second[*testObject]())) require.Equal(t, m.String(), "Not(Or(ByIndex(0), ByIndex(1)))") require.Equal(t, []*testObject{c, d}, m.Match([]*testObject{a, b, c, d})) require.Equal(t, []*testObject{}, m.Match([]*testObject{})) - m2 := Not(Last[testID, *testObject]()) + m2 := Not(Last[*testObject]()) t.Log(m.String()) require.Equal(t, []*testObject{a, b, c}, m2.Match([]*testObject{a, b, c, d})) }) t.Run("by-index", func(t *testing.T) { - m := ByIndex[testID, *testObject](2) + m := ByIndex[*testObject](2) require.Equal(t, m.String(), "ByIndex(2)") require.Equal(t, []*testObject{c}, m.Match([]*testObject{a, b, c, d})) require.Equal(t, []*testObject{c}, m.Match([]*testObject{a, b, c})) require.Equal(t, []*testObject(nil), m.Match([]*testObject{a, b})) require.Equal(t, []*testObject(nil), m.Match([]*testObject{a})) require.Equal(t, []*testObject(nil), m.Match([]*testObject{})) - m2 := ByIndex[testID, *testObject](-1) + m2 := ByIndex[*testObject](-1) require.Equal(t, []*testObject(nil), m2.Match([]*testObject{a, b})) }) } diff --git a/op-devstack/stack/matcher.go b/op-devstack/stack/matcher.go index 91f47baaeb9..d73b3f1dabb 100644 --- a/op-devstack/stack/matcher.go +++ b/op-devstack/stack/matcher.go @@ -1,7 +1,8 @@ package stack -type Identifiable[I comparable] interface { - ID() I +// Identifiable is implemented by all components that have an ID. +type Identifiable interface { + ID() ComponentID } // Matcher abstracts what can be used as getter-method argument. @@ -9,7 +10,7 @@ type Identifiable[I comparable] interface { // if the argument is an ID before searching for a match. // This enables lookups such as getting a component by labels, // by its state, by its relation to other components, etc. -type Matcher[I comparable, E Identifiable[I]] interface { +type Matcher[E Identifiable] interface { // Match finds the elements that pass the matcher. // If no element passes, it returns an empty slice. // Callers should guarantee a stable order of ids, to ensure a deterministic match. @@ -20,49 +21,40 @@ type Matcher[I comparable, E Identifiable[I]] interface { String() string } -func findByID[I comparable, E Identifiable[I]](id I, elems []E) []E { - for i, elem := range elems { - if elem.ID() == id { - return elems[i : i+1] - } - } - return nil -} - -type ClusterMatcher = Matcher[ClusterID, Cluster] +type ClusterMatcher = Matcher[Cluster] -type L1CLMatcher = Matcher[L1CLNodeID, L1CLNode] +type L1CLMatcher = Matcher[L1CLNode] -type L1ELMatcher = Matcher[L1ELNodeID, L1ELNode] +type L1ELMatcher = Matcher[L1ELNode] -type L1NetworkMatcher = Matcher[L1NetworkID, L1Network] +type L1NetworkMatcher = Matcher[L1Network] -type L2NetworkMatcher = Matcher[L2NetworkID, L2Network] +type L2NetworkMatcher = Matcher[L2Network] -type SuperchainMatcher = Matcher[SuperchainID, Superchain] +type SuperchainMatcher = Matcher[Superchain] -type L2BatcherMatcher = Matcher[L2BatcherID, L2Batcher] +type L2BatcherMatcher = Matcher[L2Batcher] -type L2ChallengerMatcher = Matcher[L2ChallengerID, L2Challenger] +type L2ChallengerMatcher = Matcher[L2Challenger] -type L2ProposerMatcher = Matcher[L2ProposerID, L2Proposer] +type L2ProposerMatcher = Matcher[L2Proposer] -type L2CLMatcher = Matcher[L2CLNodeID, L2CLNode] +type L2CLMatcher = Matcher[L2CLNode] -type SupervisorMatcher = Matcher[SupervisorID, Supervisor] +type SupervisorMatcher = Matcher[Supervisor] -type SupernodeMatcher = Matcher[SupernodeID, Supernode] +type SupernodeMatcher = Matcher[Supernode] -type TestSequencerMatcher = Matcher[TestSequencerID, TestSequencer] +type TestSequencerMatcher = Matcher[TestSequencer] -type ConductorMatcher = Matcher[ConductorID, Conductor] +type ConductorMatcher = Matcher[Conductor] -type L2ELMatcher = Matcher[L2ELNodeID, L2ELNode] +type L2ELMatcher = Matcher[L2ELNode] -type FaucetMatcher = Matcher[FaucetID, Faucet] +type FaucetMatcher = Matcher[Faucet] -type SyncTesterMatcher = Matcher[SyncTesterID, SyncTester] +type SyncTesterMatcher = Matcher[SyncTester] -type RollupBoostNodeMatcher = Matcher[RollupBoostNodeID, RollupBoostNode] +type RollupBoostNodeMatcher = Matcher[RollupBoostNode] -type OPRBuilderNodeMatcher = Matcher[OPRBuilderNodeID, OPRBuilderNode] +type OPRBuilderNodeMatcher = Matcher[OPRBuilderNode] diff --git a/op-devstack/stack/network.go b/op-devstack/stack/network.go index 66144f933bb..35c30363f2c 100644 --- a/op-devstack/stack/network.go +++ b/op-devstack/stack/network.go @@ -19,11 +19,11 @@ type Network interface { Faucet(m FaucetMatcher) Faucet Faucets() []Faucet - FaucetIDs() []FaucetID + FaucetIDs() []ComponentID SyncTester(m SyncTesterMatcher) SyncTester SyncTesters() []SyncTester - SyncTesterIDs() []SyncTesterID + SyncTesterIDs() []ComponentID } type ExtensibleNetwork interface { diff --git a/op-devstack/stack/op_rbuilder.go b/op-devstack/stack/op_rbuilder.go index 03926167f40..0f7e92396bd 100644 --- a/op-devstack/stack/op_rbuilder.go +++ b/op-devstack/stack/op_rbuilder.go @@ -1,76 +1,13 @@ package stack import ( - "log/slog" - "github.com/ethereum-optimism/optimism/op-service/apis" "github.com/ethereum-optimism/optimism/op-service/client" - "github.com/ethereum-optimism/optimism/op-service/eth" ) -// OPRBuilderNodeID identifies a L2ELNode by name and chainID, is type-safe, and can be value-copied and used as map key. -type OPRBuilderNodeID idWithChain - -var _ IDWithChain = (*OPRBuilderNodeID)(nil) - -const OPRBuilderNodeKind Kind = "OPRBuilderNode" - -func NewOPRBuilderNodeID(key string, chainID eth.ChainID) OPRBuilderNodeID { - return OPRBuilderNodeID{ - key: key, - chainID: chainID, - } -} - -func (id OPRBuilderNodeID) String() string { - return idWithChain(id).string(OPRBuilderNodeKind) -} - -func (id OPRBuilderNodeID) ChainID() eth.ChainID { - return id.chainID -} - -func (id OPRBuilderNodeID) Kind() Kind { - return OPRBuilderNodeKind -} - -func (id OPRBuilderNodeID) Key() string { - return id.key -} - -func (id OPRBuilderNodeID) LogValue() slog.Value { - return slog.StringValue(id.String()) -} - -func (id OPRBuilderNodeID) MarshalText() ([]byte, error) { - return idWithChain(id).marshalText(OPRBuilderNodeKind) -} - -func (id *OPRBuilderNodeID) UnmarshalText(data []byte) error { - return (*idWithChain)(id).unmarshalText(OPRBuilderNodeKind, data) -} - -func SortOPRBuilderIDs(ids []OPRBuilderNodeID) []OPRBuilderNodeID { - return copyAndSort(ids, func(a, b OPRBuilderNodeID) bool { - return lessIDWithChain(idWithChain(a), idWithChain(b)) - }) -} - -func SortOPRBuilderNodes(elems []OPRBuilderNode) []OPRBuilderNode { - return copyAndSort(elems, func(a, b OPRBuilderNode) bool { - return lessIDWithChain(idWithChain(a.ID()), idWithChain(b.ID())) - }) -} - -var _ OPRBuilderNodeMatcher = OPRBuilderNodeID{} - -func (id OPRBuilderNodeID) Match(elems []OPRBuilderNode) []OPRBuilderNode { - return findByID(id, elems) -} - -// L2ELNode is a L2 ethereum execution-layer node +// OPRBuilderNode is a L2 ethereum execution-layer node type OPRBuilderNode interface { - ID() OPRBuilderNodeID + ID() ComponentID L2EthClient() apis.L2EthClient L2EngineClient() apis.EngineClient FlashblocksClient() *client.WSClient diff --git a/op-devstack/stack/orchestrator.go b/op-devstack/stack/orchestrator.go index a1e636fe26b..07efe9d27f0 100644 --- a/op-devstack/stack/orchestrator.go +++ b/op-devstack/stack/orchestrator.go @@ -20,12 +20,12 @@ const ( // ControlPlane is the interface for the orchestrators to control components of the system. type ControlPlane interface { - SupervisorState(id SupervisorID, action ControlAction) - L2CLNodeState(id L2CLNodeID, action ControlAction) - L2ELNodeState(id L2ELNodeID, action ControlAction) - FakePoSState(id L1CLNodeID, action ControlAction) - RollupBoostNodeState(id RollupBoostNodeID, action ControlAction) - OPRBuilderNodeState(id OPRBuilderNodeID, action ControlAction) + SupervisorState(id ComponentID, action ControlAction) + L2CLNodeState(id ComponentID, action ControlAction) + L2ELNodeState(id ComponentID, action ControlAction) + FakePoSState(id ComponentID, action ControlAction) + RollupBoostNodeState(id ComponentID, action ControlAction) + OPRBuilderNodeState(id ComponentID, action ControlAction) } // Orchestrator is the base interface for all system orchestrators. diff --git a/op-devstack/stack/registry.go b/op-devstack/stack/registry.go index 2f11edf773c..791c292c530 100644 --- a/op-devstack/stack/registry.go +++ b/op-devstack/stack/registry.go @@ -293,10 +293,10 @@ func (r *Registry) Clear() { // Type-safe generic accessor functions. // These provide compile-time type safety when working with the registry. -// RegistryGet retrieves a component by its typed ID and returns it as the expected type. +// RegistryGet retrieves a component by its ID and returns it as the expected type. // Returns the zero value and false if not found or if the type doesn't match. -func RegistryGet[T any, M KindMarker](r *Registry, id ID[M]) (T, bool) { - component, ok := r.Get(id.ComponentID) +func RegistryGet[T any](r *Registry, id ComponentID) (T, bool) { + component, ok := r.Get(id) if !ok { var zero T return zero, false @@ -358,7 +358,7 @@ func RegistryRangeByKind[T any](r *Registry, kind ComponentKind, fn func(id Comp }) } -// RegistryRegister is a type-safe way to register a component with a typed ID. -func RegistryRegister[T any, M KindMarker](r *Registry, id ID[M], component T) { - r.Register(id.ComponentID, component) +// RegistryRegister is a type-safe way to register a component with an ID. +func RegistryRegister[T any](r *Registry, id ComponentID, component T) { + r.Register(id, component) } diff --git a/op-devstack/stack/registry_test.go b/op-devstack/stack/registry_test.go index e4d1ebeb7a5..e4951da3e54 100644 --- a/op-devstack/stack/registry_test.go +++ b/op-devstack/stack/registry_test.go @@ -461,9 +461,10 @@ func TestRegistryGet_TypeSafe(t *testing.T) { r := NewRegistry() chainID := eth.ChainIDFromUInt64(420) - id := NewL2BatcherID2("batcher1", chainID) - component := &mockComponent{id: id.ComponentID, name: "test-batcher"} + id := NewL2BatcherID("batcher1", chainID) + component := &mockComponent{id: id, name: "test-batcher"} + // Use the ID for generic registry functions RegistryRegister(r, id, component) // Type-safe get diff --git a/op-devstack/stack/rollup_boost.go b/op-devstack/stack/rollup_boost.go index 8c44e3d79d3..7079f722a81 100644 --- a/op-devstack/stack/rollup_boost.go +++ b/op-devstack/stack/rollup_boost.go @@ -1,76 +1,13 @@ package stack import ( - "log/slog" - "github.com/ethereum-optimism/optimism/op-service/apis" "github.com/ethereum-optimism/optimism/op-service/client" - "github.com/ethereum-optimism/optimism/op-service/eth" ) -// RollupBoostNodeID identifies a RollupBoost node by name and chainID, is type-safe, and can be value-copied and used as map key. -type RollupBoostNodeID L2ELNodeID - -var _ IDWithChain = (*RollupBoostNodeID)(nil) - -const RollupBoostNodeKind Kind = "RollupBoostNode" - -func NewRollupBoostNodeID(key string, chainID eth.ChainID) RollupBoostNodeID { - return RollupBoostNodeID{ - key: key, - chainID: chainID, - } -} - -func (id RollupBoostNodeID) String() string { - return idWithChain(id).string(RollupBoostNodeKind) -} - -func (id RollupBoostNodeID) ChainID() eth.ChainID { - return id.chainID -} - -func (id RollupBoostNodeID) Kind() Kind { - return RollupBoostNodeKind -} - -func (id RollupBoostNodeID) Key() string { - return id.key -} - -func (id RollupBoostNodeID) LogValue() slog.Value { - return slog.StringValue(id.String()) -} - -func (id RollupBoostNodeID) MarshalText() ([]byte, error) { - return idWithChain(id).marshalText(RollupBoostNodeKind) -} - -func (id *RollupBoostNodeID) UnmarshalText(data []byte) error { - return (*idWithChain)(id).unmarshalText(RollupBoostNodeKind, data) -} - -func SortRollupBoostIDs(ids []RollupBoostNodeID) []RollupBoostNodeID { - return copyAndSort(ids, func(a, b RollupBoostNodeID) bool { - return lessIDWithChain(idWithChain(a), idWithChain(b)) - }) -} - -func SortRollupBoostNodes(elems []RollupBoostNode) []RollupBoostNode { - return copyAndSort(elems, func(a, b RollupBoostNode) bool { - return lessIDWithChain(idWithChain(a.ID()), idWithChain(b.ID())) - }) -} - -var _ RollupBoostNodeMatcher = RollupBoostNodeID{} - -func (id RollupBoostNodeID) Match(elems []RollupBoostNode) []RollupBoostNode { - return findByID(id, elems) -} - // RollupBoostNode is a shim service between an L2 consensus-layer node and an L2 ethereum execution-layer node type RollupBoostNode interface { - ID() RollupBoostNodeID + ID() ComponentID L2EthClient() apis.L2EthClient L2EngineClient() apis.EngineClient FlashblocksClient() *client.WSClient diff --git a/op-devstack/stack/superchain.go b/op-devstack/stack/superchain.go index 4087afd1ef8..b1680bbeffd 100644 --- a/op-devstack/stack/superchain.go +++ b/op-devstack/stack/superchain.go @@ -1,8 +1,6 @@ package stack import ( - "log/slog" - "github.com/ethereum/go-ethereum/common" ) @@ -11,51 +9,10 @@ type SuperchainDeployment interface { SuperchainConfigAddr() common.Address } -// SuperchainID identifies a Superchain by name, is type-safe, and can be value-copied and used as map key. -type SuperchainID genericID - -var _ GenericID = (*SuperchainID)(nil) - -const SuperchainKind Kind = "Superchain" - -func (id SuperchainID) String() string { - return genericID(id).string(SuperchainKind) -} - -func (id SuperchainID) Kind() Kind { - return SuperchainKind -} - -func (id SuperchainID) LogValue() slog.Value { - return slog.StringValue(id.String()) -} - -func (id SuperchainID) MarshalText() ([]byte, error) { - return genericID(id).marshalText(SuperchainKind) -} - -func (id *SuperchainID) UnmarshalText(data []byte) error { - return (*genericID)(id).unmarshalText(SuperchainKind, data) -} - -func SortSuperchainIDs(ids []SuperchainID) []SuperchainID { - return copyAndSortCmp(ids) -} - -func SortSuperchains(elems []Superchain) []Superchain { - return copyAndSort(elems, lessElemOrdered[SuperchainID, Superchain]) -} - -var _ SuperchainMatcher = SuperchainID("") - -func (id SuperchainID) Match(elems []Superchain) []Superchain { - return findByID(id, elems) -} - // Superchain is a collection of L2 chains with common rules and shared configuration on L1 type Superchain interface { Common - ID() SuperchainID + ID() ComponentID Deployment() SuperchainDeployment } diff --git a/op-devstack/stack/supernode.go b/op-devstack/stack/supernode.go index c7b1fa6080f..6b5fb48abf6 100644 --- a/op-devstack/stack/supernode.go +++ b/op-devstack/stack/supernode.go @@ -2,64 +2,43 @@ package stack import ( "fmt" - "log/slog" + "sort" "github.com/ethereum-optimism/optimism/op-service/apis" "github.com/ethereum-optimism/optimism/op-service/eth" ) -// SupernodeID identifies a Supernode by name, is type-safe, and can be value-copied and used as map key. -type SupernodeID genericID - -var _ GenericID = (*SupernodeID)(nil) - -const SupernodeKind Kind = "Supernode" +// SupernodeID is kept as a semantic alias for ComponentID. +// Supernode IDs are key-only IDs with KindSupernode. +type SupernodeID = ComponentID func NewSupernodeID(key string, chains ...eth.ChainID) SupernodeID { - var s string + var suffix string for _, chain := range chains { - s += chain.String() + suffix += chain.String() } - return SupernodeID(fmt.Sprintf("%s-%s", key, s)) -} - -func (id SupernodeID) String() string { - return genericID(id).string(SupernodeKind) -} - -func (id SupernodeID) Kind() Kind { - return SupernodeKind -} - -func (id SupernodeID) LogValue() slog.Value { - return slog.StringValue(id.String()) -} - -func (id SupernodeID) MarshalText() ([]byte, error) { - return genericID(id).marshalText(SupernodeKind) -} - -func (id *SupernodeID) UnmarshalText(data []byte) error { - return (*genericID)(id).unmarshalText(SupernodeKind, data) + return NewComponentIDKeyOnly(KindSupernode, fmt.Sprintf("%s-%s", key, suffix)) } func SortSupernodeIDs(ids []SupernodeID) []SupernodeID { - return copyAndSortCmp(ids) + out := append([]SupernodeID(nil), ids...) + sort.Slice(out, func(i, j int) bool { + return out[i].Less(out[j]) + }) + return out } func SortSupernodes(elems []Supernode) []Supernode { - return copyAndSort(elems, lessElemOrdered[SupernodeID, Supernode]) -} - -var _ SupernodeMatcher = SupernodeID("") - -func (id SupernodeID) Match(elems []Supernode) []Supernode { - return findByID(id, elems) + out := append([]Supernode(nil), elems...) + sort.Slice(out, func(i, j int) bool { + return out[i].ID().Less(out[j].ID()) + }) + return out } type Supernode interface { Common - ID() SupernodeID + ID() ComponentID QueryAPI() apis.SupernodeQueryAPI } diff --git a/op-devstack/stack/supervisor.go b/op-devstack/stack/supervisor.go index b635e982375..2deac9fb536 100644 --- a/op-devstack/stack/supervisor.go +++ b/op-devstack/stack/supervisor.go @@ -1,56 +1,13 @@ package stack import ( - "log/slog" - "github.com/ethereum-optimism/optimism/op-service/apis" ) -// SupervisorID identifies a Supervisor by name and chainID, is type-safe, and can be value-copied and used as map key. -type SupervisorID genericID - -var _ GenericID = (*SupervisorID)(nil) - -const SupervisorKind Kind = "Supervisor" - -func (id SupervisorID) String() string { - return genericID(id).string(SupervisorKind) -} - -func (id SupervisorID) Kind() Kind { - return SupervisorKind -} - -func (id SupervisorID) LogValue() slog.Value { - return slog.StringValue(id.String()) -} - -func (id SupervisorID) MarshalText() ([]byte, error) { - return genericID(id).marshalText(SupervisorKind) -} - -func (id *SupervisorID) UnmarshalText(data []byte) error { - return (*genericID)(id).unmarshalText(SupervisorKind, data) -} - -func SortSupervisorIDs(ids []SupervisorID) []SupervisorID { - return copyAndSortCmp(ids) -} - -func SortSupervisors(elems []Supervisor) []Supervisor { - return copyAndSort(elems, lessElemOrdered[SupervisorID, Supervisor]) -} - -var _ SupervisorMatcher = SupervisorID("") - -func (id SupervisorID) Match(elems []Supervisor) []Supervisor { - return findByID(id, elems) -} - // Supervisor is an interop service, used to cross-verify messages between chains. type Supervisor interface { Common - ID() SupervisorID + ID() ComponentID AdminAPI() apis.SupervisorAdminAPI QueryAPI() apis.SupervisorQueryAPI diff --git a/op-devstack/stack/sync_tester.go b/op-devstack/stack/sync_tester.go index 0601e4e40fb..d08ccd9902d 100644 --- a/op-devstack/stack/sync_tester.go +++ b/op-devstack/stack/sync_tester.go @@ -1,75 +1,12 @@ package stack import ( - "log/slog" - "github.com/ethereum-optimism/optimism/op-service/apis" - "github.com/ethereum-optimism/optimism/op-service/eth" ) -// SyncTesterID identifies a syncTester by name and chainID, is type-safe, and can be value-copied and used as map key. -type SyncTesterID idWithChain - -var _ IDWithChain = (*SyncTesterID)(nil) - -const SyncTesterKind Kind = "SyncTester" - -func NewSyncTesterID(key string, chainID eth.ChainID) SyncTesterID { - return SyncTesterID{ - key: key, - chainID: chainID, - } -} - -func (id SyncTesterID) String() string { - return idWithChain(id).string(SyncTesterKind) -} - -func (id SyncTesterID) ChainID() eth.ChainID { - return idWithChain(id).chainID -} - -func (id SyncTesterID) Kind() Kind { - return SyncTesterKind -} - -func (id SyncTesterID) Key() string { - return id.key -} - -func (id SyncTesterID) LogValue() slog.Value { - return slog.StringValue(id.String()) -} - -func (id SyncTesterID) MarshalText() ([]byte, error) { - return idWithChain(id).marshalText(SyncTesterKind) -} - -func (id *SyncTesterID) UnmarshalText(data []byte) error { - return (*idWithChain)(id).unmarshalText(SyncTesterKind, data) -} - -func SortSyncTesterIDs(ids []SyncTesterID) []SyncTesterID { - return copyAndSort(ids, func(a, b SyncTesterID) bool { - return lessIDWithChain(idWithChain(a), idWithChain(b)) - }) -} - -func SortSyncTesters(elems []SyncTester) []SyncTester { - return copyAndSort(elems, func(a, b SyncTester) bool { - return lessIDWithChain(idWithChain(a.ID()), idWithChain(b.ID())) - }) -} - -var _ SyncTesterMatcher = SyncTesterID{} - -func (id SyncTesterID) Match(elems []SyncTester) []SyncTester { - return findByID(id, elems) -} - type SyncTester interface { Common - ID() SyncTesterID + ID() ComponentID API() apis.SyncTester APIWithSession(sessionID string) apis.SyncTester diff --git a/op-devstack/stack/system.go b/op-devstack/stack/system.go index c4cd7acbe00..85c5cd8debf 100644 --- a/op-devstack/stack/system.go +++ b/op-devstack/stack/system.go @@ -22,11 +22,11 @@ type System interface { Supernode(m SupernodeMatcher) Supernode TestSequencer(id TestSequencerMatcher) TestSequencer - SuperchainIDs() []SuperchainID - ClusterIDs() []ClusterID - L1NetworkIDs() []L1NetworkID - L2NetworkIDs() []L2NetworkID - SupervisorIDs() []SupervisorID + SuperchainIDs() []ComponentID + ClusterIDs() []ComponentID + L1NetworkIDs() []ComponentID + L2NetworkIDs() []ComponentID + SupervisorIDs() []ComponentID Superchains() []Superchain Clusters() []Cluster diff --git a/op-devstack/stack/test_sequencer.go b/op-devstack/stack/test_sequencer.go index 7a6a2023baa..072bbbb0b4c 100644 --- a/op-devstack/stack/test_sequencer.go +++ b/op-devstack/stack/test_sequencer.go @@ -1,56 +1,14 @@ package stack import ( - "log/slog" - "github.com/ethereum-optimism/optimism/op-service/apis" "github.com/ethereum-optimism/optimism/op-service/eth" ) -// TestSequencerID identifies a TestSequencer by name and chainID, is type-safe, and can be value-copied and used as map key. -type TestSequencerID genericID - -var _ GenericID = (*TestSequencerID)(nil) - -const TestSequencerKind Kind = "TestSequencer" - -// NewTestSequencerID creates a new TestSequencerID with the given key. -func NewTestSequencerID(key string) TestSequencerID { - return TestSequencerID(key) -} - -func (id TestSequencerID) String() string { - return genericID(id).string(TestSequencerKind) -} - -func (id TestSequencerID) Kind() Kind { - return TestSequencerKind -} - -func (id TestSequencerID) LogValue() slog.Value { - return slog.StringValue(id.String()) -} - -func (id TestSequencerID) MarshalText() ([]byte, error) { - return genericID(id).marshalText(TestSequencerKind) -} - -func (id *TestSequencerID) UnmarshalText(data []byte) error { - return (*genericID)(id).unmarshalText(TestSequencerKind, data) -} - -func SortTestSequencerIDs(ids []TestSequencerID) []TestSequencerID { - return copyAndSortCmp(ids) -} - -func SortTestSequencers(elems []TestSequencer) []TestSequencer { - return copyAndSort(elems, lessElemOrdered[TestSequencerID, TestSequencer]) -} - // TestSequencer type TestSequencer interface { Common - ID() TestSequencerID + ID() ComponentID AdminAPI() apis.TestSequencerAdminAPI BuildAPI() apis.TestSequencerBuildAPI diff --git a/op-devstack/sysext/control_plane.go b/op-devstack/sysext/control_plane.go index 65eb37d9d52..157894df5ab 100644 --- a/op-devstack/sysext/control_plane.go +++ b/op-devstack/sysext/control_plane.go @@ -26,27 +26,27 @@ func (c *ControlPlane) setLifecycleState(svcID string, mode stack.ControlAction) } } -func (c *ControlPlane) SupervisorState(id stack.SupervisorID, mode stack.ControlAction) { - c.setLifecycleState(string(id), mode) +func (c *ControlPlane) SupervisorState(id stack.ComponentID, mode stack.ControlAction) { + c.setLifecycleState(id.Key(), mode) } -func (c *ControlPlane) L2CLNodeState(id stack.L2CLNodeID, mode stack.ControlAction) { +func (c *ControlPlane) L2CLNodeState(id stack.ComponentID, mode stack.ControlAction) { c.setLifecycleState(id.Key(), mode) } -func (c *ControlPlane) L2ELNodeState(id stack.L2ELNodeID, mode stack.ControlAction) { +func (c *ControlPlane) L2ELNodeState(id stack.ComponentID, mode stack.ControlAction) { c.setLifecycleState(id.Key(), mode) } -func (c *ControlPlane) FakePoSState(id stack.L1CLNodeID, mode stack.ControlAction) { +func (c *ControlPlane) FakePoSState(id stack.ComponentID, mode stack.ControlAction) { panic("not implemented: plug in kurtosis wrapper, or gate for the test that uses this method to not run in kurtosis") } -func (c *ControlPlane) RollupBoostNodeState(id stack.RollupBoostNodeID, mode stack.ControlAction) { +func (c *ControlPlane) RollupBoostNodeState(id stack.ComponentID, mode stack.ControlAction) { c.setLifecycleState(id.Key(), mode) } -func (c *ControlPlane) OPRBuilderNodeState(id stack.OPRBuilderNodeID, mode stack.ControlAction) { +func (c *ControlPlane) OPRBuilderNodeState(id stack.ComponentID, mode stack.ControlAction) { c.setLifecycleState(id.Key(), mode) } diff --git a/op-devstack/sysext/l1.go b/op-devstack/sysext/l1.go index 467e74fe840..0ed5932e7c3 100644 --- a/op-devstack/sysext/l1.go +++ b/op-devstack/sysext/l1.go @@ -24,7 +24,7 @@ func (o *Orchestrator) hydrateL1(system stack.ExtensibleSystem) { CommonConfig: commonConfig, ChainConfig: env.Env.L1.Config, }, - ID: stack.L1NetworkID(l1ID), + ID: stack.NewL1NetworkID(l1ID), }) opts := []client.RPCOption{} diff --git a/op-devstack/sysext/l2.go b/op-devstack/sysext/l2.go index 5ec2be41558..9d2b9450ba8 100644 --- a/op-devstack/sysext/l2.go +++ b/op-devstack/sysext/l2.go @@ -24,8 +24,8 @@ import ( "github.com/ethereum/go-ethereum/rpc" ) -func getL2ID(net *descriptors.L2Chain) stack.L2NetworkID { - return stack.L2NetworkID(eth.ChainIDFromBig(net.Config.ChainID)) +func getL2ID(net *descriptors.L2Chain) stack.ComponentID { + return stack.NewL2NetworkID(eth.ChainIDFromBig(net.Config.ChainID)) } func (o *Orchestrator) hydrateL2(net *descriptors.L2Chain, system stack.ExtensibleSystem) { @@ -35,7 +35,7 @@ func (o *Orchestrator) hydrateL2(net *descriptors.L2Chain, system stack.Extensib env := o.env l2ID := getL2ID(net) - l1 := system.L1Network(stack.L1NetworkID(eth.ChainIDFromBig(env.Env.L1.Config.ChainID))) + l1 := system.L1Network(stack.ByID[stack.L1Network](stack.NewL1NetworkID(eth.ChainIDFromBig(env.Env.L1.Config.ChainID)))) cfg := shim.L2NetworkConfig{ NetworkConfig: shim.NetworkConfig{ @@ -46,11 +46,11 @@ func (o *Orchestrator) hydrateL2(net *descriptors.L2Chain, system stack.Extensib RollupConfig: net.RollupConfig, Deployment: newL2AddressBook(net.Addresses), Keys: o.defineSystemKeys(t, net), - Superchain: system.Superchain(stack.SuperchainID(env.Env.Name)), + Superchain: system.Superchain(stack.ByID[stack.Superchain](stack.NewSuperchainID(env.Env.Name))), L1: l1, } if o.isInterop() { - cfg.Cluster = system.Cluster(stack.ClusterID(env.Env.Name)) + cfg.Cluster = system.Cluster(stack.ByID[stack.Cluster](stack.NewClusterID(env.Env.Name))) } opts := []client.RPCOption{} @@ -187,7 +187,7 @@ func (o *Orchestrator) hydrateConductors(node *descriptors.Node, l2Net stack.Ext conductor := shim.NewConductor(shim.ConductorConfig{ CommonConfig: shim.NewCommonConfig(l2Net.T()), Client: conductorClient, - ID: stack.ConductorID(conductorService.Name), + ID: stack.NewConductorID(conductorService.Name), }) l2Net.AddConductor(conductor) diff --git a/op-devstack/sysext/system.go b/op-devstack/sysext/system.go index 6927517153f..01a6a186f60 100644 --- a/op-devstack/sysext/system.go +++ b/op-devstack/sysext/system.go @@ -18,7 +18,7 @@ func (o *Orchestrator) hydrateSuperchain(sys stack.ExtensibleSystem) { env := o.env sys.AddSuperchain(shim.NewSuperchain(shim.SuperchainConfig{ CommonConfig: shim.NewCommonConfig(sys.T()), - ID: stack.SuperchainID(env.Env.Name), + ID: stack.NewSuperchainID(env.Env.Name), Deployment: newL1AddressBook(sys.T(), env.Env.L1.Addresses), })) } @@ -40,7 +40,7 @@ func (o *Orchestrator) hydrateClustersMaybe(sys stack.ExtensibleSystem) { sys.AddCluster(shim.NewCluster(shim.ClusterConfig{ CommonConfig: shim.NewCommonConfig(sys.T()), - ID: stack.ClusterID(env.Env.Name), + ID: stack.NewClusterID(env.Env.Name), DependencySet: &depSet, })) } @@ -52,11 +52,11 @@ func (o *Orchestrator) hydrateSupervisorsMaybe(sys stack.ExtensibleSystem) { return } - supervisors := make(map[stack.SupervisorID]bool) + supervisors := make(map[stack.ComponentID]bool) for _, l2 := range o.env.Env.L2 { if supervisorService, ok := l2.Services["supervisor"]; ok { for _, instance := range supervisorService { - id := stack.SupervisorID(instance.Name) + id := stack.NewSupervisorID(instance.Name) if supervisors[id] { // each supervisor appears in multiple L2s (covering the dependency set), // so we need to deduplicate @@ -74,7 +74,7 @@ func (o *Orchestrator) hydrateSupervisorsMaybe(sys stack.ExtensibleSystem) { } func (o *Orchestrator) hydrateTestSequencersMaybe(sys stack.ExtensibleSystem) { - sequencers := make(map[stack.TestSequencerID]bool) + sequencers := make(map[string]bool) // Collect all L2 chain IDs and the shared JWT secret var ( @@ -95,13 +95,12 @@ func (o *Orchestrator) hydrateTestSequencersMaybe(sys stack.ExtensibleSystem) { for _, l2 := range o.env.Env.L2 { if sequencerService, ok := l2.Services["test-sequencer"]; ok { for _, instance := range sequencerService { - id := stack.TestSequencerID(instance.Name) - if sequencers[id] { + if sequencers[instance.Name] { // Each test_sequencer appears in multiple L2s // So we need to deduplicate continue } - sequencers[id] = true + sequencers[instance.Name] = true cc := make(map[eth.ChainID]client.RPC, len(chainIDs)) for _, chainID := range chainIDs { @@ -116,7 +115,7 @@ func (o *Orchestrator) hydrateTestSequencersMaybe(sys stack.ExtensibleSystem) { sys.AddTestSequencer(shim.NewTestSequencer(shim.TestSequencerConfig{ CommonConfig: shim.NewCommonConfig(sys.T()), - ID: id, + ID: stack.NewTestSequencerID(instance.Name), Client: o.rpcClient(sys.T(), instance, RPCProtocol, "/", opts...), ControlClients: cc, })) diff --git a/op-devstack/sysgo/add_game_type.go b/op-devstack/sysgo/add_game_type.go index 06c279415c3..a1407cbf259 100644 --- a/op-devstack/sysgo/add_game_type.go +++ b/op-devstack/sysgo/add_game_type.go @@ -57,7 +57,7 @@ func WithRespectedGameType(gameType gameTypes.GameType) stack.Option[*Orchestrat } } -func WithCannonGameTypeAdded(l1ELID stack.L1ELNodeID, l2ChainID eth.ChainID) stack.Option[*Orchestrator] { +func WithCannonGameTypeAdded(l1ELID stack.ComponentID, l2ChainID eth.ChainID) stack.Option[*Orchestrator] { return stack.FnOption[*Orchestrator]{ FinallyFn: func(o *Orchestrator) { // TODO(#17867): Rebuild the op-program prestate using the newly minted L2 chain configs before using it. @@ -82,7 +82,7 @@ func WithCannonKonaGameTypeAdded() stack.Option[*Orchestrator] { } } -func requireGameTypeTargetIDs(o *Orchestrator) (stack.L1ELNodeID, []stack.ComponentID) { +func requireGameTypeTargetIDs(o *Orchestrator) (stack.ComponentID, []stack.ComponentID) { require := o.P().Require() l2NetIDs := o.registry.IDsByKind(stack.KindL2Network) require.NotEmpty(l2NetIDs, "need at least one L2 network to configure game types") @@ -90,7 +90,7 @@ func requireGameTypeTargetIDs(o *Orchestrator) (stack.L1ELNodeID, []stack.Compon l1ELIDs := o.registry.IDsByKind(stack.KindL1ELNode) require.NotEmpty(l1ELIDs, "need at least one L1 EL node to configure game types") - return stack.NewL1ELNodeID(l1ELIDs[0].Key(), l1ELIDs[0].ChainID()), l2NetIDs + return l1ELIDs[0], l2NetIDs } func WithChallengerCannonKonaEnabled() stack.Option[*Orchestrator] { @@ -101,20 +101,18 @@ func WithChallengerCannonKonaEnabled() stack.Option[*Orchestrator] { } } -func setRespectedGameType(o *Orchestrator, gameType gameTypes.GameType, l1ELID stack.L1ELNodeID, l2ChainID eth.ChainID) { +func setRespectedGameType(o *Orchestrator, gameType gameTypes.GameType, l1ELID stack.ComponentID, l2ChainID eth.ChainID) { t := o.P() require := t.Require() require.NotNil(o.wb, "must have a world builder") l1ChainID := l1ELID.ChainID() - l2NetComponent, ok := o.registry.Get(stack.ConvertL2NetworkID(stack.L2NetworkID(l2ChainID)).ComponentID) + l2Network, ok := o.GetL2Network(stack.NewL2NetworkID(l2ChainID)) require.True(ok, "l2Net must exist") - l2Network := l2NetComponent.(*L2Network) portalAddr := l2Network.rollupCfg.DepositContractAddress - l1ELComponent, ok := o.registry.Get(stack.ConvertL1ELNodeID(l1ELID).ComponentID) + l1EL, ok := o.GetL1EL(l1ELID) require.True(ok, "l1El must exist") - l1EL := l1ELComponent.(L1ELNode) rpcClient, err := rpc.DialContext(t.Ctx(), l1EL.UserRPC()) require.NoError(err) @@ -155,7 +153,7 @@ func setRespectedGameType(o *Orchestrator, gameType gameTypes.GameType, l1ELID s require.Equal(rcpt.Status, gethTypes.ReceiptStatusSuccessful, "set respected game type tx did not execute correctly") } -func addGameType(o *Orchestrator, absolutePrestate common.Hash, gameType gameTypes.GameType, l1ELID stack.L1ELNodeID, l2ChainID eth.ChainID) { +func addGameType(o *Orchestrator, absolutePrestate common.Hash, gameType gameTypes.GameType, l1ELID stack.ComponentID, l2ChainID eth.ChainID) { t := o.P() require := t.Require() require.NotNil(o.wb, "must have a world builder") @@ -163,9 +161,8 @@ func addGameType(o *Orchestrator, absolutePrestate common.Hash, gameType gameTyp opcmAddr := o.wb.output.ImplementationsDeployment.OpcmImpl - l1ELComponent, ok := o.registry.Get(stack.ConvertL1ELNodeID(l1ELID).ComponentID) + l1EL, ok := o.GetL1EL(l1ELID) require.True(ok, "l1El must exist") - l1EL := l1ELComponent.(L1ELNode) rpcClient, err := rpc.DialContext(t.Ctx(), l1EL.UserRPC()) require.NoError(err) diff --git a/op-devstack/sysgo/cluster.go b/op-devstack/sysgo/cluster.go index 24392dcfa75..63eebac2e76 100644 --- a/op-devstack/sysgo/cluster.go +++ b/op-devstack/sysgo/cluster.go @@ -7,7 +7,7 @@ import ( ) type Cluster struct { - id stack.ClusterID + id stack.ComponentID cfgset depset.FullConfigSetMerged } diff --git a/op-devstack/sysgo/control_plane.go b/op-devstack/sysgo/control_plane.go index 94ecf5eda4b..1f4f019bdae 100644 --- a/op-devstack/sysgo/control_plane.go +++ b/op-devstack/sysgo/control_plane.go @@ -17,47 +17,40 @@ func control(lifecycle stack.Lifecycle, mode stack.ControlAction) { } } -func (c *ControlPlane) SupervisorState(id stack.SupervisorID, mode stack.ControlAction) { - cid := stack.ConvertSupervisorID(id) - component, ok := c.o.registry.Get(cid.ComponentID) +func (c *ControlPlane) SupervisorState(id stack.ComponentID, mode stack.ControlAction) { + component, ok := c.o.GetSupervisor(id) c.o.P().Require().True(ok, "need supervisor to change state") - control(component.(Supervisor), mode) + control(component, mode) } -func (c *ControlPlane) L2CLNodeState(id stack.L2CLNodeID, mode stack.ControlAction) { - cid := stack.ConvertL2CLNodeID(id) - component, ok := c.o.registry.Get(cid.ComponentID) +func (c *ControlPlane) L2CLNodeState(id stack.ComponentID, mode stack.ControlAction) { + component, ok := c.o.GetL2CL(id) c.o.P().Require().True(ok, "need l2cl node to change state") - control(component.(L2CLNode), mode) + control(component, mode) } -func (c *ControlPlane) L2ELNodeState(id stack.L2ELNodeID, mode stack.ControlAction) { - cid := stack.ConvertL2ELNodeID(id) - component, ok := c.o.registry.Get(cid.ComponentID) +func (c *ControlPlane) L2ELNodeState(id stack.ComponentID, mode stack.ControlAction) { + component, ok := c.o.GetL2EL(id) c.o.P().Require().True(ok, "need l2el node to change state") - control(component.(L2ELNode), mode) + control(component, mode) } -func (c *ControlPlane) FakePoSState(id stack.L1CLNodeID, mode stack.ControlAction) { - cid := stack.ConvertL1CLNodeID(id) - component, ok := c.o.registry.Get(cid.ComponentID) +func (c *ControlPlane) FakePoSState(id stack.ComponentID, mode stack.ControlAction) { + component, ok := c.o.GetL1CL(id) c.o.P().Require().True(ok, "need l1cl node to change state of fakePoS module") - s := component.(*L1CLNode) - control(s.fakepos, mode) + control(component.fakepos, mode) } -func (c *ControlPlane) OPRBuilderNodeState(id stack.OPRBuilderNodeID, mode stack.ControlAction) { - cid := stack.ConvertOPRBuilderNodeID(id) - component, ok := c.o.registry.Get(cid.ComponentID) +func (c *ControlPlane) OPRBuilderNodeState(id stack.ComponentID, mode stack.ControlAction) { + component, ok := c.o.GetOPRBuilder(id) c.o.P().Require().True(ok, "need oprbuilder node to change state") - control(component.(*OPRBuilderNode), mode) + control(component, mode) } -func (c *ControlPlane) RollupBoostNodeState(id stack.RollupBoostNodeID, mode stack.ControlAction) { - cid := stack.ConvertRollupBoostNodeID(id) - component, ok := c.o.registry.Get(cid.ComponentID) +func (c *ControlPlane) RollupBoostNodeState(id stack.ComponentID, mode stack.ControlAction) { + component, ok := c.o.GetRollupBoost(id) c.o.P().Require().True(ok, "need rollup boost node to change state") - control(component.(*RollupBoostNode), mode) + control(component, mode) } var _ stack.ControlPlane = (*ControlPlane)(nil) diff --git a/op-devstack/sysgo/control_plane_test.go b/op-devstack/sysgo/control_plane_test.go index 6c601d4ffe3..aa734be01b7 100644 --- a/op-devstack/sysgo/control_plane_test.go +++ b/op-devstack/sysgo/control_plane_test.go @@ -58,7 +58,7 @@ func TestControlPlane(gt *testing.T) { func testSupervisorRestart(ids DefaultInteropSystemIDs, system stack.System, control stack.ControlPlane) { t := system.T() logger := t.Logger() - supervisor := system.Supervisor(ids.Supervisor) + supervisor := system.Supervisor(stack.ByID[stack.Supervisor](ids.Supervisor)) // progress supervisor for range 3 { @@ -103,7 +103,7 @@ func testSupervisorRestart(ids DefaultInteropSystemIDs, system stack.System, con func testL2CLRestart(ids DefaultInteropSystemIDs, system stack.System, control stack.ControlPlane) { t := system.T() logger := t.Logger() - seqA := system.L2Network(ids.L2A).L2CLNode(ids.L2ACL) + seqA := system.L2Network(stack.ByID[stack.L2Network](ids.L2A)).L2CLNode(stack.ByID[stack.L2CLNode](ids.L2ACL)) // progress chain for range 3 { @@ -165,7 +165,7 @@ func TestControlPlaneFakePoS(gt *testing.T) { ctx := t.Ctx() - el := system.L1Network(ids.L1).L1ELNode(match.FirstL1EL) + el := system.L1Network(stack.ByID[stack.L1Network](ids.L1)).L1ELNode(match.FirstL1EL) // progress chain blockTime := time.Second * 6 diff --git a/op-devstack/sysgo/deployer.go b/op-devstack/sysgo/deployer.go index 94627337386..fa12568a2fc 100644 --- a/op-devstack/sysgo/deployer.go +++ b/op-devstack/sysgo/deployer.go @@ -85,10 +85,10 @@ func WithDeployerCacheDir(dirPath string) DeployerPipelineOption { // WithDAFootprintGasScalar sets the DA footprint gas scalar with which the networks identified by // l2IDs will be launched. If there are no l2IDs provided, all L2 networks are set with scalar. -func WithDAFootprintGasScalar(scalar uint16, l2IDs ...stack.L2NetworkID) DeployerOption { +func WithDAFootprintGasScalar(scalar uint16, l2IDs ...stack.ComponentID) DeployerOption { return func(p devtest.P, _ devkeys.Keys, builder intentbuilder.Builder) { for _, l2 := range builder.L2s() { - if len(l2IDs) == 0 || slices.ContainsFunc(l2IDs, func(id stack.L2NetworkID) bool { + if len(l2IDs) == 0 || slices.ContainsFunc(l2IDs, func(id stack.ComponentID) bool { return id.ChainID() == l2.ChainID() }) { l2.WithDAFootprintGasScalar(scalar) @@ -125,22 +125,22 @@ func WithDeployer() stack.Option[*Orchestrator] { require := o.P().Require() require.NotNil(o.wb, "must have a world builder") - l1ID := stack.L1NetworkID(eth.ChainIDFromUInt64(wb.output.AppliedIntent.L1ChainID)) - superchainID := stack.SuperchainID("main") - clusterID := stack.ClusterID("main") + l1ID := stack.NewL1NetworkID(eth.ChainIDFromUInt64(wb.output.AppliedIntent.L1ChainID)) + superchainID := stack.NewSuperchainID("main") + clusterID := stack.NewClusterID("main") l1Net := &L1Network{ id: l1ID, genesis: wb.outL1Genesis, blockTime: 6, } - o.registry.Register(stack.ConvertL1NetworkID(l1ID).ComponentID, l1Net) + o.registry.Register(l1ID, l1Net) - o.registry.Register(stack.ConvertSuperchainID(superchainID).ComponentID, &Superchain{ + o.registry.Register(superchainID, &Superchain{ id: superchainID, deployment: wb.outSuperchainDeployment, }) - o.registry.Register(stack.ConvertClusterID(clusterID).ComponentID, &Cluster{ + o.registry.Register(clusterID, &Cluster{ id: clusterID, cfgset: wb.outFullCfgSet, }) @@ -153,7 +153,7 @@ func WithDeployer() stack.Option[*Orchestrator] { l2Dep, ok := wb.outL2Deployment[chainID] require.True(ok, "L2 deployment must exist") - l2ID := stack.L2NetworkID(chainID) + l2ID := stack.NewL2NetworkID(chainID) l2Net := &L2Network{ id: l2ID, l1ChainID: l1ID.ChainID(), @@ -162,7 +162,7 @@ func WithDeployer() stack.Option[*Orchestrator] { deployment: l2Dep, keys: o.keys, } - o.registry.Register(stack.ConvertL2NetworkID(l2ID).ComponentID, l2Net) + o.registry.Register(l2ID, l2Net) } }, } diff --git a/op-devstack/sysgo/faucet.go b/op-devstack/sysgo/faucet.go index 88aba54f7de..df0261cb6c1 100644 --- a/op-devstack/sysgo/faucet.go +++ b/op-devstack/sysgo/faucet.go @@ -49,16 +49,38 @@ func (n *FaucetService) hydrate(system stack.ExtensibleSystem) { for chainID, faucetID := range n.service.Defaults() { id := stack.NewFaucetID(faucetID.String(), chainID) net := system.Network(chainID).(stack.ExtensibleNetwork) - net.Faucet(id).SetLabel("default", "true") + net.Faucet(stack.ByID[stack.Faucet](id)).SetLabel("default", "true") } } -func WithFaucets(l1ELs []stack.L1ELNodeID, l2ELs []stack.L2ELNodeID) stack.Option[*Orchestrator] { +func isL2ELFaucetKind(kind stack.ComponentKind) bool { + switch kind { + case stack.KindL2ELNode, stack.KindRollupBoostNode, stack.KindOPRBuilderNode: + return true + default: + return false + } +} + +func WithFaucets(l1ELs []stack.ComponentID, l2ELs []stack.ComponentID) stack.Option[*Orchestrator] { return stack.AfterDeploy(func(orch *Orchestrator) { + require := orch.P().Require() + + require.NotEmpty(l2ELs, "need at least one L2 EL for faucet service") + for i, l1ELID := range l1ELs { + require.Equalf(stack.KindL1ELNode, l1ELID.Kind(), "l1ELs[%d] must be kind %s", i, stack.KindL1ELNode) + require.Truef(l1ELID.HasChainID(), "l1ELs[%d] must be chain-scoped", i) + } + for i, l2ELID := range l2ELs { + require.Truef(isL2ELFaucetKind(l2ELID.Kind()), + "l2ELs[%d] must be one of %s, %s, %s", + i, stack.KindL2ELNode, stack.KindRollupBoostNode, stack.KindOPRBuilderNode) + require.Truef(l2ELID.HasChainID(), "l2ELs[%d] must be chain-scoped", i) + } + faucetID := stack.NewFaucetID("dev-faucet", l2ELs[0].ChainID()) p := orch.P().WithCtx(stack.ContextWithID(orch.P().Ctx(), faucetID)) - - require := p.Require() + require = p.Require() require.Nil(orch.faucet, "can only support a single faucet-service in sysgo") @@ -71,9 +93,8 @@ func WithFaucets(l1ELs []stack.L1ELNodeID, l2ELs []stack.L2ELNodeID) stack.Optio id := ftypes.FaucetID(fmt.Sprintf("dev-faucet-%s", elID.ChainID())) require.NotContains(faucets, id, "one faucet per chain only") - elComponent, ok := orch.registry.Get(stack.ConvertL1ELNodeID(elID).ComponentID) + el, ok := orch.GetL1EL(elID) require.True(ok, "need L1 EL for faucet", elID) - el := elComponent.(L1ELNode) faucets[id] = &fconf.FaucetEntry{ ELRPC: endpoint.MustRPC{Value: endpoint.URL(el.UserRPC())}, @@ -87,9 +108,8 @@ func WithFaucets(l1ELs []stack.L1ELNodeID, l2ELs []stack.L2ELNodeID) stack.Optio id := ftypes.FaucetID(fmt.Sprintf("dev-faucet-%s", elID.ChainID())) require.NotContains(faucets, id, "one faucet per chain only") - elComponent, ok := orch.registry.Get(stack.ConvertL2ELNodeID(elID).ComponentID) + el, ok := orch.GetL2EL(elID) require.True(ok, "need L2 EL for faucet", elID) - el := elComponent.(L2ELNode) faucets[id] = &fconf.FaucetEntry{ ELRPC: endpoint.MustRPC{Value: endpoint.URL(el.UserRPC())}, diff --git a/op-devstack/sysgo/l1_network.go b/op-devstack/sysgo/l1_network.go index 0918c0f8a15..e2cf19594c2 100644 --- a/op-devstack/sysgo/l1_network.go +++ b/op-devstack/sysgo/l1_network.go @@ -8,7 +8,7 @@ import ( ) type L1Network struct { - id stack.L1NetworkID + id stack.ComponentID genesis *core.Genesis blockTime uint64 } diff --git a/op-devstack/sysgo/l1_nodes.go b/op-devstack/sysgo/l1_nodes.go index d8d09b37a9c..7fbe95b1e45 100644 --- a/op-devstack/sysgo/l1_nodes.go +++ b/op-devstack/sysgo/l1_nodes.go @@ -21,7 +21,7 @@ type L1ELNode interface { } type L1Geth struct { - id stack.L1ELNodeID + id stack.ComponentID userRPC string authRPC string l1Geth *geth.GethInstance @@ -51,12 +51,12 @@ func (n *L1Geth) hydrate(system stack.ExtensibleSystem) { ChainID: n.id.ChainID(), }, }) - l1Net := system.L1Network(stack.L1NetworkID(n.id.ChainID())) + l1Net := system.L1Network(stack.ByID[stack.L1Network](stack.NewL1NetworkID(n.id.ChainID()))) l1Net.(stack.ExtensibleL1Network).AddL1ELNode(frontend) } type L1CLNode struct { - id stack.L1CLNodeID + id stack.ComponentID beaconHTTPAddr string beacon *fakebeacon.FakeBeacon fakepos *FakePoS @@ -69,13 +69,13 @@ func (n *L1CLNode) hydrate(system stack.ExtensibleSystem) { ID: n.id, Client: beaconCl, }) - l1Net := system.L1Network(stack.L1NetworkID(n.id.ChainID())) + l1Net := system.L1Network(stack.ByID[stack.L1Network](stack.NewL1NetworkID(n.id.ChainID()))) l1Net.(stack.ExtensibleL1Network).AddL1CLNode(frontend) } const DevstackL1ELKindEnvVar = "DEVSTACK_L1EL_KIND" -func WithL1Nodes(l1ELID stack.L1ELNodeID, l1CLID stack.L1CLNodeID) stack.Option[*Orchestrator] { +func WithL1Nodes(l1ELID stack.ComponentID, l1CLID stack.ComponentID) stack.Option[*Orchestrator] { switch os.Getenv(DevstackL1ELKindEnvVar) { case "geth": return WithL1NodesSubprocess(l1ELID, l1CLID) @@ -84,15 +84,14 @@ func WithL1Nodes(l1ELID stack.L1ELNodeID, l1CLID stack.L1CLNodeID) stack.Option[ } } -func WithL1NodesInProcess(l1ELID stack.L1ELNodeID, l1CLID stack.L1CLNodeID) stack.Option[*Orchestrator] { +func WithL1NodesInProcess(l1ELID stack.ComponentID, l1CLID stack.ComponentID) stack.Option[*Orchestrator] { return stack.AfterDeploy(func(orch *Orchestrator) { clP := orch.P().WithCtx(stack.ContextWithID(orch.P().Ctx(), l1CLID)) elP := orch.P().WithCtx(stack.ContextWithID(orch.P().Ctx(), l1ELID)) require := orch.P().Require() - l1NetComponent, ok := orch.registry.Get(stack.ConvertL1NetworkID(stack.L1NetworkID(l1ELID.ChainID())).ComponentID) + l1Net, ok := orch.GetL1Network(stack.NewL1NetworkID(l1ELID.ChainID())) require.True(ok, "L1 network must exist") - l1Net := l1NetComponent.(*L1Network) blockTimeL1 := l1Net.blockTime l1FinalizedDistance := uint64(20) @@ -138,9 +137,8 @@ func WithL1NodesInProcess(l1ELID stack.L1ELNodeID, l1CLID stack.L1CLNodeID) stac l1Geth: l1Geth, blobPath: blobPath, } - elCID := stack.ConvertL1ELNodeID(l1ELID).ComponentID - require.False(orch.registry.Has(elCID), "must not already exist") - orch.registry.Register(elCID, l1ELNode) + require.False(orch.registry.Has(l1ELID), "must not already exist") + orch.registry.Register(l1ELID, l1ELNode) l1CLNode := &L1CLNode{ id: l1CLID, @@ -148,14 +146,13 @@ func WithL1NodesInProcess(l1ELID stack.L1ELNodeID, l1CLID stack.L1CLNodeID) stac beacon: bcn, fakepos: &FakePoS{fakepos: fp, p: clP}, } - clCID := stack.ConvertL1CLNodeID(l1CLID).ComponentID - require.False(orch.registry.Has(clCID), "must not already exist") - orch.registry.Register(clCID, l1CLNode) + require.False(orch.registry.Has(l1CLID), "must not already exist") + orch.registry.Register(l1CLID, l1CLNode) }) } // WithExtL1Nodes initializes L1 EL and CL nodes that connect to external RPC endpoints -func WithExtL1Nodes(l1ELID stack.L1ELNodeID, l1CLID stack.L1CLNodeID, elRPCEndpoint string, clRPCEndpoint string) stack.Option[*Orchestrator] { +func WithExtL1Nodes(l1ELID stack.ComponentID, l1CLID stack.ComponentID, elRPCEndpoint string, clRPCEndpoint string) stack.Option[*Orchestrator] { return stack.AfterDeploy(func(orch *Orchestrator) { require := orch.P().Require() @@ -164,17 +161,15 @@ func WithExtL1Nodes(l1ELID stack.L1ELNodeID, l1CLID stack.L1CLNodeID, elRPCEndpo id: l1ELID, userRPC: elRPCEndpoint, } - elCID := stack.ConvertL1ELNodeID(l1ELID).ComponentID - require.False(orch.registry.Has(elCID), "must not already exist") - orch.registry.Register(elCID, l1ELNode) + require.False(orch.registry.Has(l1ELID), "must not already exist") + orch.registry.Register(l1ELID, l1ELNode) // Create L1 CL node with external RPC l1CLNode := &L1CLNode{ id: l1CLID, beaconHTTPAddr: clRPCEndpoint, } - clCID := stack.ConvertL1CLNodeID(l1CLID).ComponentID - require.False(orch.registry.Has(clCID), "must not already exist") - orch.registry.Register(clCID, l1CLNode) + require.False(orch.registry.Has(l1CLID), "must not already exist") + orch.registry.Register(l1CLID, l1CLNode) }) } diff --git a/op-devstack/sysgo/l1_nodes_subprocess.go b/op-devstack/sysgo/l1_nodes_subprocess.go index e35ad97aa68..43268d6618c 100644 --- a/op-devstack/sysgo/l1_nodes_subprocess.go +++ b/op-devstack/sysgo/l1_nodes_subprocess.go @@ -25,7 +25,7 @@ import ( type ExternalL1Geth struct { mu sync.Mutex - id stack.L1ELNodeID + id stack.ComponentID l1Net *L1Network // authRPC points to a proxy that forwards to geth's endpoint authRPC string @@ -53,7 +53,7 @@ func (n *ExternalL1Geth) hydrate(system stack.ExtensibleSystem) { require.NoError(err) system.T().Cleanup(rpcCl.Close) - l1Net := system.L1Network(stack.L1NetworkID(n.id.ChainID())) + l1Net := system.L1Network(stack.ByID[stack.L1Network](stack.NewL1NetworkID(n.id.ChainID()))) sysL1EL := shim.NewL1ELNode(shim.L1ELNodeConfig{ ID: n.id, ELNodeConfig: shim.ELNodeConfig{ @@ -150,7 +150,7 @@ func (n *ExternalL1Geth) AuthRPC() string { const GethExecPathEnvVar = "SYSGO_GETH_EXEC_PATH" -func WithL1NodesSubprocess(id stack.L1ELNodeID, clID stack.L1CLNodeID) stack.Option[*Orchestrator] { +func WithL1NodesSubprocess(id stack.ComponentID, clID stack.ComponentID) stack.Option[*Orchestrator] { return stack.AfterDeploy(func(orch *Orchestrator) { p := orch.P().WithCtx(stack.ContextWithID(orch.P().Ctx(), id)) require := p.Require() @@ -160,9 +160,8 @@ func WithL1NodesSubprocess(id stack.L1ELNodeID, clID stack.L1CLNodeID) stack.Opt _, err := os.Stat(execPath) p.Require().NotErrorIs(err, os.ErrNotExist, "geth executable must exist") - l1NetComponent, ok := orch.registry.Get(stack.ConvertL1NetworkID(stack.L1NetworkID(id.ChainID())).ComponentID) + l1Net, ok := orch.GetL1Network(stack.NewL1NetworkID(id.ChainID())) require.True(ok, "L1 network required") - l1Net := l1NetComponent.(*L1Network) jwtPath, jwtSecret := orch.writeDefaultJWT() @@ -208,7 +207,7 @@ func WithL1NodesSubprocess(id stack.L1ELNodeID, clID stack.L1CLNodeID) stack.Opt l1EL.Start() p.Cleanup(l1EL.Stop) p.Logger().Info("geth is ready", "userRPC", l1EL.userRPC, "authRPC", l1EL.authRPC) - elCID := stack.ConvertL1ELNodeID(id).ComponentID + elCID := id require.False(orch.registry.Has(elCID), "must be unique L1 EL node") orch.registry.Register(elCID, l1EL) @@ -236,7 +235,7 @@ func WithL1NodesSubprocess(id stack.L1ELNodeID, clID stack.L1CLNodeID) stack.Opt } fp.Start() p.Cleanup(fp.Stop) - orch.registry.Register(stack.ConvertL1CLNodeID(clID).ComponentID, &L1CLNode{ + orch.registry.Register(clID, &L1CLNode{ id: clID, beaconHTTPAddr: bcn.BeaconAddr(), beacon: bcn, diff --git a/op-devstack/sysgo/l2_batcher.go b/op-devstack/sysgo/l2_batcher.go index 3c2082e05e4..3a2013ded78 100644 --- a/op-devstack/sysgo/l2_batcher.go +++ b/op-devstack/sysgo/l2_batcher.go @@ -21,7 +21,7 @@ import ( ) type L2Batcher struct { - id stack.L2BatcherID + id stack.ComponentID service *bss.BatcherService rpc string l1RPC string @@ -40,11 +40,11 @@ func (b *L2Batcher) hydrate(system stack.ExtensibleSystem) { ID: b.id, Client: rpcCl, }) - l2Net := system.L2Network(stack.L2NetworkID(b.id.ChainID())) + l2Net := system.L2Network(stack.ByID[stack.L2Network](stack.NewL2NetworkID(b.id.ChainID()))) l2Net.(stack.ExtensibleL2Network).AddL2Batcher(bFrontend) } -type BatcherOption func(id stack.L2BatcherID, cfg *bss.CLIConfig) +type BatcherOption func(id stack.ComponentID, cfg *bss.CLIConfig) func WithBatcherOption(opt BatcherOption) stack.Option[*Orchestrator] { return stack.Deploy[*Orchestrator](func(orch *Orchestrator) { @@ -52,37 +52,32 @@ func WithBatcherOption(opt BatcherOption) stack.Option[*Orchestrator] { }) } -func WithBatcher(batcherID stack.L2BatcherID, l1ELID stack.L1ELNodeID, l2CLID stack.L2CLNodeID, l2ELID stack.L2ELNodeID) stack.Option[*Orchestrator] { +func WithBatcher(batcherID stack.ComponentID, l1ELID stack.ComponentID, l2CLID stack.ComponentID, l2ELID stack.ComponentID) stack.Option[*Orchestrator] { return stack.AfterDeploy(func(orch *Orchestrator) { p := orch.P().WithCtx(stack.ContextWithID(orch.P().Ctx(), batcherID)) require := p.Require() - batcherCID := stack.ConvertL2BatcherID(batcherID).ComponentID + batcherCID := batcherID require.False(orch.registry.Has(batcherCID), "batcher must not already exist") - l2NetComponent, ok := orch.registry.Get(stack.ConvertL2NetworkID(stack.L2NetworkID(l2CLID.ChainID())).ComponentID) + l2Net, ok := orch.GetL2Network(stack.NewL2NetworkID(l2CLID.ChainID())) require.True(ok) - l2Net := l2NetComponent.(*L2Network) - l1NetComponent, ok := orch.registry.Get(stack.ConvertL1NetworkID(stack.L1NetworkID(l1ELID.ChainID())).ComponentID) + l1Net, ok := orch.GetL1Network(stack.NewL1NetworkID(l1ELID.ChainID())) require.True(ok) - l1Net := l1NetComponent.(*L1Network) require.Equal(l2Net.l1ChainID, l1Net.id.ChainID(), "expecting L1EL on L1 of L2CL") require.Equal(l2CLID.ChainID(), l2ELID.ChainID(), "L2 CL and EL must be on same L2 chain") - l1ELComponent, ok := orch.registry.Get(stack.ConvertL1ELNodeID(l1ELID).ComponentID) + l1EL, ok := orch.GetL1EL(l1ELID) require.True(ok) - l1EL := l1ELComponent.(L1ELNode) - l2CLComponent, ok := orch.registry.Get(stack.ConvertL2CLNodeID(l2CLID).ComponentID) + l2CL, ok := orch.GetL2CL(l2CLID) require.True(ok) - l2CL := l2CLComponent.(L2CLNode) - l2ELComponent, ok := orch.registry.Get(stack.ConvertL2ELNodeID(l2ELID).ComponentID) + l2EL, ok := orch.GetL2EL(l2ELID) require.True(ok) - l2EL := l2ELComponent.(L2ELNode) batcherSecret, err := orch.keys.Secret(devkeys.BatcherRole.Key(l2ELID.ChainID().ToBig())) require.NoError(err) @@ -147,6 +142,6 @@ func WithBatcher(batcherID stack.L2BatcherID, l1ELID stack.L1ELNodeID, l2CLID st l2CLRPC: l2CL.UserRPC(), l2ELRPC: l2EL.UserRPC(), } - orch.registry.Register(stack.ConvertL2BatcherID(batcherID).ComponentID, b) + orch.registry.Register(batcherID, b) }) } diff --git a/op-devstack/sysgo/l2_challenger.go b/op-devstack/sysgo/l2_challenger.go index 25ebb39d76c..3057819b413 100644 --- a/op-devstack/sysgo/l2_challenger.go +++ b/op-devstack/sysgo/l2_challenger.go @@ -24,9 +24,9 @@ type l2ChallengerOpts struct { } type L2Challenger struct { - id stack.L2ChallengerID + id stack.ComponentID service cliapp.Lifecycle - l2NetIDs []stack.L2NetworkID + l2NetIDs []stack.ComponentID config *config.Config } @@ -38,37 +38,37 @@ func (p *L2Challenger) hydrate(system stack.ExtensibleSystem) { }) for _, netID := range p.l2NetIDs { - l2Net := system.L2Network(netID) + l2Net := system.L2Network(stack.ByID[stack.L2Network](netID)) l2Net.(stack.ExtensibleL2Network).AddL2Challenger(bFrontend) } } -func WithL2Challenger(challengerID stack.L2ChallengerID, l1ELID stack.L1ELNodeID, l1CLID stack.L1CLNodeID, - supervisorID *stack.SupervisorID, clusterID *stack.ClusterID, l2CLID *stack.L2CLNodeID, l2ELIDs []stack.L2ELNodeID, +func WithL2Challenger(challengerID stack.ComponentID, l1ELID stack.ComponentID, l1CLID stack.ComponentID, + supervisorID *stack.ComponentID, clusterID *stack.ComponentID, l2CLID *stack.ComponentID, l2ELIDs []stack.ComponentID, ) stack.Option[*Orchestrator] { return stack.AfterDeploy(func(orch *Orchestrator) { WithL2ChallengerPostDeploy(orch, challengerID, l1ELID, l1CLID, supervisorID, clusterID, l2CLID, l2ELIDs, nil) }) } -func WithSuperL2Challenger(challengerID stack.L2ChallengerID, l1ELID stack.L1ELNodeID, l1CLID stack.L1CLNodeID, - supervisorID *stack.SupervisorID, clusterID *stack.ClusterID, l2ELIDs []stack.L2ELNodeID, +func WithSuperL2Challenger(challengerID stack.ComponentID, l1ELID stack.ComponentID, l1CLID stack.ComponentID, + supervisorID *stack.ComponentID, clusterID *stack.ComponentID, l2ELIDs []stack.ComponentID, ) stack.Option[*Orchestrator] { return stack.Finally(func(orch *Orchestrator) { WithL2ChallengerPostDeploy(orch, challengerID, l1ELID, l1CLID, supervisorID, clusterID, nil, l2ELIDs, nil) }) } -func WithSupernodeL2Challenger(challengerID stack.L2ChallengerID, l1ELID stack.L1ELNodeID, l1CLID stack.L1CLNodeID, - supernodeID *stack.SupernodeID, clusterID *stack.ClusterID, l2ELIDs []stack.L2ELNodeID, +func WithSupernodeL2Challenger(challengerID stack.ComponentID, l1ELID stack.ComponentID, l1CLID stack.ComponentID, + supernodeID *stack.SupernodeID, clusterID *stack.ComponentID, l2ELIDs []stack.ComponentID, ) stack.Option[*Orchestrator] { return stack.Finally(func(orch *Orchestrator) { WithL2ChallengerPostDeploy(orch, challengerID, l1ELID, l1CLID, nil, clusterID, nil, l2ELIDs, supernodeID) }) } -func WithL2ChallengerPostDeploy(orch *Orchestrator, challengerID stack.L2ChallengerID, l1ELID stack.L1ELNodeID, l1CLID stack.L1CLNodeID, - supervisorID *stack.SupervisorID, clusterID *stack.ClusterID, l2CLID *stack.L2CLNodeID, l2ELIDs []stack.L2ELNodeID, +func WithL2ChallengerPostDeploy(orch *Orchestrator, challengerID stack.ComponentID, l1ELID stack.ComponentID, l1CLID stack.ComponentID, + supervisorID *stack.ComponentID, clusterID *stack.ComponentID, l2CLID *stack.ComponentID, l2ELIDs []stack.ComponentID, supernodeID *stack.SupernodeID, ) { ctx := orch.P().Ctx() @@ -76,7 +76,7 @@ func WithL2ChallengerPostDeploy(orch *Orchestrator, challengerID stack.L2Challen p := orch.P().WithCtx(ctx) require := p.Require() - challengerCID := stack.ConvertL2ChallengerID(challengerID).ComponentID + challengerCID := challengerID require.False(orch.registry.Has(challengerCID), "challenger must not already exist") challengerSecret, err := orch.keys.Secret(devkeys.ChallengerRole.Key(challengerID.ChainID().ToBig())) @@ -85,16 +85,14 @@ func WithL2ChallengerPostDeploy(orch *Orchestrator, challengerID stack.L2Challen logger := p.Logger() logger.Info("Challenger key acquired", "addr", crypto.PubkeyToAddress(challengerSecret.PublicKey)) - l1ELComponent, ok := orch.registry.Get(stack.ConvertL1ELNodeID(l1ELID).ComponentID) + l1EL, ok := orch.GetL1EL(l1ELID) require.True(ok) - l1EL := l1ELComponent.(L1ELNode) - l1CLComponent, ok := orch.registry.Get(stack.ConvertL1CLNodeID(l1CLID).ComponentID) + l1CL, ok := orch.GetL1CL(l1CLID) require.True(ok) - l1CL := l1CLComponent.(*L1CLNode) l2Geneses := make([]*core.Genesis, 0, len(l2ELIDs)) rollupCfgs := make([]*rollup.Config, 0, len(l2ELIDs)) - l2NetIDs := make([]stack.L2NetworkID, 0, len(l2ELIDs)) + l2NetIDs := make([]stack.ComponentID, 0, len(l2ELIDs)) var disputeGameFactoryAddr common.Address var interopScheduled bool @@ -106,9 +104,8 @@ func WithL2ChallengerPostDeploy(orch *Orchestrator, challengerID stack.L2Challen } for _, l2ELID := range l2ELIDs { chainID := l2ELID.ChainID() - l2NetComponent, ok := orch.registry.Get(stack.ConvertL2NetworkID(stack.L2NetworkID(chainID)).ComponentID) + l2Net, ok := orch.GetL2Network(stack.NewL2NetworkID(chainID)) require.Truef(ok, "l2Net %s not found", chainID) - l2Net := l2NetComponent.(*L2Network) factory := l2Net.deployment.DisputeGameFactoryProxyAddr() if disputeGameFactoryAddr == (common.Address{}) { disputeGameFactoryAddr = factory @@ -122,11 +119,10 @@ func WithL2ChallengerPostDeploy(orch *Orchestrator, challengerID stack.L2Challen l2NetIDs = append(l2NetIDs, l2Net.id) } - l1NetComponent, ok := orch.registry.Get(stack.ConvertL1NetworkID(stack.L1NetworkID(l1ELID.ChainID())).ComponentID) + l1Net, ok := orch.GetL1Network(stack.NewL1NetworkID(l1ELID.ChainID())) if !ok { require.Fail("l1 network not found") } - l1Net := l1NetComponent.(*L1Network) l1Genesis := l1Net.genesis if orch.l2ChallengerOpts.useCannonKonaConfig { @@ -144,9 +140,8 @@ func WithL2ChallengerPostDeploy(orch *Orchestrator, challengerID stack.L2Challen useSuperNode := false switch { case supervisorID != nil: - supervisorComponent, ok := orch.registry.Get(stack.ConvertSupervisorID(*supervisorID).ComponentID) + supervisorNode, ok := orch.GetSupervisor(*supervisorID) require.True(ok) - supervisorNode := supervisorComponent.(Supervisor) superRPC = supervisorNode.UserRPC() case supernodeID != nil: supernode, ok := orch.supernodes.Get(*supernodeID) @@ -159,14 +154,12 @@ func WithL2ChallengerPostDeploy(orch *Orchestrator, challengerID stack.L2Challen l2ELRPCs := make([]string, len(l2ELIDs)) for i, l2ELID := range l2ELIDs { - l2ELComponent, ok := orch.registry.Get(stack.ConvertL2ELNodeID(l2ELID).ComponentID) + l2EL, ok := orch.GetL2EL(l2ELID) require.True(ok) - l2EL := l2ELComponent.(L2ELNode) l2ELRPCs[i] = l2EL.UserRPC() } - clusterComponent, ok := orch.registry.Get(stack.ConvertClusterID(*clusterID).ComponentID) + cluster, ok := orch.GetCluster(*clusterID) require.True(ok) - cluster := clusterComponent.(*Cluster) prestateVariant := shared.InteropVariant options := []shared.Option{ shared.WithFactoryAddress(disputeGameFactoryAddr), @@ -188,7 +181,7 @@ func WithL2ChallengerPostDeploy(orch *Orchestrator, challengerID stack.L2Challen } else { require.NotNil(l2CLID, "need L2 CL to connect to pre-interop") // In a post-interop infra setup, with unscheduled interop, we may see multiple EL nodes. - var l2ELID stack.L2ELNodeID + var l2ELID stack.ComponentID for _, id := range l2ELIDs { if id.ChainID() == l2CLID.ChainID() { l2ELID = id @@ -196,9 +189,8 @@ func WithL2ChallengerPostDeploy(orch *Orchestrator, challengerID stack.L2Challen } } require.NotZero(l2ELID, "need single L2 EL to connect to pre-interop") - l2CLComponent, ok := orch.registry.Get(stack.ConvertL2CLNodeID(*l2CLID).ComponentID) + l2CL, ok := orch.GetL2CL(*l2CLID) require.True(ok) - l2CL := l2CLComponent.(L2CLNode) l2EL, ok := orch.GetL2EL(l2ELID) require.True(ok) prestateVariant := shared.MTCannonVariant @@ -249,5 +241,5 @@ func WithL2ChallengerPostDeploy(orch *Orchestrator, challengerID stack.L2Challen l2NetIDs: l2NetIDs, config: cfg, } - orch.registry.Register(stack.ConvertL2ChallengerID(challengerID).ComponentID, c) + orch.registry.Register(challengerID, c) } diff --git a/op-devstack/sysgo/l2_cl.go b/op-devstack/sysgo/l2_cl.go index 8ef75d92a52..7f4f47e6814 100644 --- a/op-devstack/sysgo/l2_cl.go +++ b/op-devstack/sysgo/l2_cl.go @@ -41,19 +41,19 @@ type L2CLConfig struct { } func L2CLSequencer() L2CLOption { - return L2CLOptionFn(func(p devtest.P, id stack.L2CLNodeID, cfg *L2CLConfig) { + return L2CLOptionFn(func(p devtest.P, id stack.ComponentID, cfg *L2CLConfig) { cfg.IsSequencer = true }) } func L2CLIndexing() L2CLOption { - return L2CLOptionFn(func(p devtest.P, id stack.L2CLNodeID, cfg *L2CLConfig) { + return L2CLOptionFn(func(p devtest.P, id stack.ComponentID, cfg *L2CLConfig) { cfg.IndexingMode = true }) } func L2CLFollowSource(source string) L2CLOption { - return L2CLOptionFn(func(p devtest.P, id stack.L2CLNodeID, cfg *L2CLConfig) { + return L2CLOptionFn(func(p devtest.P, id stack.ComponentID, cfg *L2CLConfig) { cfg.FollowSource = source }) } @@ -73,7 +73,7 @@ func DefaultL2CLConfig() *L2CLConfig { } type L2CLOption interface { - Apply(p devtest.P, id stack.L2CLNodeID, cfg *L2CLConfig) + Apply(p devtest.P, id stack.ComponentID, cfg *L2CLConfig) } // WithGlobalL2CLOption applies the L2CLOption to all L2CLNode instances in this orchestrator @@ -83,11 +83,11 @@ func WithGlobalL2CLOption(opt L2CLOption) stack.Option[*Orchestrator] { }) } -type L2CLOptionFn func(p devtest.P, id stack.L2CLNodeID, cfg *L2CLConfig) +type L2CLOptionFn func(p devtest.P, id stack.ComponentID, cfg *L2CLConfig) var _ L2CLOption = L2CLOptionFn(nil) -func (fn L2CLOptionFn) Apply(p devtest.P, id stack.L2CLNodeID, cfg *L2CLConfig) { +func (fn L2CLOptionFn) Apply(p devtest.P, id stack.ComponentID, cfg *L2CLConfig) { fn(p, id, cfg) } @@ -96,7 +96,7 @@ type L2CLOptionBundle []L2CLOption var _ L2CLOption = L2CLOptionBundle(nil) -func (l L2CLOptionBundle) Apply(p devtest.P, id stack.L2CLNodeID, cfg *L2CLConfig) { +func (l L2CLOptionBundle) Apply(p devtest.P, id stack.ComponentID, cfg *L2CLConfig) { for _, opt := range l { p.Require().NotNil(opt, "cannot Apply nil L2CLOption") opt.Apply(p, id, cfg) @@ -106,19 +106,19 @@ func (l L2CLOptionBundle) Apply(p devtest.P, id stack.L2CLNodeID, cfg *L2CLConfi // WithL2CLNode adds the default type of L2 CL node. // The default can be configured with DEVSTACK_L2CL_KIND. // Tests that depend on specific types can use options like WithKonaNode and WithOpNode directly. -func WithL2CLNode(l2CLID stack.L2CLNodeID, l1CLID stack.L1CLNodeID, l1ELID stack.L1ELNodeID, l2ELID stack.L2ELNodeID, opts ...L2CLOption) stack.Option[*Orchestrator] { +func WithL2CLNode(l2CLID stack.ComponentID, l1CLID stack.ComponentID, l1ELID stack.ComponentID, l2ELID stack.ComponentID, opts ...L2CLOption) stack.Option[*Orchestrator] { switch os.Getenv("DEVSTACK_L2CL_KIND") { case "kona": return WithKonaNode(l2CLID, l1CLID, l1ELID, l2ELID, opts...) case "supernode": - var supe stack.SupernodeID // unused; this option is only used for CL tests that don't care about a supernode running + supe := stack.NewSupernodeID("default", l2CLID.ChainID()) return WithSupernode(supe, l2CLID, l1CLID, l1ELID, l2ELID, opts...) default: return WithOpNode(l2CLID, l1CLID, l1ELID, l2ELID, opts...) } } -func WithL2CLNodeFollowL2(l2CLID stack.L2CLNodeID, l1CLID stack.L1CLNodeID, l1ELID stack.L1ELNodeID, l2ELID stack.L2ELNodeID, l2FollowSourceID stack.L2CLNodeID, opts ...L2CLOption) stack.Option[*Orchestrator] { +func WithL2CLNodeFollowL2(l2CLID stack.ComponentID, l1CLID stack.ComponentID, l1ELID stack.ComponentID, l2ELID stack.ComponentID, l2FollowSourceID stack.ComponentID, opts ...L2CLOption) stack.Option[*Orchestrator] { switch os.Getenv("DEVSTACK_L2CL_KIND") { case "kona": return WithKonaNodeFollowL2(l2CLID, l1CLID, l1ELID, l2ELID, l2FollowSourceID, opts...) diff --git a/op-devstack/sysgo/l2_cl_kona.go b/op-devstack/sysgo/l2_cl_kona.go index 0edeff4aeb4..87823bf3bc3 100644 --- a/op-devstack/sysgo/l2_cl_kona.go +++ b/op-devstack/sysgo/l2_cl_kona.go @@ -27,12 +27,12 @@ import ( type KonaNode struct { mu sync.Mutex - id stack.L2CLNodeID + id stack.ComponentID userRPC string interopEndpoint string // warning: currently not fully supported interopJwtSecret eth.Bytes32 - el stack.L2ELNodeID + el stack.ComponentID userProxy *tcpproxy.Proxy @@ -63,9 +63,9 @@ func (k *KonaNode) hydrate(system stack.ExtensibleSystem) { InteropJwtSecret: k.interopJwtSecret, }) sysL2CL.SetLabel(match.LabelVendor, string(match.KonaNode)) - l2Net := system.L2Network(stack.L2NetworkID(k.id.ChainID())) + l2Net := system.L2Network(stack.ByID[stack.L2Network](stack.NewL2NetworkID(k.id.ChainID()))) l2Net.(stack.ExtensibleL2Network).AddL2CLNode(sysL2CL) - sysL2CL.(stack.LinkableL2CLNode).LinkEL(l2Net.L2ELNode(k.el)) + sysL2CL.(stack.LinkableL2CLNode).LinkEL(l2Net.L2ELNode(stack.ByID[stack.L2ELNode](k.el))) } func (k *KonaNode) Start() { @@ -161,13 +161,12 @@ func (k *KonaNode) InteropRPC() (endpoint string, jwtSecret eth.Bytes32) { var _ L2CLNode = (*KonaNode)(nil) -func WithKonaNodeFollowL2(l2CLID stack.L2CLNodeID, l1CLID stack.L1CLNodeID, l1ELID stack.L1ELNodeID, l2ELID stack.L2ELNodeID, l2FollowSourceID stack.L2CLNodeID, opts ...L2CLOption) stack.Option[*Orchestrator] { +func WithKonaNodeFollowL2(l2CLID stack.ComponentID, l1CLID stack.ComponentID, l1ELID stack.ComponentID, l2ELID stack.ComponentID, l2FollowSourceID stack.ComponentID, opts ...L2CLOption) stack.Option[*Orchestrator] { return stack.AfterDeploy(func(orch *Orchestrator) { followSource := func(orch *Orchestrator) string { p := orch.P().WithCtx(stack.ContextWithID(orch.P().Ctx(), l2CLID)) - l2CLComponent, ok := orch.registry.Get(stack.ConvertL2CLNodeID(l2FollowSourceID).ComponentID) + l2CLFollowSource, ok := orch.GetL2CL(l2FollowSourceID) p.Require().True(ok, "l2 CL Follow Source required") - l2CLFollowSource := l2CLComponent.(L2CLNode) return l2CLFollowSource.UserRPC() }(orch) opts = append(opts, L2CLFollowSource(followSource)) @@ -175,33 +174,29 @@ func WithKonaNodeFollowL2(l2CLID stack.L2CLNodeID, l1CLID stack.L1CLNodeID, l1EL }) } -func WithKonaNode(l2CLID stack.L2CLNodeID, l1CLID stack.L1CLNodeID, l1ELID stack.L1ELNodeID, l2ELID stack.L2ELNodeID, opts ...L2CLOption) stack.Option[*Orchestrator] { +func WithKonaNode(l2CLID stack.ComponentID, l1CLID stack.ComponentID, l1ELID stack.ComponentID, l2ELID stack.ComponentID, opts ...L2CLOption) stack.Option[*Orchestrator] { return stack.AfterDeploy(withKonaNode(l2CLID, l1CLID, l1ELID, l2ELID, opts...)) } -func withKonaNode(l2CLID stack.L2CLNodeID, l1CLID stack.L1CLNodeID, l1ELID stack.L1ELNodeID, l2ELID stack.L2ELNodeID, opts ...L2CLOption) func(orch *Orchestrator) { +func withKonaNode(l2CLID stack.ComponentID, l1CLID stack.ComponentID, l1ELID stack.ComponentID, l2ELID stack.ComponentID, opts ...L2CLOption) func(orch *Orchestrator) { return func(orch *Orchestrator) { p := orch.P().WithCtx(stack.ContextWithID(orch.P().Ctx(), l2CLID)) require := p.Require() - l1NetComponent, ok := orch.registry.Get(stack.ConvertL1NetworkID(stack.L1NetworkID(l1CLID.ChainID())).ComponentID) + l1Net, ok := orch.GetL1Network(stack.NewL1NetworkID(l1CLID.ChainID())) require.True(ok, "l1 network required") - l1Net := l1NetComponent.(*L1Network) - l2NetComponent, ok := orch.registry.Get(stack.ConvertL2NetworkID(stack.L2NetworkID(l2CLID.ChainID())).ComponentID) + l2Net, ok := orch.GetL2Network(stack.NewL2NetworkID(l2CLID.ChainID())) require.True(ok, "l2 network required") - l2Net := l2NetComponent.(*L2Network) l1ChainConfig := l1Net.genesis.Config - l1ELComponent, ok := orch.registry.Get(stack.ConvertL1ELNodeID(l1ELID).ComponentID) + l1EL, ok := orch.GetL1EL(l1ELID) require.True(ok, "l1 EL node required") - l1EL := l1ELComponent.(L1ELNode) - l1CLComponent, ok := orch.registry.Get(stack.ConvertL1CLNodeID(l1CLID).ComponentID) + l1CL, ok := orch.GetL1CL(l1CLID) require.True(ok, "l1 CL node required") - l1CL := l1CLComponent.(*L1CLNode) l2EL, ok := orch.GetL2EL(l2ELID) require.True(ok, "l2 EL node required") @@ -306,7 +301,7 @@ func withKonaNode(l2CLID stack.L2CLNodeID, l1CLID stack.L1CLNodeID, l1ELID stack k.Start() p.Cleanup(k.Stop) p.Logger().Info("Kona-node is up", "rpc", k.UserRPC()) - cid := stack.ConvertL2CLNodeID(l2CLID).ComponentID + cid := l2CLID require.False(orch.registry.Has(cid), "must not already exist") orch.registry.Register(cid, k) } diff --git a/op-devstack/sysgo/l2_cl_opnode.go b/op-devstack/sysgo/l2_cl_opnode.go index 7a3e0e6659f..2b272cfaee9 100644 --- a/op-devstack/sysgo/l2_cl_opnode.go +++ b/op-devstack/sysgo/l2_cl_opnode.go @@ -41,7 +41,7 @@ import ( type OpNode struct { mu sync.Mutex - id stack.L2CLNodeID + id stack.ComponentID opNode *opnode.Opnode userRPC string interopEndpoint string @@ -49,7 +49,7 @@ type OpNode struct { cfg *config.Config p devtest.P logger log.Logger - el *stack.L2ELNodeID // Optional: nil when using SyncTester + el *stack.ComponentID // Optional: nil when using SyncTester userProxy *tcpproxy.Proxy interopProxy *tcpproxy.Proxy clock clock.Clock @@ -72,7 +72,7 @@ func (n *OpNode) hydrate(system stack.ExtensibleSystem) { InteropJwtSecret: n.interopJwtSecret, }) sysL2CL.SetLabel(match.LabelVendor, string(match.OpNode)) - l2Net := system.L2Network(stack.L2NetworkID(n.id.ChainID())) + l2Net := system.L2Network(stack.ByID[stack.L2Network](stack.NewL2NetworkID(n.id.ChainID()))) l2Net.(stack.ExtensibleL2Network).AddL2CLNode(sysL2CL) if n.el != nil { for _, el := range l2Net.L2ELNodes() { @@ -81,14 +81,14 @@ func (n *OpNode) hydrate(system stack.ExtensibleSystem) { return } } - rbID := stack.RollupBoostNodeID(*n.el) + rbID := stack.NewRollupBoostNodeID(n.el.Key(), n.el.ChainID()) for _, rb := range l2Net.RollupBoostNodes() { if rb.ID() == rbID { sysL2CL.(stack.LinkableL2CLNode).LinkRollupBoostNode(rb) return } } - oprbID := stack.OPRBuilderNodeID(*n.el) + oprbID := stack.NewOPRBuilderNodeID(n.el.Key(), n.el.ChainID()) for _, oprb := range l2Net.OPRBuilderNodes() { if oprb.ID() == oprbID { sysL2CL.(stack.LinkableL2CLNode).LinkOPRBuilderNode(oprb) @@ -162,13 +162,12 @@ func (n *OpNode) Stop() { n.opNode = nil } -func WithOpNodeFollowL2(l2CLID stack.L2CLNodeID, l1CLID stack.L1CLNodeID, l1ELID stack.L1ELNodeID, l2ELID stack.L2ELNodeID, l2FollowSourceID stack.L2CLNodeID, opts ...L2CLOption) stack.Option[*Orchestrator] { +func WithOpNodeFollowL2(l2CLID stack.ComponentID, l1CLID stack.ComponentID, l1ELID stack.ComponentID, l2ELID stack.ComponentID, l2FollowSourceID stack.ComponentID, opts ...L2CLOption) stack.Option[*Orchestrator] { return stack.AfterDeploy(func(orch *Orchestrator) { followSource := func(orch *Orchestrator) string { p := orch.P().WithCtx(stack.ContextWithID(orch.P().Ctx(), l2CLID)) - l2CLComponent, ok := orch.registry.Get(stack.ConvertL2CLNodeID(l2FollowSourceID).ComponentID) + l2CLFollowSource, ok := orch.GetL2CL(l2FollowSourceID) p.Require().True(ok, "l2 CL Follow Source required") - l2CLFollowSource := l2CLComponent.(L2CLNode) return l2CLFollowSource.UserRPC() }(orch) opts = append(opts, L2CLFollowSource(followSource)) @@ -176,31 +175,27 @@ func WithOpNodeFollowL2(l2CLID stack.L2CLNodeID, l1CLID stack.L1CLNodeID, l1ELID }) } -func WithOpNode(l2CLID stack.L2CLNodeID, l1CLID stack.L1CLNodeID, l1ELID stack.L1ELNodeID, l2ELID stack.L2ELNodeID, opts ...L2CLOption) stack.Option[*Orchestrator] { +func WithOpNode(l2CLID stack.ComponentID, l1CLID stack.ComponentID, l1ELID stack.ComponentID, l2ELID stack.ComponentID, opts ...L2CLOption) stack.Option[*Orchestrator] { return stack.AfterDeploy(withOpNode(l2CLID, l1CLID, l1ELID, l2ELID, opts...)) } -func withOpNode(l2CLID stack.L2CLNodeID, l1CLID stack.L1CLNodeID, l1ELID stack.L1ELNodeID, l2ELID stack.L2ELNodeID, opts ...L2CLOption) func(orch *Orchestrator) { +func withOpNode(l2CLID stack.ComponentID, l1CLID stack.ComponentID, l1ELID stack.ComponentID, l2ELID stack.ComponentID, opts ...L2CLOption) func(orch *Orchestrator) { return func(orch *Orchestrator) { p := orch.P().WithCtx(stack.ContextWithID(orch.P().Ctx(), l2CLID)) require := p.Require() - l1NetComponent, ok := orch.registry.Get(stack.ConvertL1NetworkID(stack.L1NetworkID(l1CLID.ChainID())).ComponentID) + l1Net, ok := orch.GetL1Network(stack.NewL1NetworkID(l1CLID.ChainID())) require.True(ok, "l1 network required") - l1Net := l1NetComponent.(*L1Network) - l2NetComponent, ok := orch.registry.Get(stack.ConvertL2NetworkID(stack.L2NetworkID(l2CLID.ChainID())).ComponentID) + l2Net, ok := orch.GetL2Network(stack.NewL2NetworkID(l2CLID.ChainID())) require.True(ok, "l2 network required") - l2Net := l2NetComponent.(*L2Network) - l1ELComponent, ok := orch.registry.Get(stack.ConvertL1ELNodeID(l1ELID).ComponentID) + l1EL, ok := orch.GetL1EL(l1ELID) require.True(ok, "l1 EL node required") - l1EL := l1ELComponent.(L1ELNode) - l1CLComponent, ok := orch.registry.Get(stack.ConvertL1CLNodeID(l1CLID).ComponentID) + l1CL, ok := orch.GetL1CL(l1CLID) require.True(ok, "l1 CL node required") - l1CL := l1CLComponent.(*L1CLNode) // Get the L2EL node (which can be a regular EL node or a SyncTesterEL) l2EL, ok := orch.GetL2EL(l2ELID) @@ -368,7 +363,7 @@ func withOpNode(l2CLID stack.L2CLNodeID, l1CLID stack.L1CLNodeID, l1ELID stack.L // Set the EL field to link to the L2EL node l2CLNode.el = &l2ELID - cid := stack.ConvertL2CLNodeID(l2CLID).ComponentID + cid := l2CLID require.False(orch.registry.Has(cid), fmt.Sprintf("must not already exist: %s", l2CLID)) orch.registry.Register(cid, l2CLNode) l2CLNode.Start() diff --git a/op-devstack/sysgo/l2_cl_p2p_util.go b/op-devstack/sysgo/l2_cl_p2p_util.go index 05a7cd3f79e..67d524dffa2 100644 --- a/op-devstack/sysgo/l2_cl_p2p_util.go +++ b/op-devstack/sysgo/l2_cl_p2p_util.go @@ -83,17 +83,15 @@ func getP2PClientsAndPeers(ctx context.Context, logger log.Logger, } // WithL2CLP2PConnection connects P2P between two L2CLs -func WithL2CLP2PConnection(l2CL1ID, l2CL2ID stack.L2CLNodeID) stack.Option[*Orchestrator] { +func WithL2CLP2PConnection(l2CL1ID, l2CL2ID stack.ComponentID) stack.Option[*Orchestrator] { return stack.AfterDeploy(func(orch *Orchestrator) { require := orch.P().Require() l := orch.P().Logger() - l2CL1Component, ok := orch.registry.Get(stack.ConvertL2CLNodeID(l2CL1ID).ComponentID) + l2CL1, ok := orch.GetL2CL(l2CL1ID) require.True(ok, "looking for L2 CL node 1 to connect p2p") - l2CL1 := l2CL1Component.(L2CLNode) - l2CL2Component, ok := orch.registry.Get(stack.ConvertL2CLNodeID(l2CL2ID).ComponentID) + l2CL2, ok := orch.GetL2CL(l2CL2ID) require.True(ok, "looking for L2 CL node 2 to connect p2p") - l2CL2 := l2CL2Component.(L2CLNode) require.Equal(l2CL1ID.ChainID(), l2CL2ID.ChainID(), "must be same l2 chain") ctx := orch.P().Ctx() diff --git a/op-devstack/sysgo/l2_cl_supernode.go b/op-devstack/sysgo/l2_cl_supernode.go index 442b7ff164c..b10f17dd742 100644 --- a/op-devstack/sysgo/l2_cl_supernode.go +++ b/op-devstack/sysgo/l2_cl_supernode.go @@ -41,7 +41,7 @@ type SuperNode struct { interopJwtSecret eth.Bytes32 p devtest.P logger log.Logger - els []*stack.L2ELNodeID // Optional: nil when using SyncTester + els []*stack.ComponentID // Optional: nil when using SyncTester chains []eth.ChainID l1UserRPC string l1BeaconAddr string @@ -140,20 +140,20 @@ func (n *SuperNode) ResumeInteropActivity() { } // WithSupernode constructs a Supernode-based L2 CL node -func WithSupernode(supernodeID stack.SupernodeID, l2CLID stack.L2CLNodeID, l1CLID stack.L1CLNodeID, l1ELID stack.L1ELNodeID, l2ELID stack.L2ELNodeID, opts ...L2CLOption) stack.Option[*Orchestrator] { +func WithSupernode(supernodeID stack.SupernodeID, l2CLID stack.ComponentID, l1CLID stack.ComponentID, l1ELID stack.ComponentID, l2ELID stack.ComponentID, opts ...L2CLOption) stack.Option[*Orchestrator] { args := []L2CLs{{CLID: l2CLID, ELID: l2ELID}} return WithSharedSupernodeCLs(supernodeID, args, l1CLID, l1ELID) } // SuperNodeProxy is a thin wrapper that points to a shared supernode instance. type SuperNodeProxy struct { - id stack.L2CLNodeID + id stack.ComponentID p devtest.P logger log.Logger userRPC string interopEndpoint string interopJwtSecret eth.Bytes32 - el *stack.L2ELNodeID + el *stack.ComponentID } var _ L2CLNode = (*SuperNodeProxy)(nil) @@ -173,10 +173,10 @@ func (n *SuperNodeProxy) hydrate(system stack.ExtensibleSystem) { InteropJwtSecret: n.interopJwtSecret, }) sysL2CL.SetLabel(match.LabelVendor, string(match.OpNode)) - l2Net := system.L2Network(stack.L2NetworkID(n.id.ChainID())) + l2Net := system.L2Network(stack.ByID[stack.L2Network](stack.NewL2NetworkID(n.id.ChainID()))) l2Net.(stack.ExtensibleL2Network).AddL2CLNode(sysL2CL) if n.el != nil { - sysL2CL.(stack.LinkableL2CLNode).LinkEL(l2Net.L2ELNode(n.el)) + sysL2CL.(stack.LinkableL2CLNode).LinkEL(l2Net.L2ELNode(stack.ByID[stack.L2ELNode](*n.el))) } } @@ -188,8 +188,8 @@ func (n *SuperNodeProxy) InteropRPC() (endpoint string, jwtSecret eth.Bytes32) { } type L2CLs struct { - CLID stack.L2CLNodeID - ELID stack.L2ELNodeID + CLID stack.ComponentID + ELID stack.ComponentID } // SupernodeConfig holds configuration options for the shared supernode. @@ -225,24 +225,23 @@ func WithSupernodeInteropAtGenesis() SupernodeOption { // WithSharedSupernodeCLsInterop starts one supernode for N L2 chains with interop enabled at genesis. // The interop activation timestamp is computed from the first chain's genesis time. -func WithSharedSupernodeCLsInterop(supernodeID stack.SupernodeID, cls []L2CLs, l1CLID stack.L1CLNodeID, l1ELID stack.L1ELNodeID) stack.Option[*Orchestrator] { +func WithSharedSupernodeCLsInterop(supernodeID stack.SupernodeID, cls []L2CLs, l1CLID stack.ComponentID, l1ELID stack.ComponentID) stack.Option[*Orchestrator] { return WithSharedSupernodeCLs(supernodeID, cls, l1CLID, l1ELID, WithSupernodeInteropAtGenesis()) } // WithSharedSupernodeCLsInteropDelayed starts one supernode for N L2 chains with interop enabled // at a specified offset from genesis. This allows testing the transition from non-interop to interop mode. -func WithSharedSupernodeCLsInteropDelayed(supernodeID stack.SupernodeID, cls []L2CLs, l1CLID stack.L1CLNodeID, l1ELID stack.L1ELNodeID, delaySeconds uint64) stack.Option[*Orchestrator] { +func WithSharedSupernodeCLsInteropDelayed(supernodeID stack.SupernodeID, cls []L2CLs, l1CLID stack.ComponentID, l1ELID stack.ComponentID, delaySeconds uint64) stack.Option[*Orchestrator] { return stack.AfterDeploy(func(orch *Orchestrator) { if len(cls) == 0 { orch.P().Require().Fail("no chains provided") return } - l2NetComponent, ok := orch.registry.Get(stack.ConvertL2NetworkID(stack.L2NetworkID(cls[0].CLID.ChainID())).ComponentID) + l2Net, ok := orch.GetL2Network(stack.NewL2NetworkID(cls[0].CLID.ChainID())) if !ok { orch.P().Require().Fail("l2 network not found") return } - l2Net := l2NetComponent.(*L2Network) genesisTime := l2Net.rollupCfg.Genesis.L2Time activationTime := genesisTime + delaySeconds orch.P().Logger().Info("enabling supernode interop with delay", @@ -255,17 +254,30 @@ func WithSharedSupernodeCLsInteropDelayed(supernodeID stack.SupernodeID, cls []L } // WithSharedSupernodeCLs starts one supernode for N L2 chains and registers thin L2CL wrappers. -func WithSharedSupernodeCLs(supernodeID stack.SupernodeID, cls []L2CLs, l1CLID stack.L1CLNodeID, l1ELID stack.L1ELNodeID, opts ...SupernodeOption) stack.Option[*Orchestrator] { +func WithSharedSupernodeCLs(supernodeID stack.SupernodeID, cls []L2CLs, l1CLID stack.ComponentID, l1ELID stack.ComponentID, opts ...SupernodeOption) stack.Option[*Orchestrator] { return stack.AfterDeploy(func(orch *Orchestrator) { withSharedSupernodeCLsImpl(orch, supernodeID, cls, l1CLID, l1ELID, opts...) }) } // withSharedSupernodeCLsImpl is the implementation for starting a shared supernode. -func withSharedSupernodeCLsImpl(orch *Orchestrator, supernodeID stack.SupernodeID, cls []L2CLs, l1CLID stack.L1CLNodeID, l1ELID stack.L1ELNodeID, opts ...SupernodeOption) { +func withSharedSupernodeCLsImpl(orch *Orchestrator, supernodeID stack.SupernodeID, cls []L2CLs, l1CLID stack.ComponentID, l1ELID stack.ComponentID, opts ...SupernodeOption) { p := orch.P() require := p.Require() + require.Equal(stack.KindSupernode, supernodeID.Kind(), "supernode ID must be kind Supernode") + require.Equal(stack.KindL1CLNode, l1CLID.Kind(), "l1 CL ID must be kind L1CLNode") + require.Equal(stack.KindL1ELNode, l1ELID.Kind(), "l1 EL ID must be kind L1ELNode") + require.Equal(l1CLID.ChainID(), l1ELID.ChainID(), "l1 CL and EL IDs must be on the same chain") + require.NotEmpty(cls, "at least one L2 CL/EL pair is required") + for i := range cls { + ids := cls[i] + require.Equalf(stack.KindL2CLNode, ids.CLID.Kind(), "cls[%d].CLID must be kind L2CLNode", i) + require.Truef(ids.CLID.HasChainID(), "cls[%d].CLID must be chain-scoped", i) + require.Truef(ids.ELID.HasChainID(), "cls[%d].ELID must be chain-scoped", i) + require.Equalf(ids.CLID.ChainID(), ids.ELID.ChainID(), "cls[%d] CL and EL IDs must be on the same chain", i) + } + // Apply options snOpts := &SupernodeConfig{} for _, opt := range opts { @@ -275,25 +287,21 @@ func withSharedSupernodeCLsImpl(orch *Orchestrator, supernodeID stack.SupernodeI // Resolve UseGenesisInterop: read the activation timestamp from the first chain's genesis. if snOpts.UseGenesisInterop && snOpts.InteropActivationTimestamp == nil { p.Require().NotEmpty(cls, "no chains provided for genesis interop resolution") - l2NetComponent, ok := orch.registry.Get(stack.ConvertL2NetworkID(stack.L2NetworkID(cls[0].CLID.ChainID())).ComponentID) - l2Net := l2NetComponent.(*L2Network) + l2Net, ok := orch.GetL2Network(stack.NewL2NetworkID(cls[0].CLID.ChainID())) p.Require().True(ok, "l2 network not found for genesis interop resolution") genesisTime := l2Net.rollupCfg.Genesis.L2Time p.Logger().Info("enabling supernode interop at genesis", "activation_timestamp", genesisTime) snOpts.InteropActivationTimestamp = &genesisTime } - l1ELComponent, ok := orch.registry.Get(stack.ConvertL1ELNodeID(l1ELID).ComponentID) + l1EL, ok := orch.GetL1EL(l1ELID) require.True(ok, "l1 EL node required") - l1EL := l1ELComponent.(L1ELNode) - l1CLComponent, ok := orch.registry.Get(stack.ConvertL1CLNodeID(l1CLID).ComponentID) + l1CL, ok := orch.GetL1CL(l1CLID) require.True(ok, "l1 CL node required") - l1CL := l1CLComponent.(*L1CLNode) // Get L1 network to access L1 chain config - l1NetComponent, ok := orch.registry.Get(stack.ConvertL1NetworkID(stack.L1NetworkID(l1ELID.ChainID())).ComponentID) + l1Net, ok := orch.GetL1Network(stack.NewL1NetworkID(l1ELID.ChainID())) require.True(ok, "l1 network required") - l1Net := l1NetComponent.(*L1Network) _, jwtSecret := orch.writeDefaultJWT() @@ -345,12 +353,11 @@ func withSharedSupernodeCLsImpl(orch *Orchestrator, supernodeID stack.SupernodeI // Gather VN configs and chain IDs vnCfgs := make(map[eth.ChainID]*config.Config) chainIDs := make([]uint64, 0, len(cls)) - els := make([]*stack.L2ELNodeID, 0, len(cls)) + els := make([]*stack.ComponentID, 0, len(cls)) for i := range cls { a := cls[i] - l2NetComponent, ok := orch.registry.Get(stack.ConvertL2NetworkID(stack.L2NetworkID(a.CLID.ChainID())).ComponentID) + l2Net, ok := orch.GetL2Network(stack.NewL2NetworkID(a.CLID.ChainID())) require.True(ok, "l2 network required") - l2Net := l2NetComponent.(*L2Network) l2ELNode, ok := orch.GetL2EL(a.ELID) require.True(ok, "l2 EL node required") l2ChainID := a.CLID.ChainID() @@ -429,7 +436,7 @@ func withSharedSupernodeCLsImpl(orch *Orchestrator, supernodeID stack.SupernodeI interopJwtSecret: jwtSecret, el: &cls[i].ELID, } - cid := stack.ConvertL2CLNodeID(a.CLID).ComponentID + cid := a.CLID require.False(orch.registry.Has(cid), fmt.Sprintf("must not already exist: %s", a.CLID)) orch.registry.Register(cid, proxy) } diff --git a/op-devstack/sysgo/l2_el.go b/op-devstack/sysgo/l2_el.go index 7242f6f1498..6ebe9e2de07 100644 --- a/op-devstack/sysgo/l2_el.go +++ b/op-devstack/sysgo/l2_el.go @@ -16,7 +16,7 @@ type L2ELNode interface { } type L2ELConfig struct { - SupervisorID *stack.SupervisorID + SupervisorID *stack.ComponentID P2PAddr string P2PPort int P2PNodeKeyHex string @@ -25,21 +25,21 @@ type L2ELConfig struct { ProofHistory bool } -func L2ELWithSupervisor(supervisorID stack.SupervisorID) L2ELOption { - return L2ELOptionFn(func(p devtest.P, id stack.L2ELNodeID, cfg *L2ELConfig) { +func L2ELWithSupervisor(supervisorID stack.ComponentID) L2ELOption { + return L2ELOptionFn(func(p devtest.P, id stack.ComponentID, cfg *L2ELConfig) { cfg.SupervisorID = &supervisorID }) } func L2ELWithProofHistory(enable bool) L2ELOption { - return L2ELOptionFn(func(p devtest.P, id stack.L2ELNodeID, cfg *L2ELConfig) { + return L2ELOptionFn(func(p devtest.P, id stack.ComponentID, cfg *L2ELConfig) { cfg.ProofHistory = enable }) } // L2ELWithP2PConfig sets deterministic P2P identity and static peers for the L2 EL. func L2ELWithP2PConfig(addr string, port int, nodeKeyHex string, staticPeers, trustedPeers []string) L2ELOption { - return L2ELOptionFn(func(p devtest.P, id stack.L2ELNodeID, cfg *L2ELConfig) { + return L2ELOptionFn(func(p devtest.P, id stack.ComponentID, cfg *L2ELConfig) { cfg.P2PAddr = addr cfg.P2PPort = port cfg.P2PNodeKeyHex = nodeKeyHex @@ -61,7 +61,7 @@ func DefaultL2ELConfig() *L2ELConfig { } type L2ELOption interface { - Apply(p devtest.P, id stack.L2ELNodeID, cfg *L2ELConfig) + Apply(p devtest.P, id stack.ComponentID, cfg *L2ELConfig) } // WithGlobalL2ELOption applies the L2ELOption to all L2ELNode instances in this orchestrator @@ -71,11 +71,11 @@ func WithGlobalL2ELOption(opt L2ELOption) stack.Option[*Orchestrator] { }) } -type L2ELOptionFn func(p devtest.P, id stack.L2ELNodeID, cfg *L2ELConfig) +type L2ELOptionFn func(p devtest.P, id stack.ComponentID, cfg *L2ELConfig) var _ L2ELOption = L2ELOptionFn(nil) -func (fn L2ELOptionFn) Apply(p devtest.P, id stack.L2ELNodeID, cfg *L2ELConfig) { +func (fn L2ELOptionFn) Apply(p devtest.P, id stack.ComponentID, cfg *L2ELConfig) { fn(p, id, cfg) } @@ -84,7 +84,7 @@ type L2ELOptionBundle []L2ELOption var _ L2ELOption = L2ELOptionBundle(nil) -func (l L2ELOptionBundle) Apply(p devtest.P, id stack.L2ELNodeID, cfg *L2ELConfig) { +func (l L2ELOptionBundle) Apply(p devtest.P, id stack.ComponentID, cfg *L2ELConfig) { for _, opt := range l { p.Require().NotNil(opt, "cannot Apply nil L2ELOption") opt.Apply(p, id, cfg) @@ -94,7 +94,7 @@ func (l L2ELOptionBundle) Apply(p devtest.P, id stack.L2ELNodeID, cfg *L2ELConfi // WithL2ELNode adds the default type of L2 CL node. // The default can be configured with DEVSTACK_L2EL_KIND. // Tests that depend on specific types can use options like WithKonaNode and WithOpNode directly. -func WithL2ELNode(id stack.L2ELNodeID, opts ...L2ELOption) stack.Option[*Orchestrator] { +func WithL2ELNode(id stack.ComponentID, opts ...L2ELOption) stack.Option[*Orchestrator] { switch os.Getenv("DEVSTACK_L2EL_KIND") { case "op-reth": return WithOpReth(id, opts...) @@ -103,7 +103,7 @@ func WithL2ELNode(id stack.L2ELNodeID, opts ...L2ELOption) stack.Option[*Orchest } } -func WithExtL2Node(id stack.L2ELNodeID, elRPCEndpoint string) stack.Option[*Orchestrator] { +func WithExtL2Node(id stack.ComponentID, elRPCEndpoint string) stack.Option[*Orchestrator] { return stack.AfterDeploy(func(orch *Orchestrator) { require := orch.P().Require() @@ -113,7 +113,7 @@ func WithExtL2Node(id stack.L2ELNodeID, elRPCEndpoint string) stack.Option[*Orch userRPC: elRPCEndpoint, readOnly: true, } - cid := stack.ConvertL2ELNodeID(id).ComponentID + cid := id require.False(orch.registry.Has(cid), "must not already exist") orch.registry.Register(cid, l2ELNode) }) diff --git a/op-devstack/sysgo/l2_el_opgeth.go b/op-devstack/sysgo/l2_el_opgeth.go index 5b2be235e7e..57370d4403d 100644 --- a/op-devstack/sysgo/l2_el_opgeth.go +++ b/op-devstack/sysgo/l2_el_opgeth.go @@ -27,7 +27,7 @@ type OpGeth struct { p devtest.P logger log.Logger - id stack.L2ELNodeID + id stack.ComponentID l2Net *L2Network jwtPath string jwtSecret [32]byte @@ -72,7 +72,7 @@ func (n *OpGeth) hydrate(system stack.ExtensibleSystem) { system.T().Cleanup(engineCl.Close) } - l2Net := system.L2Network(stack.L2NetworkID(n.id.ChainID())) + l2Net := system.L2Network(stack.ByID[stack.L2Network](stack.NewL2NetworkID(n.id.ChainID()))) sysL2EL := shim.NewL2ELNode(shim.L2ELNodeConfig{ RollupCfg: l2Net.RollupConfig(), ELNodeConfig: shim.ELNodeConfig{ @@ -179,14 +179,13 @@ func (n *OpGeth) Stop() { n.l2Geth = nil } -func WithOpGeth(id stack.L2ELNodeID, opts ...L2ELOption) stack.Option[*Orchestrator] { +func WithOpGeth(id stack.ComponentID, opts ...L2ELOption) stack.Option[*Orchestrator] { return stack.AfterDeploy(func(orch *Orchestrator) { p := orch.P().WithCtx(stack.ContextWithID(orch.P().Ctx(), id)) require := p.Require() - l2NetComponent, ok := orch.registry.Get(stack.ConvertL2NetworkID(stack.L2NetworkID(id.ChainID())).ComponentID) + l2Net, ok := orch.GetL2Network(stack.NewL2NetworkID(id.ChainID())) require.True(ok, "L2 network required") - l2Net := l2NetComponent.(*L2Network) cfg := DefaultL2ELConfig() orch.l2ELOptions.Apply(p, id, cfg) // apply global options @@ -198,9 +197,8 @@ func WithOpGeth(id stack.L2ELNodeID, opts ...L2ELOption) stack.Option[*Orchestra supervisorRPC := "" if useInterop && cfg.SupervisorID != nil { - supComponent, ok := orch.registry.Get(stack.ConvertSupervisorID(*cfg.SupervisorID).ComponentID) + sup, ok := orch.GetSupervisor(*cfg.SupervisorID) require.True(ok, "supervisor is required for interop") - sup := supComponent.(Supervisor) supervisorRPC = sup.UserRPC() } @@ -220,7 +218,7 @@ func WithOpGeth(id stack.L2ELNodeID, opts ...L2ELOption) stack.Option[*Orchestra p.Cleanup(func() { l2EL.Stop() }) - cid := stack.ConvertL2ELNodeID(id).ComponentID + cid := id require.False(orch.registry.Has(cid), "must be unique L2 EL node") orch.registry.Register(cid, l2EL) }) diff --git a/op-devstack/sysgo/l2_el_opreth.go b/op-devstack/sysgo/l2_el_opreth.go index 6f629b15bd6..e09ec756f3a 100644 --- a/op-devstack/sysgo/l2_el_opreth.go +++ b/op-devstack/sysgo/l2_el_opreth.go @@ -25,7 +25,7 @@ import ( type OpReth struct { mu sync.Mutex - id stack.L2ELNodeID + id stack.ComponentID jwtPath string jwtSecret [32]byte authRPC string @@ -62,7 +62,7 @@ func (n *OpReth) hydrate(system stack.ExtensibleSystem) { require.NoError(err) system.T().Cleanup(engineCl.Close) - l2Net := system.L2Network(stack.L2NetworkID(n.id.ChainID())) + l2Net := system.L2Network(stack.ByID[stack.L2Network](stack.NewL2NetworkID(n.id.ChainID()))) sysL2EL := shim.NewL2ELNode(shim.L2ELNodeConfig{ RollupCfg: l2Net.RollupConfig(), ELNodeConfig: shim.ELNodeConfig{ @@ -184,14 +184,13 @@ func (n *OpReth) JWTPath() string { return n.jwtPath } -func WithOpReth(id stack.L2ELNodeID, opts ...L2ELOption) stack.Option[*Orchestrator] { +func WithOpReth(id stack.ComponentID, opts ...L2ELOption) stack.Option[*Orchestrator] { return stack.AfterDeploy(func(orch *Orchestrator) { p := orch.P().WithCtx(stack.ContextWithID(orch.P().Ctx(), id)) require := p.Require() - l2NetComponent, ok := orch.registry.Get(stack.ConvertL2NetworkID(stack.L2NetworkID(id.ChainID())).ComponentID) + l2Net, ok := orch.GetL2Network(stack.NewL2NetworkID(id.ChainID())) require.True(ok, "L2 network required") - l2Net := l2NetComponent.(*L2Network) cfg := DefaultL2ELConfig() orch.l2ELOptions.Apply(p, id, cfg) // apply global options @@ -203,9 +202,8 @@ func WithOpReth(id stack.L2ELNodeID, opts ...L2ELOption) stack.Option[*Orchestra supervisorRPC := "" if useInterop && cfg.SupervisorID != nil { - supComponent, ok := orch.registry.Get(stack.ConvertSupervisorID(*cfg.SupervisorID).ComponentID) + sup, ok := orch.GetSupervisor(*cfg.SupervisorID) require.True(ok, "supervisor is required for interop") - sup := supComponent.(Supervisor) supervisorRPC = sup.UserRPC() } @@ -326,7 +324,7 @@ func WithOpReth(id stack.L2ELNodeID, opts ...L2ELOption) stack.Option[*Orchestra l2EL.Start() p.Cleanup(l2EL.Stop) p.Logger().Info("op-reth is ready", "userRPC", l2EL.userRPC, "authRPC", l2EL.authRPC) - cid := stack.ConvertL2ELNodeID(id).ComponentID + cid := id require.False(orch.registry.Has(cid), "must be unique L2 EL node") orch.registry.Register(cid, l2EL) }) diff --git a/op-devstack/sysgo/l2_el_p2p_util.go b/op-devstack/sysgo/l2_el_p2p_util.go index e78b2aaa8ce..ea4728aa0dc 100644 --- a/op-devstack/sysgo/l2_el_p2p_util.go +++ b/op-devstack/sysgo/l2_el_p2p_util.go @@ -16,7 +16,7 @@ import ( "github.com/ethereum-optimism/optimism/op-service/testreq" ) -func WithL2ELP2PConnection(l2EL1ID, l2EL2ID stack.L2ELNodeID, trusted bool) stack.Option[*Orchestrator] { +func WithL2ELP2PConnection(l2EL1ID, l2EL2ID stack.ComponentID, trusted bool) stack.Option[*Orchestrator] { return stack.AfterDeploy(func(orch *Orchestrator) { require := orch.P().Require() diff --git a/op-devstack/sysgo/l2_el_synctester.go b/op-devstack/sysgo/l2_el_synctester.go index a007a53d4bd..28b543428d0 100644 --- a/op-devstack/sysgo/l2_el_synctester.go +++ b/op-devstack/sysgo/l2_el_synctester.go @@ -18,7 +18,7 @@ import ( type SyncTesterEL struct { mu sync.Mutex - id stack.L2ELNodeID + id stack.ComponentID l2Net *L2Network jwtPath string @@ -56,7 +56,7 @@ func DefaultSyncTesterELConfig() *SyncTesterELConfig { } type SyncTesterELOption interface { - Apply(p devtest.P, id stack.L2ELNodeID, cfg *SyncTesterELConfig) + Apply(p devtest.P, id stack.ComponentID, cfg *SyncTesterELConfig) } // WithGlobalSyncTesterELOption applies the SyncTesterELOption to all SyncTesterEL instances in this orchestrator @@ -66,11 +66,11 @@ func WithGlobalSyncTesterELOption(opt SyncTesterELOption) stack.Option[*Orchestr }) } -type SyncTesterELOptionFn func(p devtest.P, id stack.L2ELNodeID, cfg *SyncTesterELConfig) +type SyncTesterELOptionFn func(p devtest.P, id stack.ComponentID, cfg *SyncTesterELConfig) var _ SyncTesterELOption = SyncTesterELOptionFn(nil) -func (fn SyncTesterELOptionFn) Apply(p devtest.P, id stack.L2ELNodeID, cfg *SyncTesterELConfig) { +func (fn SyncTesterELOptionFn) Apply(p devtest.P, id stack.ComponentID, cfg *SyncTesterELConfig) { fn(p, id, cfg) } @@ -79,7 +79,7 @@ type SyncTesterELOptionBundle []SyncTesterELOption var _ SyncTesterELOptionBundle = SyncTesterELOptionBundle(nil) -func (l SyncTesterELOptionBundle) Apply(p devtest.P, id stack.L2ELNodeID, cfg *SyncTesterELConfig) { +func (l SyncTesterELOptionBundle) Apply(p devtest.P, id stack.ComponentID, cfg *SyncTesterELConfig) { for _, opt := range l { p.Require().NotNil(opt, "cannot Apply nil SyncTesterELOption") opt.Apply(p, id, cfg) @@ -99,7 +99,7 @@ func (n *SyncTesterEL) hydrate(system stack.ExtensibleSystem) { require.NoError(err) system.T().Cleanup(engineCl.Close) - l2Net := system.L2Network(stack.L2NetworkID(n.id.ChainID())) + l2Net := system.L2Network(stack.ByID[stack.L2Network](stack.NewL2NetworkID(n.id.ChainID()))) sysL2EL := shim.NewL2ELNode(shim.L2ELNodeConfig{ RollupCfg: l2Net.RollupConfig(), ELNodeConfig: shim.ELNodeConfig{ @@ -175,14 +175,13 @@ func (n *SyncTesterEL) JWTPath() string { // WithSyncTesterL2ELNode creates a SyncTesterEL that satisfies the L2ELNode interface // The sync tester acts as an EL node that can be used by CL nodes for testing sync. -func WithSyncTesterL2ELNode(id, readonlyEL stack.L2ELNodeID, opts ...SyncTesterELOption) stack.Option[*Orchestrator] { +func WithSyncTesterL2ELNode(id, readonlyEL stack.ComponentID, opts ...SyncTesterELOption) stack.Option[*Orchestrator] { return stack.AfterDeploy(func(orch *Orchestrator) { p := orch.P().WithCtx(stack.ContextWithID(orch.P().Ctx(), id)) require := p.Require() - l2NetComponent, ok := orch.registry.Get(stack.ConvertL2NetworkID(stack.L2NetworkID(readonlyEL.ChainID())).ComponentID) + l2Net, ok := orch.GetL2Network(stack.NewL2NetworkID(readonlyEL.ChainID())) require.True(ok, "L2 network required") - l2Net := l2NetComponent.(*L2Network) cfg := DefaultSyncTesterELConfig() orch.SyncTesterELOptions.Apply(p, id, cfg) // apply global options @@ -203,7 +202,7 @@ func WithSyncTesterL2ELNode(id, readonlyEL stack.L2ELNodeID, opts ...SyncTesterE syncTesterEL.Start() p.Cleanup(syncTesterEL.Stop) p.Logger().Info("sync tester EL is ready", "userRPC", syncTesterEL.userRPC, "authRPC", syncTesterEL.authRPC) - cid := stack.ConvertL2ELNodeID(id).ComponentID + cid := id require.False(orch.registry.Has(cid), "must be unique L2 EL node") orch.registry.Register(cid, syncTesterEL) }) diff --git a/op-devstack/sysgo/l2_metrics_dashboard.go b/op-devstack/sysgo/l2_metrics_dashboard.go index 80e633b9c49..92845c08ae7 100644 --- a/op-devstack/sysgo/l2_metrics_dashboard.go +++ b/op-devstack/sysgo/l2_metrics_dashboard.go @@ -31,7 +31,7 @@ const grafanaDockerPort = "3000" type L2MetricsRegistrar interface { // RegisterL2MetricsTargets is called by components when they are started (or earlier) to register // their metrics endpoints so that a prometheus instance may be spun up to scrape metrics. - RegisterL2MetricsTargets(serviceName stack.IDWithChain, endpoints ...PrometheusMetricsTarget) + RegisterL2MetricsTargets(serviceName stack.Keyed, endpoints ...PrometheusMetricsTarget) } type PrometheusMetricsTarget string diff --git a/op-devstack/sysgo/l2_network.go b/op-devstack/sysgo/l2_network.go index e054e8d3eff..bdd3b5bb2f9 100644 --- a/op-devstack/sysgo/l2_network.go +++ b/op-devstack/sysgo/l2_network.go @@ -11,7 +11,7 @@ import ( ) type L2Network struct { - id stack.L2NetworkID + id stack.ComponentID l1ChainID eth.ChainID genesis *core.Genesis rollupCfg *rollup.Config @@ -20,7 +20,7 @@ type L2Network struct { } func (c *L2Network) hydrate(system stack.ExtensibleSystem) { - l1Net := system.L1Network(stack.L1NetworkID(c.l1ChainID)) + l1Net := system.L1Network(stack.ByID[stack.L1Network](stack.NewL1NetworkID(c.l1ChainID))) sysL2Net := shim.NewL2Network(shim.L2NetworkConfig{ NetworkConfig: shim.NetworkConfig{ CommonConfig: shim.NewCommonConfig(system.T()), diff --git a/op-devstack/sysgo/l2_network_superchain_registry.go b/op-devstack/sysgo/l2_network_superchain_registry.go index fda91a1099f..f48a1fa6bdb 100644 --- a/op-devstack/sysgo/l2_network_superchain_registry.go +++ b/op-devstack/sysgo/l2_network_superchain_registry.go @@ -13,7 +13,7 @@ import ( ) // WithL2NetworkFromSuperchainRegistry creates an L2 network using the rollup config from the superchain registry -func WithL2NetworkFromSuperchainRegistry(l2NetworkID stack.L2NetworkID, networkName string) stack.Option[*Orchestrator] { +func WithL2NetworkFromSuperchainRegistry(l2NetworkID stack.ComponentID, networkName string) stack.Option[*Orchestrator] { return stack.BeforeDeploy(func(orch *Orchestrator) { p := orch.P().WithCtx(stack.ContextWithID(orch.P().Ctx(), l2NetworkID)) require := p.Require() @@ -44,14 +44,14 @@ func WithL2NetworkFromSuperchainRegistry(l2NetworkID stack.L2NetworkID, networkN keys: orch.keys, } - cid := stack.ConvertL2NetworkID(l2NetworkID).ComponentID + cid := l2NetworkID require.False(orch.registry.Has(cid), fmt.Sprintf("must not already exist: %s", l2NetworkID)) orch.registry.Register(cid, l2Net) }) } // WithEmptyDepSet creates an L2 network using the rollup config from the superchain registry -func WithEmptyDepSet(l2NetworkID stack.L2NetworkID, networkName string) stack.Option[*Orchestrator] { +func WithEmptyDepSet(l2NetworkID stack.ComponentID, networkName string) stack.Option[*Orchestrator] { return stack.Combine( WithL2NetworkFromSuperchainRegistry(l2NetworkID, networkName), stack.BeforeDeploy(func(orch *Orchestrator) { @@ -63,13 +63,13 @@ func WithEmptyDepSet(l2NetworkID stack.L2NetworkID, networkName string) stack.Op require.NotNil(chainCfg, "chain config not found for network %s", networkName) // Create a minimal cluster with empty dependency set - clusterID := stack.ClusterID(networkName) + clusterID := stack.NewClusterID(networkName) cluster := &Cluster{ id: clusterID, cfgset: depset.FullConfigSetMerged{}, } - orch.registry.Register(stack.ConvertClusterID(clusterID).ComponentID, cluster) + orch.registry.Register(clusterID, cluster) }), ) } diff --git a/op-devstack/sysgo/l2_proposer.go b/op-devstack/sysgo/l2_proposer.go index 538dac741a1..25007aef2b6 100644 --- a/op-devstack/sysgo/l2_proposer.go +++ b/op-devstack/sysgo/l2_proposer.go @@ -21,7 +21,7 @@ import ( ) type L2Proposer struct { - id stack.L2ProposerID + id stack.ComponentID service *ps.ProposerService userRPC string } @@ -37,11 +37,11 @@ func (p *L2Proposer) hydrate(system stack.ExtensibleSystem) { ID: p.id, Client: rpcCl, }) - l2Net := system.L2Network(stack.L2NetworkID(p.id.ChainID())) + l2Net := system.L2Network(stack.ByID[stack.L2Network](stack.NewL2NetworkID(p.id.ChainID()))) l2Net.(stack.ExtensibleL2Network).AddL2Proposer(bFrontend) } -type ProposerOption func(id stack.L2ProposerID, cfg *ps.CLIConfig) +type ProposerOption func(id stack.ComponentID, cfg *ps.CLIConfig) func WithProposerOption(opt ProposerOption) stack.Option[*Orchestrator] { return stack.BeforeDeploy(func(o *Orchestrator) { @@ -49,35 +49,35 @@ func WithProposerOption(opt ProposerOption) stack.Option[*Orchestrator] { }) } -func WithProposer(proposerID stack.L2ProposerID, l1ELID stack.L1ELNodeID, - l2CLID *stack.L2CLNodeID, supervisorID *stack.SupervisorID) stack.Option[*Orchestrator] { +func WithProposer(proposerID stack.ComponentID, l1ELID stack.ComponentID, + l2CLID *stack.ComponentID, supervisorID *stack.ComponentID) stack.Option[*Orchestrator] { return stack.AfterDeploy(func(orch *Orchestrator) { WithProposerPostDeploy(orch, proposerID, l1ELID, l2CLID, supervisorID, nil) }) } -func WithSuperProposer(proposerID stack.L2ProposerID, l1ELID stack.L1ELNodeID, - supervisorID *stack.SupervisorID) stack.Option[*Orchestrator] { +func WithSuperProposer(proposerID stack.ComponentID, l1ELID stack.ComponentID, + supervisorID *stack.ComponentID) stack.Option[*Orchestrator] { return stack.Finally(func(orch *Orchestrator) { WithProposerPostDeploy(orch, proposerID, l1ELID, nil, supervisorID, nil) }) } -func WithSupernodeProposer(proposerID stack.L2ProposerID, l1ELID stack.L1ELNodeID, +func WithSupernodeProposer(proposerID stack.ComponentID, l1ELID stack.ComponentID, supernodeID *stack.SupernodeID) stack.Option[*Orchestrator] { return stack.Finally(func(orch *Orchestrator) { WithProposerPostDeploy(orch, proposerID, l1ELID, nil, nil, supernodeID) }) } -func WithProposerPostDeploy(orch *Orchestrator, proposerID stack.L2ProposerID, l1ELID stack.L1ELNodeID, - l2CLID *stack.L2CLNodeID, supervisorID *stack.SupervisorID, supernodeID *stack.SupernodeID) { +func WithProposerPostDeploy(orch *Orchestrator, proposerID stack.ComponentID, l1ELID stack.ComponentID, + l2CLID *stack.ComponentID, supervisorID *stack.ComponentID, supernodeID *stack.SupernodeID) { ctx := orch.P().Ctx() ctx = stack.ContextWithID(ctx, proposerID) p := orch.P().WithCtx(ctx) require := p.Require() - proposerCID := stack.ConvertL2ProposerID(proposerID).ComponentID + proposerCID := proposerID require.False(orch.registry.Has(proposerCID), "proposer must not already exist") if supervisorID != nil && supernodeID != nil { require.Fail("cannot have both supervisorID and supernodeID set for proposer") @@ -89,13 +89,11 @@ func WithProposerPostDeploy(orch *Orchestrator, proposerID stack.L2ProposerID, l logger := p.Logger() logger.Info("Proposer key acquired", "addr", crypto.PubkeyToAddress(proposerSecret.PublicKey)) - l1ELComponent, ok := orch.registry.Get(stack.ConvertL1ELNodeID(l1ELID).ComponentID) + l1EL, ok := orch.GetL1EL(l1ELID) require.True(ok) - l1EL := l1ELComponent.(L1ELNode) - l2NetComponent, ok := orch.registry.Get(stack.ConvertL2NetworkID(stack.L2NetworkID(proposerID.ChainID())).ComponentID) + l2Net, ok := orch.GetL2Network(stack.NewL2NetworkID(proposerID.ChainID())) require.True(ok) - l2Net := l2NetComponent.(*L2Network) disputeGameFactoryAddr := l2Net.deployment.DisputeGameFactoryProxyAddr() disputeGameType := 1 // Permissioned game type is the only one currently deployed if orch.wb.outInteropMigration != nil { @@ -130,9 +128,8 @@ func WithProposerPostDeploy(orch *Orchestrator, proposerID stack.L2ProposerID, l // If supervisor is available, use it. Otherwise, connect to L2 CL. switch { case supervisorID != nil: - supervisorComponent, ok := orch.registry.Get(stack.ConvertSupervisorID(*supervisorID).ComponentID) + supervisorNode, ok := orch.GetSupervisor(*supervisorID) require.True(ok, "supervisor not found") - supervisorNode := supervisorComponent.(Supervisor) proposerCLIConfig.SupervisorRpcs = []string{supervisorNode.UserRPC()} case supernodeID != nil: supernode, ok := orch.supernodes.Get(*supernodeID) @@ -140,9 +137,8 @@ func WithProposerPostDeploy(orch *Orchestrator, proposerID stack.L2ProposerID, l proposerCLIConfig.SuperNodeRpcs = []string{supernode.UserRPC()} default: require.NotNil(l2CLID, "need L2 CL to connect to when no supervisor") - l2CLComponent, ok := orch.registry.Get(stack.ConvertL2CLNodeID(*l2CLID).ComponentID) - require.True(ok, "L2 CL not found") - l2CL := l2CLComponent.(L2CLNode) + l2CL, ok := orch.GetL2CL(*l2CLID) + require.True(ok) proposerCLIConfig.RollupRpc = l2CL.UserRPC() } @@ -163,5 +159,5 @@ func WithProposerPostDeploy(orch *Orchestrator, proposerID stack.L2ProposerID, l service: proposer, userRPC: proposer.HTTPEndpoint(), } - orch.registry.Register(stack.ConvertL2ProposerID(proposerID).ComponentID, prop) + orch.registry.Register(proposerID, prop) } diff --git a/op-devstack/sysgo/op_rbuilder.go b/op-devstack/sysgo/op_rbuilder.go index 69b0ea1d0e0..b77bfbf0f3f 100644 --- a/op-devstack/sysgo/op_rbuilder.go +++ b/op-devstack/sysgo/op_rbuilder.go @@ -25,7 +25,7 @@ import ( type OPRBuilderNode struct { mu sync.Mutex - id stack.OPRBuilderNodeID + id stack.ComponentID rollupCfg *rollup.Config wsProxyURL string @@ -251,7 +251,7 @@ func (cfg *OPRBuilderNodeConfig) LaunchSpec(p devtest.P) (args []string, env []s } type OPRBuilderNodeOption interface { - Apply(p devtest.P, id stack.OPRBuilderNodeID, cfg *OPRBuilderNodeConfig) + Apply(p devtest.P, id stack.ComponentID, cfg *OPRBuilderNodeConfig) } func WithGlobalOPRBuilderNodeOption(opt OPRBuilderNodeOption) stack.Option[*Orchestrator] { @@ -260,11 +260,11 @@ func WithGlobalOPRBuilderNodeOption(opt OPRBuilderNodeOption) stack.Option[*Orch }) } -type OPRBuilderNodeOptionFn func(p devtest.P, id stack.OPRBuilderNodeID, cfg *OPRBuilderNodeConfig) +type OPRBuilderNodeOptionFn func(p devtest.P, id stack.ComponentID, cfg *OPRBuilderNodeConfig) var _ OPRBuilderNodeOption = OPRBuilderNodeOptionFn(nil) -func (fn OPRBuilderNodeOptionFn) Apply(p devtest.P, id stack.OPRBuilderNodeID, cfg *OPRBuilderNodeConfig) { +func (fn OPRBuilderNodeOptionFn) Apply(p devtest.P, id stack.ComponentID, cfg *OPRBuilderNodeConfig) { fn(p, id, cfg) } @@ -273,7 +273,7 @@ type OPRBuilderNodeOptionBundle []OPRBuilderNodeOption var _ OPRBuilderNodeOption = OPRBuilderNodeOptionBundle(nil) -func (b OPRBuilderNodeOptionBundle) Apply(p devtest.P, id stack.OPRBuilderNodeID, cfg *OPRBuilderNodeConfig) { +func (b OPRBuilderNodeOptionBundle) Apply(p devtest.P, id stack.ComponentID, cfg *OPRBuilderNodeConfig) { for _, opt := range b { p.Require().NotNil(opt, "cannot Apply nil OPRBuilderNodeOption") opt.Apply(p, id, cfg) @@ -282,7 +282,7 @@ func (b OPRBuilderNodeOptionBundle) Apply(p devtest.P, id stack.OPRBuilderNodeID // OPRBuilderWithP2PConfig sets deterministic P2P identity and static peers for the builder EL. func OPRBuilderWithP2PConfig(addr string, port int, nodeKeyHex string, staticPeers, trustedPeers []string) OPRBuilderNodeOption { - return OPRBuilderNodeOptionFn(func(p devtest.P, id stack.OPRBuilderNodeID, cfg *OPRBuilderNodeConfig) { + return OPRBuilderNodeOptionFn(func(p devtest.P, id stack.ComponentID, cfg *OPRBuilderNodeConfig) { cfg.P2PAddr = addr cfg.P2PPort = port cfg.P2PNodeKeyHex = nodeKeyHex @@ -293,7 +293,7 @@ func OPRBuilderWithP2PConfig(addr string, port int, nodeKeyHex string, staticPee // OPRBuilderWithNodeIdentity applies an ELNodeIdentity directly to the builder EL. func OPRBuilderWithNodeIdentity(identity *ELNodeIdentity, addr string, staticPeers, trustedPeers []string) OPRBuilderNodeOption { - return OPRBuilderNodeOptionFn(func(p devtest.P, id stack.OPRBuilderNodeID, cfg *OPRBuilderNodeConfig) { + return OPRBuilderNodeOptionFn(func(p devtest.P, id stack.ComponentID, cfg *OPRBuilderNodeConfig) { cfg.P2PAddr = addr cfg.P2PPort = identity.Port cfg.P2PNodeKeyHex = identity.KeyHex() @@ -303,13 +303,13 @@ func OPRBuilderWithNodeIdentity(identity *ELNodeIdentity, addr string, staticPee } func OPRBuilderNodeWithExtraArgs(args ...string) OPRBuilderNodeOption { - return OPRBuilderNodeOptionFn(func(p devtest.P, id stack.OPRBuilderNodeID, cfg *OPRBuilderNodeConfig) { + return OPRBuilderNodeOptionFn(func(p devtest.P, id stack.ComponentID, cfg *OPRBuilderNodeConfig) { cfg.ExtraArgs = append(cfg.ExtraArgs, args...) }) } func OPRBuilderNodeWithEnv(env ...string) OPRBuilderNodeOption { - return OPRBuilderNodeOptionFn(func(p devtest.P, id stack.OPRBuilderNodeID, cfg *OPRBuilderNodeConfig) { + return OPRBuilderNodeOptionFn(func(p devtest.P, id stack.ComponentID, cfg *OPRBuilderNodeConfig) { cfg.Env = append(cfg.Env, env...) }) } @@ -336,7 +336,7 @@ func (b *OPRBuilderNode) hydrate(system stack.ExtensibleSystem) { RollupCfg: b.rollupCfg, FlashblocksClient: wsClient, }) - system.L2Network(stack.L2NetworkID(b.id.ChainID())).(stack.ExtensibleL2Network).AddOPRBuilderNode(node) + system.L2Network(stack.ByID[stack.L2Network](stack.NewL2NetworkID(b.id.ChainID()))).(stack.ExtensibleL2Network).AddOPRBuilderNode(node) } func (b *OPRBuilderNode) Start() { @@ -480,12 +480,11 @@ func (b *OPRBuilderNode) Stop() { } // WithOPRBuilderNode constructs and starts an OPRbuilderNode using the provided options. -func WithOPRBuilderNode(id stack.OPRBuilderNodeID, opts ...OPRBuilderNodeOption) stack.Option[*Orchestrator] { +func WithOPRBuilderNode(id stack.ComponentID, opts ...OPRBuilderNodeOption) stack.Option[*Orchestrator] { return stack.AfterDeploy(func(orch *Orchestrator) { p := orch.P().WithCtx(stack.ContextWithID(orch.P().Ctx(), id)) - l2NetComponent, ok := orch.registry.Get(stack.ConvertL2NetworkID(stack.L2NetworkID(id.ChainID())).ComponentID) + l2Net, ok := orch.GetL2Network(stack.NewL2NetworkID(id.ChainID())) p.Require().True(ok, "l2 network required") - l2Net := l2NetComponent.(*L2Network) tempDir := p.TempDir() data, err := json.Marshal(l2Net.genesis) @@ -510,7 +509,7 @@ func WithOPRBuilderNode(id stack.OPRBuilderNodeID, opts ...OPRBuilderNodeOption) p.Logger().Info("Starting OPRbuilderNode") rb.Start() p.Cleanup(rb.Stop) - orch.registry.Register(stack.ConvertOPRBuilderNodeID(id).ComponentID, rb) + orch.registry.Register(id, rb) }) } diff --git a/op-devstack/sysgo/orchestrator.go b/op-devstack/sysgo/orchestrator.go index 28c61738f41..42929cc4513 100644 --- a/op-devstack/sysgo/orchestrator.go +++ b/op-devstack/sysgo/orchestrator.go @@ -41,8 +41,8 @@ type Orchestrator struct { // Unified component registry - replaces the 15 separate locks.RWMap fields registry *stack.Registry - // supernodes is stored separately because SupernodeID cannot be converted to ComponentID - supernodes locks.RWMap[stack.SupernodeID, *SuperNode] + // supernodes are stored separately from the registry and hydrated explicitly. + supernodes locks.RWMap[stack.ComponentID, *SuperNode] // service name => prometheus endpoints to scrape l2MetricsEndpoints locks.RWMap[string, []PrometheusMetricsTarget] @@ -85,19 +85,11 @@ func (o *Orchestrator) EnableTimeTravel() { } } -// GetL2EL retrieves an L2 EL node by its ID from the registry. -// Supports polymorphic lookup: if the ID was converted from another L2EL-capable type -// (e.g., OPRBuilderNodeID), searches across all L2EL-capable kinds using same key/chainID. -func (o *Orchestrator) GetL2EL(id stack.L2ELNodeID) (L2ELNode, bool) { - for _, kind := range stack.L2ELCapableKinds() { - cid := stack.NewComponentID(kind, id.Key(), id.ChainID()) - if component, ok := o.registry.Get(cid); ok { - if el, ok := component.(L2ELNode); ok { - return el, true - } - } - } - return nil, false +// GetL2EL returns the component at the exact ID if it implements L2ELNode. +// This supports polymorphism via interface implementation (e.g. OpGeth, OpReth, +// RollupBoostNode, OPRBuilderNode), but does not rewrite IDs across kinds. +func (o *Orchestrator) GetL2EL(id stack.ComponentID) (L2ELNode, bool) { + return stack.RegistryGet[L2ELNode](o.registry, id) } var _ stack.Orchestrator = (*Orchestrator)(nil) @@ -146,7 +138,7 @@ func (o *Orchestrator) Hydrate(sys stack.ExtensibleSystem) { }) } - o.supernodes.Range(rangeHydrateFn[stack.SupernodeID, *SuperNode](sys)) + o.supernodes.Range(rangeHydrateFn[stack.ComponentID, *SuperNode](sys)) if o.syncTester != nil { o.syncTester.hydrate(sys) @@ -155,7 +147,7 @@ func (o *Orchestrator) Hydrate(sys stack.ExtensibleSystem) { o.sysHook.PostHydrate(sys) } -func (o *Orchestrator) RegisterL2MetricsTargets(id stack.IDWithChain, endpoints ...PrometheusMetricsTarget) { +func (o *Orchestrator) RegisterL2MetricsTargets(id stack.Keyed, endpoints ...PrometheusMetricsTarget) { wasSet := o.l2MetricsEndpoints.SetIfMissing(id.Key(), endpoints) if !wasSet { existing, _ := o.l2MetricsEndpoints.Get(id.Key()) diff --git a/op-devstack/sysgo/orchestrator_getters.go b/op-devstack/sysgo/orchestrator_getters.go new file mode 100644 index 00000000000..19dd2e57002 --- /dev/null +++ b/op-devstack/sysgo/orchestrator_getters.go @@ -0,0 +1,48 @@ +package sysgo + +import "github.com/ethereum-optimism/optimism/op-devstack/stack" + +// GetL1Network returns an L1 network by ID. +func (o *Orchestrator) GetL1Network(id stack.ComponentID) (*L1Network, bool) { + return stack.RegistryGet[*L1Network](o.registry, id) +} + +// GetL2Network returns an L2 network by ID. +func (o *Orchestrator) GetL2Network(id stack.ComponentID) (*L2Network, bool) { + return stack.RegistryGet[*L2Network](o.registry, id) +} + +// GetCluster returns a cluster by ID. +func (o *Orchestrator) GetCluster(id stack.ComponentID) (*Cluster, bool) { + return stack.RegistryGet[*Cluster](o.registry, id) +} + +// GetL1EL returns an L1 execution node by ID. +func (o *Orchestrator) GetL1EL(id stack.ComponentID) (L1ELNode, bool) { + return stack.RegistryGet[L1ELNode](o.registry, id) +} + +// GetL1CL returns an L1 consensus node by ID. +func (o *Orchestrator) GetL1CL(id stack.ComponentID) (*L1CLNode, bool) { + return stack.RegistryGet[*L1CLNode](o.registry, id) +} + +// GetL2CL returns an L2 consensus node by ID. +func (o *Orchestrator) GetL2CL(id stack.ComponentID) (L2CLNode, bool) { + return stack.RegistryGet[L2CLNode](o.registry, id) +} + +// GetSupervisor returns a supervisor by ID. +func (o *Orchestrator) GetSupervisor(id stack.ComponentID) (Supervisor, bool) { + return stack.RegistryGet[Supervisor](o.registry, id) +} + +// GetOPRBuilder returns an OPR builder node by ID. +func (o *Orchestrator) GetOPRBuilder(id stack.ComponentID) (*OPRBuilderNode, bool) { + return stack.RegistryGet[*OPRBuilderNode](o.registry, id) +} + +// GetRollupBoost returns a rollup-boost node by ID. +func (o *Orchestrator) GetRollupBoost(id stack.ComponentID) (*RollupBoostNode, bool) { + return stack.RegistryGet[*RollupBoostNode](o.registry, id) +} diff --git a/op-devstack/sysgo/rollup_boost.go b/op-devstack/sysgo/rollup_boost.go index 12246cadca2..2585920b6ce 100644 --- a/op-devstack/sysgo/rollup_boost.go +++ b/op-devstack/sysgo/rollup_boost.go @@ -24,7 +24,7 @@ import ( type RollupBoostNode struct { mu sync.Mutex - id stack.RollupBoostNodeID + id stack.ComponentID wsProxyURL string wsProxy *tcpproxy.Proxy @@ -65,10 +65,10 @@ func (r *RollupBoostNode) hydrate(system stack.ExtensibleSystem) { Client: elRPC, ChainID: r.id.ChainID(), }, - RollupCfg: system.L2Network(stack.L2NetworkID(r.id.ChainID())).RollupConfig(), + RollupCfg: system.L2Network(stack.ByID[stack.L2Network](stack.NewL2NetworkID(r.id.ChainID()))).RollupConfig(), FlashblocksClient: wsClient, }) - system.L2Network(stack.L2NetworkID(r.id.ChainID())).(stack.ExtensibleL2Network).AddRollupBoostNode(node) + system.L2Network(stack.ByID[stack.L2Network](stack.NewL2NetworkID(r.id.ChainID()))).(stack.ExtensibleL2Network).AddRollupBoostNode(node) } func (r *RollupBoostNode) Start() { @@ -177,7 +177,7 @@ func (r *RollupBoostNode) Stop() { // WithRollupBoost starts a rollup-boost process using the provided options // and registers a WSClient on the target L2 chain. // l2ELID is required to link the proxy to the L2 EL it serves. -func WithRollupBoost(id stack.RollupBoostNodeID, l2ELID stack.L2ELNodeID, opts ...RollupBoostOption) stack.Option[*Orchestrator] { +func WithRollupBoost(id stack.ComponentID, l2ELID stack.ComponentID, opts ...RollupBoostOption) stack.Option[*Orchestrator] { return stack.AfterDeploy(func(orch *Orchestrator) { p := orch.P().WithCtx(stack.ContextWithID(orch.P().Ctx(), id)) logger := p.Logger() @@ -209,7 +209,7 @@ func WithRollupBoost(id stack.RollupBoostNodeID, l2ELID stack.L2ELNodeID, opts . // Apply any node-level link options for _, opt := range opts { if linkOpt, ok := opt.(interface { - applyNode(p devtest.P, id stack.RollupBoostNodeID, r *RollupBoostNode) + applyNode(p devtest.P, id stack.ComponentID, r *RollupBoostNode) }); ok { linkOpt.applyNode(p, id, r) } @@ -218,7 +218,7 @@ func WithRollupBoost(id stack.RollupBoostNodeID, l2ELID stack.L2ELNodeID, opts . r.Start() p.Cleanup(r.Stop) // Register for hydration - orch.registry.Register(stack.ConvertRollupBoostNodeID(id).ComponentID, r) + orch.registry.Register(id, r) }) } @@ -355,14 +355,14 @@ func (cfg *RollupBoostConfig) LaunchSpec(p devtest.P) (args []string, env []stri } type RollupBoostOption interface { - Apply(orch *Orchestrator, id stack.RollupBoostNodeID, cfg *RollupBoostConfig) + Apply(orch *Orchestrator, id stack.ComponentID, cfg *RollupBoostConfig) } -type RollupBoostOptionFn func(orch *Orchestrator, id stack.RollupBoostNodeID, cfg *RollupBoostConfig) +type RollupBoostOptionFn func(orch *Orchestrator, id stack.ComponentID, cfg *RollupBoostConfig) var _ RollupBoostOption = RollupBoostOptionFn(nil) -func (fn RollupBoostOptionFn) Apply(orch *Orchestrator, id stack.RollupBoostNodeID, cfg *RollupBoostConfig) { +func (fn RollupBoostOptionFn) Apply(orch *Orchestrator, id stack.ComponentID, cfg *RollupBoostConfig) { fn(orch, id, cfg) } @@ -370,7 +370,7 @@ type RollupBoostOptionBundle []RollupBoostOption var _ RollupBoostOption = RollupBoostOptionBundle(nil) -func (b RollupBoostOptionBundle) Apply(orch *Orchestrator, id stack.RollupBoostNodeID, cfg *RollupBoostConfig) { +func (b RollupBoostOptionBundle) Apply(orch *Orchestrator, id stack.ComponentID, cfg *RollupBoostConfig) { for _, opt := range b { orch.P().Require().NotNil(opt, "cannot Apply nil RollupBoostOption") opt.Apply(orch, id, cfg) @@ -379,30 +379,29 @@ func (b RollupBoostOptionBundle) Apply(orch *Orchestrator, id stack.RollupBoostN // Convenience options func RollupBoostWithExecutionMode(mode string) RollupBoostOption { - return RollupBoostOptionFn(func(orch *Orchestrator, id stack.RollupBoostNodeID, cfg *RollupBoostConfig) { + return RollupBoostOptionFn(func(orch *Orchestrator, id stack.ComponentID, cfg *RollupBoostConfig) { cfg.ExecutionMode = mode }) } func RollupBoostWithEnv(env ...string) RollupBoostOption { - return RollupBoostOptionFn(func(orch *Orchestrator, id stack.RollupBoostNodeID, cfg *RollupBoostConfig) { + return RollupBoostOptionFn(func(orch *Orchestrator, id stack.ComponentID, cfg *RollupBoostConfig) { cfg.Env = append(cfg.Env, env...) }) } func RollupBoostWithExtraArgs(args ...string) RollupBoostOption { - return RollupBoostOptionFn(func(orch *Orchestrator, id stack.RollupBoostNodeID, cfg *RollupBoostConfig) { + return RollupBoostOptionFn(func(orch *Orchestrator, id stack.ComponentID, cfg *RollupBoostConfig) { cfg.ExtraArgs = append(cfg.ExtraArgs, args...) }) } -func RollupBoostWithBuilderNode(id stack.OPRBuilderNodeID) RollupBoostOption { - return RollupBoostOptionFn(func(orch *Orchestrator, rbID stack.RollupBoostNodeID, cfg *RollupBoostConfig) { - builderComponent, ok := orch.registry.Get(stack.ConvertOPRBuilderNodeID(id).ComponentID) +func RollupBoostWithBuilderNode(id stack.ComponentID) RollupBoostOption { + return RollupBoostOptionFn(func(orch *Orchestrator, rbID stack.ComponentID, cfg *RollupBoostConfig) { + builderNode, ok := orch.GetOPRBuilder(id) if !ok { orch.P().Require().FailNow("builder node not found") } - builderNode := builderComponent.(*OPRBuilderNode) cfg.BuilderURL = ensureHTTPURL(builderNode.authProxyURL) cfg.BuilderJWTPath = builderNode.cfg.AuthRPCJWTPath cfg.FlashblocksBuilderURL = builderNode.wsProxyURL @@ -410,7 +409,7 @@ func RollupBoostWithBuilderNode(id stack.OPRBuilderNodeID) RollupBoostOption { } func RollupBoostWithFlashblocksDisabled() RollupBoostOption { - return RollupBoostOptionFn(func(orch *Orchestrator, id stack.RollupBoostNodeID, cfg *RollupBoostConfig) { + return RollupBoostOptionFn(func(orch *Orchestrator, id stack.ComponentID, cfg *RollupBoostConfig) { cfg.EnableFlashblocks = false }) } diff --git a/op-devstack/sysgo/superchain.go b/op-devstack/sysgo/superchain.go index 6570b234572..ff421c88e03 100644 --- a/op-devstack/sysgo/superchain.go +++ b/op-devstack/sysgo/superchain.go @@ -22,7 +22,7 @@ func (d *SuperchainDeployment) ProtocolVersionsAddr() common.Address { } type Superchain struct { - id stack.SuperchainID + id stack.ComponentID deployment *SuperchainDeployment } diff --git a/op-devstack/sysgo/superroot.go b/op-devstack/sysgo/superroot.go index bd19fdd7f37..7c05b3f1ea9 100644 --- a/op-devstack/sysgo/superroot.go +++ b/op-devstack/sysgo/superroot.go @@ -48,19 +48,19 @@ type MigrateInputV2 struct { StartingRespectedGameType uint32 } -func WithSuperRoots(l1ChainID eth.ChainID, l1ELID stack.L1ELNodeID, clIDs []stack.L2CLNodeID, supervisorID stack.SupervisorID, primaryL2 eth.ChainID) stack.Option[*Orchestrator] { +func WithSuperRoots(l1ChainID eth.ChainID, l1ELID stack.ComponentID, clIDs []stack.ComponentID, supervisorID stack.ComponentID, primaryL2 eth.ChainID) stack.Option[*Orchestrator] { return withSuperRoots(l1ChainID, l1ELID, clIDs, primaryL2, func(t devtest.CommonT, o *Orchestrator, timestamp uint64) eth.Bytes32 { return getSuperRoot(t, o, timestamp, supervisorID) }) } -func WithSuperRootsFromSupernode(l1ChainID eth.ChainID, l1ELID stack.L1ELNodeID, clIDs []stack.L2CLNodeID, supernodeID stack.SupernodeID, primaryL2 eth.ChainID) stack.Option[*Orchestrator] { +func WithSuperRootsFromSupernode(l1ChainID eth.ChainID, l1ELID stack.ComponentID, clIDs []stack.ComponentID, supernodeID stack.SupernodeID, primaryL2 eth.ChainID) stack.Option[*Orchestrator] { return withSuperRoots(l1ChainID, l1ELID, clIDs, primaryL2, func(t devtest.CommonT, o *Orchestrator, timestamp uint64) eth.Bytes32 { return getSuperRootFromSupernode(t, o, timestamp, supernodeID) }) } -func withSuperRoots(l1ChainID eth.ChainID, l1ELID stack.L1ELNodeID, clIDs []stack.L2CLNodeID, primaryL2 eth.ChainID, getSuperRootAtTimestamp func(t devtest.CommonT, o *Orchestrator, timestamp uint64) eth.Bytes32) stack.Option[*Orchestrator] { +func withSuperRoots(l1ChainID eth.ChainID, l1ELID stack.ComponentID, clIDs []stack.ComponentID, primaryL2 eth.ChainID, getSuperRootAtTimestamp func(t devtest.CommonT, o *Orchestrator, timestamp uint64) eth.Bytes32) stack.Option[*Orchestrator] { return stack.FnOption[*Orchestrator]{ FinallyFn: func(o *Orchestrator) { t := o.P() @@ -68,9 +68,8 @@ func withSuperRoots(l1ChainID eth.ChainID, l1ELID stack.L1ELNodeID, clIDs []stac require.NotNil(o.wb, "must have a world builder") require.NotEmpty(o.wb.output.ImplementationsDeployment.OpcmImpl, "must have an OPCM implementation") - l1ELComponent, ok := o.registry.Get(stack.ConvertL1ELNodeID(l1ELID).ComponentID) + l1EL, ok := o.GetL1EL(l1ELID) require.True(ok, "must have L1 EL node") - l1EL := l1ELComponent.(L1ELNode) rpcClient, err := rpc.DialContext(t.Ctx(), l1EL.UserRPC()) require.NoError(err) client := ethclient.NewClient(rpcClient) @@ -80,9 +79,8 @@ func withSuperRoots(l1ChainID eth.ChainID, l1ELID stack.L1ELNodeID, clIDs []stac // Supernode does not support super roots at genesis. // So let's wait for safe heads to advance before querying atTimestamp. for _, clID := range clIDs { - l2CLComponent, ok := o.registry.Get(stack.ConvertL2CLNodeID(clID).ComponentID) + l2CL, ok := o.GetL2CL(clID) require.True(ok, "must have L2 CL node") - l2CL := l2CLComponent.(L2CLNode) // TODO(#18947): Ideally, we should be able to wait on the supernode's SyncStatus directly // rather than check the sync statuses of all CLs rollupClient, err := dial.DialRollupClientWithTimeout(t.Ctx(), t.Logger(), l2CL.UserRPC()) @@ -287,10 +285,9 @@ func deployDelegateCallProxy(t devtest.CommonT, transactOpts *bind.TransactOpts, return deployAddress, proxyContract } -func getSuperRoot(t devtest.CommonT, o *Orchestrator, timestamp uint64, supervisorID stack.SupervisorID) eth.Bytes32 { - supervisorComponent, ok := o.registry.Get(stack.ConvertSupervisorID(supervisorID).ComponentID) +func getSuperRoot(t devtest.CommonT, o *Orchestrator, timestamp uint64, supervisorID stack.ComponentID) eth.Bytes32 { + supervisor, ok := o.GetSupervisor(supervisorID) t.Require().True(ok, "must have supervisor") - supervisor := supervisorComponent.(Supervisor) client, err := dial.DialSupervisorClientWithTimeout(t.Ctx(), t.Logger(), supervisor.UserRPC()) t.Require().NoError(err) diff --git a/op-devstack/sysgo/supervisor.go b/op-devstack/sysgo/supervisor.go index ca74091f27c..08b8d37e2a9 100644 --- a/op-devstack/sysgo/supervisor.go +++ b/op-devstack/sysgo/supervisor.go @@ -15,7 +15,7 @@ type Supervisor interface { UserRPC() string } -func WithSupervisor(supervisorID stack.SupervisorID, clusterID stack.ClusterID, l1ELID stack.L1ELNodeID) stack.Option[*Orchestrator] { +func WithSupervisor(supervisorID stack.ComponentID, clusterID stack.ComponentID, l1ELID stack.ComponentID) stack.Option[*Orchestrator] { switch os.Getenv("DEVSTACK_SUPERVISOR_KIND") { case "kona": return WithKonaSupervisor(supervisorID, clusterID, l1ELID) @@ -24,18 +24,16 @@ func WithSupervisor(supervisorID stack.SupervisorID, clusterID stack.ClusterID, } } -func WithManagedBySupervisor(l2CLID stack.L2CLNodeID, supervisorID stack.SupervisorID) stack.Option[*Orchestrator] { +func WithManagedBySupervisor(l2CLID stack.ComponentID, supervisorID stack.ComponentID) stack.Option[*Orchestrator] { return stack.AfterDeploy(func(orch *Orchestrator) { require := orch.P().Require() - l2CLComponent, ok := orch.registry.Get(stack.ConvertL2CLNodeID(l2CLID).ComponentID) + l2CL, ok := orch.GetL2CL(l2CLID) require.True(ok, "looking for L2 CL node to connect to supervisor") - l2CL := l2CLComponent.(L2CLNode) interopEndpoint, secret := l2CL.InteropRPC() - supComponent, ok := orch.registry.Get(stack.ConvertSupervisorID(supervisorID).ComponentID) + s, ok := orch.GetSupervisor(supervisorID) require.True(ok, "looking for supervisor") - s := supComponent.(Supervisor) ctx := orch.P().Ctx() supClient, err := dial.DialSupervisorClientWithTimeout(ctx, orch.P().Logger(), s.UserRPC(), client.WithLazyDial()) diff --git a/op-devstack/sysgo/supervisor_kona.go b/op-devstack/sysgo/supervisor_kona.go index fa9d9387c2d..8ae222b4c5c 100644 --- a/op-devstack/sysgo/supervisor_kona.go +++ b/op-devstack/sysgo/supervisor_kona.go @@ -17,7 +17,7 @@ import ( type KonaSupervisor struct { mu sync.Mutex - id stack.SupervisorID + id stack.ComponentID userRPC string userProxy *tcpproxy.Proxy @@ -114,18 +114,16 @@ func (s *KonaSupervisor) Stop() { s.sub = nil } -func WithKonaSupervisor(supervisorID stack.SupervisorID, clusterID stack.ClusterID, l1ELID stack.L1ELNodeID) stack.Option[*Orchestrator] { +func WithKonaSupervisor(supervisorID stack.ComponentID, clusterID stack.ComponentID, l1ELID stack.ComponentID) stack.Option[*Orchestrator] { return stack.AfterDeploy(func(orch *Orchestrator) { p := orch.P().WithCtx(stack.ContextWithID(orch.P().Ctx(), supervisorID)) require := p.Require() - l1ELComponent, ok := orch.registry.Get(stack.ConvertL1ELNodeID(l1ELID).ComponentID) + l1EL, ok := orch.GetL1EL(l1ELID) require.True(ok, "need L1 EL node to connect supervisor to") - l1EL := l1ELComponent.(L1ELNode) - clusterComponent, ok := orch.registry.Get(stack.ConvertClusterID(clusterID).ComponentID) + cluster, ok := orch.GetCluster(clusterID) require.True(ok, "need cluster to determine dependency set") - cluster := clusterComponent.(*Cluster) require.NotNil(cluster.cfgset, "need a full config set") require.NoError(cluster.cfgset.CheckChains(), "config set must be valid") @@ -141,8 +139,8 @@ func WithKonaSupervisor(supervisorID stack.SupervisorID, clusterID stack.Cluster rollupCfgPath := cfgDir + "/rollup-config-*.json" for _, l2NetID := range orch.registry.IDsByKind(stack.KindL2Network) { - l2NetComponent, _ := orch.registry.Get(l2NetID) - l2Net := l2NetComponent.(*L2Network) + l2Net, ok := orch.GetL2Network(l2NetID) + require.True(ok, "need l2 network") chainID := l2Net.id.ChainID() rollupData, err := json.Marshal(l2Net.rollupCfg) require.NoError(err, "failed to marshal rollup config") @@ -178,7 +176,7 @@ func WithKonaSupervisor(supervisorID stack.SupervisorID, clusterID stack.Cluster env: envVars, p: p, } - orch.registry.Register(stack.ConvertSupervisorID(supervisorID).ComponentID, konaSupervisor) + orch.registry.Register(supervisorID, konaSupervisor) p.Logger().Info("Starting kona-supervisor") konaSupervisor.Start() p.Cleanup(konaSupervisor.Stop) diff --git a/op-devstack/sysgo/supervisor_op.go b/op-devstack/sysgo/supervisor_op.go index d7b867da896..e7ffe9c0eaa 100644 --- a/op-devstack/sysgo/supervisor_op.go +++ b/op-devstack/sysgo/supervisor_op.go @@ -24,7 +24,7 @@ import ( type OpSupervisor struct { mu sync.Mutex - id stack.SupervisorID + id stack.ComponentID userRPC string cfg *supervisorConfig.Config @@ -99,18 +99,16 @@ func (s *OpSupervisor) Stop() { s.service = nil } -func WithOPSupervisor(supervisorID stack.SupervisorID, clusterID stack.ClusterID, l1ELID stack.L1ELNodeID) stack.Option[*Orchestrator] { +func WithOPSupervisor(supervisorID stack.ComponentID, clusterID stack.ComponentID, l1ELID stack.ComponentID) stack.Option[*Orchestrator] { return stack.AfterDeploy(func(orch *Orchestrator) { p := orch.P().WithCtx(stack.ContextWithID(orch.P().Ctx(), supervisorID)) require := p.Require() - l1ELComponent, ok := orch.registry.Get(stack.ConvertL1ELNodeID(l1ELID).ComponentID) + l1EL, ok := orch.GetL1EL(l1ELID) require.True(ok, "need L1 EL node to connect supervisor to") - l1EL := l1ELComponent.(L1ELNode) - clusterComponent, ok := orch.registry.Get(stack.ConvertClusterID(clusterID).ComponentID) + cluster, ok := orch.GetCluster(clusterID) require.True(ok, "need cluster to determine dependency set") - cluster := clusterComponent.(*Cluster) require.NotNil(cluster.cfgset, "need a full config set") require.NoError(cluster.cfgset.CheckChains(), "config set must be valid") @@ -153,7 +151,7 @@ func WithOPSupervisor(supervisorID stack.SupervisorID, clusterID stack.ClusterID logger: plog, service: nil, // set on start } - orch.registry.Register(stack.ConvertSupervisorID(supervisorID).ComponentID, supervisorNode) + orch.registry.Register(supervisorID, supervisorNode) supervisorNode.Start() orch.p.Cleanup(supervisorNode.Stop) }) diff --git a/op-devstack/sysgo/sync_tester.go b/op-devstack/sysgo/sync_tester.go index 144f736921f..185f3618bb2 100644 --- a/op-devstack/sysgo/sync_tester.go +++ b/op-devstack/sysgo/sync_tester.go @@ -20,7 +20,7 @@ import ( // Caveat: id is binded by a single EL(chainID), but service can support multiple ELs type SyncTesterService struct { - id stack.SyncTesterID + id stack.ComponentID service *synctester.Service } @@ -44,7 +44,7 @@ func (n *SyncTesterService) hydrate(system stack.ExtensibleSystem) { } } -func WithSyncTester(syncTesterID stack.SyncTesterID, l2ELs []stack.L2ELNodeID) stack.Option[*Orchestrator] { +func WithSyncTester(syncTesterID stack.ComponentID, l2ELs []stack.ComponentID) stack.Option[*Orchestrator] { return stack.AfterDeploy(func(orch *Orchestrator) { p := orch.P().WithCtx(stack.ContextWithID(orch.P().Ctx(), syncTesterID)) @@ -90,7 +90,7 @@ func WithSyncTester(syncTesterID stack.SyncTesterID, l2ELs []stack.L2ELNodeID) s }) } -func WithSyncTesterWithExternalEndpoint(syncTesterID stack.SyncTesterID, endpointRPC string, chainID eth.ChainID) stack.Option[*Orchestrator] { +func WithSyncTesterWithExternalEndpoint(syncTesterID stack.ComponentID, endpointRPC string, chainID eth.ChainID) stack.Option[*Orchestrator] { return stack.AfterDeploy(func(orch *Orchestrator) { p := orch.P().WithCtx(stack.ContextWithID(orch.P().Ctx(), syncTesterID)) diff --git a/op-devstack/sysgo/system.go b/op-devstack/sysgo/system.go index 54ef3252edb..71cc861e60b 100644 --- a/op-devstack/sysgo/system.go +++ b/op-devstack/sysgo/system.go @@ -14,27 +14,27 @@ var ( ) type DefaultMinimalSystemIDs struct { - L1 stack.L1NetworkID - L1EL stack.L1ELNodeID - L1CL stack.L1CLNodeID + L1 stack.ComponentID + L1EL stack.ComponentID + L1CL stack.ComponentID - L2 stack.L2NetworkID - L2CL stack.L2CLNodeID - L2EL stack.L2ELNodeID + L2 stack.ComponentID + L2CL stack.ComponentID + L2EL stack.ComponentID - L2Batcher stack.L2BatcherID - L2Proposer stack.L2ProposerID - L2Challenger stack.L2ChallengerID + L2Batcher stack.ComponentID + L2Proposer stack.ComponentID + L2Challenger stack.ComponentID - TestSequencer stack.TestSequencerID + TestSequencer stack.ComponentID } func NewDefaultMinimalSystemIDs(l1ID, l2ID eth.ChainID) DefaultMinimalSystemIDs { ids := DefaultMinimalSystemIDs{ - L1: stack.L1NetworkID(l1ID), + L1: stack.NewL1NetworkID(l1ID), L1EL: stack.NewL1ELNodeID("l1", l1ID), L1CL: stack.NewL1CLNodeID("l1", l1ID), - L2: stack.L2NetworkID(l2ID), + L2: stack.NewL2NetworkID(l2ID), L2CL: stack.NewL2CLNodeID("sequencer", l2ID), L2EL: stack.NewL2ELNodeID("sequencer", l2ID), L2Batcher: stack.NewL2BatcherID("main", l2ID), @@ -74,11 +74,11 @@ func defaultMinimalSystemOpts(ids *DefaultMinimalSystemIDs, dest *DefaultMinimal opt.Add(WithBatcher(ids.L2Batcher, ids.L1EL, ids.L2CL, ids.L2EL)) opt.Add(WithProposer(ids.L2Proposer, ids.L1EL, &ids.L2CL, nil)) - opt.Add(WithFaucets([]stack.L1ELNodeID{ids.L1EL}, []stack.L2ELNodeID{ids.L2EL})) + opt.Add(WithFaucets([]stack.ComponentID{ids.L1EL}, []stack.ComponentID{ids.L2EL})) opt.Add(WithTestSequencer(ids.TestSequencer, ids.L1CL, ids.L2CL, ids.L1EL, ids.L2EL)) - opt.Add(WithL2Challenger(ids.L2Challenger, ids.L1EL, ids.L1CL, nil, nil, &ids.L2CL, []stack.L2ELNodeID{ + opt.Add(WithL2Challenger(ids.L2Challenger, ids.L1EL, ids.L1CL, nil, nil, &ids.L2CL, []stack.ComponentID{ ids.L2EL, })) @@ -95,35 +95,35 @@ func defaultMinimalSystemOpts(ids *DefaultMinimalSystemIDs, dest *DefaultMinimal // without interop or supervisor: both L2s get their own ELs, and we attach L2CL nodes // via the default L2CL selector (which can be set to supernode to share a single process). type DefaultTwoL2SystemIDs struct { - L1 stack.L1NetworkID - L1EL stack.L1ELNodeID - L1CL stack.L1CLNodeID + L1 stack.ComponentID + L1EL stack.ComponentID + L1CL stack.ComponentID - L2A stack.L2NetworkID - L2ACL stack.L2CLNodeID - L2AEL stack.L2ELNodeID + L2A stack.ComponentID + L2ACL stack.ComponentID + L2AEL stack.ComponentID - L2B stack.L2NetworkID - L2BCL stack.L2CLNodeID - L2BEL stack.L2ELNodeID + L2B stack.ComponentID + L2BCL stack.ComponentID + L2BEL stack.ComponentID Supernode stack.SupernodeID - TestSequencer stack.TestSequencerID - L2ABatcher stack.L2BatcherID - L2AProposer stack.L2ProposerID - L2BBatcher stack.L2BatcherID - L2BProposer stack.L2ProposerID + TestSequencer stack.ComponentID + L2ABatcher stack.ComponentID + L2AProposer stack.ComponentID + L2BBatcher stack.ComponentID + L2BProposer stack.ComponentID } func NewDefaultTwoL2SystemIDs(l1ID, l2AID, l2BID eth.ChainID) DefaultTwoL2SystemIDs { return DefaultTwoL2SystemIDs{ - L1: stack.L1NetworkID(l1ID), + L1: stack.NewL1NetworkID(l1ID), L1EL: stack.NewL1ELNodeID("l1", l1ID), L1CL: stack.NewL1CLNodeID("l1", l1ID), - L2A: stack.L2NetworkID(l2AID), + L2A: stack.NewL2NetworkID(l2AID), L2ACL: stack.NewL2CLNodeID("sequencer", l2AID), L2AEL: stack.NewL2ELNodeID("sequencer", l2AID), - L2B: stack.L2NetworkID(l2BID), + L2B: stack.NewL2NetworkID(l2BID), L2BCL: stack.NewL2CLNodeID("sequencer", l2BID), L2BEL: stack.NewL2ELNodeID("sequencer", l2BID), Supernode: stack.NewSupernodeID("supernode-two-l2-system", l2AID, l2BID), @@ -167,7 +167,7 @@ func DefaultTwoL2System(dest *DefaultTwoL2SystemIDs) stack.Option[*Orchestrator] opt.Add(WithBatcher(ids.L2BBatcher, ids.L1EL, ids.L2BCL, ids.L2BEL)) opt.Add(WithProposer(ids.L2BProposer, ids.L1EL, &ids.L2BCL, nil)) - opt.Add(WithFaucets([]stack.L1ELNodeID{ids.L1EL}, []stack.L2ELNodeID{ids.L2AEL, ids.L2BEL})) + opt.Add(WithFaucets([]stack.ComponentID{ids.L1EL}, []stack.ComponentID{ids.L2AEL, ids.L2BEL})) opt.Add(WithL2MetricsDashboard()) @@ -212,7 +212,7 @@ func DefaultSupernodeTwoL2System(dest *DefaultTwoL2SystemIDs) stack.Option[*Orch opt.Add(WithBatcher(ids.L2BBatcher, ids.L1EL, ids.L2BCL, ids.L2BEL)) opt.Add(WithProposer(ids.L2BProposer, ids.L1EL, &ids.L2BCL, nil)) - opt.Add(WithFaucets([]stack.L1ELNodeID{ids.L1EL}, []stack.L2ELNodeID{ids.L2AEL, ids.L2BEL})) + opt.Add(WithFaucets([]stack.ComponentID{ids.L1EL}, []stack.ComponentID{ids.L2AEL, ids.L2BEL})) opt.Add(stack.Finally(func(orch *Orchestrator) { *dest = ids @@ -266,7 +266,7 @@ func DefaultSupernodeInteropTwoL2System(dest *DefaultTwoL2SystemIDs, delaySecond opt.Add(WithBatcher(ids.L2BBatcher, ids.L1EL, ids.L2BCL, ids.L2BEL)) opt.Add(WithProposer(ids.L2BProposer, ids.L1EL, &ids.L2BCL, nil)) - opt.Add(WithFaucets([]stack.L1ELNodeID{ids.L1EL}, []stack.L2ELNodeID{ids.L2AEL, ids.L2BEL})) + opt.Add(WithFaucets([]stack.ComponentID{ids.L1EL}, []stack.ComponentID{ids.L2AEL, ids.L2BEL})) // Test sequencer for deterministic block building on both L2 chains opt.Add(WithTestSequencer2L2(ids.TestSequencer, ids.L1CL, ids.L2ACL, ids.L2BCL, ids.L1EL, ids.L2AEL, ids.L2BEL)) @@ -281,7 +281,7 @@ func DefaultSupernodeInteropTwoL2System(dest *DefaultTwoL2SystemIDs, delaySecond type DefaultMinimalSystemWithSyncTesterIDs struct { DefaultMinimalSystemIDs - SyncTester stack.SyncTesterID + SyncTester stack.ComponentID } func NewDefaultMinimalSystemWithSyncTesterIDs(l1ID, l2ID eth.ChainID) DefaultMinimalSystemWithSyncTesterIDs { @@ -320,15 +320,15 @@ func DefaultMinimalSystemWithSyncTester(dest *DefaultMinimalSystemWithSyncTester opt.Add(WithBatcher(ids.L2Batcher, ids.L1EL, ids.L2CL, ids.L2EL)) opt.Add(WithProposer(ids.L2Proposer, ids.L1EL, &ids.L2CL, nil)) - opt.Add(WithFaucets([]stack.L1ELNodeID{ids.L1EL}, []stack.L2ELNodeID{ids.L2EL})) + opt.Add(WithFaucets([]stack.ComponentID{ids.L1EL}, []stack.ComponentID{ids.L2EL})) opt.Add(WithTestSequencer(ids.TestSequencer, ids.L1CL, ids.L2CL, ids.L1EL, ids.L2EL)) - opt.Add(WithL2Challenger(ids.L2Challenger, ids.L1EL, ids.L1CL, nil, nil, &ids.L2CL, []stack.L2ELNodeID{ + opt.Add(WithL2Challenger(ids.L2Challenger, ids.L1EL, ids.L1CL, nil, nil, &ids.L2CL, []stack.ComponentID{ ids.L2EL, })) - opt.Add(WithSyncTester(ids.SyncTester, []stack.L2ELNodeID{ids.L2EL})) + opt.Add(WithSyncTester(ids.SyncTester, []stack.ComponentID{ids.L2EL})) opt.Add(WithL2MetricsDashboard()) @@ -340,35 +340,35 @@ func DefaultMinimalSystemWithSyncTester(dest *DefaultMinimalSystemWithSyncTester } type DefaultSingleChainInteropSystemIDs struct { - L1 stack.L1NetworkID - L1EL stack.L1ELNodeID - L1CL stack.L1CLNodeID + L1 stack.ComponentID + L1EL stack.ComponentID + L1CL stack.ComponentID - Superchain stack.SuperchainID - Cluster stack.ClusterID + Superchain stack.ComponentID + Cluster stack.ComponentID - Supervisor stack.SupervisorID - TestSequencer stack.TestSequencerID + Supervisor stack.ComponentID + TestSequencer stack.ComponentID - L2A stack.L2NetworkID - L2ACL stack.L2CLNodeID - L2AEL stack.L2ELNodeID + L2A stack.ComponentID + L2ACL stack.ComponentID + L2AEL stack.ComponentID - L2ABatcher stack.L2BatcherID - L2AProposer stack.L2ProposerID - L2ChallengerA stack.L2ChallengerID + L2ABatcher stack.ComponentID + L2AProposer stack.ComponentID + L2ChallengerA stack.ComponentID } func NewDefaultSingleChainInteropSystemIDs(l1ID, l2AID eth.ChainID) DefaultSingleChainInteropSystemIDs { ids := DefaultSingleChainInteropSystemIDs{ - L1: stack.L1NetworkID(l1ID), + L1: stack.NewL1NetworkID(l1ID), L1EL: stack.NewL1ELNodeID("l1", l1ID), L1CL: stack.NewL1CLNodeID("l1", l1ID), - Superchain: "main", // TODO(#15244): hardcoded to match the deployer default ID - Cluster: stack.ClusterID("main"), - Supervisor: "1-primary", // prefix with number for ordering of supervisors + Superchain: stack.NewSuperchainID("main"), // TODO(#15244): hardcoded to match the deployer default ID + Cluster: stack.NewClusterID("main"), + Supervisor: stack.NewSupervisorID("1-primary"), // prefix with number for ordering of supervisors TestSequencer: stack.NewTestSequencerID("dev"), - L2A: stack.L2NetworkID(l2AID), + L2A: stack.NewL2NetworkID(l2AID), L2ACL: stack.NewL2CLNodeID("sequencer", l2AID), L2AEL: stack.NewL2ELNodeID("sequencer", l2AID), L2ABatcher: stack.NewL2BatcherID("main", l2AID), @@ -383,11 +383,11 @@ func DefaultSingleChainInteropSystem(dest *DefaultSingleChainInteropSystemIDs) s opt := stack.Combine[*Orchestrator]() opt.Add(baseInteropSystem(&ids)) - opt.Add(WithL2Challenger(ids.L2ChallengerA, ids.L1EL, ids.L1CL, &ids.Supervisor, &ids.Cluster, &ids.L2ACL, []stack.L2ELNodeID{ + opt.Add(WithL2Challenger(ids.L2ChallengerA, ids.L1EL, ids.L1CL, &ids.Supervisor, &ids.Cluster, &ids.L2ACL, []stack.ComponentID{ ids.L2AEL, })) - opt.Add(WithFaucets([]stack.L1ELNodeID{ids.L1EL}, []stack.L2ELNodeID{ids.L2AEL})) + opt.Add(WithFaucets([]stack.ComponentID{ids.L1EL}, []stack.ComponentID{ids.L2AEL})) // Upon evaluation of the option, export the contents we created. // Ids here are static, but other things may be exported too. @@ -428,7 +428,7 @@ func DefaultMinimalInteropSystem(dest *DefaultMinimalSystemIDs) stack.Option[*Or opt.Add(WithBatcher(ids.L2Batcher, ids.L1EL, ids.L2CL, ids.L2EL)) opt.Add(WithProposer(ids.L2Proposer, ids.L1EL, &ids.L2CL, nil)) - opt.Add(WithFaucets([]stack.L1ELNodeID{ids.L1EL}, []stack.L2ELNodeID{ids.L2EL})) + opt.Add(WithFaucets([]stack.ComponentID{ids.L1EL}, []stack.ComponentID{ids.L2EL})) opt.Add(WithL2MetricsDashboard()) @@ -483,19 +483,19 @@ func baseInteropSystem(ids *DefaultSingleChainInteropSystemIDs) stack.Option[*Or type DefaultInteropSystemIDs struct { DefaultSingleChainInteropSystemIDs - L2B stack.L2NetworkID - L2BCL stack.L2CLNodeID - L2BEL stack.L2ELNodeID + L2B stack.ComponentID + L2BCL stack.ComponentID + L2BEL stack.ComponentID - L2BBatcher stack.L2BatcherID - L2BProposer stack.L2ProposerID - L2ChallengerB stack.L2ChallengerID + L2BBatcher stack.ComponentID + L2BProposer stack.ComponentID + L2ChallengerB stack.ComponentID } func NewDefaultInteropSystemIDs(l1ID, l2AID, l2BID eth.ChainID) DefaultInteropSystemIDs { ids := DefaultInteropSystemIDs{ DefaultSingleChainInteropSystemIDs: NewDefaultSingleChainInteropSystemIDs(l1ID, l2AID), - L2B: stack.L2NetworkID(l2BID), + L2B: stack.NewL2NetworkID(l2BID), L2BCL: stack.NewL2CLNodeID("sequencer", l2BID), L2BEL: stack.NewL2ELNodeID("sequencer", l2BID), L2BBatcher: stack.NewL2BatcherID("main", l2BID), @@ -528,14 +528,14 @@ func DefaultInteropSystem(dest *DefaultInteropSystemIDs) stack.Option[*Orchestra // Deploy separate challengers for each chain. Can be reduced to a single challenger when the DisputeGameFactory // is actually shared. - opt.Add(WithL2Challenger(ids.L2ChallengerA, ids.L1EL, ids.L1CL, &ids.Supervisor, &ids.Cluster, &ids.L2ACL, []stack.L2ELNodeID{ + opt.Add(WithL2Challenger(ids.L2ChallengerA, ids.L1EL, ids.L1CL, &ids.Supervisor, &ids.Cluster, &ids.L2ACL, []stack.ComponentID{ ids.L2AEL, ids.L2BEL, })) - opt.Add(WithL2Challenger(ids.L2ChallengerB, ids.L1EL, ids.L1CL, &ids.Supervisor, &ids.Cluster, &ids.L2BCL, []stack.L2ELNodeID{ + opt.Add(WithL2Challenger(ids.L2ChallengerB, ids.L1EL, ids.L1CL, &ids.Supervisor, &ids.Cluster, &ids.L2BCL, []stack.ComponentID{ ids.L2BEL, ids.L2AEL, })) - opt.Add(WithFaucets([]stack.L1ELNodeID{ids.L1EL}, []stack.L2ELNodeID{ids.L2AEL, ids.L2BEL})) + opt.Add(WithFaucets([]stack.ComponentID{ids.L1EL}, []stack.ComponentID{ids.L2AEL, ids.L2BEL})) opt.Add(WithL2MetricsDashboard()) @@ -616,17 +616,17 @@ func defaultSupernodeSuperProofsSystem(dest *DefaultSupernodeInteropProofsSystem opt.Add(WithBatcher(ids.L2BBatcher, ids.L1EL, ids.L2BCL, ids.L2BEL)) // Run super roots migration using supernode as super root source - opt.Add(WithSuperRootsFromSupernode(ids.L1.ChainID(), ids.L1EL, []stack.L2CLNodeID{ids.L2ACL, ids.L2BCL}, ids.Supernode, ids.L2A.ChainID())) + opt.Add(WithSuperRootsFromSupernode(ids.L1.ChainID(), ids.L1EL, []stack.ComponentID{ids.L2ACL, ids.L2BCL}, ids.Supernode, ids.L2A.ChainID())) // Start challenger after migration; use supernode RPCs as super-roots source. - opt.Add(WithSupernodeL2Challenger(ids.L2ChallengerA, ids.L1EL, ids.L1CL, &ids.Supernode, &ids.Cluster, []stack.L2ELNodeID{ + opt.Add(WithSupernodeL2Challenger(ids.L2ChallengerA, ids.L1EL, ids.L1CL, &ids.Supernode, &ids.Cluster, []stack.ComponentID{ ids.L2BEL, ids.L2AEL, })) // Start proposer after migration; use supernode RPCs as proposal source. opt.Add(WithSupernodeProposer(ids.L2AProposer, ids.L1EL, &ids.Supernode)) - opt.Add(WithFaucets([]stack.L1ELNodeID{ids.L1EL}, []stack.L2ELNodeID{ids.L2AEL, ids.L2BEL})) + opt.Add(WithFaucets([]stack.ComponentID{ids.L1EL}, []stack.ComponentID{ids.L2AEL, ids.L2BEL})) opt.Add(WithL2MetricsDashboard()) @@ -697,17 +697,17 @@ func defaultSingleChainSupernodeSuperProofsSystem(dest *DefaultSingleChainSupern opt.Add(WithBatcher(ids.L2ABatcher, ids.L1EL, ids.L2ACL, ids.L2AEL)) // Run super roots migration using supernode as super root source - opt.Add(WithSuperRootsFromSupernode(ids.L1.ChainID(), ids.L1EL, []stack.L2CLNodeID{ids.L2ACL}, ids.Supernode, ids.L2A.ChainID())) + opt.Add(WithSuperRootsFromSupernode(ids.L1.ChainID(), ids.L1EL, []stack.ComponentID{ids.L2ACL}, ids.Supernode, ids.L2A.ChainID())) // Start challenger after migration; use supernode RPCs as super-roots source. - opt.Add(WithSupernodeL2Challenger(ids.L2ChallengerA, ids.L1EL, ids.L1CL, &ids.Supernode, &ids.Cluster, []stack.L2ELNodeID{ + opt.Add(WithSupernodeL2Challenger(ids.L2ChallengerA, ids.L1EL, ids.L1CL, &ids.Supernode, &ids.Cluster, []stack.ComponentID{ ids.L2AEL, })) // Start proposer after migration; use supernode RPCs as proposal source. opt.Add(WithSupernodeProposer(ids.L2AProposer, ids.L1EL, &ids.Supernode)) - opt.Add(WithFaucets([]stack.L1ELNodeID{ids.L1EL}, []stack.L2ELNodeID{ids.L2AEL})) + opt.Add(WithFaucets([]stack.ComponentID{ids.L1EL}, []stack.ComponentID{ids.L2AEL})) opt.Add(WithL2MetricsDashboard()) @@ -755,13 +755,13 @@ func defaultSuperProofsSystem(dest *DefaultInteropSystemIDs, deployerOpts ...Dep opt.Add(WithManagedBySupervisor(ids.L2ACL, ids.Supervisor)) opt.Add(WithManagedBySupervisor(ids.L2BCL, ids.Supervisor)) - opt.Add(WithFaucets([]stack.L1ELNodeID{ids.L1EL}, []stack.L2ELNodeID{ids.L2AEL, ids.L2BEL})) + opt.Add(WithFaucets([]stack.ComponentID{ids.L1EL}, []stack.ComponentID{ids.L2AEL, ids.L2BEL})) - opt.Add(WithSuperRoots(ids.L1.ChainID(), ids.L1EL, []stack.L2CLNodeID{ids.L2ACL, ids.L2BCL}, ids.Supervisor, ids.L2A.ChainID())) + opt.Add(WithSuperRoots(ids.L1.ChainID(), ids.L1EL, []stack.ComponentID{ids.L2ACL, ids.L2BCL}, ids.Supervisor, ids.L2A.ChainID())) opt.Add(WithSuperProposer(ids.L2AProposer, ids.L1EL, &ids.Supervisor)) - opt.Add(WithSuperL2Challenger(ids.L2ChallengerA, ids.L1EL, ids.L1CL, &ids.Supervisor, &ids.Cluster, []stack.L2ELNodeID{ + opt.Add(WithSuperL2Challenger(ids.L2ChallengerA, ids.L1EL, ids.L1CL, &ids.Supervisor, &ids.Cluster, []stack.ComponentID{ ids.L2BEL, ids.L2AEL, })) @@ -780,18 +780,18 @@ type MultiSupervisorInteropSystemIDs struct { DefaultInteropSystemIDs // Supervisor does not support multinode so need a additional supervisor for verifier nodes - SupervisorSecondary stack.SupervisorID + SupervisorSecondary stack.ComponentID - L2A2CL stack.L2CLNodeID - L2A2EL stack.L2ELNodeID - L2B2CL stack.L2CLNodeID - L2B2EL stack.L2ELNodeID + L2A2CL stack.ComponentID + L2A2EL stack.ComponentID + L2B2CL stack.ComponentID + L2B2EL stack.ComponentID } func MultiSupervisorInteropSystem(dest *MultiSupervisorInteropSystemIDs) stack.Option[*Orchestrator] { ids := MultiSupervisorInteropSystemIDs{ DefaultInteropSystemIDs: NewDefaultInteropSystemIDs(DefaultL1ID, DefaultL2AID, DefaultL2BID), - SupervisorSecondary: "2-secondary", // prefix with number for ordering of supervisors + SupervisorSecondary: stack.NewSupervisorID("2-secondary"), // prefix with number for ordering of supervisors L2A2CL: stack.NewL2CLNodeID("verifier", DefaultL2AID), L2A2EL: stack.NewL2ELNodeID("verifier", DefaultL2AID), L2B2CL: stack.NewL2CLNodeID("verifier", DefaultL2BID), @@ -841,29 +841,29 @@ func ProofSystem(dest *DefaultMinimalSystemIDs) stack.Option[*Orchestrator] { } type SingleChainSystemWithFlashblocksIDs struct { - L1 stack.L1NetworkID - L1EL stack.L1ELNodeID - L1CL stack.L1CLNodeID + L1 stack.ComponentID + L1EL stack.ComponentID + L1CL stack.ComponentID - L2 stack.L2NetworkID - L2CL stack.L2CLNodeID - L2EL stack.L2ELNodeID - L2Builder stack.OPRBuilderNodeID - L2RollupBoost stack.RollupBoostNodeID + L2 stack.ComponentID + L2CL stack.ComponentID + L2EL stack.ComponentID + L2Builder stack.ComponentID + L2RollupBoost stack.ComponentID - L2Batcher stack.L2BatcherID - L2Proposer stack.L2ProposerID - L2Challenger stack.L2ChallengerID + L2Batcher stack.ComponentID + L2Proposer stack.ComponentID + L2Challenger stack.ComponentID - TestSequencer stack.TestSequencerID + TestSequencer stack.ComponentID } func NewDefaultSingleChainSystemWithFlashblocksIDs(l1ID, l2ID eth.ChainID) SingleChainSystemWithFlashblocksIDs { ids := SingleChainSystemWithFlashblocksIDs{ - L1: stack.L1NetworkID(l1ID), + L1: stack.NewL1NetworkID(l1ID), L1EL: stack.NewL1ELNodeID("l1", l1ID), L1CL: stack.NewL1CLNodeID("l1", l1ID), - L2: stack.L2NetworkID(l2ID), + L2: stack.NewL2NetworkID(l2ID), L2CL: stack.NewL2CLNodeID("sequencer", l2ID), L2EL: stack.NewL2ELNodeID("sequencer", l2ID), L2Builder: stack.NewOPRBuilderNodeID("sequencer-builder", l2ID), @@ -906,21 +906,21 @@ func singleChainSystemWithFlashblocksOpts(ids *SingleChainSystemWithFlashblocksI opt.Add(WithL2ELNode(ids.L2EL, L2ELWithP2PConfig("127.0.0.1", seqID.Port, seqID.KeyHex(), nil, nil))) opt.Add(WithOPRBuilderNode(ids.L2Builder, OPRBuilderWithNodeIdentity(builderID, "127.0.0.1", nil, nil))) // Sequencer adds builder as regular static peer (not trusted) - opt.Add(WithL2ELP2PConnection(ids.L2EL, stack.L2ELNodeID(ids.L2Builder), false)) + opt.Add(WithL2ELP2PConnection(ids.L2EL, ids.L2Builder, false)) // Builder adds sequencer as trusted peer - opt.Add(WithL2ELP2PConnection(stack.L2ELNodeID(ids.L2Builder), ids.L2EL, true)) + opt.Add(WithL2ELP2PConnection(ids.L2Builder, ids.L2EL, true)) opt.Add(WithRollupBoost(ids.L2RollupBoost, ids.L2EL, RollupBoostWithBuilderNode(ids.L2Builder))) - opt.Add(WithL2CLNode(ids.L2CL, ids.L1CL, ids.L1EL, stack.L2ELNodeID(ids.L2RollupBoost), L2CLSequencer())) + opt.Add(WithL2CLNode(ids.L2CL, ids.L1CL, ids.L1EL, ids.L2RollupBoost, L2CLSequencer())) opt.Add(WithBatcher(ids.L2Batcher, ids.L1EL, ids.L2CL, ids.L2EL)) opt.Add(WithProposer(ids.L2Proposer, ids.L1EL, &ids.L2CL, nil)) - opt.Add(WithFaucets([]stack.L1ELNodeID{ids.L1EL}, []stack.L2ELNodeID{ids.L2EL})) + opt.Add(WithFaucets([]stack.ComponentID{ids.L1EL}, []stack.ComponentID{ids.L2EL})) opt.Add(WithTestSequencer(ids.TestSequencer, ids.L1CL, ids.L2CL, ids.L1EL, ids.L2EL)) - opt.Add(WithL2Challenger(ids.L2Challenger, ids.L1EL, ids.L1CL, nil, nil, &ids.L2CL, []stack.L2ELNodeID{ + opt.Add(WithL2Challenger(ids.L2Challenger, ids.L1EL, ids.L1CL, nil, nil, &ids.L2CL, []stack.ComponentID{ ids.L2EL, })) diff --git a/op-devstack/sysgo/system_singlechain_multinode.go b/op-devstack/sysgo/system_singlechain_multinode.go index 893cdb5f9b6..2a2e1070d8d 100644 --- a/op-devstack/sysgo/system_singlechain_multinode.go +++ b/op-devstack/sysgo/system_singlechain_multinode.go @@ -8,14 +8,14 @@ import ( type DefaultSingleChainMultiNodeSystemIDs struct { DefaultMinimalSystemIDs - L2CLB stack.L2CLNodeID - L2ELB stack.L2ELNodeID + L2CLB stack.ComponentID + L2ELB stack.ComponentID } type DefaultSingleChainMultiNodeWithTestSeqSystemIDs struct { DefaultSingleChainMultiNodeSystemIDs - TestSequencer stack.TestSequencerID + TestSequencer stack.ComponentID } func NewDefaultSingleChainMultiNodeSystemIDs(l1ID, l2ID eth.ChainID) DefaultSingleChainMultiNodeSystemIDs { @@ -30,7 +30,7 @@ func NewDefaultSingleChainMultiNodeSystemIDs(l1ID, l2ID eth.ChainID) DefaultSing func NewDefaultSingleChainMultiNodeWithTestSeqSystemIDs(l1ID, l2ID eth.ChainID) DefaultSingleChainMultiNodeWithTestSeqSystemIDs { return DefaultSingleChainMultiNodeWithTestSeqSystemIDs{ DefaultSingleChainMultiNodeSystemIDs: NewDefaultSingleChainMultiNodeSystemIDs(l1ID, l2ID), - TestSequencer: "dev", + TestSequencer: stack.NewTestSequencerID("dev"), } } diff --git a/op-devstack/sysgo/system_singlechain_twoverifiers.go b/op-devstack/sysgo/system_singlechain_twoverifiers.go index 2e960517712..3a38587fc22 100644 --- a/op-devstack/sysgo/system_singlechain_twoverifiers.go +++ b/op-devstack/sysgo/system_singlechain_twoverifiers.go @@ -9,10 +9,10 @@ import ( type DefaultSingleChainTwoVerifiersSystemIDs struct { DefaultSingleChainMultiNodeSystemIDs - L2CLC stack.L2CLNodeID - L2ELC stack.L2ELNodeID + L2CLC stack.ComponentID + L2ELC stack.ComponentID - TestSequencer stack.TestSequencerID + TestSequencer stack.ComponentID } func NewDefaultSingleChainTwoVerifiersSystemIDs(l1ID, l2ID eth.ChainID) DefaultSingleChainTwoVerifiersSystemIDs { @@ -20,6 +20,7 @@ func NewDefaultSingleChainTwoVerifiersSystemIDs(l1ID, l2ID eth.ChainID) DefaultS DefaultSingleChainMultiNodeSystemIDs: NewDefaultSingleChainMultiNodeSystemIDs(l1ID, l2ID), L2CLC: stack.NewL2CLNodeID("c", l2ID), L2ELC: stack.NewL2ELNodeID("c", l2ID), + TestSequencer: stack.NewTestSequencerID("dev"), } } @@ -62,11 +63,11 @@ func DefaultSingleChainTwoVerifiersFollowL2System(dest *DefaultSingleChainTwoVer opt.Add(WithBatcher(ids.L2Batcher, ids.L1EL, ids.L2CL, ids.L2EL)) opt.Add(WithProposer(ids.L2Proposer, ids.L1EL, &ids.L2CL, nil)) - opt.Add(WithFaucets([]stack.L1ELNodeID{ids.L1EL}, []stack.L2ELNodeID{ids.L2EL})) + opt.Add(WithFaucets([]stack.ComponentID{ids.L1EL}, []stack.ComponentID{ids.L2EL})) opt.Add(WithTestSequencer(ids.TestSequencer, ids.L1CL, ids.L2CLB, ids.L1EL, ids.L2ELB)) - opt.Add(WithL2Challenger(ids.L2Challenger, ids.L1EL, ids.L1CL, nil, nil, &ids.L2CL, []stack.L2ELNodeID{ + opt.Add(WithL2Challenger(ids.L2Challenger, ids.L1EL, ids.L1CL, nil, nil, &ids.L2CL, []stack.ComponentID{ ids.L2EL, })) diff --git a/op-devstack/sysgo/system_synctester.go b/op-devstack/sysgo/system_synctester.go index d6bc9f5a5fc..5ba3c133157 100644 --- a/op-devstack/sysgo/system_synctester.go +++ b/op-devstack/sysgo/system_synctester.go @@ -9,9 +9,9 @@ import ( type DefaultSimpleSystemWithSyncTesterIDs struct { DefaultMinimalSystemIDs - L2CL2 stack.L2CLNodeID - SyncTesterL2EL stack.L2ELNodeID - SyncTester stack.SyncTesterID + L2CL2 stack.ComponentID + SyncTesterL2EL stack.ComponentID + SyncTester stack.ComponentID } func NewDefaultSimpleSystemWithSyncTesterIDs(l1ID, l2ID eth.ChainID) DefaultSimpleSystemWithSyncTesterIDs { @@ -52,15 +52,15 @@ func DefaultSimpleSystemWithSyncTester(dest *DefaultSimpleSystemWithSyncTesterID opt.Add(WithBatcher(ids.L2Batcher, ids.L1EL, ids.L2CL, ids.L2EL)) opt.Add(WithProposer(ids.L2Proposer, ids.L1EL, &ids.L2CL, nil)) - opt.Add(WithFaucets([]stack.L1ELNodeID{ids.L1EL}, []stack.L2ELNodeID{ids.L2EL})) + opt.Add(WithFaucets([]stack.ComponentID{ids.L1EL}, []stack.ComponentID{ids.L2EL})) opt.Add(WithTestSequencer(ids.TestSequencer, ids.L1CL, ids.L2CL, ids.L1EL, ids.L2EL)) - opt.Add(WithL2Challenger(ids.L2Challenger, ids.L1EL, ids.L1CL, nil, nil, &ids.L2CL, []stack.L2ELNodeID{ + opt.Add(WithL2Challenger(ids.L2Challenger, ids.L1EL, ids.L1CL, nil, nil, &ids.L2CL, []stack.ComponentID{ ids.L2EL, })) - opt.Add(WithSyncTester(ids.SyncTester, []stack.L2ELNodeID{ids.L2EL})) + opt.Add(WithSyncTester(ids.SyncTester, []stack.ComponentID{ids.L2EL})) // Create a SyncTesterEL with the same chain ID as the EL node opt.Add(WithSyncTesterL2ELNode(ids.SyncTesterL2EL, ids.L2EL)) diff --git a/op-devstack/sysgo/system_synctester_ext.go b/op-devstack/sysgo/system_synctester_ext.go index b27c981cc75..a05820b1789 100644 --- a/op-devstack/sysgo/system_synctester_ext.go +++ b/op-devstack/sysgo/system_synctester_ext.go @@ -11,24 +11,24 @@ import ( ) type DefaultMinimalExternalELSystemIDs struct { - L1 stack.L1NetworkID - L1EL stack.L1ELNodeID - L1CL stack.L1CLNodeID + L1 stack.ComponentID + L1EL stack.ComponentID + L1CL stack.ComponentID - L2 stack.L2NetworkID - L2CL stack.L2CLNodeID - L2EL stack.L2ELNodeID - L2ELReadOnly stack.L2ELNodeID + L2 stack.ComponentID + L2CL stack.ComponentID + L2EL stack.ComponentID + L2ELReadOnly stack.ComponentID - SyncTester stack.SyncTesterID + SyncTester stack.ComponentID } func NewExternalELSystemIDs(l1ID, l2ID eth.ChainID) DefaultMinimalExternalELSystemIDs { ids := DefaultMinimalExternalELSystemIDs{ - L1: stack.L1NetworkID(l1ID), + L1: stack.NewL1NetworkID(l1ID), L1EL: stack.NewL1ELNodeID("l1", l1ID), L1CL: stack.NewL1CLNodeID("l1", l1ID), - L2: stack.L2NetworkID(l2ID), + L2: stack.NewL2NetworkID(l2ID), L2CL: stack.NewL2CLNodeID("verifier", l2ID), L2EL: stack.NewL2ELNodeID("sync-tester-el", l2ID), L2ELReadOnly: stack.NewL2ELNodeID("l2-el-readonly", l2ID), @@ -72,14 +72,14 @@ func ExternalELSystemWithEndpointAndSuperchainRegistry(dest *DefaultMinimalExter }, blockTime: 12, } - o.registry.Register(stack.ConvertL1NetworkID(ids.L1).ComponentID, l1Net) + o.registry.Register(ids.L1, l1Net) })) opt.Add(WithExtL1Nodes(ids.L1EL, ids.L1CL, networkPreset.L1ELEndpoint, networkPreset.L1CLBeaconEndpoint)) // Use empty dependency set and minimal cluster instead of deployer opt.Add(WithEmptyDepSet( - stack.L2NetworkID(l2ChainID), + stack.NewL2NetworkID(l2ChainID), networkPreset.L2NetworkName, )) diff --git a/op-devstack/sysgo/system_test.go b/op-devstack/sysgo/system_test.go index 77f7504f2f6..feddda2c9b6 100644 --- a/op-devstack/sysgo/system_test.go +++ b/op-devstack/sysgo/system_test.go @@ -94,7 +94,7 @@ func testSystem(ids DefaultInteropSystemIDs, system stack.System) { require.Equal("", netB.Label("nickname")) netB.SetLabel("nickname", "Network B") require.Equal("Network B", netB.Label("nickname")) - v := system.L2Network(match.WithLabel[stack.L2NetworkID, stack.L2Network]( + v := system.L2Network(match.WithLabel[stack.L2Network]( "nickname", "Network B")) require.Equal(ids.L2B, v.ID()) }) @@ -112,8 +112,8 @@ func testSystem(ids DefaultInteropSystemIDs, system stack.System) { t.Run("sync", func(t devtest.T) { require := t.Require() - seqA := system.L2Network(ids.L2A).L2CLNode(ids.L2ACL) - seqB := system.L2Network(ids.L2B).L2CLNode(ids.L2BCL) + seqA := system.L2Network(stack.ByID[stack.L2Network](ids.L2A)).L2CLNode(stack.ByID[stack.L2CLNode](ids.L2ACL)) + seqB := system.L2Network(stack.ByID[stack.L2Network](ids.L2B)).L2CLNode(stack.ByID[stack.L2CLNode](ids.L2BCL)) blocks := uint64(5) // wait for this many blocks, with some margin for delays for i := uint64(0); i < blocks*2+10; i++ { diff --git a/op-devstack/sysgo/system_two_l2_follow_l2.go b/op-devstack/sysgo/system_two_l2_follow_l2.go index 2ac09522f49..01c01c8dabc 100644 --- a/op-devstack/sysgo/system_two_l2_follow_l2.go +++ b/op-devstack/sysgo/system_two_l2_follow_l2.go @@ -10,10 +10,10 @@ import ( type DefaultTwoL2SupernodeFollowL2SystemIDs struct { DefaultTwoL2SystemIDs - L2AFollowerCL stack.L2CLNodeID - L2AFollowerEL stack.L2ELNodeID - L2BFollowerCL stack.L2CLNodeID - L2BFollowerEL stack.L2ELNodeID + L2AFollowerCL stack.ComponentID + L2AFollowerEL stack.ComponentID + L2BFollowerCL stack.ComponentID + L2BFollowerEL stack.ComponentID } func NewDefaultTwoL2SupernodeFollowL2SystemIDs(l1ID, l2AID, l2BID eth.ChainID) DefaultTwoL2SupernodeFollowL2SystemIDs { diff --git a/op-devstack/sysgo/test_sequencer.go b/op-devstack/sysgo/test_sequencer.go index 7971eb7e884..5da43b784e9 100644 --- a/op-devstack/sysgo/test_sequencer.go +++ b/op-devstack/sysgo/test_sequencer.go @@ -40,7 +40,7 @@ import ( ) type TestSequencer struct { - id stack.TestSequencerID + id stack.ComponentID userRPC string jwtSecret [32]byte sequencers map[eth.ChainID]seqtypes.SequencerID @@ -77,20 +77,20 @@ func (s *TestSequencer) hydrate(sys stack.ExtensibleSystem) { // l2ChainIDs pairs together the CL and EL node IDs for an L2 chain. type l2ChainIDs struct { - CLID stack.L2CLNodeID - ELID stack.L2ELNodeID + CLID stack.ComponentID + ELID stack.ComponentID } -func WithTestSequencer(testSequencerID stack.TestSequencerID, l1CLID stack.L1CLNodeID, l2CLID stack.L2CLNodeID, l1ELID stack.L1ELNodeID, l2ELID stack.L2ELNodeID) stack.Option[*Orchestrator] { +func WithTestSequencer(testSequencerID stack.ComponentID, l1CLID stack.ComponentID, l2CLID stack.ComponentID, l1ELID stack.ComponentID, l2ELID stack.ComponentID) stack.Option[*Orchestrator] { return withTestSequencerImpl(testSequencerID, l1CLID, l1ELID, l2ChainIDs{CLID: l2CLID, ELID: l2ELID}) } // WithTestSequencer2L2 creates a test sequencer that can build blocks on two L2 chains. // This is useful for testing same-timestamp interop scenarios where we need deterministic // block timestamps on both chains. -func WithTestSequencer2L2(testSequencerID stack.TestSequencerID, l1CLID stack.L1CLNodeID, - l2ACLID stack.L2CLNodeID, l2BCLID stack.L2CLNodeID, - l1ELID stack.L1ELNodeID, l2AELID stack.L2ELNodeID, l2BELID stack.L2ELNodeID) stack.Option[*Orchestrator] { +func WithTestSequencer2L2(testSequencerID stack.ComponentID, l1CLID stack.ComponentID, + l2ACLID stack.ComponentID, l2BCLID stack.ComponentID, + l1ELID stack.ComponentID, l2AELID stack.ComponentID, l2BELID stack.ComponentID) stack.Option[*Orchestrator] { return withTestSequencerImpl(testSequencerID, l1CLID, l1ELID, l2ChainIDs{CLID: l2ACLID, ELID: l2AELID}, l2ChainIDs{CLID: l2BCLID, ELID: l2BELID}, @@ -99,7 +99,7 @@ func WithTestSequencer2L2(testSequencerID stack.TestSequencerID, l1CLID stack.L1 // withTestSequencerImpl is the shared implementation for creating test sequencers. // It supports any number of L2 chains. -func withTestSequencerImpl(testSequencerID stack.TestSequencerID, l1CLID stack.L1CLNodeID, l1ELID stack.L1ELNodeID, l2Chains ...l2ChainIDs) stack.Option[*Orchestrator] { +func withTestSequencerImpl(testSequencerID stack.ComponentID, l1CLID stack.ComponentID, l1ELID stack.ComponentID, l2Chains ...l2ChainIDs) stack.Option[*Orchestrator] { return stack.AfterDeploy(func(orch *Orchestrator) { p := orch.P().WithCtx(stack.ContextWithID(orch.P().Ctx(), testSequencerID)) require := p.Require() @@ -107,21 +107,18 @@ func withTestSequencerImpl(testSequencerID stack.TestSequencerID, l1CLID stack.L // Setup L1 components orch.writeDefaultJWT() - l1ELComponent, ok := orch.registry.Get(stack.ConvertL1ELNodeID(l1ELID).ComponentID) + l1EL, ok := orch.GetL1EL(l1ELID) require.True(ok, "l1 EL node required") - l1EL := l1ELComponent.(L1ELNode) l1ELClient, err := ethclient.DialContext(p.Ctx(), l1EL.UserRPC()) require.NoError(err) engineCl, err := dialEngine(p.Ctx(), l1EL.AuthRPC(), orch.jwtSecret) require.NoError(err) - l1CLComponent, ok := orch.registry.Get(stack.ConvertL1CLNodeID(l1CLID).ComponentID) + l1CL, ok := orch.GetL1CL(l1CLID) require.True(ok, "l1 CL node required") - l1CL := l1CLComponent.(*L1CLNode) - l1NetComponent, ok := orch.registry.Get(stack.ConvertL1NetworkID(stack.L1NetworkID(l1ELID.ChainID())).ComponentID) + l1Net, ok := orch.GetL1Network(stack.NewL1NetworkID(l1ELID.ChainID())) require.True(ok, "l1 net required") - l1Net := l1NetComponent.(*L1Network) // L1 sequencer IDs bid_L1 := seqtypes.BuilderID("test-l1-builder") @@ -184,9 +181,8 @@ func withTestSequencerImpl(testSequencerID stack.TestSequencerID, l1CLID stack.L l2EL, ok := orch.GetL2EL(l2Chain.ELID) require.True(ok, "l2 EL node required for chain %d", i) - l2CLComponent, ok := orch.registry.Get(stack.ConvertL2CLNodeID(l2Chain.CLID).ComponentID) + l2CL, ok := orch.GetL2CL(l2Chain.CLID) require.True(ok, "l2 CL node required for chain %d", i) - l2CL := l2CLComponent.(L2CLNode) // Generate unique IDs for this L2 chain (use suffix for multi-chain, no suffix for single chain) suffix := "" @@ -320,6 +316,6 @@ func withTestSequencerImpl(testSequencerID stack.TestSequencerID, l1CLID stack.L sequencers: sequencerIDs, } logger.Info("Sequencer User RPC", "http_endpoint", testSequencerNode.userRPC) - orch.registry.Register(stack.ConvertTestSequencerID(testSequencerID).ComponentID, testSequencerNode) + orch.registry.Register(testSequencerID, testSequencerNode) }) } diff --git a/op-up/main.go b/op-up/main.go index a7a31dc0f96..4ea3ec0b137 100644 --- a/op-up/main.go +++ b/op-up/main.go @@ -136,7 +136,7 @@ func runOpUp(ctx context.Context, stderr io.Writer, opUpDir string) error { sysgo.WithBatcher(ids.L2Batcher, ids.L1EL, ids.L2CL, ids.L2EL), sysgo.WithProposer(ids.L2Proposer, ids.L1EL, &ids.L2CL, nil), - sysgo.WithFaucets([]stack.L1ELNodeID{ids.L1EL}, []stack.L2ELNodeID{ids.L2EL}), + sysgo.WithFaucets([]stack.ComponentID{ids.L1EL}, []stack.ComponentID{ids.L2EL}), ) orch := sysgo.NewOrchestrator(p, opts) diff --git a/rust/kona/tests/node/common/conductor_test.go b/rust/kona/tests/node/common/conductor_test.go index a414d5946a1..5011e306c09 100644 --- a/rust/kona/tests/node/common/conductor_test.go +++ b/rust/kona/tests/node/common/conductor_test.go @@ -54,7 +54,7 @@ func TestConductorLeadershipTransfer(gt *testing.T) { idToConductor := make(map[string]conductorWithInfo) for _, conductor := range conductors { - conductorId := strings.TrimPrefix(conductor.String(), stack.ConductorKind.String()+"-") + conductorId := strings.TrimPrefix(conductor.String(), stack.KindConductor.String()+"-") idToConductor[conductorId] = conductorWithInfo{conductor, consensus.ServerInfo{}} } for _, memberInfo := range membership.Servers { diff --git a/rust/kona/tests/node/utils/mixed_preset.go b/rust/kona/tests/node/utils/mixed_preset.go index e959f7e4320..f80eb415cc4 100644 --- a/rust/kona/tests/node/utils/mixed_preset.go +++ b/rust/kona/tests/node/utils/mixed_preset.go @@ -204,12 +204,8 @@ func (m *MixedOpKonaPreset) L2CLKonaNodes() []dsl.L2CLNode { return append(m.L2CLKonaValidatorNodes, m.L2CLKonaSequencerNodes...) } -func L2NodeMatcher[ - I interface { - comparable - Key() string - }, E stack.Identifiable[I]](value ...string) stack.Matcher[I, E] { - return match.MatchElemFn[I, E](func(elem E) bool { +func L2NodeMatcher[E stack.Identifiable](value ...string) stack.Matcher[E] { + return match.MatchElemFn[E](func(elem E) bool { for _, v := range value { if !strings.Contains(elem.ID().Key(), v) { return false @@ -258,16 +254,16 @@ func NewMixedOpKona(t devtest.T) *MixedOpKonaPreset { t.Gate().GreaterOrEqual(len(l2Net.L2CLNodes()), 2, "expected at least two L2CL nodes") - opSequencerCLNodes := L2NodeMatcher[stack.L2CLNodeID, stack.L2CLNode](string(OpNode), string(Sequencer)).Match(l2Net.L2CLNodes()) - konaSequencerCLNodes := L2NodeMatcher[stack.L2CLNodeID, stack.L2CLNode](string(KonaNode), string(Sequencer)).Match(l2Net.L2CLNodes()) + opSequencerCLNodes := L2NodeMatcher[stack.L2CLNode](string(OpNode), string(Sequencer)).Match(l2Net.L2CLNodes()) + konaSequencerCLNodes := L2NodeMatcher[stack.L2CLNode](string(KonaNode), string(Sequencer)).Match(l2Net.L2CLNodes()) - opCLNodes := L2NodeMatcher[stack.L2CLNodeID, stack.L2CLNode](string(OpNode), string(Validator)).Match(l2Net.L2CLNodes()) - konaCLNodes := L2NodeMatcher[stack.L2CLNodeID, stack.L2CLNode](string(KonaNode), string(Validator)).Match(l2Net.L2CLNodes()) + opCLNodes := L2NodeMatcher[stack.L2CLNode](string(OpNode), string(Validator)).Match(l2Net.L2CLNodes()) + konaCLNodes := L2NodeMatcher[stack.L2CLNode](string(KonaNode), string(Validator)).Match(l2Net.L2CLNodes()) - opSequencerELNodes := L2NodeMatcher[stack.L2ELNodeID, stack.L2ELNode](string(OpNode), string(Sequencer)).Match(l2Net.L2ELNodes()) - konaSequencerELNodes := L2NodeMatcher[stack.L2ELNodeID, stack.L2ELNode](string(KonaNode), string(Sequencer)).Match(l2Net.L2ELNodes()) - opELNodes := L2NodeMatcher[stack.L2ELNodeID, stack.L2ELNode](string(OpNode), string(Validator)).Match(l2Net.L2ELNodes()) - konaELNodes := L2NodeMatcher[stack.L2ELNodeID, stack.L2ELNode](string(KonaNode), string(Validator)).Match(l2Net.L2ELNodes()) + opSequencerELNodes := L2NodeMatcher[stack.L2ELNode](string(OpNode), string(Sequencer)).Match(l2Net.L2ELNodes()) + konaSequencerELNodes := L2NodeMatcher[stack.L2ELNode](string(KonaNode), string(Sequencer)).Match(l2Net.L2ELNodes()) + opELNodes := L2NodeMatcher[stack.L2ELNode](string(OpNode), string(Validator)).Match(l2Net.L2ELNodes()) + konaELNodes := L2NodeMatcher[stack.L2ELNode](string(KonaNode), string(Validator)).Match(l2Net.L2ELNodes()) out := &MixedOpKonaPreset{ Log: t.Logger(), @@ -297,95 +293,95 @@ func NewMixedOpKona(t devtest.T) *MixedOpKonaPreset { } type DefaultMixedOpKonaSystemIDs struct { - L1 stack.L1NetworkID - L1EL stack.L1ELNodeID - L1CL stack.L1CLNodeID + L1 stack.ComponentID + L1EL stack.ComponentID + L1CL stack.ComponentID - L2 stack.L2NetworkID + L2 stack.ComponentID - L2ELOpGethSequencerNodes []stack.L2ELNodeID - L2ELOpRethSequencerNodes []stack.L2ELNodeID + L2ELOpGethSequencerNodes []stack.ComponentID + L2ELOpRethSequencerNodes []stack.ComponentID - L2CLOpGethSequencerNodes []stack.L2CLNodeID - L2CLOpRethSequencerNodes []stack.L2CLNodeID + L2CLOpGethSequencerNodes []stack.ComponentID + L2CLOpRethSequencerNodes []stack.ComponentID - L2ELKonaGethSequencerNodes []stack.L2ELNodeID - L2ELKonaRethSequencerNodes []stack.L2ELNodeID + L2ELKonaGethSequencerNodes []stack.ComponentID + L2ELKonaRethSequencerNodes []stack.ComponentID - L2CLKonaGethSequencerNodes []stack.L2CLNodeID - L2CLKonaRethSequencerNodes []stack.L2CLNodeID + L2CLKonaGethSequencerNodes []stack.ComponentID + L2CLKonaRethSequencerNodes []stack.ComponentID - L2CLOpGethNodes []stack.L2CLNodeID - L2ELOpGethNodes []stack.L2ELNodeID + L2CLOpGethNodes []stack.ComponentID + L2ELOpGethNodes []stack.ComponentID - L2CLOpRethNodes []stack.L2CLNodeID - L2ELOpRethNodes []stack.L2ELNodeID + L2CLOpRethNodes []stack.ComponentID + L2ELOpRethNodes []stack.ComponentID - L2CLKonaGethNodes []stack.L2CLNodeID - L2ELKonaGethNodes []stack.L2ELNodeID + L2CLKonaGethNodes []stack.ComponentID + L2ELKonaGethNodes []stack.ComponentID - L2CLKonaRethNodes []stack.L2CLNodeID - L2ELKonaRethNodes []stack.L2ELNodeID + L2CLKonaRethNodes []stack.ComponentID + L2ELKonaRethNodes []stack.ComponentID - L2Batcher stack.L2BatcherID - L2Proposer stack.L2ProposerID + L2Batcher stack.ComponentID + L2Proposer stack.ComponentID } -func (ids *DefaultMixedOpKonaSystemIDs) L2CLSequencerNodes() []stack.L2CLNodeID { +func (ids *DefaultMixedOpKonaSystemIDs) L2CLSequencerNodes() []stack.ComponentID { list := append(ids.L2CLOpGethSequencerNodes, ids.L2CLOpRethSequencerNodes...) list = append(list, ids.L2CLKonaGethSequencerNodes...) list = append(list, ids.L2CLKonaRethSequencerNodes...) return list } -func (ids *DefaultMixedOpKonaSystemIDs) L2ELSequencerNodes() []stack.L2ELNodeID { +func (ids *DefaultMixedOpKonaSystemIDs) L2ELSequencerNodes() []stack.ComponentID { list := append(ids.L2ELOpGethSequencerNodes, ids.L2ELOpRethSequencerNodes...) list = append(list, ids.L2ELKonaGethSequencerNodes...) list = append(list, ids.L2ELKonaRethSequencerNodes...) return list } -func (ids *DefaultMixedOpKonaSystemIDs) L2CLValidatorNodes() []stack.L2CLNodeID { +func (ids *DefaultMixedOpKonaSystemIDs) L2CLValidatorNodes() []stack.ComponentID { list := append(ids.L2CLOpGethNodes, ids.L2CLOpRethNodes...) list = append(list, ids.L2CLKonaGethNodes...) list = append(list, ids.L2CLKonaRethNodes...) return list } -func (ids *DefaultMixedOpKonaSystemIDs) L2ELValidatorNodes() []stack.L2ELNodeID { +func (ids *DefaultMixedOpKonaSystemIDs) L2ELValidatorNodes() []stack.ComponentID { list := append(ids.L2ELOpGethNodes, ids.L2ELOpRethNodes...) list = append(list, ids.L2ELKonaGethNodes...) list = append(list, ids.L2ELKonaRethNodes...) return list } -func (ids *DefaultMixedOpKonaSystemIDs) L2CLNodes() []stack.L2CLNodeID { +func (ids *DefaultMixedOpKonaSystemIDs) L2CLNodes() []stack.ComponentID { return append(ids.L2CLSequencerNodes(), ids.L2CLValidatorNodes()...) } -func (ids *DefaultMixedOpKonaSystemIDs) L2ELNodes() []stack.L2ELNodeID { +func (ids *DefaultMixedOpKonaSystemIDs) L2ELNodes() []stack.ComponentID { return append(ids.L2ELSequencerNodes(), ids.L2ELValidatorNodes()...) } func NewDefaultMixedOpKonaSystemIDs(l1ID, l2ID eth.ChainID, l2NodeConfig L2NodeConfig) DefaultMixedOpKonaSystemIDs { - rethOpCLNodes := make([]stack.L2CLNodeID, l2NodeConfig.OpNodesWithReth) - rethOpELNodes := make([]stack.L2ELNodeID, l2NodeConfig.OpNodesWithReth) - rethKonaCLNodes := make([]stack.L2CLNodeID, l2NodeConfig.KonaNodesWithReth) - rethKonaELNodes := make([]stack.L2ELNodeID, l2NodeConfig.KonaNodesWithReth) - - gethOpCLNodes := make([]stack.L2CLNodeID, l2NodeConfig.OpNodesWithGeth) - gethOpELNodes := make([]stack.L2ELNodeID, l2NodeConfig.OpNodesWithGeth) - gethKonaCLNodes := make([]stack.L2CLNodeID, l2NodeConfig.KonaNodesWithGeth) - gethKonaELNodes := make([]stack.L2ELNodeID, l2NodeConfig.KonaNodesWithGeth) - - gethOpSequencerCLNodes := make([]stack.L2CLNodeID, l2NodeConfig.OpSequencerNodesWithGeth) - gethOpSequencerELNodes := make([]stack.L2ELNodeID, l2NodeConfig.OpSequencerNodesWithGeth) - gethKonaSequencerCLNodes := make([]stack.L2CLNodeID, l2NodeConfig.KonaSequencerNodesWithGeth) - gethKonaSequencerELNodes := make([]stack.L2ELNodeID, l2NodeConfig.KonaSequencerNodesWithGeth) - - rethOpSequencerCLNodes := make([]stack.L2CLNodeID, l2NodeConfig.OpSequencerNodesWithReth) - rethOpSequencerELNodes := make([]stack.L2ELNodeID, l2NodeConfig.OpSequencerNodesWithReth) - rethKonaSequencerCLNodes := make([]stack.L2CLNodeID, l2NodeConfig.KonaSequencerNodesWithReth) - rethKonaSequencerELNodes := make([]stack.L2ELNodeID, l2NodeConfig.KonaSequencerNodesWithReth) + rethOpCLNodes := make([]stack.ComponentID, l2NodeConfig.OpNodesWithReth) + rethOpELNodes := make([]stack.ComponentID, l2NodeConfig.OpNodesWithReth) + rethKonaCLNodes := make([]stack.ComponentID, l2NodeConfig.KonaNodesWithReth) + rethKonaELNodes := make([]stack.ComponentID, l2NodeConfig.KonaNodesWithReth) + + gethOpCLNodes := make([]stack.ComponentID, l2NodeConfig.OpNodesWithGeth) + gethOpELNodes := make([]stack.ComponentID, l2NodeConfig.OpNodesWithGeth) + gethKonaCLNodes := make([]stack.ComponentID, l2NodeConfig.KonaNodesWithGeth) + gethKonaELNodes := make([]stack.ComponentID, l2NodeConfig.KonaNodesWithGeth) + + gethOpSequencerCLNodes := make([]stack.ComponentID, l2NodeConfig.OpSequencerNodesWithGeth) + gethOpSequencerELNodes := make([]stack.ComponentID, l2NodeConfig.OpSequencerNodesWithGeth) + gethKonaSequencerCLNodes := make([]stack.ComponentID, l2NodeConfig.KonaSequencerNodesWithGeth) + gethKonaSequencerELNodes := make([]stack.ComponentID, l2NodeConfig.KonaSequencerNodesWithGeth) + + rethOpSequencerCLNodes := make([]stack.ComponentID, l2NodeConfig.OpSequencerNodesWithReth) + rethOpSequencerELNodes := make([]stack.ComponentID, l2NodeConfig.OpSequencerNodesWithReth) + rethKonaSequencerCLNodes := make([]stack.ComponentID, l2NodeConfig.KonaSequencerNodesWithReth) + rethKonaSequencerELNodes := make([]stack.ComponentID, l2NodeConfig.KonaSequencerNodesWithReth) for i := range l2NodeConfig.OpSequencerNodesWithGeth { gethOpSequencerCLNodes[i] = stack.NewL2CLNodeID(fmt.Sprintf("cl-geth-op-sequencer-%d", i), l2ID) @@ -428,10 +424,10 @@ func NewDefaultMixedOpKonaSystemIDs(l1ID, l2ID eth.ChainID, l2NodeConfig L2NodeC } ids := DefaultMixedOpKonaSystemIDs{ - L1: stack.L1NetworkID(l1ID), + L1: stack.NewL1NetworkID(l1ID), L1EL: stack.NewL1ELNodeID("l1", l1ID), L1CL: stack.NewL1CLNodeID("l1", l1ID), - L2: stack.L2NetworkID(l2ID), + L2: stack.NewL2NetworkID(l2ID), L2CLOpGethSequencerNodes: gethOpSequencerCLNodes, L2ELOpGethSequencerNodes: gethOpSequencerELNodes, @@ -488,7 +484,7 @@ func DefaultMixedOpKonaSystem(dest *DefaultMixedOpKonaSystemIDs, l2NodeConfig L2 // Spawn all nodes. for i := range ids.L2CLKonaGethSequencerNodes { opt.Add(sysgo.WithOpGeth(ids.L2ELKonaGethSequencerNodes[i])) - opt.Add(sysgo.WithKonaNode(ids.L2CLKonaGethSequencerNodes[i], ids.L1CL, ids.L1EL, ids.L2ELKonaGethSequencerNodes[i], sysgo.L2CLOptionFn(func(p devtest.P, id stack.L2CLNodeID, cfg *sysgo.L2CLConfig) { + opt.Add(sysgo.WithKonaNode(ids.L2CLKonaGethSequencerNodes[i], ids.L1CL, ids.L1EL, ids.L2ELKonaGethSequencerNodes[i], sysgo.L2CLOptionFn(func(p devtest.P, id stack.ComponentID, cfg *sysgo.L2CLConfig) { cfg.IsSequencer = true cfg.SequencerSyncMode = sync.ELSync cfg.VerifierSyncMode = sync.ELSync @@ -497,14 +493,14 @@ func DefaultMixedOpKonaSystem(dest *DefaultMixedOpKonaSystemIDs, l2NodeConfig L2 for i := range ids.L2CLOpGethSequencerNodes { opt.Add(sysgo.WithOpGeth(ids.L2ELOpGethSequencerNodes[i])) - opt.Add(sysgo.WithOpNode(ids.L2CLOpGethSequencerNodes[i], ids.L1CL, ids.L1EL, ids.L2ELOpGethSequencerNodes[i], sysgo.L2CLOptionFn(func(p devtest.P, id stack.L2CLNodeID, cfg *sysgo.L2CLConfig) { + opt.Add(sysgo.WithOpNode(ids.L2CLOpGethSequencerNodes[i], ids.L1CL, ids.L1EL, ids.L2ELOpGethSequencerNodes[i], sysgo.L2CLOptionFn(func(p devtest.P, id stack.ComponentID, cfg *sysgo.L2CLConfig) { cfg.IsSequencer = true }))) } for i := range ids.L2CLKonaRethSequencerNodes { opt.Add(sysgo.WithOpReth(ids.L2ELKonaRethSequencerNodes[i])) - opt.Add(sysgo.WithKonaNode(ids.L2CLKonaRethSequencerNodes[i], ids.L1CL, ids.L1EL, ids.L2ELKonaRethSequencerNodes[i], sysgo.L2CLOptionFn(func(p devtest.P, id stack.L2CLNodeID, cfg *sysgo.L2CLConfig) { + opt.Add(sysgo.WithKonaNode(ids.L2CLKonaRethSequencerNodes[i], ids.L1CL, ids.L1EL, ids.L2ELKonaRethSequencerNodes[i], sysgo.L2CLOptionFn(func(p devtest.P, id stack.ComponentID, cfg *sysgo.L2CLConfig) { cfg.IsSequencer = true cfg.SequencerSyncMode = sync.ELSync cfg.VerifierSyncMode = sync.ELSync @@ -513,14 +509,14 @@ func DefaultMixedOpKonaSystem(dest *DefaultMixedOpKonaSystemIDs, l2NodeConfig L2 for i := range ids.L2CLOpRethSequencerNodes { opt.Add(sysgo.WithOpReth(ids.L2ELOpRethSequencerNodes[i])) - opt.Add(sysgo.WithOpNode(ids.L2CLOpRethSequencerNodes[i], ids.L1CL, ids.L1EL, ids.L2ELOpRethSequencerNodes[i], sysgo.L2CLOptionFn(func(p devtest.P, id stack.L2CLNodeID, cfg *sysgo.L2CLConfig) { + opt.Add(sysgo.WithOpNode(ids.L2CLOpRethSequencerNodes[i], ids.L1CL, ids.L1EL, ids.L2ELOpRethSequencerNodes[i], sysgo.L2CLOptionFn(func(p devtest.P, id stack.ComponentID, cfg *sysgo.L2CLConfig) { cfg.IsSequencer = true }))) } for i := range ids.L2CLKonaGethNodes { opt.Add(sysgo.WithOpGeth(ids.L2ELKonaGethNodes[i])) - opt.Add(sysgo.WithKonaNode(ids.L2CLKonaGethNodes[i], ids.L1CL, ids.L1EL, ids.L2ELKonaGethNodes[i], sysgo.L2CLOptionFn(func(p devtest.P, id stack.L2CLNodeID, cfg *sysgo.L2CLConfig) { + opt.Add(sysgo.WithKonaNode(ids.L2CLKonaGethNodes[i], ids.L1CL, ids.L1EL, ids.L2ELKonaGethNodes[i], sysgo.L2CLOptionFn(func(p devtest.P, id stack.ComponentID, cfg *sysgo.L2CLConfig) { cfg.SequencerSyncMode = sync.ELSync cfg.VerifierSyncMode = sync.ELSync }))) @@ -533,7 +529,7 @@ func DefaultMixedOpKonaSystem(dest *DefaultMixedOpKonaSystemIDs, l2NodeConfig L2 for i := range ids.L2CLKonaRethNodes { opt.Add(sysgo.WithOpReth(ids.L2ELKonaRethNodes[i])) - opt.Add(sysgo.WithKonaNode(ids.L2CLKonaRethNodes[i], ids.L1CL, ids.L1EL, ids.L2ELKonaRethNodes[i], sysgo.L2CLOptionFn(func(p devtest.P, id stack.L2CLNodeID, cfg *sysgo.L2CLConfig) { + opt.Add(sysgo.WithKonaNode(ids.L2CLKonaRethNodes[i], ids.L1CL, ids.L1EL, ids.L2ELKonaRethNodes[i], sysgo.L2CLOptionFn(func(p devtest.P, id stack.ComponentID, cfg *sysgo.L2CLConfig) { cfg.SequencerSyncMode = sync.ELSync cfg.VerifierSyncMode = sync.ELSync }))) @@ -558,7 +554,7 @@ func DefaultMixedOpKonaSystem(dest *DefaultMixedOpKonaSystemIDs, l2NodeConfig L2 opt.Add(sysgo.WithBatcher(ids.L2Batcher, ids.L1EL, CLNodeIDs[0], ELNodeIDs[0])) opt.Add(sysgo.WithProposer(ids.L2Proposer, ids.L1EL, &CLNodeIDs[0], nil)) - opt.Add(sysgo.WithFaucets([]stack.L1ELNodeID{ids.L1EL}, []stack.L2ELNodeID{ELNodeIDs[0]})) + opt.Add(sysgo.WithFaucets([]stack.ComponentID{ids.L1EL}, []stack.ComponentID{ELNodeIDs[0]})) opt.Add(stack.Finally(func(orch *sysgo.Orchestrator) { *dest = ids diff --git a/rust/kona/tests/node/utils/mixed_preset_with_conductor.go b/rust/kona/tests/node/utils/mixed_preset_with_conductor.go index e8b11c82de0..5e8a4f929db 100644 --- a/rust/kona/tests/node/utils/mixed_preset_with_conductor.go +++ b/rust/kona/tests/node/utils/mixed_preset_with_conductor.go @@ -12,7 +12,7 @@ import ( type MinimalWithConductors struct { *MixedOpKonaPreset - ConductorSets map[stack.L2NetworkID]dsl.ConductorSet + ConductorSets map[stack.ComponentID]dsl.ConductorSet } func NewMixedOpKonaWithConductors(t devtest.T) *MinimalWithConductors { @@ -20,7 +20,7 @@ func NewMixedOpKonaWithConductors(t devtest.T) *MinimalWithConductors { orch := presets.Orchestrator() orch.Hydrate(system) chains := system.L2Networks() - conductorSets := make(map[stack.L2NetworkID]dsl.ConductorSet) + conductorSets := make(map[stack.ComponentID]dsl.ConductorSet) for _, chain := range chains { chainMatcher := match.L2ChainById(chain.ID()) l2 := system.L2Network(match.Assume(t, chainMatcher)) diff --git a/rust/kona/tests/node/utils/test_sequencer_preset.go b/rust/kona/tests/node/utils/test_sequencer_preset.go index 5fbaf463272..56dcdaa18af 100644 --- a/rust/kona/tests/node/utils/test_sequencer_preset.go +++ b/rust/kona/tests/node/utils/test_sequencer_preset.go @@ -44,7 +44,7 @@ func NewMixedOpKonaWithTestSequencer(t devtest.T) *MinimalWithTestSequencersPres type DefaultMinimalWithTestSequencerIds struct { DefaultMixedOpKonaSystemIDs DefaultMixedOpKonaSystemIDs - TestSequencerId stack.TestSequencerID + TestSequencerId stack.ComponentID } func NewDefaultMinimalWithTestSequencerIds(l2Config L2NodeConfig) DefaultMinimalWithTestSequencerIds { @@ -57,7 +57,7 @@ func NewDefaultMinimalWithTestSequencerIds(l2Config L2NodeConfig) DefaultMinimal KonaNodesWithGeth: l2Config.KonaNodesWithGeth, KonaNodesWithReth: l2Config.KonaNodesWithReth, }), - TestSequencerId: "test-sequencer", + TestSequencerId: stack.NewTestSequencerID("test-sequencer"), } } diff --git a/rust/kona/tests/supervisor/presets/interop_minimal.go b/rust/kona/tests/supervisor/presets/interop_minimal.go index 64d9c77e98b..e454a3b9c16 100644 --- a/rust/kona/tests/supervisor/presets/interop_minimal.go +++ b/rust/kona/tests/supervisor/presets/interop_minimal.go @@ -38,7 +38,7 @@ func DefaultMinimalInteropSystem(dest *sysgo.DefaultInteropSystemIDs) stack.Opti // Since we may create an interop infra-setup, before interop is even scheduled to run. opt.Add(sysgo.WithProposer(ids.L2BProposer, ids.L1EL, &ids.L2BCL, &ids.Supervisor)) - opt.Add(sysgo.WithFaucets([]stack.L1ELNodeID{ids.L1EL}, []stack.L2ELNodeID{ids.L2AEL, ids.L2BEL})) + opt.Add(sysgo.WithFaucets([]stack.ComponentID{ids.L1EL}, []stack.ComponentID{ids.L2AEL, ids.L2BEL})) // Upon evaluation of the option, export the contents we created. // Ids here are static, but other things may be exported too. diff --git a/rust/op-reth/crates/tests/proofs/utils/preset.go b/rust/op-reth/crates/tests/proofs/utils/preset.go index 166adec2eda..55cbc804103 100644 --- a/rust/op-reth/crates/tests/proofs/utils/preset.go +++ b/rust/op-reth/crates/tests/proofs/utils/preset.go @@ -22,14 +22,14 @@ import ( type L2ELClient string const ( - L2ELClientGeth L2ELClient = "geth" - L2ELClientReth L2ELClient = "reth" + L2ELClientGeth L2ELClient = "geth" + L2ELClientReth L2ELClient = "reth" L2ELClientRethWithProofs L2ELClient = "reth-with-proof" ) type L2ELNodeID struct { - stack.L2ELNodeID - Client L2ELClient + L2ELNodeID stack.ComponentID + Client L2ELClient } type L2ELNode struct { @@ -117,12 +117,8 @@ func WithMixedOpProofPreset() stack.CommonOption { return stack.MakeCommon(DefaultMixedOpProofSystem(&DefaultMixedOpProofSystemIDs{})) } -func L2NodeMatcher[ - I interface { - comparable - Key() string - }, E stack.Identifiable[I]](value ...string) stack.Matcher[I, E] { - return match.MatchElemFn[I, E](func(elem E) bool { +func L2NodeMatcher[E stack.Identifiable](value ...string) stack.Matcher[E] { + return match.MatchElemFn[E](func(elem E) bool { for _, v := range value { if !strings.Contains(elem.ID().Key(), v) { return false @@ -223,37 +219,37 @@ func NewMixedOpProofPreset(t devtest.T) *MixedOpProofPreset { } type DefaultMixedOpProofSystemIDs struct { - L1 stack.L1NetworkID - L1EL stack.L1ELNodeID - L1CL stack.L1CLNodeID + L1 stack.ComponentID + L1EL stack.ComponentID + L1CL stack.ComponentID - L2 stack.L2NetworkID + L2 stack.ComponentID - L2CLSequencer stack.L2CLNodeID + L2CLSequencer stack.ComponentID L2ELSequencer L2ELNodeID - L2CLValidator stack.L2CLNodeID + L2CLValidator stack.ComponentID L2ELValidator L2ELNodeID - L2Batcher stack.L2BatcherID - L2Proposer stack.L2ProposerID - L2Challenger stack.L2ChallengerID + L2Batcher stack.ComponentID + L2Proposer stack.ComponentID + L2Challenger stack.ComponentID - TestSequencer stack.TestSequencerID + TestSequencer stack.ComponentID } func NewDefaultMixedOpProofSystemIDs(l1ID, l2ID eth.ChainID) DefaultMixedOpProofSystemIDs { ids := DefaultMixedOpProofSystemIDs{ - L1: stack.L1NetworkID(l1ID), + L1: stack.NewL1NetworkID(l1ID), L1EL: stack.NewL1ELNodeID("l1", l1ID), L1CL: stack.NewL1CLNodeID("l1", l1ID), - L2: stack.L2NetworkID(l2ID), + L2: stack.NewL2NetworkID(l2ID), L2CLSequencer: stack.NewL2CLNodeID("sequencer", l2ID), L2CLValidator: stack.NewL2CLNodeID("validator", l2ID), L2Batcher: stack.NewL2BatcherID("main", l2ID), L2Proposer: stack.NewL2ProposerID("main", l2ID), L2Challenger: stack.NewL2ChallengerID("main", l2ID), - TestSequencer: "test-sequencer", + TestSequencer: stack.NewTestSequencerID("test-sequencer"), } // default to op-geth for sequencer and op-reth-with-proof for validator @@ -360,7 +356,7 @@ func defaultMixedOpProofSystemOpts(src, dest *DefaultMixedOpProofSystemIDs) stac opt.Add(sysgo.WithBatcher(src.L2Batcher, src.L1EL, src.L2CLSequencer, src.L2ELSequencer.L2ELNodeID)) opt.Add(sysgo.WithProposer(src.L2Proposer, src.L1EL, &src.L2CLSequencer, nil)) - opt.Add(sysgo.WithFaucets([]stack.L1ELNodeID{src.L1EL}, []stack.L2ELNodeID{src.L2ELSequencer.L2ELNodeID})) + opt.Add(sysgo.WithFaucets([]stack.ComponentID{src.L1EL}, []stack.ComponentID{src.L2ELSequencer.L2ELNodeID})) opt.Add(sysgo.WithTestSequencer(src.TestSequencer, src.L1CL, src.L2CLSequencer, src.L1EL, src.L2ELSequencer.L2ELNodeID))