From 23df09338c9e788f3592fd41001bcc767760e1fc Mon Sep 17 00:00:00 2001 From: Samuel Stokes Date: Thu, 16 May 2024 00:00:28 -0400 Subject: [PATCH] Add unit tests for CheckForkActivation --- op-node/rollup/chain_spec.go | 53 +++++++++++++++++------------- op-node/rollup/chain_spec_test.go | 54 +++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 23 deletions(-) diff --git a/op-node/rollup/chain_spec.go b/op-node/rollup/chain_spec.go index 726bd0183b3e..0eaedd2c1c1e 100644 --- a/op-node/rollup/chain_spec.go +++ b/op-node/rollup/chain_spec.go @@ -34,6 +34,7 @@ const maxSequencerDriftFjord = 1800 type ForkName string const ( + Bedrock ForkName = "bedrock" Regolith ForkName = "regolith" Canyon ForkName = "canyon" Delta ForkName = "delta" @@ -44,6 +45,7 @@ const ( ) var nextFork = map[ForkName]ForkName{ + Bedrock: Regolith, Regolith: Canyon, Canyon: Delta, Delta: Ecotone, @@ -53,8 +55,8 @@ var nextFork = map[ForkName]ForkName{ } type ChainSpec struct { - config *Config - nextFork ForkName + config *Config + currentFork ForkName } func NewChainSpec(config *Config) *ChainSpec { @@ -106,33 +108,38 @@ func (s *ChainSpec) MaxSequencerDrift(t uint64) uint64 { } func (s *ChainSpec) CheckForkActivation(log log.Logger, block eth.L2BlockRef) { - if s.nextFork == None { + if s.currentFork == Interop { return } - if s.nextFork == "" { - // Initialize c.nextFork if it is not set yet - if !s.config.IsRegolith(block.Time) { - s.nextFork = Regolith - } else if !s.config.IsCanyon(block.Time) { - s.nextFork = Canyon - } else if !s.config.IsDelta(block.Time) { - s.nextFork = Delta - } else if !s.config.IsEcotone(block.Time) { - s.nextFork = Ecotone - } else if !s.config.IsFjord(block.Time) { - s.nextFork = Fjord - } else if !s.config.IsInterop(block.Time) { - s.nextFork = Interop - } else { - s.nextFork = None - return + if s.currentFork == "" { + // Initialize currentFork if it is not set yet + s.currentFork = Bedrock + if s.config.IsRegolith(block.Time) { + s.currentFork = Regolith } + if s.config.IsCanyon(block.Time) { + s.currentFork = Canyon + } + if s.config.IsDelta(block.Time) { + s.currentFork = Delta + } + if s.config.IsEcotone(block.Time) { + s.currentFork = Ecotone + } + if s.config.IsFjord(block.Time) { + s.currentFork = Fjord + } + if s.config.IsInterop(block.Time) { + s.currentFork = Interop + } + log.Info("Current hardfork version detected", "forkName", s.currentFork) + return } foundActivationBlock := false - switch s.nextFork { + switch nextFork[s.currentFork] { case Regolith: foundActivationBlock = s.config.IsRegolithActivationBlock(block.Time) case Canyon: @@ -148,7 +155,7 @@ func (s *ChainSpec) CheckForkActivation(log log.Logger, block eth.L2BlockRef) { } if foundActivationBlock { - log.Info("Detected hardfork activation block", "forkName", s.nextFork, "timestamp", block.Time, "blockNum", block.Number, "hash", block.Hash) - s.nextFork = nextFork[s.nextFork] + s.currentFork = nextFork[s.currentFork] + log.Info("Detected hardfork activation block", "forkName", s.currentFork, "timestamp", block.Time, "blockNum", block.Number, "hash", block.Hash) } } diff --git a/op-node/rollup/chain_spec_test.go b/op-node/rollup/chain_spec_test.go index 54036289684f..b6547835cdba 100644 --- a/op-node/rollup/chain_spec_test.go +++ b/op-node/rollup/chain_spec_test.go @@ -5,8 +5,10 @@ import ( "testing" "github.com/ethereum-optimism/optimism/op-service/eth" + "github.com/ethereum-optimism/optimism/op-service/testlog" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" + "golang.org/x/exp/slog" ) func u64ptr(n uint64) *uint64 { @@ -142,3 +144,55 @@ func TestChainSpec_MaxSequencerDrift(t *testing.T) { }) } } + +func TestCheckForkActivation(t *testing.T) { + tests := []struct { + name string + block eth.L2BlockRef + expectedCurrentFork ForkName + expectedLog string + }{ + { + name: "Regolith activation", + block: eth.L2BlockRef{Time: 10, Number: 5, Hash: common.Hash{0x5}}, + expectedCurrentFork: Regolith, + expectedLog: "Detected hardfork activation block", + }, + { + name: "Still Regolith", + block: eth.L2BlockRef{Time: 11, Number: 6, Hash: common.Hash{0x6}}, + expectedCurrentFork: Regolith, + expectedLog: "", + }, + { + name: "Canyon activation", + block: eth.L2BlockRef{Time: 20, Number: 7, Hash: common.Hash{0x7}}, + expectedCurrentFork: Canyon, + expectedLog: "Detected hardfork activation block", + }, + { + name: "No more hardforks", + block: eth.L2BlockRef{Time: 700, Number: 8, Hash: common.Hash{0x8}}, + expectedCurrentFork: Fjord, + expectedLog: "", + }, + } + + hasInfoLevel := testlog.NewLevelFilter(slog.LevelInfo) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + lgr, logs := testlog.CaptureLogger(t, slog.LevelDebug) + + chainSpec := NewChainSpec(&testConfig) + // First call initializes chainSpec.currentFork value + chainSpec.CheckForkActivation(lgr, eth.L2BlockRef{Time: tt.block.Time - 1, Number: 1, Hash: common.Hash{0x1}}) + chainSpec.CheckForkActivation(lgr, tt.block) + require.Equal(t, tt.expectedCurrentFork, chainSpec.currentFork) + if tt.expectedLog != "" { + require.NotNil(t, logs.FindLog( + hasInfoLevel, + testlog.NewMessageContainsFilter(tt.expectedLog))) + } + }) + } +}