From 1f399badd0357200b2bedbac06066db6a6888094 Mon Sep 17 00:00:00 2001 From: Maciej Kulawik Date: Mon, 29 Jan 2024 21:41:07 +0000 Subject: [PATCH 01/18] add state recovery option --- cmd/conf/init.go | 59 +++++++++--------- cmd/nitro/init.go | 8 +++ cmd/staterecovery/staterecovery.go | 83 +++++++++++++++++++++++++ execution/gethexec/blockchain.go | 1 + system_tests/staterecovery_test.go | 99 ++++++++++++++++++++++++++++++ 5 files changed, 222 insertions(+), 28 deletions(-) create mode 100644 cmd/staterecovery/staterecovery.go create mode 100644 system_tests/staterecovery_test.go diff --git a/cmd/conf/init.go b/cmd/conf/init.go index bebf1955b7..313e5bbee5 100644 --- a/cmd/conf/init.go +++ b/cmd/conf/init.go @@ -7,37 +7,39 @@ import ( ) type InitConfig struct { - Force bool `koanf:"force"` - Url string `koanf:"url"` - DownloadPath string `koanf:"download-path"` - DownloadPoll time.Duration `koanf:"download-poll"` - DevInit bool `koanf:"dev-init"` - DevInitAddress string `koanf:"dev-init-address"` - DevInitBlockNum uint64 `koanf:"dev-init-blocknum"` - Empty bool `koanf:"empty"` - AccountsPerSync uint `koanf:"accounts-per-sync"` - ImportFile string `koanf:"import-file"` - ThenQuit bool `koanf:"then-quit"` - Prune string `koanf:"prune"` - PruneBloomSize uint64 `koanf:"prune-bloom-size"` - ResetToMessage int64 `koanf:"reset-to-message"` + Force bool `koanf:"force"` + Url string `koanf:"url"` + DownloadPath string `koanf:"download-path"` + DownloadPoll time.Duration `koanf:"download-poll"` + DevInit bool `koanf:"dev-init"` + DevInitAddress string `koanf:"dev-init-address"` + DevInitBlockNum uint64 `koanf:"dev-init-blocknum"` + Empty bool `koanf:"empty"` + AccountsPerSync uint `koanf:"accounts-per-sync"` + ImportFile string `koanf:"import-file"` + ThenQuit bool `koanf:"then-quit"` + Prune string `koanf:"prune"` + PruneBloomSize uint64 `koanf:"prune-bloom-size"` + ResetToMessage int64 `koanf:"reset-to-message"` + RecreateMissingState bool `koanf:"recreate-missing-state"` } var InitConfigDefault = InitConfig{ - Force: false, - Url: "", - DownloadPath: "/tmp/", - DownloadPoll: time.Minute, - DevInit: false, - DevInitAddress: "", - DevInitBlockNum: 0, - Empty: false, - ImportFile: "", - AccountsPerSync: 100000, - ThenQuit: false, - Prune: "", - PruneBloomSize: 2048, - ResetToMessage: -1, + Force: false, + Url: "", + DownloadPath: "/tmp/", + DownloadPoll: time.Minute, + DevInit: false, + DevInitAddress: "", + DevInitBlockNum: 0, + Empty: false, + ImportFile: "", + AccountsPerSync: 100000, + ThenQuit: false, + Prune: "", + PruneBloomSize: 2048, + ResetToMessage: -1, + RecreateMissingState: false, } func InitConfigAddOptions(prefix string, f *pflag.FlagSet) { @@ -55,4 +57,5 @@ func InitConfigAddOptions(prefix string, f *pflag.FlagSet) { f.String(prefix+".prune", InitConfigDefault.Prune, "pruning for a given use: \"full\" for full nodes serving RPC requests, or \"validator\" for validators") f.Uint64(prefix+".prune-bloom-size", InitConfigDefault.PruneBloomSize, "the amount of memory in megabytes to use for the pruning bloom filter (higher values prune better)") f.Int64(prefix+".reset-to-message", InitConfigDefault.ResetToMessage, "forces a reset to an old message height. Also set max-reorg-resequence-depth=0 to force re-reading messages") + f.Bool(prefix+".recreate-missing-state", InitConfigDefault.RecreateMissingState, "if true: in case database exists and force=false, missing state will be recreated and committed to disk") } diff --git a/cmd/nitro/init.go b/cmd/nitro/init.go index 4cf5dcda06..bab15b6157 100644 --- a/cmd/nitro/init.go +++ b/cmd/nitro/init.go @@ -34,6 +34,7 @@ import ( "github.com/offchainlabs/nitro/cmd/conf" "github.com/offchainlabs/nitro/cmd/ipfshelper" "github.com/offchainlabs/nitro/cmd/pruning" + "github.com/offchainlabs/nitro/cmd/staterecovery" "github.com/offchainlabs/nitro/cmd/util" "github.com/offchainlabs/nitro/execution/gethexec" "github.com/offchainlabs/nitro/statetransfer" @@ -183,6 +184,13 @@ func openInitializeChainDb(ctx context.Context, stack *node.Node, config *NodeCo if err != nil { return chainDb, l2BlockChain, err } + if config.Init.RecreateMissingState { + err = staterecovery.RecreateMissingStates(chainDb, l2BlockChain, cachingConfig) + if err != nil { + return chainDb, l2BlockChain, err + } + } + return chainDb, l2BlockChain, nil } readOnlyDb.Close() diff --git a/cmd/staterecovery/staterecovery.go b/cmd/staterecovery/staterecovery.go new file mode 100644 index 0000000000..0f2eba5c60 --- /dev/null +++ b/cmd/staterecovery/staterecovery.go @@ -0,0 +1,83 @@ +package staterecovery + +import ( + "fmt" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/trie" + "github.com/ethereum/go-ethereum/trie/triedb/hashdb" +) + +func RecreateMissingStates(chainDb ethdb.Database, bc *core.BlockChain, cacheConfig *core.CacheConfig) error { + log.Info("Recreating missing states...") + start := time.Now() + current := bc.Genesis().NumberU64() + 1 + last := bc.CurrentBlock().Number.Uint64() + + previousBlock := bc.GetBlockByNumber(current - 1) + if previousBlock == nil { + return fmt.Errorf("genesis block is missing") + } + hashConfig := *hashdb.Defaults + hashConfig.CleanCacheSize = cacheConfig.TrieCleanLimit + trieConfig := &trie.Config{ + Preimages: false, + HashDB: &hashConfig, + } + database := state.NewDatabaseWithConfig(chainDb, trieConfig) + defer database.TrieDB().Close() + previousState, err := state.New(previousBlock.Root(), database, nil) + if err != nil { + return fmt.Errorf("genesis state is missing: %w", err) + } + database.TrieDB().Reference(previousBlock.Root(), common.Hash{}) + logged := time.Now() + recreated := 0 + for current <= last { + if time.Since(logged) > 1*time.Minute { + log.Info("Recreating missing states", "block", current, "target", last, "remaining", last-current, "elapsed", time.Since(start), "recreated", recreated) + logged = time.Now() + } + currentBlock := bc.GetBlockByNumber(current) + if currentBlock == nil { + return fmt.Errorf("missing block %d", current) + } + currentState, err := state.New(currentBlock.Root(), database, nil) + if err != nil { + _, _, _, err := bc.Processor().Process(currentBlock, previousState, vm.Config{}) + if err != nil { + return fmt.Errorf("processing block %d failed: %v", current, err) + } + root, err := previousState.Commit(current, bc.Config().IsEIP158(currentBlock.Number())) + if err != nil { + return fmt.Errorf("StateDB commit failed, number %d root %v: %w", current, currentBlock.Root().Hex(), err) + } + if root.Cmp(currentBlock.Root()) != 0 { + return fmt.Errorf("reached different state root after processing block %d, want %v, have %v", current, currentBlock.Root(), root) + } + // commit to disk + err = database.TrieDB().Commit(root, false) // TODO report = true, do we want this many logs? + if err != nil { + return fmt.Errorf("TrieDB commit failed, number %d root %v: %w", current, root, err) + } + currentState, err = state.New(currentBlock.Root(), database, nil) + if err != nil { + return fmt.Errorf("state reset after block %d failed: %v", current, err) + } + database.TrieDB().Reference(currentBlock.Root(), common.Hash{}) + database.TrieDB().Dereference(previousBlock.Root()) + recreated++ + } + current++ + previousState = currentState + previousBlock = currentBlock + } + log.Info("Finished recreating missing states", "elapsed", time.Since(start), "recreated", recreated) + return nil +} diff --git a/execution/gethexec/blockchain.go b/execution/gethexec/blockchain.go index a85224b635..2a20c3da26 100644 --- a/execution/gethexec/blockchain.go +++ b/execution/gethexec/blockchain.go @@ -67,6 +67,7 @@ var DefaultCachingConfig = CachingConfig{ MaxAmountOfGasToSkipStateSaving: 0, } +// TODO remove stack from parameters as it is no longer needed here func DefaultCacheConfigFor(stack *node.Node, cachingConfig *CachingConfig) *core.CacheConfig { baseConf := ethconfig.Defaults if cachingConfig.Archive { diff --git a/system_tests/staterecovery_test.go b/system_tests/staterecovery_test.go new file mode 100644 index 0000000000..561e889153 --- /dev/null +++ b/system_tests/staterecovery_test.go @@ -0,0 +1,99 @@ +package arbtest + +import ( + "context" + "testing" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/node" + "github.com/ethereum/go-ethereum/trie" + "github.com/offchainlabs/nitro/cmd/staterecovery" + "github.com/offchainlabs/nitro/execution/gethexec" +) + +func TestRectreateMissingStates(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + builder := NewNodeBuilder(ctx).DefaultConfig(t, true) + builder.execConfig.Caching.MaxNumberOfBlocksToSkipStateSaving = 16 + _ = builder.Build(t) + l2cleanupDone := false + defer func() { + if !l2cleanupDone { + builder.L2.cleanup() + } + builder.L1.cleanup() + }() + builder.L2Info.GenerateAccount("User2") + var txs []*types.Transaction + for i := uint64(0); i < 200; i++ { + tx := builder.L2Info.PrepareTx("Owner", "User2", builder.L2Info.TransferGas, common.Big1, nil) + txs = append(txs, tx) + err := builder.L2.Client.SendTransaction(ctx, tx) + Require(t, err) + } + for _, tx := range txs { + _, err := builder.L2.EnsureTxSucceeded(tx) + Require(t, err) + } + lastBlock, err := builder.L2.Client.BlockNumber(ctx) + Require(t, err) + l2cleanupDone = true + builder.L2.cleanup() + t.Log("stopped l2 node") + func() { + stack, err := node.New(builder.l2StackConfig) + Require(t, err) + defer stack.Close() + chainDb, err := stack.OpenDatabase("chaindb", 0, 0, "", false) + Require(t, err) + defer chainDb.Close() + cacheConfig := gethexec.DefaultCacheConfigFor(stack, &gethexec.DefaultCachingConfig) + bc, err := gethexec.GetBlockChain(chainDb, cacheConfig, builder.chainConfig, builder.execConfig.TxLookupLimit) + Require(t, err) + err = staterecovery.RecreateMissingStates(chainDb, bc, cacheConfig) + Require(t, err) + }() + + testClient, cleanup := builder.Build2ndNode(t, &SecondNodeParams{stackConfig: builder.l2StackConfig}) + defer cleanup() + + currentBlock := uint64(0) + // wait for the chain to catch up + for currentBlock < lastBlock { + currentBlock, err = testClient.Client.BlockNumber(ctx) + Require(t, err) + time.Sleep(20 * time.Millisecond) + } + + currentBlock, err = testClient.Client.BlockNumber(ctx) + Require(t, err) + bc := testClient.ExecNode.Backend.ArbInterface().BlockChain() + triedb := bc.StateCache().TrieDB() + var start uint64 + if currentBlock+1 >= builder.execConfig.Caching.BlockCount { + start = currentBlock + 1 - builder.execConfig.Caching.BlockCount + } else { + start = 0 + } + for i := start; i <= currentBlock; i++ { + header := bc.GetHeaderByNumber(i) + _, err := bc.StateAt(header.Root) + Require(t, err) + tr, err := trie.New(trie.TrieID(header.Root), triedb) + Require(t, err) + it, err := tr.NodeIterator(nil) + Require(t, err) + for it.Next(true) { + } + Require(t, it.Error()) + } + + tx := builder.L2Info.PrepareTx("Owner", "User2", builder.L2Info.TransferGas, common.Big1, nil) + err = testClient.Client.SendTransaction(ctx, tx) + Require(t, err) + _, err = testClient.EnsureTxSucceeded(tx) + Require(t, err) +} From 333e46fa5513e3996856b11eae74be4a09e08dd0 Mon Sep 17 00:00:00 2001 From: Maciej Kulawik Date: Mon, 29 Jan 2024 21:47:14 +0000 Subject: [PATCH 02/18] fix referencing --- cmd/nitro/init.go | 2 +- cmd/staterecovery/staterecovery.go | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/cmd/nitro/init.go b/cmd/nitro/init.go index bab15b6157..c7d850ac77 100644 --- a/cmd/nitro/init.go +++ b/cmd/nitro/init.go @@ -185,7 +185,7 @@ func openInitializeChainDb(ctx context.Context, stack *node.Node, config *NodeCo return chainDb, l2BlockChain, err } if config.Init.RecreateMissingState { - err = staterecovery.RecreateMissingStates(chainDb, l2BlockChain, cachingConfig) + err = staterecovery.RecreateMissingStates(chainDb, l2BlockChain, cacheConfig) if err != nil { return chainDb, l2BlockChain, err } diff --git a/cmd/staterecovery/staterecovery.go b/cmd/staterecovery/staterecovery.go index 0f2eba5c60..a2918a81fe 100644 --- a/cmd/staterecovery/staterecovery.go +++ b/cmd/staterecovery/staterecovery.go @@ -36,7 +36,7 @@ func RecreateMissingStates(chainDb ethdb.Database, bc *core.BlockChain, cacheCon if err != nil { return fmt.Errorf("genesis state is missing: %w", err) } - database.TrieDB().Reference(previousBlock.Root(), common.Hash{}) + _ = database.TrieDB().Reference(previousBlock.Root(), common.Hash{}) logged := time.Now() recreated := 0 for current <= last { @@ -52,11 +52,11 @@ func RecreateMissingStates(chainDb ethdb.Database, bc *core.BlockChain, cacheCon if err != nil { _, _, _, err := bc.Processor().Process(currentBlock, previousState, vm.Config{}) if err != nil { - return fmt.Errorf("processing block %d failed: %v", current, err) + return fmt.Errorf("processing block %d failed: %w", current, err) } root, err := previousState.Commit(current, bc.Config().IsEIP158(currentBlock.Number())) if err != nil { - return fmt.Errorf("StateDB commit failed, number %d root %v: %w", current, currentBlock.Root().Hex(), err) + return fmt.Errorf("StateDB commit failed, number %d root %v: %w", current, currentBlock.Root(), err) } if root.Cmp(currentBlock.Root()) != 0 { return fmt.Errorf("reached different state root after processing block %d, want %v, have %v", current, currentBlock.Root(), root) @@ -68,16 +68,17 @@ func RecreateMissingStates(chainDb ethdb.Database, bc *core.BlockChain, cacheCon } currentState, err = state.New(currentBlock.Root(), database, nil) if err != nil { - return fmt.Errorf("state reset after block %d failed: %v", current, err) + return fmt.Errorf("state reset after block %d failed: %w", current, err) } - database.TrieDB().Reference(currentBlock.Root(), common.Hash{}) - database.TrieDB().Dereference(previousBlock.Root()) recreated++ } + _ = database.TrieDB().Reference(currentBlock.Root(), common.Hash{}) + _ = database.TrieDB().Dereference(previousBlock.Root()) current++ - previousState = currentState previousBlock = currentBlock + previousState = currentState } + _ = database.TrieDB().Dereference(previousBlock.Root()) log.Info("Finished recreating missing states", "elapsed", time.Since(start), "recreated", recreated) return nil } From c53c26ac50dfafb5402b2bafb532c85f10a9ecda Mon Sep 17 00:00:00 2001 From: Maciej Kulawik Date: Tue, 30 Jan 2024 18:20:09 +0000 Subject: [PATCH 03/18] defer last dereference call --- cmd/staterecovery/staterecovery.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cmd/staterecovery/staterecovery.go b/cmd/staterecovery/staterecovery.go index a2918a81fe..43faa64053 100644 --- a/cmd/staterecovery/staterecovery.go +++ b/cmd/staterecovery/staterecovery.go @@ -37,6 +37,9 @@ func RecreateMissingStates(chainDb ethdb.Database, bc *core.BlockChain, cacheCon return fmt.Errorf("genesis state is missing: %w", err) } _ = database.TrieDB().Reference(previousBlock.Root(), common.Hash{}) + defer func() { + _ = database.TrieDB().Dereference(previousBlock.Root()) + }() logged := time.Now() recreated := 0 for current <= last { @@ -78,7 +81,6 @@ func RecreateMissingStates(chainDb ethdb.Database, bc *core.BlockChain, cacheCon previousBlock = currentBlock previousState = currentState } - _ = database.TrieDB().Dereference(previousBlock.Root()) log.Info("Finished recreating missing states", "elapsed", time.Since(start), "recreated", recreated) return nil } From 2cb13424eec12b336ed62c5213d75d2a63c5a9df Mon Sep 17 00:00:00 2001 From: Maciej Kulawik Date: Tue, 30 Jan 2024 18:42:13 +0000 Subject: [PATCH 04/18] don't use referencing when recovering states --- cmd/staterecovery/staterecovery.go | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/cmd/staterecovery/staterecovery.go b/cmd/staterecovery/staterecovery.go index 43faa64053..f2feb5c7aa 100644 --- a/cmd/staterecovery/staterecovery.go +++ b/cmd/staterecovery/staterecovery.go @@ -4,7 +4,6 @@ import ( "fmt" "time" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/vm" @@ -36,10 +35,9 @@ func RecreateMissingStates(chainDb ethdb.Database, bc *core.BlockChain, cacheCon if err != nil { return fmt.Errorf("genesis state is missing: %w", err) } - _ = database.TrieDB().Reference(previousBlock.Root(), common.Hash{}) - defer func() { - _ = database.TrieDB().Dereference(previousBlock.Root()) - }() + // we don't need to reference states with `trie.Database.Reference` here, because: + // * either the state nodes will be read from disk and then cached in cleans cache + // * or they will be recreated, saved to disk and then also cached in cleans cache logged := time.Now() recreated := 0 for current <= last { @@ -75,8 +73,6 @@ func RecreateMissingStates(chainDb ethdb.Database, bc *core.BlockChain, cacheCon } recreated++ } - _ = database.TrieDB().Reference(currentBlock.Root(), common.Hash{}) - _ = database.TrieDB().Dereference(previousBlock.Root()) current++ previousBlock = currentBlock previousState = currentState From a594bc23bc2fa00053bb71cdedf984a1e11861d0 Mon Sep 17 00:00:00 2001 From: Maciej Kulawik Date: Tue, 30 Jan 2024 19:04:21 +0000 Subject: [PATCH 05/18] remove unsused assignment --- cmd/staterecovery/staterecovery.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/cmd/staterecovery/staterecovery.go b/cmd/staterecovery/staterecovery.go index f2feb5c7aa..f21d213ba7 100644 --- a/cmd/staterecovery/staterecovery.go +++ b/cmd/staterecovery/staterecovery.go @@ -19,8 +19,8 @@ func RecreateMissingStates(chainDb ethdb.Database, bc *core.BlockChain, cacheCon current := bc.Genesis().NumberU64() + 1 last := bc.CurrentBlock().Number.Uint64() - previousBlock := bc.GetBlockByNumber(current - 1) - if previousBlock == nil { + genesisBlock := bc.GetBlockByNumber(current - 1) + if genesisBlock == nil { return fmt.Errorf("genesis block is missing") } hashConfig := *hashdb.Defaults @@ -31,7 +31,7 @@ func RecreateMissingStates(chainDb ethdb.Database, bc *core.BlockChain, cacheCon } database := state.NewDatabaseWithConfig(chainDb, trieConfig) defer database.TrieDB().Close() - previousState, err := state.New(previousBlock.Root(), database, nil) + previousState, err := state.New(genesisBlock.Root(), database, nil) if err != nil { return fmt.Errorf("genesis state is missing: %w", err) } @@ -60,7 +60,7 @@ func RecreateMissingStates(chainDb ethdb.Database, bc *core.BlockChain, cacheCon return fmt.Errorf("StateDB commit failed, number %d root %v: %w", current, currentBlock.Root(), err) } if root.Cmp(currentBlock.Root()) != 0 { - return fmt.Errorf("reached different state root after processing block %d, want %v, have %v", current, currentBlock.Root(), root) + return fmt.Errorf("reached different state root after processing block %d, have %v, want %v", current, root, currentBlock.Root()) } // commit to disk err = database.TrieDB().Commit(root, false) // TODO report = true, do we want this many logs? @@ -74,7 +74,6 @@ func RecreateMissingStates(chainDb ethdb.Database, bc *core.BlockChain, cacheCon recreated++ } current++ - previousBlock = currentBlock previousState = currentState } log.Info("Finished recreating missing states", "elapsed", time.Since(start), "recreated", recreated) From aa304a9e321bec9985d8d00b8248816e1e381b81 Mon Sep 17 00:00:00 2001 From: Maciej Kulawik Date: Tue, 30 Jan 2024 21:24:18 +0000 Subject: [PATCH 06/18] don't rely on BlockChain.CurrentBlock to get last available block --- cmd/nitro/init.go | 2 +- cmd/staterecovery/staterecovery.go | 14 +++++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/cmd/nitro/init.go b/cmd/nitro/init.go index c7d850ac77..65c8962aa9 100644 --- a/cmd/nitro/init.go +++ b/cmd/nitro/init.go @@ -187,7 +187,7 @@ func openInitializeChainDb(ctx context.Context, stack *node.Node, config *NodeCo if config.Init.RecreateMissingState { err = staterecovery.RecreateMissingStates(chainDb, l2BlockChain, cacheConfig) if err != nil { - return chainDb, l2BlockChain, err + return chainDb, l2BlockChain, fmt.Errorf("failed to recreate missing states: %w", err) } } diff --git a/cmd/staterecovery/staterecovery.go b/cmd/staterecovery/staterecovery.go index f21d213ba7..0d35d89b25 100644 --- a/cmd/staterecovery/staterecovery.go +++ b/cmd/staterecovery/staterecovery.go @@ -1,6 +1,7 @@ package staterecovery import ( + "errors" "fmt" "time" @@ -14,15 +15,18 @@ import ( ) func RecreateMissingStates(chainDb ethdb.Database, bc *core.BlockChain, cacheConfig *core.CacheConfig) error { - log.Info("Recreating missing states...") start := time.Now() current := bc.Genesis().NumberU64() + 1 - last := bc.CurrentBlock().Number.Uint64() - genesisBlock := bc.GetBlockByNumber(current - 1) if genesisBlock == nil { - return fmt.Errorf("genesis block is missing") + return errors.New("genesis block is missing") + } + // find last available block - we cannot rely on bc.CurrentBlock() + last := current + for bc.GetBlockByNumber(last) != nil { + last++ } + last-- hashConfig := *hashdb.Defaults hashConfig.CleanCacheSize = cacheConfig.TrieCleanLimit trieConfig := &trie.Config{ @@ -38,7 +42,7 @@ func RecreateMissingStates(chainDb ethdb.Database, bc *core.BlockChain, cacheCon // we don't need to reference states with `trie.Database.Reference` here, because: // * either the state nodes will be read from disk and then cached in cleans cache // * or they will be recreated, saved to disk and then also cached in cleans cache - logged := time.Now() + logged := time.Unix(0, 0) recreated := 0 for current <= last { if time.Since(logged) > 1*time.Minute { From 43a8aeb122f4ee87810d992f9d6be20a661a1a4a Mon Sep 17 00:00:00 2001 From: Maciej Kulawik Date: Tue, 30 Jan 2024 21:32:30 +0000 Subject: [PATCH 07/18] improve recovery test --- system_tests/staterecovery_test.go | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/system_tests/staterecovery_test.go b/system_tests/staterecovery_test.go index 561e889153..33608bc8aa 100644 --- a/system_tests/staterecovery_test.go +++ b/system_tests/staterecovery_test.go @@ -72,13 +72,7 @@ func TestRectreateMissingStates(t *testing.T) { Require(t, err) bc := testClient.ExecNode.Backend.ArbInterface().BlockChain() triedb := bc.StateCache().TrieDB() - var start uint64 - if currentBlock+1 >= builder.execConfig.Caching.BlockCount { - start = currentBlock + 1 - builder.execConfig.Caching.BlockCount - } else { - start = 0 - } - for i := start; i <= currentBlock; i++ { + for i := uint64(0); i <= currentBlock; i++ { header := bc.GetHeaderByNumber(i) _, err := bc.StateAt(header.Root) Require(t, err) From d5989b5a8cc00a385f3f094a220e21968fd95620 Mon Sep 17 00:00:00 2001 From: Maciej Kulawik Date: Tue, 30 Jan 2024 21:49:25 +0000 Subject: [PATCH 08/18] add recreate-missing-state config validation --- cmd/conf/init.go | 8 ++++++++ cmd/nitro/nitro.go | 6 ++++++ 2 files changed, 14 insertions(+) diff --git a/cmd/conf/init.go b/cmd/conf/init.go index 313e5bbee5..73848ebcf2 100644 --- a/cmd/conf/init.go +++ b/cmd/conf/init.go @@ -3,6 +3,7 @@ package conf import ( "time" + "github.com/ethereum/go-ethereum/log" "github.com/spf13/pflag" ) @@ -59,3 +60,10 @@ func InitConfigAddOptions(prefix string, f *pflag.FlagSet) { f.Int64(prefix+".reset-to-message", InitConfigDefault.ResetToMessage, "forces a reset to an old message height. Also set max-reorg-resequence-depth=0 to force re-reading messages") f.Bool(prefix+".recreate-missing-state", InitConfigDefault.RecreateMissingState, "if true: in case database exists and force=false, missing state will be recreated and committed to disk") } + +func (c *InitConfig) Validate() error { + if c.Force && c.RecreateMissingState { + log.Warn("--init.force enabled, --init.recreate-missing-state will have no effect") + } + return nil +} diff --git a/cmd/nitro/nitro.go b/cmd/nitro/nitro.go index 45f539488d..4838d981e3 100644 --- a/cmd/nitro/nitro.go +++ b/cmd/nitro/nitro.go @@ -781,6 +781,12 @@ func (c *NodeConfig) CanReload(new *NodeConfig) error { } func (c *NodeConfig) Validate() error { + if c.Init.RecreateMissingState && !c.Execution.Caching.Archive { + return errors.New("--init.recreate-missing-state enabled for a non-archive node") + } + if err := c.Init.Validate(); err != nil { + return err + } if err := c.ParentChain.Validate(); err != nil { return err } From 6f9d044f92b15e1bf0bf5a22466f3a25991a46dc Mon Sep 17 00:00:00 2001 From: Maciej Kulawik Date: Tue, 30 Jan 2024 21:52:20 +0000 Subject: [PATCH 09/18] update log messages --- cmd/conf/init.go | 2 +- cmd/nitro/nitro.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/conf/init.go b/cmd/conf/init.go index 73848ebcf2..b9617f30ac 100644 --- a/cmd/conf/init.go +++ b/cmd/conf/init.go @@ -63,7 +63,7 @@ func InitConfigAddOptions(prefix string, f *pflag.FlagSet) { func (c *InitConfig) Validate() error { if c.Force && c.RecreateMissingState { - log.Warn("--init.force enabled, --init.recreate-missing-state will have no effect") + log.Warn("force init enabled, recreate-missing-state will have no effect") } return nil } diff --git a/cmd/nitro/nitro.go b/cmd/nitro/nitro.go index 4838d981e3..3932e0ed94 100644 --- a/cmd/nitro/nitro.go +++ b/cmd/nitro/nitro.go @@ -782,7 +782,7 @@ func (c *NodeConfig) CanReload(new *NodeConfig) error { func (c *NodeConfig) Validate() error { if c.Init.RecreateMissingState && !c.Execution.Caching.Archive { - return errors.New("--init.recreate-missing-state enabled for a non-archive node") + return errors.New("recreate-missing-state enabled for a non-archive node") } if err := c.Init.Validate(); err != nil { return err From f61ad77e1f0253f12059aec3e17ae7a7a10821b1 Mon Sep 17 00:00:00 2001 From: Maciej Kulawik Date: Thu, 1 Feb 2024 20:23:42 +0000 Subject: [PATCH 10/18] allow setting start block for missing states recreation, fix tests --- cmd/conf/init.go | 66 +++++++++++++++--------------- cmd/nitro/init.go | 4 +- cmd/nitro/nitro.go | 4 +- cmd/staterecovery/staterecovery.go | 22 ++++++---- system_tests/Session.vim | 34 +++++++++++++++ system_tests/staterecovery_test.go | 4 +- 6 files changed, 87 insertions(+), 47 deletions(-) create mode 100644 system_tests/Session.vim diff --git a/cmd/conf/init.go b/cmd/conf/init.go index b9617f30ac..71709a8303 100644 --- a/cmd/conf/init.go +++ b/cmd/conf/init.go @@ -8,39 +8,39 @@ import ( ) type InitConfig struct { - Force bool `koanf:"force"` - Url string `koanf:"url"` - DownloadPath string `koanf:"download-path"` - DownloadPoll time.Duration `koanf:"download-poll"` - DevInit bool `koanf:"dev-init"` - DevInitAddress string `koanf:"dev-init-address"` - DevInitBlockNum uint64 `koanf:"dev-init-blocknum"` - Empty bool `koanf:"empty"` - AccountsPerSync uint `koanf:"accounts-per-sync"` - ImportFile string `koanf:"import-file"` - ThenQuit bool `koanf:"then-quit"` - Prune string `koanf:"prune"` - PruneBloomSize uint64 `koanf:"prune-bloom-size"` - ResetToMessage int64 `koanf:"reset-to-message"` - RecreateMissingState bool `koanf:"recreate-missing-state"` + Force bool `koanf:"force"` + Url string `koanf:"url"` + DownloadPath string `koanf:"download-path"` + DownloadPoll time.Duration `koanf:"download-poll"` + DevInit bool `koanf:"dev-init"` + DevInitAddress string `koanf:"dev-init-address"` + DevInitBlockNum uint64 `koanf:"dev-init-blocknum"` + Empty bool `koanf:"empty"` + AccountsPerSync uint `koanf:"accounts-per-sync"` + ImportFile string `koanf:"import-file"` + ThenQuit bool `koanf:"then-quit"` + Prune string `koanf:"prune"` + PruneBloomSize uint64 `koanf:"prune-bloom-size"` + ResetToMessage int64 `koanf:"reset-to-message"` + RecreateMissingStateFrom uint64 `koanf:"recreate-missing-state-from"` } var InitConfigDefault = InitConfig{ - Force: false, - Url: "", - DownloadPath: "/tmp/", - DownloadPoll: time.Minute, - DevInit: false, - DevInitAddress: "", - DevInitBlockNum: 0, - Empty: false, - ImportFile: "", - AccountsPerSync: 100000, - ThenQuit: false, - Prune: "", - PruneBloomSize: 2048, - ResetToMessage: -1, - RecreateMissingState: false, + Force: false, + Url: "", + DownloadPath: "/tmp/", + DownloadPoll: time.Minute, + DevInit: false, + DevInitAddress: "", + DevInitBlockNum: 0, + Empty: false, + ImportFile: "", + AccountsPerSync: 100000, + ThenQuit: false, + Prune: "", + PruneBloomSize: 2048, + ResetToMessage: -1, + RecreateMissingStateFrom: 0, // 0 = disabled } func InitConfigAddOptions(prefix string, f *pflag.FlagSet) { @@ -58,12 +58,12 @@ func InitConfigAddOptions(prefix string, f *pflag.FlagSet) { f.String(prefix+".prune", InitConfigDefault.Prune, "pruning for a given use: \"full\" for full nodes serving RPC requests, or \"validator\" for validators") f.Uint64(prefix+".prune-bloom-size", InitConfigDefault.PruneBloomSize, "the amount of memory in megabytes to use for the pruning bloom filter (higher values prune better)") f.Int64(prefix+".reset-to-message", InitConfigDefault.ResetToMessage, "forces a reset to an old message height. Also set max-reorg-resequence-depth=0 to force re-reading messages") - f.Bool(prefix+".recreate-missing-state", InitConfigDefault.RecreateMissingState, "if true: in case database exists and force=false, missing state will be recreated and committed to disk") + f.Uint64(prefix+".recreate-missing-state-from", InitConfigDefault.RecreateMissingStateFrom, "block number to start recreating missing states form (0 = disabled)") } func (c *InitConfig) Validate() error { - if c.Force && c.RecreateMissingState { - log.Warn("force init enabled, recreate-missing-state will have no effect") + if c.Force && c.RecreateMissingStateFrom > 0 { + log.Warn("force init enabled, recreate-missing-state-from will have no effect") } return nil } diff --git a/cmd/nitro/init.go b/cmd/nitro/init.go index 65c8962aa9..ebc57b13b8 100644 --- a/cmd/nitro/init.go +++ b/cmd/nitro/init.go @@ -184,8 +184,8 @@ func openInitializeChainDb(ctx context.Context, stack *node.Node, config *NodeCo if err != nil { return chainDb, l2BlockChain, err } - if config.Init.RecreateMissingState { - err = staterecovery.RecreateMissingStates(chainDb, l2BlockChain, cacheConfig) + if config.Init.RecreateMissingStateFrom > 0 { + err = staterecovery.RecreateMissingStates(chainDb, l2BlockChain, cacheConfig, config.Init.RecreateMissingStateFrom) if err != nil { return chainDb, l2BlockChain, fmt.Errorf("failed to recreate missing states: %w", err) } diff --git a/cmd/nitro/nitro.go b/cmd/nitro/nitro.go index 3932e0ed94..e5b97d4a1c 100644 --- a/cmd/nitro/nitro.go +++ b/cmd/nitro/nitro.go @@ -781,8 +781,8 @@ func (c *NodeConfig) CanReload(new *NodeConfig) error { } func (c *NodeConfig) Validate() error { - if c.Init.RecreateMissingState && !c.Execution.Caching.Archive { - return errors.New("recreate-missing-state enabled for a non-archive node") + if c.Init.RecreateMissingStateFrom > 0 && !c.Execution.Caching.Archive { + return errors.New("recreate-missing-state-from enabled for a non-archive node") } if err := c.Init.Validate(); err != nil { return err diff --git a/cmd/staterecovery/staterecovery.go b/cmd/staterecovery/staterecovery.go index 0d35d89b25..4b5f9b846f 100644 --- a/cmd/staterecovery/staterecovery.go +++ b/cmd/staterecovery/staterecovery.go @@ -1,7 +1,6 @@ package staterecovery import ( - "errors" "fmt" "time" @@ -14,12 +13,17 @@ import ( "github.com/ethereum/go-ethereum/trie/triedb/hashdb" ) -func RecreateMissingStates(chainDb ethdb.Database, bc *core.BlockChain, cacheConfig *core.CacheConfig) error { +func RecreateMissingStates(chainDb ethdb.Database, bc *core.BlockChain, cacheConfig *core.CacheConfig, startBlock uint64) error { start := time.Now() - current := bc.Genesis().NumberU64() + 1 - genesisBlock := bc.GetBlockByNumber(current - 1) - if genesisBlock == nil { - return errors.New("genesis block is missing") + current := startBlock + genesis := bc.Config().ArbitrumChainParams.GenesisBlockNum + if current < genesis+1 { + log.Warn("recreate-missing-states-from before genesis+1, starting from genesis+1") + current = genesis + 1 + } + previousBlock := bc.GetBlockByNumber(current - 1) + if previousBlock == nil { + return fmt.Errorf("start block parent is missing, parent block number: %d", current-1) } // find last available block - we cannot rely on bc.CurrentBlock() last := current @@ -35,9 +39,9 @@ func RecreateMissingStates(chainDb ethdb.Database, bc *core.BlockChain, cacheCon } database := state.NewDatabaseWithConfig(chainDb, trieConfig) defer database.TrieDB().Close() - previousState, err := state.New(genesisBlock.Root(), database, nil) + previousState, err := state.New(previousBlock.Root(), database, nil) if err != nil { - return fmt.Errorf("genesis state is missing: %w", err) + return fmt.Errorf("state of start block parent is missing: %w", err) } // we don't need to reference states with `trie.Database.Reference` here, because: // * either the state nodes will be read from disk and then cached in cleans cache @@ -67,7 +71,7 @@ func RecreateMissingStates(chainDb ethdb.Database, bc *core.BlockChain, cacheCon return fmt.Errorf("reached different state root after processing block %d, have %v, want %v", current, root, currentBlock.Root()) } // commit to disk - err = database.TrieDB().Commit(root, false) // TODO report = true, do we want this many logs? + err = database.TrieDB().Commit(root, false) if err != nil { return fmt.Errorf("TrieDB commit failed, number %d root %v: %w", current, root, err) } diff --git a/system_tests/Session.vim b/system_tests/Session.vim new file mode 100644 index 0000000000..fd61e42444 --- /dev/null +++ b/system_tests/Session.vim @@ -0,0 +1,34 @@ +let SessionLoad = 1 +let s:so_save = &g:so | let s:siso_save = &g:siso | setg so=0 siso=0 | setl so=-1 siso=-1 +let v:this_session=expand(":p") +silent only +silent tabonly +cd ~/repos/nitro3/system_tests +if expand('%') == '' && !&modified && line('$') <= 1 && getline(1) == '' + let s:wipebuf = bufnr('%') +endif +let s:shortmess_save = &shortmess +if &shortmess =~ 'A' + set shortmess=aoOA +else + set shortmess=aoO +endif +argglobal +%argdel +tabnext 1 +if exists('s:wipebuf') && len(win_findbuf(s:wipebuf)) == 0 && getbufvar(s:wipebuf, '&buftype') isnot# 'terminal' + silent exe 'bwipe ' . s:wipebuf +endif +unlet! s:wipebuf +set winheight=1 winwidth=20 +let &shortmess = s:shortmess_save +let s:sx = expand(":p:r")."x.vim" +if filereadable(s:sx) + exe "source " . fnameescape(s:sx) +endif +let &g:so = s:so_save | let &g:siso = s:siso_save +set hlsearch +nohlsearch +doautoall SessionLoadPost +unlet SessionLoad +" vim: set ft=vim : diff --git a/system_tests/staterecovery_test.go b/system_tests/staterecovery_test.go index 33608bc8aa..ac30038cc1 100644 --- a/system_tests/staterecovery_test.go +++ b/system_tests/staterecovery_test.go @@ -17,7 +17,9 @@ func TestRectreateMissingStates(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() builder := NewNodeBuilder(ctx).DefaultConfig(t, true) + builder.execConfig.Caching.Archive = true builder.execConfig.Caching.MaxNumberOfBlocksToSkipStateSaving = 16 + builder.execConfig.Caching.SnapshotCache = 0 // disable snapshots _ = builder.Build(t) l2cleanupDone := false defer func() { @@ -53,7 +55,7 @@ func TestRectreateMissingStates(t *testing.T) { cacheConfig := gethexec.DefaultCacheConfigFor(stack, &gethexec.DefaultCachingConfig) bc, err := gethexec.GetBlockChain(chainDb, cacheConfig, builder.chainConfig, builder.execConfig.TxLookupLimit) Require(t, err) - err = staterecovery.RecreateMissingStates(chainDb, bc, cacheConfig) + err = staterecovery.RecreateMissingStates(chainDb, bc, cacheConfig, 1) Require(t, err) }() From ea34814fbfebc1a6b3d2eaf29d49d8b03e8a2378 Mon Sep 17 00:00:00 2001 From: Maciej Kulawik Date: Thu, 1 Feb 2024 20:28:03 +0000 Subject: [PATCH 11/18] remove Session.vim added by mistake --- system_tests/Session.vim | 34 ---------------------------------- 1 file changed, 34 deletions(-) delete mode 100644 system_tests/Session.vim diff --git a/system_tests/Session.vim b/system_tests/Session.vim deleted file mode 100644 index fd61e42444..0000000000 --- a/system_tests/Session.vim +++ /dev/null @@ -1,34 +0,0 @@ -let SessionLoad = 1 -let s:so_save = &g:so | let s:siso_save = &g:siso | setg so=0 siso=0 | setl so=-1 siso=-1 -let v:this_session=expand(":p") -silent only -silent tabonly -cd ~/repos/nitro3/system_tests -if expand('%') == '' && !&modified && line('$') <= 1 && getline(1) == '' - let s:wipebuf = bufnr('%') -endif -let s:shortmess_save = &shortmess -if &shortmess =~ 'A' - set shortmess=aoOA -else - set shortmess=aoO -endif -argglobal -%argdel -tabnext 1 -if exists('s:wipebuf') && len(win_findbuf(s:wipebuf)) == 0 && getbufvar(s:wipebuf, '&buftype') isnot# 'terminal' - silent exe 'bwipe ' . s:wipebuf -endif -unlet! s:wipebuf -set winheight=1 winwidth=20 -let &shortmess = s:shortmess_save -let s:sx = expand(":p:r")."x.vim" -if filereadable(s:sx) - exe "source " . fnameescape(s:sx) -endif -let &g:so = s:so_save | let &g:siso = s:siso_save -set hlsearch -nohlsearch -doautoall SessionLoadPost -unlet SessionLoad -" vim: set ft=vim : From b9a1c4945de373d41f16957b46692b0ca9ce0d64 Mon Sep 17 00:00:00 2001 From: Chris Buckland Date: Thu, 1 Feb 2024 20:36:37 +0000 Subject: [PATCH 12/18] Log error data where available --- util/rpcclient/rpcclient.go | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/util/rpcclient/rpcclient.go b/util/rpcclient/rpcclient.go index dee6e9252a..d88e6dfc36 100644 --- a/util/rpcclient/rpcclient.go +++ b/util/rpcclient/rpcclient.go @@ -155,13 +155,25 @@ func (c *RpcClient) CallContext(ctx_in context.Context, result interface{}, meth ctx, cancelCtx = context.WithCancel(ctx_in) } err = c.client.CallContext(ctx, result, method, args...) + cancelCtx() logger := log.Trace limit := int(c.config().ArgLogLimit) if err != nil && err.Error() != "already known" { logger = log.Info } - logger("rpc response", "method", method, "logId", logId, "err", err, "result", limitedMarshal{limit, result}, "attempt", i, "args", limitedArgumentsMarshal{limit, args}) + logEntry := []interface{}{ + "method", method, + "logId", logId, + "err", err, + "result", limitedMarshal{limit, result}, + "attempt", i, + "args", limitedArgumentsMarshal{limit, args}, + } + if da, ok := err.(rpc.DataError); ok { + logEntry = append(logEntry, "errorData", limitedMarshal{limit, da.ErrorData()}) + } + logger("rpc response", logEntry...) if err == nil { return nil } From e8167fee6804ba612ed0721b39d42a6b858094ed Mon Sep 17 00:00:00 2001 From: Chris Buckland Date: Thu, 1 Feb 2024 20:58:31 +0000 Subject: [PATCH 13/18] Use lint reco for errors.as --- util/rpcclient/rpcclient.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/util/rpcclient/rpcclient.go b/util/rpcclient/rpcclient.go index d88e6dfc36..dbc145d490 100644 --- a/util/rpcclient/rpcclient.go +++ b/util/rpcclient/rpcclient.go @@ -170,8 +170,9 @@ func (c *RpcClient) CallContext(ctx_in context.Context, result interface{}, meth "attempt", i, "args", limitedArgumentsMarshal{limit, args}, } - if da, ok := err.(rpc.DataError); ok { - logEntry = append(logEntry, "errorData", limitedMarshal{limit, da.ErrorData()}) + var dataErr rpc.DataError + if errors.As(err, &dataErr) { + logEntry = append(logEntry, "errorData", limitedMarshal{limit, dataErr.ErrorData()}) } logger("rpc response", logEntry...) if err == nil { From 5bda2077f85595aa4f176330d922393edc0b9ebb Mon Sep 17 00:00:00 2001 From: Maciej Kulawik Date: Thu, 1 Feb 2024 22:27:58 +0000 Subject: [PATCH 14/18] fix typo --- cmd/conf/init.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/conf/init.go b/cmd/conf/init.go index 71709a8303..8a6c5096fb 100644 --- a/cmd/conf/init.go +++ b/cmd/conf/init.go @@ -58,7 +58,7 @@ func InitConfigAddOptions(prefix string, f *pflag.FlagSet) { f.String(prefix+".prune", InitConfigDefault.Prune, "pruning for a given use: \"full\" for full nodes serving RPC requests, or \"validator\" for validators") f.Uint64(prefix+".prune-bloom-size", InitConfigDefault.PruneBloomSize, "the amount of memory in megabytes to use for the pruning bloom filter (higher values prune better)") f.Int64(prefix+".reset-to-message", InitConfigDefault.ResetToMessage, "forces a reset to an old message height. Also set max-reorg-resequence-depth=0 to force re-reading messages") - f.Uint64(prefix+".recreate-missing-state-from", InitConfigDefault.RecreateMissingStateFrom, "block number to start recreating missing states form (0 = disabled)") + f.Uint64(prefix+".recreate-missing-state-from", InitConfigDefault.RecreateMissingStateFrom, "block number to start recreating missing states from (0 = disabled)") } func (c *InitConfig) Validate() error { From b94cf9c2455fd2c687493b32ccb9a124b007fd62 Mon Sep 17 00:00:00 2001 From: Maciej Kulawik Date: Thu, 1 Feb 2024 22:49:37 +0000 Subject: [PATCH 15/18] address review comment --- cmd/staterecovery/staterecovery.go | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/cmd/staterecovery/staterecovery.go b/cmd/staterecovery/staterecovery.go index 4b5f9b846f..97c570e9b0 100644 --- a/cmd/staterecovery/staterecovery.go +++ b/cmd/staterecovery/staterecovery.go @@ -25,12 +25,6 @@ func RecreateMissingStates(chainDb ethdb.Database, bc *core.BlockChain, cacheCon if previousBlock == nil { return fmt.Errorf("start block parent is missing, parent block number: %d", current-1) } - // find last available block - we cannot rely on bc.CurrentBlock() - last := current - for bc.GetBlockByNumber(last) != nil { - last++ - } - last-- hashConfig := *hashdb.Defaults hashConfig.CleanCacheSize = cacheConfig.TrieCleanLimit trieConfig := &trie.Config{ @@ -48,14 +42,18 @@ func RecreateMissingStates(chainDb ethdb.Database, bc *core.BlockChain, cacheCon // * or they will be recreated, saved to disk and then also cached in cleans cache logged := time.Unix(0, 0) recreated := 0 - for current <= last { - if time.Since(logged) > 1*time.Minute { - log.Info("Recreating missing states", "block", current, "target", last, "remaining", last-current, "elapsed", time.Since(start), "recreated", recreated) - logged = time.Now() - } + for { currentBlock := bc.GetBlockByNumber(current) if currentBlock == nil { - return fmt.Errorf("missing block %d", current) + break + } + if time.Since(logged) > 1*time.Minute { + var target uint64 + if h := bc.CurrentBlock(); h != nil { + target = h.Number.Uint64() + } + log.Info("Recreating missing states", "block", current, "target", target, "remaining", target-current, "elapsed", time.Since(start), "recreated", recreated) + logged = time.Now() } currentState, err := state.New(currentBlock.Root(), database, nil) if err != nil { From b3f42cdd7e7bcb8ee064c19504caa07ee684bb58 Mon Sep 17 00:00:00 2001 From: Maciej Kulawik Date: Thu, 1 Feb 2024 23:04:36 +0000 Subject: [PATCH 16/18] set target only once --- cmd/staterecovery/staterecovery.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/cmd/staterecovery/staterecovery.go b/cmd/staterecovery/staterecovery.go index 97c570e9b0..bb67830354 100644 --- a/cmd/staterecovery/staterecovery.go +++ b/cmd/staterecovery/staterecovery.go @@ -15,6 +15,11 @@ import ( func RecreateMissingStates(chainDb ethdb.Database, bc *core.BlockChain, cacheConfig *core.CacheConfig, startBlock uint64) error { start := time.Now() + currentHeader := bc.CurrentBlock() + if currentHeader == nil { + return fmt.Errorf("current header is nil") + } + target := currentHeader.Number.Uint64() current := startBlock genesis := bc.Config().ArbitrumChainParams.GenesisBlockNum if current < genesis+1 { @@ -48,11 +53,7 @@ func RecreateMissingStates(chainDb ethdb.Database, bc *core.BlockChain, cacheCon break } if time.Since(logged) > 1*time.Minute { - var target uint64 - if h := bc.CurrentBlock(); h != nil { - target = h.Number.Uint64() - } - log.Info("Recreating missing states", "block", current, "target", target, "remaining", target-current, "elapsed", time.Since(start), "recreated", recreated) + log.Info("Recreating missing states", "block", current, "target", target, "remaining", int64(target)-int64(current), "elapsed", time.Since(start), "recreated", recreated) logged = time.Now() } currentState, err := state.New(currentBlock.Root(), database, nil) From f632620e486df8b5a9fcbf2d4501aab0696c1787 Mon Sep 17 00:00:00 2001 From: Maciej Kulawik Date: Thu, 1 Feb 2024 23:45:17 +0000 Subject: [PATCH 17/18] update override warning --- cmd/staterecovery/staterecovery.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/staterecovery/staterecovery.go b/cmd/staterecovery/staterecovery.go index bb67830354..6390826a91 100644 --- a/cmd/staterecovery/staterecovery.go +++ b/cmd/staterecovery/staterecovery.go @@ -23,8 +23,8 @@ func RecreateMissingStates(chainDb ethdb.Database, bc *core.BlockChain, cacheCon current := startBlock genesis := bc.Config().ArbitrumChainParams.GenesisBlockNum if current < genesis+1 { - log.Warn("recreate-missing-states-from before genesis+1, starting from genesis+1") current = genesis + 1 + log.Warn("recreate-missing-states-from before genesis+1, starting from genesis+1", "configured", startBlock, "override", current) } previousBlock := bc.GetBlockByNumber(current - 1) if previousBlock == nil { From acc85b37dd2796fc49de3f15a3fd30c4749850e3 Mon Sep 17 00:00:00 2001 From: Lee Bousfield Date: Fri, 2 Feb 2024 10:31:44 -0700 Subject: [PATCH 18/18] Gate GetScheduledUpgrade to ArbOS 20 --- precompiles/precompile.go | 1 + 1 file changed, 1 insertion(+) diff --git a/precompiles/precompile.go b/precompiles/precompile.go index 5d2ecce745..5a16a1f903 100644 --- a/precompiles/precompile.go +++ b/precompiles/precompile.go @@ -560,6 +560,7 @@ func Precompiles() map[addr]ArbosPrecompile { ArbOwnerPublic.methodsByName["GetInfraFeeAccount"].arbosVersion = 5 ArbOwnerPublic.methodsByName["RectifyChainOwner"].arbosVersion = 11 ArbOwnerPublic.methodsByName["GetBrotliCompressionLevel"].arbosVersion = 20 + ArbOwnerPublic.methodsByName["GetScheduledUpgrade"].arbosVersion = 20 ArbRetryableImpl := &ArbRetryableTx{Address: types.ArbRetryableTxAddress} ArbRetryable := insert(MakePrecompile(templates.ArbRetryableTxMetaData, ArbRetryableImpl))