mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-24 21:56:43 +00:00
fix: an attempt at making witness generation more stable (#1166)
This commit is contained in:
parent
d482b2fdb4
commit
ad017f50ec
6 changed files with 39 additions and 23 deletions
|
|
@ -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
|
// Enable prefetching to pull in trie node paths while processing transactions
|
||||||
statedb.StartPrefetcher("chain", nil)
|
statedb.StartPrefetcher("chain")
|
||||||
activeState = statedb
|
activeState = statedb
|
||||||
|
|
||||||
// If we have a followup block, run that against the current state to pre-cache
|
// 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
|
return nil, NonStatTy, err
|
||||||
}
|
}
|
||||||
|
|
||||||
statedb.StartPrefetcher("l1sync", nil)
|
statedb.StartPrefetcher("l1sync")
|
||||||
defer statedb.StopPrefetcher()
|
defer statedb.StopPrefetcher()
|
||||||
|
|
||||||
header.ParentHash = parentBlock.Hash()
|
header.ParentHash = parentBlock.Hash()
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"slices"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/scroll-tech/go-ethereum/common"
|
"github.com/scroll-tech/go-ethereum/common"
|
||||||
|
|
@ -344,8 +345,17 @@ func (s *stateObject) updateTrie(db Database) Trie {
|
||||||
tr := s.getTrie(db)
|
tr := s.getTrie(db)
|
||||||
hasher := s.db.hasher
|
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))
|
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
|
// Skip noop changes, persist actual changes
|
||||||
if value == s.originStorage[key] {
|
if value == s.originStorage[key] {
|
||||||
continue
|
continue
|
||||||
|
|
|
||||||
|
|
@ -18,9 +18,11 @@
|
||||||
package state
|
package state
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"slices"
|
||||||
"sort"
|
"sort"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -160,18 +162,20 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error)
|
||||||
return sdb, nil
|
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
|
// 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
|
// state trie concurrently while the state is mutated so that when we reach the
|
||||||
// commit phase, most of the needed data is already hot.
|
// 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 {
|
if s.prefetcher != nil {
|
||||||
s.prefetcher.close()
|
s.prefetcher.close()
|
||||||
s.prefetcher = nil
|
s.prefetcher = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enable witness collection if requested
|
|
||||||
s.witness = witness
|
|
||||||
|
|
||||||
if s.snap != nil {
|
if s.snap != nil {
|
||||||
s.prefetcher = newTriePrefetcher(s.db, s.originalRoot, namespace)
|
s.prefetcher = newTriePrefetcher(s.db, s.originalRoot, namespace)
|
||||||
}
|
}
|
||||||
|
|
@ -967,8 +971,17 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
|
||||||
s.trie = trie
|
s.trie = trie
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
usedAddrs := make([][]byte, 0, len(s.stateObjectsPending))
|
|
||||||
|
sortedPendingAddrs := make([]common.Address, 0, len(s.stateObjectsPending))
|
||||||
for addr := range 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 {
|
if obj := s.stateObjects[addr]; obj.deleted {
|
||||||
s.deleteStateObject(obj)
|
s.deleteStateObject(obj)
|
||||||
s.AccountDeleted += 1
|
s.AccountDeleted += 1
|
||||||
|
|
|
||||||
19
eth/api.go
19
eth/api.go
|
|
@ -29,6 +29,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/syndtr/goleveldb/leveldb"
|
||||||
|
|
||||||
"github.com/scroll-tech/go-ethereum/common"
|
"github.com/scroll-tech/go-ethereum/common"
|
||||||
"github.com/scroll-tech/go-ethereum/common/hexutil"
|
"github.com/scroll-tech/go-ethereum/common/hexutil"
|
||||||
"github.com/scroll-tech/go-ethereum/core"
|
"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/rollup/rcfg"
|
||||||
"github.com/scroll-tech/go-ethereum/rpc"
|
"github.com/scroll-tech/go-ethereum/rpc"
|
||||||
"github.com/scroll-tech/go-ethereum/trie"
|
"github.com/scroll-tech/go-ethereum/trie"
|
||||||
"github.com/syndtr/goleveldb/leveldb"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// PublicEthereumAPI provides an API to access Ethereum full node-related
|
// PublicEthereumAPI provides an API to access Ethereum full node-related
|
||||||
|
|
@ -354,13 +355,11 @@ func generateWitness(blockchain *core.BlockChain, block *types.Block) (*stateles
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to retrieve parent state: %w", err)
|
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
|
// Collect storage locations that prover needs but sequencer might not touch necessarily
|
||||||
statedb.GetState(rcfg.L2MessageQueueAddress, rcfg.WithdrawTrieRootSlot)
|
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())
|
receipts, _, usedGas, err := blockchain.Processor().Process(block, statedb, *blockchain.GetVMConfig())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to process block %d: %w", block.Number(), err)
|
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
|
||||||
return nil, fmt.Errorf("failed to validate block %d: %w", block.Number(), err)
|
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
|
if err = testWitness(blockchain, block, witness); err != nil {
|
||||||
// after processing the block based on witness. We need to investigate the root cause and fix it.
|
return nil, err
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return witness, err
|
return witness, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func testWitness(blockchain *core.BlockChain, block *types.Block, witness *stateless.Witness) error {
|
func testWitness(blockchain *core.BlockChain, block *types.Block, witness *stateless.Witness) error {
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ import (
|
||||||
const (
|
const (
|
||||||
VersionMajor = 5 // Major version component of the current release
|
VersionMajor = 5 // Major version component of the current release
|
||||||
VersionMinor = 8 // Minor 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
|
VersionMeta = "mainnet" // Version metadata to append to the version string
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
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())
|
downstreamCh := make(chan *BlockCandidate, p.downstreamChCapacity())
|
||||||
resCh := make(chan error)
|
resCh := make(chan error)
|
||||||
p.wg.Add(1)
|
p.wg.Add(1)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue