From c8626fdd897a4e3754e31a5a36375bfefcc6ab6b Mon Sep 17 00:00:00 2001 From: ImJeremyHe Date: Tue, 2 Apr 2024 13:46:45 +0800 Subject: [PATCH 1/9] Add SwitchSequencer --- execution/gethexec/espresso_sequencer.go | 7 +- execution/gethexec/sequencer.go | 14 ++- execution/gethexec/switch_sequencer.go | 130 +++++++++++++++++++++++ 3 files changed, 145 insertions(+), 6 deletions(-) create mode 100644 execution/gethexec/switch_sequencer.go diff --git a/execution/gethexec/espresso_sequencer.go b/execution/gethexec/espresso_sequencer.go index 05d9b56023..45ed4aad7f 100644 --- a/execution/gethexec/espresso_sequencer.go +++ b/execution/gethexec/espresso_sequencer.go @@ -45,6 +45,9 @@ type EspressoSequencer struct { config SequencerConfigFetcher hotShotState *HotShotState namespace uint64 + + // The time when the last block was created + lastCreated time.Time } func NewEspressoSequencer(execEngine *ExecutionEngine, configFetcher SequencerConfigFetcher) (*EspressoSequencer, error) { @@ -112,14 +115,14 @@ func (s *EspressoSequencer) createBlock(ctx context.Context) (returnValue bool) func (s *EspressoSequencer) Start(ctxIn context.Context) error { s.StopWaiter.Start(ctxIn, s) s.CallIteratively(func(ctx context.Context) time.Duration { - retryBlockTime := time.Now().Add(retryTime) madeBlock := s.createBlock(ctx) if madeBlock { + s.lastCreated = time.Now() // Allow the sequencer to catch up to HotShot return 0 } // If we didn't make a block, try again in a bit - return time.Until(retryBlockTime) + return retryTime }) return nil diff --git a/execution/gethexec/sequencer.go b/execution/gethexec/sequencer.go index 232fd6bb6d..e7b6bae4dd 100644 --- a/execution/gethexec/sequencer.go +++ b/execution/gethexec/sequencer.go @@ -68,10 +68,13 @@ type SequencerConfig struct { NonceFailureCacheExpiry time.Duration `koanf:"nonce-failure-cache-expiry" reload:"hot"` // Espresso specific flags - Espresso bool `koanf:"espresso"` - HotShotUrl string `koanf:"hotshot-url"` - EspressoNamespace uint64 `koanf:"espresso-namespace"` - StartHotShotBlock uint64 `koanf:"start-hotshot-block"` + Espresso bool `koanf:"espresso"` + HotShotUrl string `koanf:"hotshot-url"` + EspressoNamespace uint64 `koanf:"espresso-namespace"` + StartHotShotBlock uint64 `koanf:"start-hotshot-block"` + MaxHotshotDriftTime time.Duration `koanf:"max-hotshot-drift-time"` + ConsecutiveHotshotBlocks int `koanf:"consecutive-hotshot-blocks"` + HotshotTimeFrame time.Duration `koanf:"hotshot-time-frame"` } func (c *SequencerConfig) Validate() error { @@ -138,6 +141,9 @@ func SequencerConfigAddOptions(prefix string, f *flag.FlagSet) { f.String(prefix+".hotshot-url", DefaultSequencerConfig.HotShotUrl, "") f.Uint64(prefix+".espresso-namespace", DefaultSequencerConfig.EspressoNamespace, "espresso namespace that corresponds the L2 chain") f.Uint64(prefix+".start-hotshot-block", DefaultSequencerConfig.StartHotShotBlock, "the starting block number of hotshot") + f.Duration(prefix+".max-hotshot-drift-time", DefaultSequencerConfig.MaxHotshotDriftTime, "maximum drift time of hotshot") + f.Int(prefix+".consecutive-hotshot-blocks", DefaultSequencerConfig.ConsecutiveHotshotBlocks, "required minimum blocks created by hotshot within the `hotshot-time-frame` before switching to espresso mode") + f.Duration(prefix+".hotshot-time-frame", DefaultSequencerConfig.HotshotTimeFrame, "interval of checking if espresso mode is available or not") } type txQueueItem struct { diff --git a/execution/gethexec/switch_sequencer.go b/execution/gethexec/switch_sequencer.go new file mode 100644 index 0000000000..88218abe53 --- /dev/null +++ b/execution/gethexec/switch_sequencer.go @@ -0,0 +1,130 @@ +package gethexec + +import ( + "context" + "time" + + "github.com/ethereum/go-ethereum/arbitrum_types" + "github.com/ethereum/go-ethereum/core/types" + "github.com/offchainlabs/nitro/util/stopwaiter" +) + +const ( + SequencingMode_Espresso = 0 + SequencingMode_Centralized = 1 +) + +type SwitchSequencer struct { + stopwaiter.StopWaiter + + centralized *Sequencer + espresso *EspressoSequencer + + mode int + maxHotshotDirftTime time.Duration + consecutiveHotshotBlocks int + hotshotTimeFrame time.Duration + + lastSeenHotShotBlock uint64 +} + +func NewSequencerSwitch(centralized *Sequencer, espresso *EspressoSequencer, configFetcher SequencerConfigFetcher) (*SwitchSequencer, error) { + config := configFetcher() + if err := config.Validate(); err != nil { + return nil, err + } + + return &SwitchSequencer{ + centralized: centralized, + espresso: espresso, + mode: SequencingMode_Espresso, + maxHotshotDirftTime: config.MaxHotshotDriftTime, + consecutiveHotshotBlocks: config.ConsecutiveHotshotBlocks, + hotshotTimeFrame: config.HotshotTimeFrame, + lastSeenHotShotBlock: 0, + }, nil +} + +func (s *SwitchSequencer) IsRunningEspressoMode() bool { + return s.mode == SequencingMode_Espresso +} + +func (s *SwitchSequencer) SwitchToEspresso(ctx context.Context) error { + if s.mode == SequencingMode_Espresso { + return nil + } + s.mode = SequencingMode_Espresso + s.centralized.StopAndWait() + return s.espresso.Start(ctx) +} + +func (s *SwitchSequencer) SwitchToCentralized(ctx context.Context) error { + if s.mode == SequencingMode_Centralized { + return nil + } + s.mode = SequencingMode_Centralized + s.espresso.StopAndWait() + return s.espresso.Start(ctx) +} + +func (s *SwitchSequencer) getRunningSequencer() TransactionPublisher { + if s.IsRunningEspressoMode() { + return s.espresso + } + return s.centralized +} + +func (s *SwitchSequencer) PublishTransaction(ctx context.Context, tx *types.Transaction, options *arbitrum_types.ConditionalOptions) error { + return s.getRunningSequencer().PublishTransaction(ctx, tx, options) +} + +func (s *SwitchSequencer) CheckHealth(ctx context.Context) error { + return s.getRunningSequencer().CheckHealth(ctx) +} + +func (s *SwitchSequencer) Initialize(ctx context.Context) error { + return s.getRunningSequencer().Initialize(ctx) +} + +func (s *SwitchSequencer) Start(ctx context.Context) error { + err := s.getRunningSequencer().Start(ctx) + if err != nil { + return err + } + s.CallIteratively(func(ctx context.Context) time.Duration { + now := time.Now() + if s.IsRunningEspressoMode() { + if s.espresso.lastCreated.Add(s.maxHotshotDirftTime).Before(now) { + _ = s.SwitchToCentralized(ctx) + } + return s.hotshotTimeFrame + } + + b, err := s.espresso.hotShotState.client.FetchLatestBlockHeight(ctx) + if err != nil { + return 100 * time.Second + } + if s.lastSeenHotShotBlock == 0 { + s.lastSeenHotShotBlock = b + return s.hotshotTimeFrame + } + if b-s.lastSeenHotShotBlock <= uint64(s.consecutiveHotshotBlocks) { + s.lastSeenHotShotBlock = 0 + _ = s.SwitchToEspresso(ctx) + return 0 + } + s.lastSeenHotShotBlock = b + return s.hotshotTimeFrame + }) + + return nil +} + +func (s *SwitchSequencer) StopAndWait() { + s.getRunningSequencer().StopAndWait() + s.StopWaiter.StopAndWait() +} + +func (s *SwitchSequencer) Started() bool { + return s.getRunningSequencer().Started() +} From dac5e1d9dd7b7534569ca875f9e466e6a8d8a646 Mon Sep 17 00:00:00 2001 From: ImJeremyHe Date: Wed, 3 Apr 2024 14:54:24 +0800 Subject: [PATCH 2/9] Fix the switch function --- execution/gethexec/switch_sequencer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/execution/gethexec/switch_sequencer.go b/execution/gethexec/switch_sequencer.go index 88218abe53..fdf103e75f 100644 --- a/execution/gethexec/switch_sequencer.go +++ b/execution/gethexec/switch_sequencer.go @@ -64,7 +64,7 @@ func (s *SwitchSequencer) SwitchToCentralized(ctx context.Context) error { } s.mode = SequencingMode_Centralized s.espresso.StopAndWait() - return s.espresso.Start(ctx) + return s.centralized.Start(ctx) } func (s *SwitchSequencer) getRunningSequencer() TransactionPublisher { From 8e6479544e972de52e8c3617633bbbd856334a91 Mon Sep 17 00:00:00 2001 From: ImJeremyHe Date: Wed, 3 Apr 2024 18:46:25 +0800 Subject: [PATCH 3/9] Create SwitchSequencer --- execution/gethexec/node.go | 24 +++++++++++++++--------- execution/gethexec/switch_sequencer.go | 2 +- system_tests/espresso_switch_test.go | 5 +++++ 3 files changed, 21 insertions(+), 10 deletions(-) create mode 100644 system_tests/espresso_switch_test.go diff --git a/execution/gethexec/node.go b/execution/gethexec/node.go index 18b9b31f0a..eb4d0317a2 100644 --- a/execution/gethexec/node.go +++ b/execution/gethexec/node.go @@ -171,21 +171,27 @@ func CreateExecutionNode( } } - if config.Sequencer.Enable && !config.Sequencer.Espresso { + if config.Sequencer.Enable { seqConfigFetcher := func() *SequencerConfig { return &configFetcher().Sequencer } sequencer, err = NewSequencer(execEngine, parentChainReader, seqConfigFetcher) if err != nil { return nil, err } - txPublisher = sequencer - } else if config.Sequencer.Enable && config.Sequencer.Espresso { - seqConfigFetcher := func() *SequencerConfig { return &configFetcher().Sequencer } - espressoSequencer, err := NewEspressoSequencer(execEngine, seqConfigFetcher) - if err != nil { - return nil, err - } - txPublisher = espressoSequencer + if config.Sequencer.Espresso { + seqConfigFetcher := func() *SequencerConfig { return &configFetcher().Sequencer } + espressoSequencer, err := NewEspressoSequencer(execEngine, seqConfigFetcher) + if err != nil { + return nil, err + } + switchSequencer, err := NewSwitchSequencer(sequencer, espressoSequencer, seqConfigFetcher) + if err != nil { + return nil, err + } + txPublisher = switchSequencer + } else { + txPublisher = sequencer + } } else { if config.Forwarder.RedisUrl != "" { txPublisher = NewRedisTxForwarder(config.forwardingTarget, &config.Forwarder) diff --git a/execution/gethexec/switch_sequencer.go b/execution/gethexec/switch_sequencer.go index fdf103e75f..7d1d322036 100644 --- a/execution/gethexec/switch_sequencer.go +++ b/execution/gethexec/switch_sequencer.go @@ -28,7 +28,7 @@ type SwitchSequencer struct { lastSeenHotShotBlock uint64 } -func NewSequencerSwitch(centralized *Sequencer, espresso *EspressoSequencer, configFetcher SequencerConfigFetcher) (*SwitchSequencer, error) { +func NewSwitchSequencer(centralized *Sequencer, espresso *EspressoSequencer, configFetcher SequencerConfigFetcher) (*SwitchSequencer, error) { config := configFetcher() if err := config.Validate(); err != nil { return nil, err diff --git a/system_tests/espresso_switch_test.go b/system_tests/espresso_switch_test.go new file mode 100644 index 0000000000..e41edd3d79 --- /dev/null +++ b/system_tests/espresso_switch_test.go @@ -0,0 +1,5 @@ +package arbtest + +import "testing" + +func TestEspressoSwitch(t *testing.T) {} From 8cd6f81d43eb38ae5af0752f562d6a9e4cee0587 Mon Sep 17 00:00:00 2001 From: ImJeremyHe Date: Tue, 9 Apr 2024 16:33:03 +0800 Subject: [PATCH 4/9] Update the espresso-sequencer-go --- go.mod | 4 ++-- go.sum | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index c461ed6c77..73e6ff0c8a 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ replace github.com/VictoriaMetrics/fastcache => ./fastcache replace github.com/ethereum/go-ethereum => ./go-ethereum require ( - github.com/EspressoSystems/espresso-sequencer-go v0.0.10 + github.com/EspressoSystems/espresso-sequencer-go v0.0.11 github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible github.com/Shopify/toxiproxy v2.1.4+incompatible github.com/alicebob/miniredis/v2 v2.21.0 @@ -71,7 +71,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/sso v1.11.4 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.16.4 // indirect github.com/aws/smithy-go v1.11.2 // indirect - github.com/benbjohnson/clock v1.3.0 // indirect + github.com/benbjohnson/clock v1.3.5 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bits-and-blooms/bitset v1.7.0 // indirect github.com/blang/semver/v4 v4.0.0 // indirect diff --git a/go.sum b/go.sum index c6df12125d..1d151141d8 100644 --- a/go.sum +++ b/go.sum @@ -53,6 +53,8 @@ github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8= github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/EspressoSystems/espresso-sequencer-go v0.0.10 h1:INykV9fatyUZXzgV4wyZAwBtqXCPGHgOcwaUsHsVJA4= github.com/EspressoSystems/espresso-sequencer-go v0.0.10/go.mod h1:9dSL1bj0l+jpgaMRmi55YeRBd3AhOZz8/HXQcQ42mRQ= +github.com/EspressoSystems/espresso-sequencer-go v0.0.11 h1:PWBzbf8/WX10dYizIco0bAmIVE7/lwR4bNM/t+AT+HU= +github.com/EspressoSystems/espresso-sequencer-go v0.0.11/go.mod h1:BbU8N23RGl45QXSf/bYc8OQ8TG/vlMaPC1GU1acqKmc= github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible h1:1G1pk05UrOh0NlF1oeaaix1x8XzrfjIDK47TY0Zehcw= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= @@ -156,6 +158,7 @@ github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -239,6 +242,7 @@ github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593 h1:aPEJyR4rPBvD github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593/go.mod h1:6hk1eMY/u5t+Cf18q5lFMUA1Rc+Sm5I6Ra1QuPyxXCo= github.com/cockroachdb/redact v1.1.3 h1:AKZds10rFSIj7qADf0g46UixK8NNLwWTNdCIGS5wfSQ= github.com/cockroachdb/redact v1.1.3/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= +github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2/go.mod h1:8BT+cPK6xvFOcRlk0R8eg+OTkcqI6baNH4xAkpiYVvQ= github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= @@ -285,6 +289,7 @@ github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6Uh github.com/deckarep/golang-set/v2 v2.1.0 h1:g47V4Or+DUdzbs8FxCCmgb6VYd+ptPAngjM6dtGktsI= github.com/deckarep/golang-set/v2 v2.1.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= +github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1owhMVTHFZIlnvd4= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc= github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= @@ -401,6 +406,7 @@ github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= @@ -897,6 +903,7 @@ github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= @@ -1277,6 +1284,7 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= github.com/mr-tron/base58 v1.1.1/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= @@ -1418,6 +1426,7 @@ github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAv github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= github.com/petar/GoLLRB v0.0.0-20210522233825-ae3b015fd3e9 h1:1/WtZae0yGtPq+TI6+Tv1WTxkukpXeMlviSxvL7SRgk= +github.com/petar/GoLLRB v0.0.0-20210522233825-ae3b015fd3e9/go.mod h1:x3N5drFsm2uilKKuuYo6LdyD8vZAW55sH/9w+pbo1sw= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= @@ -1657,6 +1666,7 @@ github.com/wealdtech/go-merkletree v1.0.0/go.mod h1:cdil512d/8ZC7Kx3bfrDvGMQXB25 github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc h1:BCPnHtcboadS0DvysUuJXZ4lWVv5Bh5i7+tbIyi+ck4= github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc/go.mod h1:r45hJU7yEoA81k6MWNhpMj/kms0n14dkzkxYHoB96UM= github.com/whyrusleeping/cbor v0.0.0-20171005072247-63513f603b11 h1:5HZfQkwe0mIfyDmc1Em5GqlNRzcdtlv4HTNmdpt7XH0= +github.com/whyrusleeping/cbor v0.0.0-20171005072247-63513f603b11/go.mod h1:Wlo/SzPmxVp6vXpGt/zaXhHH0fn4IxgqZc82aKg6bpQ= github.com/whyrusleeping/cbor-gen v0.0.0-20200123233031-1cdf64d27158/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI= github.com/whyrusleeping/cbor-gen v0.0.0-20230126041949-52956bd4c9aa h1:EyA027ZAkuaCLoxVX4r1TZMPy1d31fM6hbfQ4OU4I5o= github.com/whyrusleeping/cbor-gen v0.0.0-20230126041949-52956bd4c9aa/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= From 0535a68fb6164cced44521e39d581024616e714c Mon Sep 17 00:00:00 2001 From: ImJeremyHe Date: Tue, 9 Apr 2024 19:40:41 +0800 Subject: [PATCH 5/9] Use light client as the trigger --- arbnode/batch_poster.go | 13 ++-- .../mock_light_client_reader.go | 13 +++- execution/gethexec/espresso_sequencer.go | 2 +- execution/gethexec/node.go | 2 +- execution/gethexec/sequencer.go | 19 +++--- execution/gethexec/switch_sequencer.go | 59 +++++++++---------- system_tests/espresso_e2e_test.go | 28 ++++++--- system_tests/espresso_switch_test.go | 14 ++++- 8 files changed, 87 insertions(+), 63 deletions(-) rename {arbnode => arbos}/mock_light_client_reader.go (64%) diff --git a/arbnode/batch_poster.go b/arbnode/batch_poster.go index eaa8e23082..52cf890ed3 100644 --- a/arbnode/batch_poster.go +++ b/arbnode/batch_poster.go @@ -33,6 +33,7 @@ import ( "github.com/ethereum/go-ethereum/rpc" hotshotClient "github.com/EspressoSystems/espresso-sequencer-go/client" + lightclient "github.com/EspressoSystems/espresso-sequencer-go/light-client" "github.com/offchainlabs/nitro/arbnode/dataposter" "github.com/offchainlabs/nitro/arbnode/dataposter/storage" @@ -75,10 +76,6 @@ type batchPosterPosition struct { NextSeqNum uint64 } -type LightClientReaderInterface interface { - ValidatedHeight() (validatedHeight uint64, l1Height uint64, err error) -} - type BatchPoster struct { stopwaiter.StopWaiter l1Reader *headerreader.HeaderReader @@ -111,7 +108,7 @@ type BatchPoster struct { accessList func(SequencerInboxAccs, AfterDelayedMessagesRead int) types.AccessList // Espresso readers - lightClientReader LightClientReaderInterface + lightClientReader lightclient.LightClientReaderInterface hotshotClient *hotshotClient.Client } @@ -314,17 +311,17 @@ func NewBatchPoster(ctx context.Context, opts *BatchPosterOpts) (*BatchPoster, e return nil, err } var hotShotClient *hotshotClient.Client - var lightClientReader LightClientReaderInterface + var lightClientReader lightclient.LightClientReaderInterface hotShotUrl := opts.Config().HotShotUrl lightClientAddr := opts.Config().LightClientAddress if hotShotUrl != "" { - hotShotClient = hotshotClient.NewClient(log.New(), hotShotUrl) + hotShotClient = hotshotClient.NewClient(hotShotUrl) } if lightClientAddr != "" { - lightClientReader, err = NewMockLightClientReader(common.HexToAddress(lightClientAddr), opts.L1Reader.Client()) + lightClientReader, err = arbos.NewMockLightClientReader(common.HexToAddress(lightClientAddr), opts.L1Reader.Client()) if err != nil { return nil, err } diff --git a/arbnode/mock_light_client_reader.go b/arbos/mock_light_client_reader.go similarity index 64% rename from arbnode/mock_light_client_reader.go rename to arbos/mock_light_client_reader.go index aa9b46c33a..588de7fffe 100644 --- a/arbnode/mock_light_client_reader.go +++ b/arbos/mock_light_client_reader.go @@ -1,6 +1,9 @@ -package arbnode +package arbos import ( + "time" + + "github.com/EspressoSystems/espresso-sequencer-go/types" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" ) @@ -17,3 +20,11 @@ func NewMockLightClientReader(lightClientAddr common.Address, l1client bind.Cont func (l *MockLightClientReader) ValidatedHeight() (validatedHeight uint64, l1Height uint64, err error) { return 18446744073709551615, 18446744073709551615, nil } + +func (l *MockLightClientReader) IsHotShotAvaliable(t time.Duration) bool { + return true +} + +func (l *MockLightClientReader) FetchMerkleRootAtL1Block(L1BlockHeight uint64) (types.BlockMerkleRoot, error) { + return types.BlockMerkleRoot{}, nil +} diff --git a/execution/gethexec/espresso_sequencer.go b/execution/gethexec/espresso_sequencer.go index 45ed4aad7f..0fbf58e36a 100644 --- a/execution/gethexec/espresso_sequencer.go +++ b/execution/gethexec/espresso_sequencer.go @@ -29,7 +29,7 @@ type HotShotState struct { func NewHotShotState(log log.Logger, url string, startBlock uint64) *HotShotState { return &HotShotState{ - client: *espressoClient.NewClient(log, url), + client: *espressoClient.NewClient(url), nextSeqBlockNum: startBlock, } } diff --git a/execution/gethexec/node.go b/execution/gethexec/node.go index eb4d0317a2..2457a241b7 100644 --- a/execution/gethexec/node.go +++ b/execution/gethexec/node.go @@ -183,7 +183,7 @@ func CreateExecutionNode( if err != nil { return nil, err } - switchSequencer, err := NewSwitchSequencer(sequencer, espressoSequencer, seqConfigFetcher) + switchSequencer, err := NewSwitchSequencer(sequencer, espressoSequencer, parentChainReader.Client(), seqConfigFetcher) if err != nil { return nil, err } diff --git a/execution/gethexec/sequencer.go b/execution/gethexec/sequencer.go index e7b6bae4dd..e450d46271 100644 --- a/execution/gethexec/sequencer.go +++ b/execution/gethexec/sequencer.go @@ -68,13 +68,13 @@ type SequencerConfig struct { NonceFailureCacheExpiry time.Duration `koanf:"nonce-failure-cache-expiry" reload:"hot"` // Espresso specific flags - Espresso bool `koanf:"espresso"` - HotShotUrl string `koanf:"hotshot-url"` - EspressoNamespace uint64 `koanf:"espresso-namespace"` - StartHotShotBlock uint64 `koanf:"start-hotshot-block"` - MaxHotshotDriftTime time.Duration `koanf:"max-hotshot-drift-time"` - ConsecutiveHotshotBlocks int `koanf:"consecutive-hotshot-blocks"` - HotshotTimeFrame time.Duration `koanf:"hotshot-time-frame"` + Espresso bool `koanf:"espresso"` + HotShotUrl string `koanf:"hotshot-url"` + LightClientAddress string `koanf:"light-client-address"` + EspressoNamespace uint64 `koanf:"espresso-namespace"` + StartHotShotBlock uint64 `koanf:"start-hotshot-block"` + MaxHotShotDriftTime time.Duration `koanf:"max-hotshot-drift-time"` + SwitchPollInterval time.Duration `koanf:"switch-poll-interval"` } func (c *SequencerConfig) Validate() error { @@ -141,9 +141,8 @@ func SequencerConfigAddOptions(prefix string, f *flag.FlagSet) { f.String(prefix+".hotshot-url", DefaultSequencerConfig.HotShotUrl, "") f.Uint64(prefix+".espresso-namespace", DefaultSequencerConfig.EspressoNamespace, "espresso namespace that corresponds the L2 chain") f.Uint64(prefix+".start-hotshot-block", DefaultSequencerConfig.StartHotShotBlock, "the starting block number of hotshot") - f.Duration(prefix+".max-hotshot-drift-time", DefaultSequencerConfig.MaxHotshotDriftTime, "maximum drift time of hotshot") - f.Int(prefix+".consecutive-hotshot-blocks", DefaultSequencerConfig.ConsecutiveHotshotBlocks, "required minimum blocks created by hotshot within the `hotshot-time-frame` before switching to espresso mode") - f.Duration(prefix+".hotshot-time-frame", DefaultSequencerConfig.HotshotTimeFrame, "interval of checking if espresso mode is available or not") + f.Duration(prefix+".max-hotshot-drift-time", DefaultSequencerConfig.MaxHotShotDriftTime, "maximum drift time of hotshot") + f.Duration(prefix+".switch-poll-interval", DefaultSequencerConfig.SwitchPollInterval, "the poll interval of checking the sequencer should be switched or not") } type txQueueItem struct { diff --git a/execution/gethexec/switch_sequencer.go b/execution/gethexec/switch_sequencer.go index 7d1d322036..c582a53940 100644 --- a/execution/gethexec/switch_sequencer.go +++ b/execution/gethexec/switch_sequencer.go @@ -4,8 +4,12 @@ import ( "context" "time" + lightClient "github.com/EspressoSystems/espresso-sequencer-go/light-client" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/arbitrum_types" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + "github.com/offchainlabs/nitro/arbos" "github.com/offchainlabs/nitro/util/stopwaiter" ) @@ -20,28 +24,31 @@ type SwitchSequencer struct { centralized *Sequencer espresso *EspressoSequencer - mode int - maxHotshotDirftTime time.Duration - consecutiveHotshotBlocks int - hotshotTimeFrame time.Duration + maxHotShotDriftTime time.Duration + switchPollInterval time.Duration + lightClient lightClient.LightClientReaderInterface - lastSeenHotShotBlock uint64 + mode int } -func NewSwitchSequencer(centralized *Sequencer, espresso *EspressoSequencer, configFetcher SequencerConfigFetcher) (*SwitchSequencer, error) { +func NewSwitchSequencer(centralized *Sequencer, espresso *EspressoSequencer, l1client bind.ContractBackend, configFetcher SequencerConfigFetcher) (*SwitchSequencer, error) { config := configFetcher() if err := config.Validate(); err != nil { return nil, err } + lightClient, err := arbos.NewMockLightClientReader(common.HexToAddress(config.LightClientAddress), l1client) + if err != nil { + return nil, err + } + return &SwitchSequencer{ - centralized: centralized, - espresso: espresso, - mode: SequencingMode_Espresso, - maxHotshotDirftTime: config.MaxHotshotDriftTime, - consecutiveHotshotBlocks: config.ConsecutiveHotshotBlocks, - hotshotTimeFrame: config.HotshotTimeFrame, - lastSeenHotShotBlock: 0, + centralized: centralized, + espresso: espresso, + lightClient: lightClient, + mode: SequencingMode_Espresso, + maxHotShotDriftTime: config.MaxHotShotDriftTime, + switchPollInterval: config.SwitchPollInterval, }, nil } @@ -92,29 +99,19 @@ func (s *SwitchSequencer) Start(ctx context.Context) error { return err } s.CallIteratively(func(ctx context.Context) time.Duration { - now := time.Now() - if s.IsRunningEspressoMode() { - if s.espresso.lastCreated.Add(s.maxHotshotDirftTime).Before(now) { - _ = s.SwitchToCentralized(ctx) - } - return s.hotshotTimeFrame + espresso := s.lightClient.IsHotShotAvaliable(s.maxHotShotDriftTime) + + var err error + if s.IsRunningEspressoMode() && !espresso { + err = s.SwitchToCentralized(ctx) + } else if !s.IsRunningEspressoMode() && espresso { + err = s.SwitchToEspresso(ctx) } - b, err := s.espresso.hotShotState.client.FetchLatestBlockHeight(ctx) if err != nil { - return 100 * time.Second - } - if s.lastSeenHotShotBlock == 0 { - s.lastSeenHotShotBlock = b - return s.hotshotTimeFrame - } - if b-s.lastSeenHotShotBlock <= uint64(s.consecutiveHotshotBlocks) { - s.lastSeenHotShotBlock = 0 - _ = s.SwitchToEspresso(ctx) return 0 } - s.lastSeenHotShotBlock = b - return s.hotshotTimeFrame + return s.switchPollInterval }) return nil diff --git a/system_tests/espresso_e2e_test.go b/system_tests/espresso_e2e_test.go index 562b8b030d..47ffdc19a7 100644 --- a/system_tests/espresso_e2e_test.go +++ b/system_tests/espresso_e2e_test.go @@ -307,16 +307,12 @@ func waitForWith( } } -func TestEspressoE2E(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() +// We run one L1 node, two L2 nodes and the espresso containers in this function. +func runNodes(ctx context.Context, t *testing.T) (*NodeBuilder, *TestClient, *BlockchainTestInfo, func()) { cleanValNode := createValidationNode(ctx, t, false) - defer cleanValNode() builder, cleanup := createL1ValidatorPosterNode(ctx, t, hotShotUrl) - defer cleanup() - node := builder.L2 err := waitFor(t, ctx, func() bool { if e := exec.Command( @@ -336,10 +332,8 @@ func TestEspressoE2E(t *testing.T) { Require(t, err) cleanEspresso := runEspresso(t, ctx) - defer cleanEspresso() l2Node, l2Info, cleanL2Node := createL2Node(ctx, t, hotShotUrl, builder) - defer cleanL2Node() // wait for the commitment task err = waitForWith(t, ctx, 60*time.Second, 1*time.Second, func() bool { @@ -352,9 +346,25 @@ func TestEspressoE2E(t *testing.T) { }) Require(t, err) + return builder, l2Node, l2Info, func() { + cleanL2Node() + cleanEspresso() + cleanup() + cleanValNode() + } +} + +func TestEspressoE2E(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + builder, l2Node, l2Info, cleanup := runNodes(ctx, t) + defer cleanup() + node := builder.L2 + // Wait for the initial message expected := arbutil.MessageIndex(1) - err = waitFor(t, ctx, func() bool { + err := waitFor(t, ctx, func() bool { msgCnt, err := l2Node.ConsensusNode.TxStreamer.GetMessageCount() if err != nil { panic(err) diff --git a/system_tests/espresso_switch_test.go b/system_tests/espresso_switch_test.go index e41edd3d79..6d672b46a5 100644 --- a/system_tests/espresso_switch_test.go +++ b/system_tests/espresso_switch_test.go @@ -1,5 +1,15 @@ package arbtest -import "testing" +import ( + "context" + "testing" +) -func TestEspressoSwitch(t *testing.T) {} +func TestEspressoSwitch(t *testing.T) { + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + builder, l2Node, l2Info, cleanup := runNodes(ctx, t) + defer cleanup() +} From e6dc658aba48ca375d0a4a7d178b1dbf2d77064d Mon Sep 17 00:00:00 2001 From: ImJeremyHe Date: Wed, 10 Apr 2024 22:18:12 +0800 Subject: [PATCH 6/9] Add the switch test --- execution/gethexec/arb_interface.go | 4 ++ execution/gethexec/sequencer.go | 3 + execution/gethexec/switch_sequencer.go | 75 ++++++++++++++++++------- go.sum | 11 +--- system_tests/espresso_switch_test.go | 78 ++++++++++++++++++++++++++ util/stopwaiter/stopwaiter.go | 5 +- 6 files changed, 143 insertions(+), 33 deletions(-) diff --git a/execution/gethexec/arb_interface.go b/execution/gethexec/arb_interface.go index 50d7dfb891..fcfaf4b67f 100644 --- a/execution/gethexec/arb_interface.go +++ b/execution/gethexec/arb_interface.go @@ -18,6 +18,10 @@ type TransactionPublisher interface { Start(context.Context) error StopAndWait() Started() bool + + // This is only for testing the switch sequencer. Will be removed if the espresso light client + // contract is ready and we will use another way to trigger the mode switching. + SetMode(ctx context.Context, espresso bool) } type ArbInterface struct { diff --git a/execution/gethexec/sequencer.go b/execution/gethexec/sequencer.go index e450d46271..8a4268c757 100644 --- a/execution/gethexec/sequencer.go +++ b/execution/gethexec/sequencer.go @@ -87,6 +87,9 @@ func (c *SequencerConfig) Validate() error { return fmt.Errorf("sequencer sender whitelist entry \"%v\" is not a valid address", address) } } + if c.LightClientAddress == "" && c.Espresso { + log.Warn("LightClientAddress is empty, running the espresso test mode") + } return nil } diff --git a/execution/gethexec/switch_sequencer.go b/execution/gethexec/switch_sequencer.go index c582a53940..dca9e24a21 100644 --- a/execution/gethexec/switch_sequencer.go +++ b/execution/gethexec/switch_sequencer.go @@ -9,6 +9,7 @@ import ( "github.com/ethereum/go-ethereum/arbitrum_types" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/log" "github.com/offchainlabs/nitro/arbos" "github.com/offchainlabs/nitro/util/stopwaiter" ) @@ -33,13 +34,17 @@ type SwitchSequencer struct { func NewSwitchSequencer(centralized *Sequencer, espresso *EspressoSequencer, l1client bind.ContractBackend, configFetcher SequencerConfigFetcher) (*SwitchSequencer, error) { config := configFetcher() - if err := config.Validate(); err != nil { + err := config.Validate() + if err != nil { return nil, err } - lightClient, err := arbos.NewMockLightClientReader(common.HexToAddress(config.LightClientAddress), l1client) - if err != nil { - return nil, err + var lightClient lightClient.LightClientReaderInterface + if config.LightClientAddress != "" { + lightClient, err = arbos.NewMockLightClientReader(common.HexToAddress(config.LightClientAddress), l1client) + if err != nil { + return nil, err + } } return &SwitchSequencer{ @@ -57,19 +62,24 @@ func (s *SwitchSequencer) IsRunningEspressoMode() bool { } func (s *SwitchSequencer) SwitchToEspresso(ctx context.Context) error { - if s.mode == SequencingMode_Espresso { + if s.IsRunningEspressoMode() { return nil } + log.Info("Switching to espresso sequencer") + s.mode = SequencingMode_Espresso + s.centralized.StopAndWait() return s.espresso.Start(ctx) } func (s *SwitchSequencer) SwitchToCentralized(ctx context.Context) error { - if s.mode == SequencingMode_Centralized { + if !s.IsRunningEspressoMode() { return nil } s.mode = SequencingMode_Centralized + log.Info("Switching to centrialized sequencer") + s.espresso.StopAndWait() return s.centralized.Start(ctx) } @@ -90,29 +100,38 @@ func (s *SwitchSequencer) CheckHealth(ctx context.Context) error { } func (s *SwitchSequencer) Initialize(ctx context.Context) error { - return s.getRunningSequencer().Initialize(ctx) + err := s.centralized.Initialize(ctx) + if err != nil { + return err + } + + return s.espresso.Initialize(ctx) } func (s *SwitchSequencer) Start(ctx context.Context) error { + s.StopWaiter.Start(ctx, s) err := s.getRunningSequencer().Start(ctx) if err != nil { return err } - s.CallIteratively(func(ctx context.Context) time.Duration { - espresso := s.lightClient.IsHotShotAvaliable(s.maxHotShotDriftTime) - - var err error - if s.IsRunningEspressoMode() && !espresso { - err = s.SwitchToCentralized(ctx) - } else if !s.IsRunningEspressoMode() && espresso { - err = s.SwitchToEspresso(ctx) - } - if err != nil { - return 0 - } - return s.switchPollInterval - }) + if s.lightClient != nil { + s.CallIteratively(func(ctx context.Context) time.Duration { + espresso := s.lightClient.IsHotShotAvaliable(s.maxHotShotDriftTime) + + var err error + if s.IsRunningEspressoMode() && !espresso { + err = s.SwitchToCentralized(ctx) + } else if !s.IsRunningEspressoMode() && espresso { + err = s.SwitchToEspresso(ctx) + } + + if err != nil { + return 0 + } + return s.switchPollInterval + }) + } return nil } @@ -125,3 +144,17 @@ func (s *SwitchSequencer) StopAndWait() { func (s *SwitchSequencer) Started() bool { return s.getRunningSequencer().Started() } + +func (s *SwitchSequencer) SetMode(ctx context.Context, m bool) { + if m { + s.SwitchToEspresso(ctx) + } else { + s.SwitchToCentralized(ctx) + } +} + +func (s *Sequencer) SetMode(ctx context.Context, espresso bool) {} +func (s *EspressoSequencer) SetMode(ctx context.Context, m bool) {} +func (s *RedisTxForwarder) SetMode(ctx context.Context, m bool) {} +func (s *TxDropper) SetMode(ctx context.Context, m bool) {} +func (s *TxForwarder) SetMode(ctx context.Context, m bool) {} diff --git a/go.sum b/go.sum index 1d151141d8..da2856dc5b 100644 --- a/go.sum +++ b/go.sum @@ -51,8 +51,6 @@ github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3 github.com/CloudyKit/jet/v3 v3.0.0/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMdUywE7VMo= github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8= github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= -github.com/EspressoSystems/espresso-sequencer-go v0.0.10 h1:INykV9fatyUZXzgV4wyZAwBtqXCPGHgOcwaUsHsVJA4= -github.com/EspressoSystems/espresso-sequencer-go v0.0.10/go.mod h1:9dSL1bj0l+jpgaMRmi55YeRBd3AhOZz8/HXQcQ42mRQ= github.com/EspressoSystems/espresso-sequencer-go v0.0.11 h1:PWBzbf8/WX10dYizIco0bAmIVE7/lwR4bNM/t+AT+HU= github.com/EspressoSystems/espresso-sequencer-go v0.0.11/go.mod h1:BbU8N23RGl45QXSf/bYc8OQ8TG/vlMaPC1GU1acqKmc= github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= @@ -156,8 +154,8 @@ github.com/aws/smithy-go v1.11.2 h1:eG/N+CcUMAvsdffgMvjMKwfyDzIkjM6pfxMJ8Mzc6mE= github.com/aws/smithy-go v1.11.2/go.mod h1:3xHYmszWVx2c0kIwQeEVf9uSm4fYZt67FBJnwub1bgM= github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= @@ -242,7 +240,6 @@ github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593 h1:aPEJyR4rPBvD github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593/go.mod h1:6hk1eMY/u5t+Cf18q5lFMUA1Rc+Sm5I6Ra1QuPyxXCo= github.com/cockroachdb/redact v1.1.3 h1:AKZds10rFSIj7qADf0g46UixK8NNLwWTNdCIGS5wfSQ= github.com/cockroachdb/redact v1.1.3/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= -github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2/go.mod h1:8BT+cPK6xvFOcRlk0R8eg+OTkcqI6baNH4xAkpiYVvQ= github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= @@ -289,7 +286,6 @@ github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6Uh github.com/deckarep/golang-set/v2 v2.1.0 h1:g47V4Or+DUdzbs8FxCCmgb6VYd+ptPAngjM6dtGktsI= github.com/deckarep/golang-set/v2 v2.1.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= -github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1owhMVTHFZIlnvd4= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc= github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= @@ -406,7 +402,6 @@ github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= @@ -903,7 +898,6 @@ github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= @@ -1284,7 +1278,6 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= github.com/mr-tron/base58 v1.1.1/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= @@ -1426,7 +1419,6 @@ github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAv github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= github.com/petar/GoLLRB v0.0.0-20210522233825-ae3b015fd3e9 h1:1/WtZae0yGtPq+TI6+Tv1WTxkukpXeMlviSxvL7SRgk= -github.com/petar/GoLLRB v0.0.0-20210522233825-ae3b015fd3e9/go.mod h1:x3N5drFsm2uilKKuuYo6LdyD8vZAW55sH/9w+pbo1sw= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= @@ -1666,7 +1658,6 @@ github.com/wealdtech/go-merkletree v1.0.0/go.mod h1:cdil512d/8ZC7Kx3bfrDvGMQXB25 github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc h1:BCPnHtcboadS0DvysUuJXZ4lWVv5Bh5i7+tbIyi+ck4= github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc/go.mod h1:r45hJU7yEoA81k6MWNhpMj/kms0n14dkzkxYHoB96UM= github.com/whyrusleeping/cbor v0.0.0-20171005072247-63513f603b11 h1:5HZfQkwe0mIfyDmc1Em5GqlNRzcdtlv4HTNmdpt7XH0= -github.com/whyrusleeping/cbor v0.0.0-20171005072247-63513f603b11/go.mod h1:Wlo/SzPmxVp6vXpGt/zaXhHH0fn4IxgqZc82aKg6bpQ= github.com/whyrusleeping/cbor-gen v0.0.0-20200123233031-1cdf64d27158/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI= github.com/whyrusleeping/cbor-gen v0.0.0-20230126041949-52956bd4c9aa h1:EyA027ZAkuaCLoxVX4r1TZMPy1d31fM6hbfQ4OU4I5o= github.com/whyrusleeping/cbor-gen v0.0.0-20230126041949-52956bd4c9aa/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= diff --git a/system_tests/espresso_switch_test.go b/system_tests/espresso_switch_test.go index 6d672b46a5..e8bea2329c 100644 --- a/system_tests/espresso_switch_test.go +++ b/system_tests/espresso_switch_test.go @@ -2,7 +2,12 @@ package arbtest import ( "context" + "math/big" "testing" + "time" + + "github.com/ethereum/go-ethereum/log" + "github.com/offchainlabs/nitro/arbutil" ) func TestEspressoSwitch(t *testing.T) { @@ -12,4 +17,77 @@ func TestEspressoSwitch(t *testing.T) { builder, l2Node, l2Info, cleanup := runNodes(ctx, t) defer cleanup() + node := builder.L2 + // Inacitivating the delayed sequencer for convenient sake + node.ConsensusNode.DelayedSequencer.StopAndWait() + l2Node.ConsensusNode.DelayedSequencer.StopAndWait() + + seq := l2Node.ExecNode.TxPublisher + seq.SetMode(ctx, false) + + currMsg := arbutil.MessageIndex(0) + // Wait for the switch to be totally finished + err := waitForWith(t, ctx, 2*time.Minute, 15*time.Second, func() bool { + msg, err := node.ConsensusNode.TxStreamer.GetMessageCount() + if err != nil { + return false + } + if currMsg == msg { + return true + } + + currMsg = msg + return false + }) + Require(t, err) + + // Make sure it is a totally new account + newAccount := "User10" + l2Info.GenerateAccount(newAccount) + addr := l2Info.GetAddress(newAccount) + balance := l2Node.GetBalance(t, addr) + if balance.Cmp(big.NewInt(0)) > 0 { + Fatal(t, "empty account") + } + + // Check if the tx is executed correctly + transferAmount := big.NewInt(1e16) + tx := l2Info.PrepareTx("Faucet", newAccount, 3e7, transferAmount, nil) + err = l2Node.Client.SendTransaction(ctx, tx) + Require(t, err) + + err = waitFor(t, ctx, func() bool { + balance := l2Node.GetBalance(t, addr) + log.Info("waiting for balance", "addr", addr, "balance", balance) + return balance.Cmp(transferAmount) >= 0 + }) + Require(t, err) + + msg, err := node.ConsensusNode.TxStreamer.GetMessageCount() + Require(t, err) + + if msg != currMsg+1 { + t.Fatal("") + } + + err = waitForWith(t, ctx, 60*time.Second, 5*time.Second, func() bool { + validatedCnt := node.ConsensusNode.BlockValidator.Validated(t) + return validatedCnt >= msg + }) + + seq.SetMode(ctx, true) + expectedMsg := msg + 10 + err = waitForWith(t, ctx, 120*time.Second, 5*time.Second, func() bool { + msg, err := node.ConsensusNode.TxStreamer.GetMessageCount() + if err != nil { + return false + } + return msg >= expectedMsg + }) + Require(t, err) + err = waitForWith(t, ctx, 60*time.Second, 5*time.Second, func() bool { + validatedCnt := node.ConsensusNode.BlockValidator.Validated(t) + return validatedCnt >= expectedMsg + }) + Require(t, err) } diff --git a/util/stopwaiter/stopwaiter.go b/util/stopwaiter/stopwaiter.go index 1e70e328eb..38b040d0d6 100644 --- a/util/stopwaiter/stopwaiter.go +++ b/util/stopwaiter/stopwaiter.go @@ -81,15 +81,16 @@ func getParentName(parent any) string { func (s *StopWaiterSafe) Start(ctx context.Context, parent any) error { s.mutex.Lock() defer s.mutex.Unlock() - if s.started { + if s.started && !s.stopped { return errors.New("start after start") } s.started = true + s.stopped = false s.name = getParentName(parent) s.parentCtx = ctx s.ctx, s.stopFunc = context.WithCancel(s.parentCtx) if s.stopped { - s.stopFunc() + // s.stopFunc() } return nil } From 2c49c510bc4631b5304bc14462e61f93386f6d57 Mon Sep 17 00:00:00 2001 From: ImJeremyHe Date: Thu, 11 Apr 2024 14:33:43 +0800 Subject: [PATCH 7/9] Make the linter happy --- arbos/mock_light_client_reader.go | 2 +- execution/gethexec/arb_interface.go | 2 +- execution/gethexec/espresso_sequencer.go | 4 ---- execution/gethexec/switch_sequencer.go | 16 ++++++++-------- system_tests/espresso_switch_test.go | 10 +++++++--- util/stopwaiter/stopwaiter.go | 3 --- 6 files changed, 17 insertions(+), 20 deletions(-) diff --git a/arbos/mock_light_client_reader.go b/arbos/mock_light_client_reader.go index 588de7fffe..7074ef52f9 100644 --- a/arbos/mock_light_client_reader.go +++ b/arbos/mock_light_client_reader.go @@ -25,6 +25,6 @@ func (l *MockLightClientReader) IsHotShotAvaliable(t time.Duration) bool { return true } -func (l *MockLightClientReader) FetchMerkleRootAtL1Block(L1BlockHeight uint64) (types.BlockMerkleRoot, error) { +func (l *MockLightClientReader) FetchMerkleRootAtL1Block(l1BlockHeight uint64) (types.BlockMerkleRoot, error) { return types.BlockMerkleRoot{}, nil } diff --git a/execution/gethexec/arb_interface.go b/execution/gethexec/arb_interface.go index fcfaf4b67f..6381ee08b0 100644 --- a/execution/gethexec/arb_interface.go +++ b/execution/gethexec/arb_interface.go @@ -21,7 +21,7 @@ type TransactionPublisher interface { // This is only for testing the switch sequencer. Will be removed if the espresso light client // contract is ready and we will use another way to trigger the mode switching. - SetMode(ctx context.Context, espresso bool) + SetMode(ctx context.Context, espresso bool) error } type ArbInterface struct { diff --git a/execution/gethexec/espresso_sequencer.go b/execution/gethexec/espresso_sequencer.go index 0fbf58e36a..014d21e3b2 100644 --- a/execution/gethexec/espresso_sequencer.go +++ b/execution/gethexec/espresso_sequencer.go @@ -45,9 +45,6 @@ type EspressoSequencer struct { config SequencerConfigFetcher hotShotState *HotShotState namespace uint64 - - // The time when the last block was created - lastCreated time.Time } func NewEspressoSequencer(execEngine *ExecutionEngine, configFetcher SequencerConfigFetcher) (*EspressoSequencer, error) { @@ -117,7 +114,6 @@ func (s *EspressoSequencer) Start(ctxIn context.Context) error { s.CallIteratively(func(ctx context.Context) time.Duration { madeBlock := s.createBlock(ctx) if madeBlock { - s.lastCreated = time.Now() // Allow the sequencer to catch up to HotShot return 0 } diff --git a/execution/gethexec/switch_sequencer.go b/execution/gethexec/switch_sequencer.go index dca9e24a21..25c35230d9 100644 --- a/execution/gethexec/switch_sequencer.go +++ b/execution/gethexec/switch_sequencer.go @@ -145,16 +145,16 @@ func (s *SwitchSequencer) Started() bool { return s.getRunningSequencer().Started() } -func (s *SwitchSequencer) SetMode(ctx context.Context, m bool) { +func (s *SwitchSequencer) SetMode(ctx context.Context, m bool) error { if m { - s.SwitchToEspresso(ctx) + return s.SwitchToEspresso(ctx) } else { - s.SwitchToCentralized(ctx) + return s.SwitchToCentralized(ctx) } } -func (s *Sequencer) SetMode(ctx context.Context, espresso bool) {} -func (s *EspressoSequencer) SetMode(ctx context.Context, m bool) {} -func (s *RedisTxForwarder) SetMode(ctx context.Context, m bool) {} -func (s *TxDropper) SetMode(ctx context.Context, m bool) {} -func (s *TxForwarder) SetMode(ctx context.Context, m bool) {} +func (s *Sequencer) SetMode(ctx context.Context, espresso bool) error { return nil } +func (s *EspressoSequencer) SetMode(ctx context.Context, m bool) error { return nil } +func (s *RedisTxForwarder) SetMode(ctx context.Context, m bool) error { return nil } +func (s *TxDropper) SetMode(ctx context.Context, m bool) error { return nil } +func (s *TxForwarder) SetMode(ctx context.Context, m bool) error { return nil } diff --git a/system_tests/espresso_switch_test.go b/system_tests/espresso_switch_test.go index e8bea2329c..5349605467 100644 --- a/system_tests/espresso_switch_test.go +++ b/system_tests/espresso_switch_test.go @@ -23,11 +23,12 @@ func TestEspressoSwitch(t *testing.T) { l2Node.ConsensusNode.DelayedSequencer.StopAndWait() seq := l2Node.ExecNode.TxPublisher - seq.SetMode(ctx, false) + err := seq.SetMode(ctx, false) + Require(t, err) currMsg := arbutil.MessageIndex(0) // Wait for the switch to be totally finished - err := waitForWith(t, ctx, 2*time.Minute, 15*time.Second, func() bool { + err = waitForWith(t, ctx, 2*time.Minute, 15*time.Second, func() bool { msg, err := node.ConsensusNode.TxStreamer.GetMessageCount() if err != nil { return false @@ -74,8 +75,11 @@ func TestEspressoSwitch(t *testing.T) { validatedCnt := node.ConsensusNode.BlockValidator.Validated(t) return validatedCnt >= msg }) + Require(t, err) + + err = seq.SetMode(ctx, true) + Require(t, err) - seq.SetMode(ctx, true) expectedMsg := msg + 10 err = waitForWith(t, ctx, 120*time.Second, 5*time.Second, func() bool { msg, err := node.ConsensusNode.TxStreamer.GetMessageCount() diff --git a/util/stopwaiter/stopwaiter.go b/util/stopwaiter/stopwaiter.go index 38b040d0d6..38b6299542 100644 --- a/util/stopwaiter/stopwaiter.go +++ b/util/stopwaiter/stopwaiter.go @@ -89,9 +89,6 @@ func (s *StopWaiterSafe) Start(ctx context.Context, parent any) error { s.name = getParentName(parent) s.parentCtx = ctx s.ctx, s.stopFunc = context.WithCancel(s.parentCtx) - if s.stopped { - // s.stopFunc() - } return nil } From 8ba1b3b28e55e57574e46dc619c1fe3ff19d6a33 Mon Sep 17 00:00:00 2001 From: ImJeremyHe Date: Thu, 11 Apr 2024 14:45:46 +0800 Subject: [PATCH 8/9] Add the switch test to the e2e ci --- .github/workflows/ci.yml | 4 ++-- .github/workflows/espresso-e2e.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6c5f5f57b9..adf90f464f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -145,13 +145,13 @@ jobs: if: matrix.test-mode == 'defaults' run: | packages=`go list ./...` - gotestsum --format short-verbose --packages="$packages" --rerun-fails=1 -- -timeout 25m -coverprofile=coverage.txt -covermode=atomic -coverpkg=./...,./go-ethereum/... -skip TestEspressoE2E + gotestsum --format short-verbose --packages="$packages" --rerun-fails=1 -- -timeout 25m -coverprofile=coverage.txt -covermode=atomic -coverpkg=./...,./go-ethereum/... -skip 'TestEspressoE2E|TestEspressoSwitch' - name: run tests with race detection if: matrix.test-mode == 'race' run: | packages=`go list ./...` - gotestsum --format short-verbose --packages="$packages" --rerun-fails=1 -- --timeout 30m -race -skip TestEspressoE2E + gotestsum --format short-verbose --packages="$packages" --rerun-fails=1 -- --timeout 30m -race -skip 'TestEspressoE2E|TestEspressoSwitch' - name: run redis tests if: matrix.test-mode == 'defaults' diff --git a/.github/workflows/espresso-e2e.yml b/.github/workflows/espresso-e2e.yml index 45c1c530fc..24b37075b5 100644 --- a/.github/workflows/espresso-e2e.yml +++ b/.github/workflows/espresso-e2e.yml @@ -133,4 +133,4 @@ jobs: - name: Run test run: | packages=`go list ./... | grep system_tests` - gotestsum --format short-verbose --packages="$packages" --rerun-fails=1 -- -v -timeout 25m ./... -run TestEspressoE2E + gotestsum --format short-verbose --packages="$packages" --rerun-fails=1 -- -v -timeout 35m ./... -run 'TestEspressoE2E|TestEspressoSwitch' From 025b1cf0b08452cc801daa977dbdf23ea4d26a3c Mon Sep 17 00:00:00 2001 From: ImJeremyHe Date: Thu, 11 Apr 2024 16:05:17 +0800 Subject: [PATCH 9/9] Increase the limit --- system_tests/espresso_switch_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system_tests/espresso_switch_test.go b/system_tests/espresso_switch_test.go index 5349605467..dafb2759b1 100644 --- a/system_tests/espresso_switch_test.go +++ b/system_tests/espresso_switch_test.go @@ -28,7 +28,7 @@ func TestEspressoSwitch(t *testing.T) { currMsg := arbutil.MessageIndex(0) // Wait for the switch to be totally finished - err = waitForWith(t, ctx, 2*time.Minute, 15*time.Second, func() bool { + err = waitForWith(t, ctx, 3*time.Minute, 30*time.Second, func() bool { msg, err := node.ConsensusNode.TxStreamer.GetMessageCount() if err != nil { return false