mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-25 06:06:44 +00:00
add pre-block fetcher and pass test in vanilla block processor
This commit is contained in:
parent
c25104f696
commit
bed539369c
3 changed files with 151 additions and 54 deletions
60
core/paralle_state_provider.go
Normal file
60
core/paralle_state_provider.go
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
)
|
||||
|
||||
type PreStateType int
|
||||
|
||||
const (
|
||||
BALPreState PreStateType = iota
|
||||
SeqPreState // Only for debug
|
||||
)
|
||||
|
||||
const preStateType = SeqPreState
|
||||
|
||||
type PreStateProvider interface {
|
||||
PrestateAtIndex(i int) (*state.StateDB, error)
|
||||
}
|
||||
|
||||
type SequentialPrestateProvider struct {
|
||||
statedb *state.StateDB
|
||||
block *types.Block
|
||||
gp *GasPool
|
||||
signer types.Signer
|
||||
// contex
|
||||
usedGas *uint64
|
||||
evm *vm.EVM
|
||||
}
|
||||
|
||||
func (s *SequentialPrestateProvider) PrestateAtIndex(i int) (*state.StateDB, error) {
|
||||
if i < 0 || i > len(s.block.Transactions()) {
|
||||
return nil, fmt.Errorf("tx index %d out of range [0, %d)", i, len(s.block.Transactions()))
|
||||
}
|
||||
if i == 0 {
|
||||
return s.statedb.Copy(), nil // first transaction uses the original state
|
||||
}
|
||||
i = i - 1
|
||||
tx := s.block.Transactions()[i]
|
||||
signer := s.signer
|
||||
header := s.block.Header()
|
||||
statedb := s.statedb
|
||||
blockHash := s.block.Hash()
|
||||
blockNumber := s.block.Number()
|
||||
// execute the transaction again to simulate the state changes
|
||||
msg, err := TransactionToMessage(tx, signer, header.BaseFee)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
|
||||
}
|
||||
statedb.SetTxContext(tx.Hash(), i)
|
||||
|
||||
_, err = ApplyTransactionWithEVM(msg, s.gp, statedb, blockNumber, blockHash, tx, s.usedGas, s.evm)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
|
||||
}
|
||||
return statedb.Copy(), nil
|
||||
}
|
||||
|
|
@ -14,15 +14,6 @@ import (
|
|||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
type PreStateType int
|
||||
|
||||
const (
|
||||
BALPreState PreStateType = iota
|
||||
SeqPreState // Only for debug
|
||||
)
|
||||
|
||||
const preStateType = SeqPreState
|
||||
|
||||
type ParallelStateProcessor struct {
|
||||
config *params.ChainConfig // Chain configuration options
|
||||
chain *HeaderChain // Canonical header chain
|
||||
|
|
@ -127,9 +118,6 @@ func (p *ParallelStateProcessor) executeParallel(block *types.Block, statedb *st
|
|||
receipts[i] = receipt
|
||||
postEntries[i] = entries
|
||||
|
||||
// if i == len(block.Transactions())-1 {
|
||||
// *statedb = *cleanStatedb
|
||||
// }
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
|
@ -217,45 +205,3 @@ func ApplyTransactionWithParallelEVM(msg *Message, gp *GasPool, statedb *state.S
|
|||
|
||||
return MakeReceipt(evm, result, statedb, blockNumber, blockHash, tx, *usedGas, root), entries, nil
|
||||
}
|
||||
|
||||
type PreStateProvider interface {
|
||||
PrestateAtIndex(i int) (*state.StateDB, error)
|
||||
}
|
||||
|
||||
type SequentialPrestateProvider struct {
|
||||
statedb *state.StateDB
|
||||
block *types.Block
|
||||
gp *GasPool
|
||||
signer types.Signer
|
||||
// contex
|
||||
usedGas *uint64
|
||||
evm *vm.EVM
|
||||
}
|
||||
|
||||
func (s *SequentialPrestateProvider) PrestateAtIndex(i int) (*state.StateDB, error) {
|
||||
if i < 0 || i > len(s.block.Transactions()) {
|
||||
return nil, fmt.Errorf("tx index %d out of range [0, %d)", i, len(s.block.Transactions()))
|
||||
}
|
||||
if i == 0 {
|
||||
return s.statedb.Copy(), nil // first transaction uses the original state
|
||||
}
|
||||
i = i - 1
|
||||
tx := s.block.Transactions()[i]
|
||||
signer := s.signer
|
||||
header := s.block.Header()
|
||||
statedb := s.statedb
|
||||
blockHash := s.block.Hash()
|
||||
blockNumber := s.block.Number()
|
||||
// execute the transaction again to simulate the state changes
|
||||
msg, err := TransactionToMessage(tx, signer, header.BaseFee)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
|
||||
}
|
||||
statedb.SetTxContext(tx.Hash(), i)
|
||||
|
||||
_, err = ApplyTransactionWithEVM(msg, s.gp, statedb, blockNumber, blockHash, tx, s.usedGas, s.evm)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
|
||||
}
|
||||
return statedb.Copy(), nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -159,6 +159,9 @@ type StateDB struct {
|
|||
StorageLoaded int // Number of storage slots retrieved from the database during the state transition
|
||||
StorageUpdated atomic.Int64 // Number of storage slots updated during the state transition
|
||||
StorageDeleted atomic.Int64 // Number of storage slots deleted during the state transition
|
||||
|
||||
// The block number context for BALs
|
||||
blockNumber uint64
|
||||
}
|
||||
|
||||
type BALType int
|
||||
|
|
@ -276,6 +279,94 @@ func NewWithReader(root common.Hash, db Database, reader Reader) (*StateDB, erro
|
|||
return sdb, nil
|
||||
}
|
||||
|
||||
func (s *StateDB) PrefetchStateBAL(blockNumber uint64) {
|
||||
s.blockNumber = blockNumber
|
||||
switch balType {
|
||||
case BalPreblockKeysPostValues:
|
||||
s.PrefetchBalPreblockKeys()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *StateDB) PrefetchBalPreblockKeys() {
|
||||
log.Info("PrefetchBalPreblockKeys...")
|
||||
type StorageKV struct {
|
||||
addr *common.Address
|
||||
key *common.Hash
|
||||
val *common.Hash
|
||||
}
|
||||
var (
|
||||
preBal = AllBlockAccessLists[s.blockNumber]
|
||||
lenSlots = 0
|
||||
workers errgroup.Group
|
||||
)
|
||||
|
||||
workers.SetLimit(25)
|
||||
// Fetch pre-block acccount state
|
||||
accounts := make(chan *stateObject, len(preBal))
|
||||
for _, acl := range preBal {
|
||||
addr := acl.Address
|
||||
lenSlots += len(acl.StorageKeys)
|
||||
|
||||
workers.Go(func() error {
|
||||
acct, err := s.reader.Account(addr)
|
||||
obj := newObject(s, addr, acct)
|
||||
accounts <- obj
|
||||
if err != nil {
|
||||
log.Error("fail to fetch account from BALs:", addr)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
workers.Wait()
|
||||
|
||||
for range len(preBal) {
|
||||
obj := <-accounts
|
||||
// must set it first to avoid accounts read later in storageBAL fetching
|
||||
s.setStateObject(obj)
|
||||
}
|
||||
|
||||
// Fetch pre-block storage state
|
||||
storages := make(chan *StorageKV, lenSlots)
|
||||
for _, acl := range preBal {
|
||||
addr := acl.Address
|
||||
keys := acl.StorageKeys
|
||||
for _, key := range keys {
|
||||
workers.Go(func() error {
|
||||
val, err := s.reader.Storage(addr, key)
|
||||
kv := &StorageKV{&addr, &key, &val}
|
||||
storages <- kv
|
||||
if err != nil {
|
||||
log.Error("fail to fetch storage from BALs:", addr, key)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
}
|
||||
workers.Wait()
|
||||
|
||||
for range lenSlots {
|
||||
kv := <-storages
|
||||
account := s.getStateObject(*kv.addr)
|
||||
if account != nil {
|
||||
account.originStorage[*kv.key] = *kv.val
|
||||
s.setStateObject(account)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *StateDB) PreStateAtTxIndex(index int) *StateDB {
|
||||
// 1. Fetch all pre-block state
|
||||
// 2. Merge with post-state
|
||||
if balType != BalPreblockKeysPostValues {
|
||||
panic("PreStateAtTxIndex is only supported with BalPreblockKeysPostValues")
|
||||
}
|
||||
|
||||
// Merge with BALs post state
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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.
|
||||
|
|
|
|||
Loading…
Reference in a new issue