mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-24 13:46:43 +00:00
perf: add snapShot to postState reader
This commit is contained in:
parent
6f4f78b568
commit
9c003a2cd8
4 changed files with 172 additions and 124 deletions
|
|
@ -95,7 +95,7 @@ func (p *ParallelStateProcessor) Process(block *types.Block, statedb *state.Stat
|
|||
defer wg.Done()
|
||||
|
||||
start := time.Now()
|
||||
statedb.PreComputePostState(block.NumberU64())
|
||||
statedb.PreComputePostState(block.NumberU64(), runtime.NumCPU()/2)
|
||||
PrefetchMergeBALTime += time.Since(start)
|
||||
|
||||
exeStart := time.Now()
|
||||
|
|
@ -120,6 +120,8 @@ func (p *ParallelStateProcessor) executeParallel(block *types.Block, statedb *st
|
|||
blockHash = block.Hash()
|
||||
blockNumber = block.Number()
|
||||
allLogs []*types.Log
|
||||
maxLayer = runtime.NumCPU() / 2
|
||||
lenTx = len(block.Transactions())
|
||||
|
||||
preStateProvider PreStateProvider
|
||||
workers errgroup.Group
|
||||
|
|
@ -131,10 +133,6 @@ func (p *ParallelStateProcessor) executeParallel(block *types.Block, statedb *st
|
|||
switch preStateType {
|
||||
case BALPreState:
|
||||
{
|
||||
err := initialdb.SetPostBAL(statedb.PostBAL(), blockNumber.Uint64())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
case SeqPreState: // must set workers limit = 1
|
||||
|
|
@ -167,7 +165,8 @@ func (p *ParallelStateProcessor) executeParallel(block *types.Block, statedb *st
|
|||
{
|
||||
cleanStatedb = initialdb.Copy()
|
||||
cleanStatedb.SetTxContext(tx.Hash(), i)
|
||||
err = cleanStatedb.SetTxBALReader(statedb)
|
||||
postSnapshot, postBals := statedb.PostBAL()
|
||||
err = cleanStatedb.SetTxBALReader(statedb, blockNumber.Uint64(), maxLayer, lenTx, postSnapshot, postBals)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/trie/utils"
|
||||
"github.com/ethereum/go-ethereum/triedb"
|
||||
"github.com/ethereum/go-ethereum/triedb/database"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
// ContractCodeReader defines the interface for accessing contract code.
|
||||
|
|
@ -538,75 +539,134 @@ func (r *readerWithCache) Storage(addr common.Address, slot common.Hash) (common
|
|||
}
|
||||
|
||||
type readerWithBAL struct {
|
||||
Reader // Reader with cache
|
||||
txIndex int
|
||||
postBal map[int]types.TxPostValues // Shared accoss txs and mustn't be changed
|
||||
Reader // Reader with cache
|
||||
txIndex int
|
||||
maxLayer int
|
||||
step int // Must be larger than 1
|
||||
postSnapshot map[int]types.TxPostValues // Shared accoss txs and mustn't be changed
|
||||
postVals map[int]types.TxPostValues
|
||||
}
|
||||
|
||||
func newReaderWithBAL(reader Reader, txIndex int, postBal map[int]types.TxPostValues) *readerWithBAL {
|
||||
func newReaderWithBAL(reader Reader, txIndex int, maxLayer int, step int, postSnapshot, postVals map[int]types.TxPostValues) *readerWithBAL {
|
||||
return &readerWithBAL{
|
||||
reader, txIndex, postBal,
|
||||
reader, txIndex, maxLayer, step, postSnapshot, postVals,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *readerWithBAL) overlayAccount(addr common.Address) *types.AcctPostValues {
|
||||
layer := r.txIndex / r.step
|
||||
|
||||
var (
|
||||
nonce uint64
|
||||
balance *uint256.Int
|
||||
code []byte
|
||||
)
|
||||
|
||||
for i := r.txIndex - 1; i > layer*r.step-1; i-- {
|
||||
postState, ok := r.postVals[i]
|
||||
if ok && postState[addr] != nil {
|
||||
if nonce == 0 && postState[addr].Nonce > 0 {
|
||||
nonce = postState[addr].Nonce
|
||||
}
|
||||
|
||||
if balance == nil && postState[addr].Balance != nil {
|
||||
balance = postState[addr].Balance
|
||||
}
|
||||
|
||||
if code == nil && postState[addr].Code != nil {
|
||||
code = postState[addr].Code
|
||||
}
|
||||
|
||||
if nonce > 0 && balance != nil && code != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
snapShot := r.postSnapshot[layer]
|
||||
if snapShot[addr] != nil {
|
||||
if nonce == 0 {
|
||||
nonce = snapShot[addr].Nonce
|
||||
}
|
||||
if balance == nil {
|
||||
balance = snapShot[addr].Balance
|
||||
}
|
||||
if code == nil {
|
||||
code = snapShot[addr].Code
|
||||
}
|
||||
}
|
||||
|
||||
return &types.AcctPostValues{
|
||||
Nonce: nonce,
|
||||
Balance: balance,
|
||||
Code: code,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *readerWithBAL) Account(addr common.Address) (*types.StateAccount, error) {
|
||||
postVals, ok := r.postBal[r.txIndex-1]
|
||||
if ok {
|
||||
acctVal, ok := postVals[addr]
|
||||
if ok {
|
||||
acct, err := r.Reader.Account(addr)
|
||||
if acct == nil || err != nil {
|
||||
// acct is nil, just return the postAcct
|
||||
return &types.StateAccount{
|
||||
Nonce: acctVal.Nonce,
|
||||
Balance: acctVal.Balance,
|
||||
CodeHash: acctVal.CodeHash,
|
||||
}, nil
|
||||
}
|
||||
acctVal := r.overlayAccount(addr)
|
||||
|
||||
// acct mustn't be modified, or it'll change the cached pre-block values in readerwithcache
|
||||
nonce := acctVal.Nonce
|
||||
balance := acctVal.Balance
|
||||
codeHash := acct.CodeHash
|
||||
acct, err := r.Reader.Account(addr)
|
||||
if acct == nil || err != nil {
|
||||
// acct is nil, just return the postAcct
|
||||
return &types.StateAccount{
|
||||
Nonce: acctVal.Nonce,
|
||||
Balance: acctVal.Balance,
|
||||
CodeHash: acctVal.CodeHash,
|
||||
}, nil
|
||||
}
|
||||
|
||||
if acct.Nonce > acctVal.Nonce {
|
||||
nonce = acct.Nonce
|
||||
}
|
||||
if acctVal.Balance == nil {
|
||||
balance = acct.Balance
|
||||
}
|
||||
// acct mustn't be modified, or it'll change the cached pre-block values in readerwithcache
|
||||
nonce := acctVal.Nonce
|
||||
balance := acctVal.Balance
|
||||
codeHash := acct.CodeHash
|
||||
|
||||
// codeHash
|
||||
if acctVal.Code != nil {
|
||||
codeHash = crypto.Keccak256(acctVal.Code)
|
||||
}
|
||||
if acct.Nonce > nonce {
|
||||
nonce = acct.Nonce
|
||||
}
|
||||
if balance == nil {
|
||||
balance = acct.Balance
|
||||
}
|
||||
|
||||
return &types.StateAccount{
|
||||
Nonce: nonce,
|
||||
Balance: balance,
|
||||
Root: acct.Root,
|
||||
CodeHash: codeHash,
|
||||
}, nil
|
||||
// codeHash
|
||||
if acctVal.Code != nil {
|
||||
codeHash = crypto.Keccak256(acctVal.Code)
|
||||
}
|
||||
|
||||
return &types.StateAccount{
|
||||
Nonce: nonce,
|
||||
Balance: balance,
|
||||
Root: acct.Root,
|
||||
CodeHash: codeHash,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r *readerWithBAL) overlayStorage(addr common.Address, slot common.Hash) (common.Hash, bool) {
|
||||
layer := r.txIndex / r.step
|
||||
|
||||
for i := r.txIndex - 1; i > layer*r.step-1; i-- {
|
||||
postState, ok := r.postVals[i]
|
||||
if ok && postState[addr] != nil {
|
||||
// Shouldn't use common.Hash{} to judge where slot exist, because it might just be common.Hash{}
|
||||
if val, ok := postState[addr].StorageKV[slot]; ok {
|
||||
return val, true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
acct, err := r.Reader.Account(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
snapShot := r.postSnapshot[layer]
|
||||
if snapShot[addr] != nil {
|
||||
if val, ok := snapShot[addr].StorageKV[slot]; ok {
|
||||
return val, true
|
||||
}
|
||||
}
|
||||
return acct, nil
|
||||
return common.Hash{}, false
|
||||
}
|
||||
|
||||
func (r *readerWithBAL) Storage(addr common.Address, slot common.Hash) (common.Hash, error) {
|
||||
postVals, ok := r.postBal[r.txIndex-1]
|
||||
val, ok := r.overlayStorage(addr, slot)
|
||||
if ok {
|
||||
acct, ok := postVals[addr]
|
||||
if ok {
|
||||
val, ok := acct.StorageKV[slot]
|
||||
if ok {
|
||||
return val, nil
|
||||
}
|
||||
}
|
||||
return val, nil
|
||||
}
|
||||
|
||||
val, err := r.Reader.Storage(addr, slot)
|
||||
|
|
@ -618,23 +678,11 @@ func (r *readerWithBAL) Storage(addr common.Address, slot common.Hash) (common.H
|
|||
}
|
||||
|
||||
func (r *readerWithBAL) Code(addr common.Address, codeHash common.Hash) ([]byte, error) {
|
||||
postVals, ok := r.postBal[r.txIndex-1]
|
||||
if ok {
|
||||
acctVal, ok := postVals[addr]
|
||||
if ok {
|
||||
code := acctVal.Code
|
||||
if code != nil {
|
||||
return code, nil
|
||||
}
|
||||
if acctVal.CodeHash != nil {
|
||||
code, err := r.Reader.Code(addr, common.Hash(acctVal.CodeHash))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot get code from code for addr:%x, err:%v", addr, err)
|
||||
}
|
||||
return code, nil
|
||||
}
|
||||
}
|
||||
acctVal := r.overlayAccount(addr)
|
||||
if acctVal.Code != nil {
|
||||
return acctVal.Code, nil
|
||||
}
|
||||
|
||||
acct, err := r.Reader.Account(addr)
|
||||
if err != nil || acct == nil {
|
||||
return nil, fmt.Errorf("cannot get code from acct for addr:%x, err:%v", addr, err)
|
||||
|
|
|
|||
|
|
@ -164,8 +164,9 @@ type StateDB struct {
|
|||
// The block number context for BALs
|
||||
blockNumber uint64
|
||||
// postState after appling tx
|
||||
postStates map[int]*StateDB
|
||||
postBAL map[int]types.TxPostValues
|
||||
postStates map[int]*StateDB
|
||||
postSnapshot map[int]types.TxPostValues
|
||||
postVals map[int]types.TxPostValues
|
||||
}
|
||||
|
||||
type BALType int
|
||||
|
|
@ -273,71 +274,70 @@ func NewWithReader(root common.Hash, db Database, reader Reader) (*StateDB, erro
|
|||
return sdb, nil
|
||||
}
|
||||
|
||||
func (s *StateDB) PreComputePostState(blockNumber uint64) {
|
||||
|
||||
func (s *StateDB) PreComputePostState(blockNumber uint64, maxLayer int) {
|
||||
s.blockNumber = blockNumber
|
||||
postBal := map[int]types.TxPostValues{}
|
||||
for k, v := range AllBlockTxPostValues[blockNumber] {
|
||||
// Clone the map to avoid race with MergePostBalStates
|
||||
postBal[k] = types.TxPostValues{}
|
||||
for key, val := range v {
|
||||
postBal[k][key] = val.Clone()
|
||||
}
|
||||
postVals := AllBlockTxPostValues[blockNumber]
|
||||
|
||||
postSnapshot := make(map[int]types.TxPostValues)
|
||||
lenTxWithPreSys := len(postVals) - 1
|
||||
step := lenTxWithPreSys/maxLayer + 1
|
||||
if step == 1 {
|
||||
maxLayer = lenTxWithPreSys
|
||||
}
|
||||
|
||||
// -1 and len(postBal)-1 are syscalls pre and post all txs.
|
||||
for i := -1; i < len(postBal)-2; i++ {
|
||||
prevVals := postBal[i]
|
||||
postVals := postBal[i+1]
|
||||
for addr, prevAcct := range prevVals {
|
||||
if postAcct, ok := postVals[addr]; ok {
|
||||
for k, v := range prevAcct.StorageKV {
|
||||
if _, exists := postAcct.StorageKV[k]; !exists {
|
||||
postAcct.StorageKV[k] = v
|
||||
postSnapshot[0] = postVals[-1]
|
||||
for layer := 1; layer < maxLayer; layer++ {
|
||||
prev := postSnapshot[layer-1]
|
||||
curr := make(types.TxPostValues, len(prev))
|
||||
for key, val := range prev {
|
||||
curr[key] = val.Clone()
|
||||
}
|
||||
|
||||
for i := (layer - 1) * step; i < layer*step && i < lenTxWithPreSys-1; i++ {
|
||||
postTxVal := postVals[i]
|
||||
for addr, acct := range postTxVal {
|
||||
if curr[addr] == nil {
|
||||
curr[addr] = &types.AcctPostValues{
|
||||
StorageKV: map[common.Hash]common.Hash{},
|
||||
}
|
||||
}
|
||||
if postAcct.Balance == nil {
|
||||
postAcct.Balance = prevAcct.Balance
|
||||
if acct.Destruct {
|
||||
delete(curr, addr)
|
||||
continue
|
||||
}
|
||||
if postAcct.Code == nil {
|
||||
postAcct.Code = prevAcct.Code
|
||||
if acct.Balance != nil {
|
||||
curr[addr].Balance = acct.Balance
|
||||
}
|
||||
// Storage changes but nonce didn't change
|
||||
if postAcct.Nonce == 0 {
|
||||
postAcct.Nonce = prevAcct.Nonce
|
||||
if acct.Code != nil {
|
||||
curr[addr].Code = acct.Code
|
||||
}
|
||||
} else {
|
||||
postVals[addr] = prevAcct
|
||||
if acct.Nonce > curr[addr].Nonce {
|
||||
curr[addr].Nonce = acct.Nonce
|
||||
}
|
||||
maps.Copy(curr[addr].StorageKV, acct.StorageKV)
|
||||
}
|
||||
}
|
||||
postSnapshot[layer] = curr
|
||||
}
|
||||
s.postBAL = postBal
|
||||
s.postSnapshot = postSnapshot
|
||||
s.postVals = postVals
|
||||
}
|
||||
|
||||
func (s *StateDB) PostBAL() map[int]types.TxPostValues {
|
||||
return s.postBAL
|
||||
func (s *StateDB) PostBAL() (postSnapshot, postVals map[int]types.TxPostValues) {
|
||||
postSnapshot = s.postSnapshot
|
||||
postVals = s.postVals
|
||||
return
|
||||
}
|
||||
|
||||
func (s *StateDB) SetTxBALReader(preblockReader Reader) error {
|
||||
if s.postBAL == nil {
|
||||
func (s *StateDB) SetTxBALReader(preblockReader Reader, blockNumber uint64, maxLayer int, lenTx int, postSnapshot, postVals map[int]types.TxPostValues) error {
|
||||
if postSnapshot == nil || postVals == nil {
|
||||
return errors.New("cannot set bal reader without postBAL")
|
||||
}
|
||||
s.reader = newReaderWithBAL(preblockReader, s.txIndex, s.postBAL)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *StateDB) SetBlocknumber(bn uint64) error {
|
||||
s.blockNumber = bn
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *StateDB) SetPostBAL(postBal map[int]types.TxPostValues, bn uint64) error {
|
||||
if postBal == nil {
|
||||
return errors.New("cannot set postBAL without postBAL")
|
||||
}
|
||||
s.blockNumber = bn
|
||||
s.postBAL = postBal
|
||||
s.prefetcher = nil
|
||||
step := (lenTx+1)/maxLayer + 1
|
||||
s.postVals = postVals
|
||||
s.postSnapshot = postSnapshot
|
||||
s.blockNumber = blockNumber
|
||||
s.reader = newReaderWithBAL(preblockReader, s.txIndex, maxLayer, step, s.postSnapshot, s.postVals)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -1144,7 +1144,8 @@ func (s *StateDB) Copy() *StateDB {
|
|||
// The update journal is not copies to avoid duplicated updates in later transactions.
|
||||
blockNumber: s.blockNumber,
|
||||
updateJournal: newJournal(),
|
||||
postBAL: s.postBAL,
|
||||
postSnapshot: s.postSnapshot,
|
||||
postVals: s.postVals,
|
||||
}
|
||||
if s.witness != nil {
|
||||
state.witness = s.witness.Copy()
|
||||
|
|
|
|||
|
|
@ -36,6 +36,6 @@ func (v *AcctPostValues) Clone() *AcctPostValues {
|
|||
Destruct: false,
|
||||
CodeHash: v.CodeHash,
|
||||
Root: v.Root,
|
||||
Cached: false,
|
||||
Cached: false,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue