Skip to content

Commit ad017f5

Browse files
authored
fix: an attempt at making witness generation more stable (#1166)
1 parent d482b2f commit ad017f5

File tree

6 files changed

+39
-23
lines changed

6 files changed

+39
-23
lines changed

core/blockchain.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1699,7 +1699,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er
16991699
}
17001700

17011701
// Enable prefetching to pull in trie node paths while processing transactions
1702-
statedb.StartPrefetcher("chain", nil)
1702+
statedb.StartPrefetcher("chain")
17031703
activeState = statedb
17041704

17051705
// 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
18361836
return nil, NonStatTy, err
18371837
}
18381838

1839-
statedb.StartPrefetcher("l1sync", nil)
1839+
statedb.StartPrefetcher("l1sync")
18401840
defer statedb.StopPrefetcher()
18411841

18421842
header.ParentHash = parentBlock.Hash()

core/state/state_object.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"fmt"
2222
"io"
2323
"math/big"
24+
"slices"
2425
"time"
2526

2627
"github.com/scroll-tech/go-ethereum/common"
@@ -344,8 +345,17 @@ func (s *stateObject) updateTrie(db Database) Trie {
344345
tr := s.getTrie(db)
345346
hasher := s.db.hasher
346347

348+
sortedPendingStorages := make([]common.Hash, 0, len(s.pendingStorage))
349+
for key := range s.pendingStorage {
350+
sortedPendingStorages = append(sortedPendingStorages, key)
351+
}
352+
slices.SortFunc(sortedPendingStorages, func(a, b common.Hash) int {
353+
return bytes.Compare(a[:], b[:])
354+
})
355+
347356
usedStorage := make([][]byte, 0, len(s.pendingStorage))
348-
for key, value := range s.pendingStorage {
357+
for _, key := range sortedPendingStorages {
358+
value := s.pendingStorage[key]
349359
// Skip noop changes, persist actual changes
350360
if value == s.originStorage[key] {
351361
continue

core/state/statedb.go

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@
1818
package state
1919

2020
import (
21+
"bytes"
2122
"errors"
2223
"fmt"
2324
"math/big"
25+
"slices"
2426
"sort"
2527
"time"
2628

@@ -160,18 +162,20 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error)
160162
return sdb, nil
161163
}
162164

165+
// WithWitness sets the witness for the state database.
166+
func (s *StateDB) WithWitness(witness *stateless.Witness) {
167+
s.witness = witness
168+
}
169+
163170
// StartPrefetcher initializes a new trie prefetcher to pull in nodes from the
164171
// state trie concurrently while the state is mutated so that when we reach the
165172
// commit phase, most of the needed data is already hot.
166-
func (s *StateDB) StartPrefetcher(namespace string, witness *stateless.Witness) {
173+
func (s *StateDB) StartPrefetcher(namespace string) {
167174
if s.prefetcher != nil {
168175
s.prefetcher.close()
169176
s.prefetcher = nil
170177
}
171178

172-
// Enable witness collection if requested
173-
s.witness = witness
174-
175179
if s.snap != nil {
176180
s.prefetcher = newTriePrefetcher(s.db, s.originalRoot, namespace)
177181
}
@@ -967,8 +971,17 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
967971
s.trie = trie
968972
}
969973
}
970-
usedAddrs := make([][]byte, 0, len(s.stateObjectsPending))
974+
975+
sortedPendingAddrs := make([]common.Address, 0, len(s.stateObjectsPending))
971976
for addr := range s.stateObjectsPending {
977+
sortedPendingAddrs = append(sortedPendingAddrs, addr)
978+
}
979+
slices.SortFunc(sortedPendingAddrs, func(a, b common.Address) int {
980+
return bytes.Compare(a[:], b[:])
981+
})
982+
983+
usedAddrs := make([][]byte, 0, len(s.stateObjectsPending))
984+
for _, addr := range sortedPendingAddrs {
972985
if obj := s.stateObjects[addr]; obj.deleted {
973986
s.deleteStateObject(obj)
974987
s.AccountDeleted += 1

eth/api.go

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ import (
2929
"strings"
3030
"time"
3131

32+
"github.com/syndtr/goleveldb/leveldb"
33+
3234
"github.com/scroll-tech/go-ethereum/common"
3335
"github.com/scroll-tech/go-ethereum/common/hexutil"
3436
"github.com/scroll-tech/go-ethereum/core"
@@ -44,7 +46,6 @@ import (
4446
"github.com/scroll-tech/go-ethereum/rollup/rcfg"
4547
"github.com/scroll-tech/go-ethereum/rpc"
4648
"github.com/scroll-tech/go-ethereum/trie"
47-
"github.com/syndtr/goleveldb/leveldb"
4849
)
4950

5051
// PublicEthereumAPI provides an API to access Ethereum full node-related
@@ -354,13 +355,11 @@ func generateWitness(blockchain *core.BlockChain, block *types.Block) (*stateles
354355
if err != nil {
355356
return nil, fmt.Errorf("failed to retrieve parent state: %w", err)
356357
}
358+
statedb.WithWitness(witness)
357359

358360
// Collect storage locations that prover needs but sequencer might not touch necessarily
359361
statedb.GetState(rcfg.L2MessageQueueAddress, rcfg.WithdrawTrieRootSlot)
360362

361-
statedb.StartPrefetcher("debug_execution_witness", witness)
362-
defer statedb.StopPrefetcher()
363-
364363
receipts, _, usedGas, err := blockchain.Processor().Process(block, statedb, *blockchain.GetVMConfig())
365364
if err != nil {
366365
return nil, fmt.Errorf("failed to process block %d: %w", block.Number(), err)
@@ -370,16 +369,10 @@ func generateWitness(blockchain *core.BlockChain, block *types.Block) (*stateles
370369
return nil, fmt.Errorf("failed to validate block %d: %w", block.Number(), err)
371370
}
372371

373-
// FIXME: testWitness will fail from time to time, the problem is caused by occasional state root mismatch
374-
// after processing the block based on witness. We need to investigate the root cause and fix it.
375-
for retries := 0; retries < 5; retries++ {
376-
if err = testWitness(blockchain, block, witness); err == nil {
377-
return witness, nil
378-
} else {
379-
log.Warn("Failed to validate witness", "block", block.Number(), "error", err)
380-
}
372+
if err = testWitness(blockchain, block, witness); err != nil {
373+
return nil, err
381374
}
382-
return witness, err
375+
return witness, nil
383376
}
384377

385378
func testWitness(blockchain *core.BlockChain, block *types.Block, witness *stateless.Witness) error {

params/version.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import (
2424
const (
2525
VersionMajor = 5 // Major version component of the current release
2626
VersionMinor = 8 // Minor version component of the current release
27-
VersionPatch = 35 // Patch version component of the current release
27+
VersionPatch = 36 // Patch version component of the current release
2828
VersionMeta = "mainnet" // Version metadata to append to the version string
2929
)
3030

rollup/pipeline/pipeline.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ func sendCancellable[T any, C comparable](resCh chan T, msg T, cancelCh <-chan C
228228
}
229229

230230
func (p *Pipeline) traceAndApplyStage(txsIn <-chan *types.Transaction) (<-chan error, <-chan *BlockCandidate, error) {
231-
p.state.StartPrefetcher("miner", nil)
231+
p.state.StartPrefetcher("miner")
232232
downstreamCh := make(chan *BlockCandidate, p.downstreamChCapacity())
233233
resCh := make(chan error)
234234
p.wg.Add(1)

0 commit comments

Comments
 (0)