This commit is contained in:
Jared Wasinger 2024-02-19 20:03:20 -08:00
parent 9100e2e566
commit 095a65e2b7
2 changed files with 32 additions and 69 deletions

View file

@ -30,6 +30,7 @@ import (
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum/go-ethereum/trie"
"github.com/holiman/uint256"
)
// Proof-of-stake protocol constants.
@ -352,7 +353,13 @@ func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types.
beacon.ethone.Finalize(chain, header, state, txs, uncles, nil)
return
}
state.ApplyWithdrawals(withdrawals)
// Withdrawals processing.
for _, w := range withdrawals {
// Convert amount from gwei to wei.
amount := new(uint256.Int).SetUint64(w.Amount)
amount = amount.Mul(amount, uint256.NewInt(params.GWei))
state.AddBalance(w.Address, amount)
}
// No block reward which is issued by consensus layer instead.
}

View file

@ -62,6 +62,7 @@ type StateDB struct {
db Database
prefetcher *triePrefetcher
trie Trie
witness *Witness
hasher crypto.KeccakState
snaps *snapshot.Tree // Nil if snapshot is not available
snap snapshot.Snapshot // Nil if snapshot is not available
@ -138,9 +139,6 @@ type StateDB struct {
// Testing hooks
onCommit func(states *triestate.Set) // Hook invoked when commit is performed
witness *Witness
readPrefetcher *triePrefetcher
}
// NewWithWitnessRecording creates a new state from a given trie. The state is configured to construct a stateless
@ -191,20 +189,11 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error)
// commit phase, most of the needed data is already hot.
func (s *StateDB) StartPrefetcher(namespace string) {
if s.prefetcher != nil {
s.prefetcher.wait()
s.prefetcher.close()
s.prefetcher = nil
}
if s.readPrefetcher != nil {
s.readPrefetcher.wait()
s.readPrefetcher.close()
s.readPrefetcher = nil
}
if s.snap != nil {
s.prefetcher = newTriePrefetcher(s.db, s.originalRoot, namespace)
if s.witness != nil {
s.readPrefetcher = newTriePrefetcher(s.db, s.originalRoot, namespace)
}
}
}
@ -212,15 +201,9 @@ func (s *StateDB) StartPrefetcher(namespace string) {
// from the gathered metrics.
func (s *StateDB) StopPrefetcher() {
if s.prefetcher != nil {
s.prefetcher.wait()
s.prefetcher.close()
s.prefetcher = nil
}
if s.readPrefetcher != nil {
s.readPrefetcher.wait()
s.readPrefetcher.close()
s.readPrefetcher = nil
}
}
// setError remembers the first non-nil error it is called with.
@ -601,6 +584,11 @@ func (s *StateDB) getDeletedStateObject(addr common.Address) *stateObject {
s.SnapshotAccountReads += time.Since(start)
}
if err == nil {
// If witness building is enabled, prefetch any trie paths loaded directly
// via the snapshots
if s.prefetcher != nil && s.witness != nil {
s.prefetcher.prefetch(common.Hash{}, s.originalRoot, common.Address{}, [][]byte{addr[:]})
}
if acc == nil {
return nil
}
@ -634,15 +622,9 @@ func (s *StateDB) getDeletedStateObject(addr common.Address) *stateObject {
return nil
}
}
// Insert into the live set
obj := newObject(s, addr, data)
s.setStateObject(obj)
if s.witness != nil && s.snap != nil {
// when building witness with snap enabled, prefetch all read accounts to later be collected and
// included in the witness
s.readPrefetcher.prefetch(common.Hash{}, s.originalRoot, common.Address{}, [][]byte{addr[:]})
}
return obj
}
@ -719,7 +701,10 @@ func (s *StateDB) CreateAccount(addr common.Address) {
}
// Copy creates a deep, independent copy of the state.
// Snapshots of the copied state cannot be applied to the copy.
//
// Note:
// - Snapshots of the copied state cannot be applied to the copy.
// - Pre-fetchers will not be copied nor active in the copy.
func (s *StateDB) Copy() *StateDB {
// Copy all the basic fields, initialize the memory ones
state := &StateDB{
@ -816,12 +801,6 @@ func (s *StateDB) Copy() *StateDB {
state.accessList = s.accessList.Copy()
state.transientStorage = s.transientStorage.Copy()
// If there's a prefetcher running, make an inactive copy of it that can
// only access data but does not actively preload (since the user will not
// know that they need to explicitly terminate an active copy).
if s.prefetcher != nil {
state.prefetcher = s.prefetcher.copy()
}
return state
}
@ -909,7 +888,7 @@ func (s *StateDB) collectReadStorageAccessLists() {
for _, obj := range s.stateObjects {
// load read storage slots from the finished trie in the prefetcher as these continue to be prefetched
// until commit.
tr := s.readPrefetcher.trie(obj.addrHash, obj.data.Root)
tr := s.prefetcher.trie(obj.addrHash, obj.data.Root)
if tr == nil {
continue
}
@ -921,9 +900,9 @@ func (s *StateDB) collectReadStorageAccessLists() {
}
func (s *StateDB) collectReadAccountsAccessLists() {
tr := s.readPrefetcher.trie(common.Hash{}, s.originalRoot)
tr := s.prefetcher.trie(common.Hash{}, s.originalRoot)
if tr == nil {
// TODO: ensure this case is b/c of empty block
// empty block
return
}
accessList := tr.AccessList()
@ -942,21 +921,14 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
prefetcher := s.prefetcher
if s.prefetcher != nil {
defer func() {
// TODO: need to wait for read accounts to be resolved in prefetcher main trie?
s.prefetcher.wait()
s.prefetcher.close()
if s.witness != nil {
s.collectReadStorageAccessLists()
s.collectReadAccountsAccessLists()
}
s.prefetcher = nil
}()
}
if s.readPrefetcher != nil {
// TODO: move read prefetcher logic into Commit?
s.readPrefetcher.wait()
s.collectReadStorageAccessLists()
s.collectReadAccountsAccessLists()
s.readPrefetcher.close()
s.readPrefetcher = nil
}
// Although naively it makes sense to retrieve the account trie and then do
// the contract storage and account updates sequentially, that short circuits
// the account prefetcher. Instead, let's process all the storage updates
@ -978,11 +950,12 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
}
usedAddrs := make([][]byte, 0, len(s.stateObjectsPending))
// perform updates before deletions. In the case where a full node
// has two children, one of them selfdestructs and makes the recipient
// another non-existing sibling, applying deletion before update would
// result in the unecessary premature collapse of the full node into a short node
// for the untouched third sibling.
// Perform updates before deletions. This is needed for stateless execution in MPT:
//
// Take value nodes 1, 2 who share the same full node parent 3 and have no other siblings.
// 1 self-destructs specifying a non-existing recipient account which would be a child of 3.
// If the deletion of 1 happens before the account-creating balance transfer, 3 will temporarily
// be collapsed to a short node on 2, requiring 2 to be unecessarily resolved.
var deletedObjects []*stateObject
for addr := range s.stateObjectsPending {
if obj := s.stateObjects[addr]; !obj.deleted {
@ -1250,22 +1223,6 @@ func (s *StateDB) Witness() *Witness {
return s.witness
}
// ApplyWithdrawals credits the balance of each account that is the recipient
// of a withdrawal.
func (s *StateDB) ApplyWithdrawals(withdrawals types.Withdrawals) {
for _, w := range withdrawals {
// Convert amount from gwei to wei.
amount := new(uint256.Int).SetUint64(w.Amount)
amount = amount.Mul(amount, uint256.NewInt(params.GWei))
s.AddBalance(w.Address, amount)
}
if s.witness != nil {
al := s.trie.AccessList()
s.witness.addAccessList(common.Hash{}, al)
}
}
// Commit writes the state to the underlying in-memory trie database.
// Once the state is committed, tries cached in stateDB (including account
// trie, storage tries) will no longer be functional. A new state instance
@ -1308,11 +1265,10 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er
// computation of a new trie root hash where a value has been deleted could
// collapse a parent branch node + sibling into a full node for the sibling.
// In this case, the sibling would only be read during root hash computation.
// TODO: verify the above assertion is the case.
for addr := range s.stateObjects {
obj := s.stateObjects[addr]
if _, ok := s.stateObjectsDirty[addr]; ok && !obj.deleted {
// collect dirty object access witness if/when we commit them
// collect dirty object access witness when we commit them
continue
}
if obj.trie != nil {