From 0af50ddff7a63acc7ad5daecb19cbcafe8841829 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Faruk=20Irmak?= Date: Thu, 3 Apr 2025 11:16:44 +0300 Subject: [PATCH 1/4] fix: an attempt at making witness generation more stable --- core/blockchain.go | 4 ++-- core/state/statedb.go | 10 ++++++---- eth/api.go | 4 +--- rollup/pipeline/pipeline.go | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 2b881ceed235..1a46a315c278 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1699,7 +1699,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er } // Enable prefetching to pull in trie node paths while processing transactions - statedb.StartPrefetcher("chain", nil) + statedb.StartPrefetcher("chain") activeState = statedb // If we have a followup block, run that against the current state to pre-cache @@ -1836,7 +1836,7 @@ func (bc *BlockChain) BuildAndWriteBlock(parentBlock *types.Block, header *types return nil, NonStatTy, err } - statedb.StartPrefetcher("l1sync", nil) + statedb.StartPrefetcher("l1sync") defer statedb.StopPrefetcher() header.ParentHash = parentBlock.Hash() diff --git a/core/state/statedb.go b/core/state/statedb.go index 7affd81fc409..42fc881a8011 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -160,18 +160,20 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error) return sdb, nil } +// WithWitness sets the witness for the state database. +func (s *StateDB) WithWitness(witness *stateless.Witness) { + s.witness = witness +} + // StartPrefetcher initializes a new trie prefetcher to pull in nodes from the // state trie concurrently while the state is mutated so that when we reach the // commit phase, most of the needed data is already hot. -func (s *StateDB) StartPrefetcher(namespace string, witness *stateless.Witness) { +func (s *StateDB) StartPrefetcher(namespace string) { if s.prefetcher != nil { s.prefetcher.close() s.prefetcher = nil } - // Enable witness collection if requested - s.witness = witness - if s.snap != nil { s.prefetcher = newTriePrefetcher(s.db, s.originalRoot, namespace) } diff --git a/eth/api.go b/eth/api.go index cd8df1111e3b..d32826c5a291 100644 --- a/eth/api.go +++ b/eth/api.go @@ -354,13 +354,11 @@ func generateWitness(blockchain *core.BlockChain, block *types.Block) (*stateles if err != nil { return nil, fmt.Errorf("failed to retrieve parent state: %w", err) } + statedb.WithWitness(witness) // Collect storage locations that prover needs but sequencer might not touch necessarily statedb.GetState(rcfg.L2MessageQueueAddress, rcfg.WithdrawTrieRootSlot) - statedb.StartPrefetcher("debug_execution_witness", witness) - defer statedb.StopPrefetcher() - receipts, _, usedGas, err := blockchain.Processor().Process(block, statedb, *blockchain.GetVMConfig()) if err != nil { return nil, fmt.Errorf("failed to process block %d: %w", block.Number(), err) diff --git a/rollup/pipeline/pipeline.go b/rollup/pipeline/pipeline.go index 77ac3aee24a0..90c6149b3858 100644 --- a/rollup/pipeline/pipeline.go +++ b/rollup/pipeline/pipeline.go @@ -228,7 +228,7 @@ func sendCancellable[T any, C comparable](resCh chan T, msg T, cancelCh <-chan C } func (p *Pipeline) traceAndApplyStage(txsIn <-chan *types.Transaction) (<-chan error, <-chan *BlockCandidate, error) { - p.state.StartPrefetcher("miner", nil) + p.state.StartPrefetcher("miner") downstreamCh := make(chan *BlockCandidate, p.downstreamChCapacity()) resCh := make(chan error) p.wg.Add(1) From aa8bed769d785f2764ddd2f396002c0782a6c7a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Faruk=20Irmak?= Date: Thu, 3 Apr 2025 17:18:27 +0300 Subject: [PATCH 2/4] fix: make trie update order deterministic --- core/state/state_object.go | 12 +++++++++++- core/state/statedb.go | 13 ++++++++++++- eth/api.go | 12 +++--------- 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/core/state/state_object.go b/core/state/state_object.go index 4fb9e82c2ed7..2b615d94082c 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -21,6 +21,7 @@ import ( "fmt" "io" "math/big" + "slices" "time" "github.com/scroll-tech/go-ethereum/common" @@ -344,8 +345,17 @@ func (s *stateObject) updateTrie(db Database) Trie { tr := s.getTrie(db) hasher := s.db.hasher + sortedPendingStorages := make([]common.Hash, 0, len(s.pendingStorage)) + for key := range s.pendingStorage { + sortedPendingStorages = append(sortedPendingStorages, key) + } + slices.SortFunc(sortedPendingStorages, func(a, b common.Hash) int { + return bytes.Compare(a[:], b[:]) + }) + usedStorage := make([][]byte, 0, len(s.pendingStorage)) - for key, value := range s.pendingStorage { + for _, key := range sortedPendingStorages { + value := s.pendingStorage[key] // Skip noop changes, persist actual changes if value == s.originStorage[key] { continue diff --git a/core/state/statedb.go b/core/state/statedb.go index 42fc881a8011..94a89349afbb 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -18,9 +18,11 @@ package state import ( + "bytes" "errors" "fmt" "math/big" + "slices" "sort" "time" @@ -969,8 +971,17 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { s.trie = trie } } - usedAddrs := make([][]byte, 0, len(s.stateObjectsPending)) + + sortedPendingAddrs := make([]common.Address, 0, len(s.stateObjectsPending)) for addr := range s.stateObjectsPending { + sortedPendingAddrs = append(sortedPendingAddrs, addr) + } + slices.SortFunc(sortedPendingAddrs, func(a, b common.Address) int { + return bytes.Compare(a[:], b[:]) + }) + + usedAddrs := make([][]byte, 0, len(s.stateObjectsPending)) + for _, addr := range sortedPendingAddrs { if obj := s.stateObjects[addr]; obj.deleted { s.deleteStateObject(obj) s.AccountDeleted += 1 diff --git a/eth/api.go b/eth/api.go index d32826c5a291..fea405adbe24 100644 --- a/eth/api.go +++ b/eth/api.go @@ -368,16 +368,10 @@ func generateWitness(blockchain *core.BlockChain, block *types.Block) (*stateles return nil, fmt.Errorf("failed to validate block %d: %w", block.Number(), err) } - // FIXME: testWitness will fail from time to time, the problem is caused by occasional state root mismatch - // after processing the block based on witness. We need to investigate the root cause and fix it. - for retries := 0; retries < 5; retries++ { - if err = testWitness(blockchain, block, witness); err == nil { - return witness, nil - } else { - log.Warn("Failed to validate witness", "block", block.Number(), "error", err) - } + if err = testWitness(blockchain, block, witness); err != nil { + return nil, err } - return witness, err + return witness, nil } func testWitness(blockchain *core.BlockChain, block *types.Block, witness *stateless.Witness) error { From 5129f609e903c85e80cd2aba75fe307fac707c1b Mon Sep 17 00:00:00 2001 From: omerfirmak <10325815+omerfirmak@users.noreply.github.com> Date: Mon, 7 Apr 2025 14:19:54 +0000 Subject: [PATCH 3/4] =?UTF-8?q?chore:=20auto=20version=20bump=E2=80=89[bot?= =?UTF-8?q?]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- params/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/params/version.go b/params/version.go index 4b80652f5b78..8744e190e3f4 100644 --- a/params/version.go +++ b/params/version.go @@ -24,7 +24,7 @@ import ( const ( VersionMajor = 5 // Major version component of the current release VersionMinor = 8 // Minor version component of the current release - VersionPatch = 35 // Patch version component of the current release + VersionPatch = 36 // Patch version component of the current release VersionMeta = "mainnet" // Version metadata to append to the version string ) From 37d29718ff4dc1d372afce0cc69e829c01ff8c7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Faruk=20Irmak?= Date: Mon, 7 Apr 2025 17:52:30 +0300 Subject: [PATCH 4/4] fix lint --- eth/api.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/eth/api.go b/eth/api.go index fea405adbe24..e8b66b9e4e57 100644 --- a/eth/api.go +++ b/eth/api.go @@ -29,6 +29,8 @@ import ( "strings" "time" + "github.com/syndtr/goleveldb/leveldb" + "github.com/scroll-tech/go-ethereum/common" "github.com/scroll-tech/go-ethereum/common/hexutil" "github.com/scroll-tech/go-ethereum/core" @@ -44,7 +46,6 @@ import ( "github.com/scroll-tech/go-ethereum/rollup/rcfg" "github.com/scroll-tech/go-ethereum/rpc" "github.com/scroll-tech/go-ethereum/trie" - "github.com/syndtr/goleveldb/leveldb" ) // PublicEthereumAPI provides an API to access Ethereum full node-related