mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
fix
This commit is contained in:
parent
9100e2e566
commit
095a65e2b7
2 changed files with 32 additions and 69 deletions
|
|
@ -30,6 +30,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Proof-of-stake protocol constants.
|
// 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)
|
beacon.ethone.Finalize(chain, header, state, txs, uncles, nil)
|
||||||
return
|
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.
|
// No block reward which is issued by consensus layer instead.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,7 @@ type StateDB struct {
|
||||||
db Database
|
db Database
|
||||||
prefetcher *triePrefetcher
|
prefetcher *triePrefetcher
|
||||||
trie Trie
|
trie Trie
|
||||||
|
witness *Witness
|
||||||
hasher crypto.KeccakState
|
hasher crypto.KeccakState
|
||||||
snaps *snapshot.Tree // Nil if snapshot is not available
|
snaps *snapshot.Tree // Nil if snapshot is not available
|
||||||
snap snapshot.Snapshot // Nil if snapshot is not available
|
snap snapshot.Snapshot // Nil if snapshot is not available
|
||||||
|
|
@ -138,9 +139,6 @@ type StateDB struct {
|
||||||
|
|
||||||
// Testing hooks
|
// Testing hooks
|
||||||
onCommit func(states *triestate.Set) // Hook invoked when commit is performed
|
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
|
// 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.
|
// commit phase, most of the needed data is already hot.
|
||||||
func (s *StateDB) StartPrefetcher(namespace string) {
|
func (s *StateDB) StartPrefetcher(namespace string) {
|
||||||
if s.prefetcher != nil {
|
if s.prefetcher != nil {
|
||||||
s.prefetcher.wait()
|
|
||||||
s.prefetcher.close()
|
s.prefetcher.close()
|
||||||
s.prefetcher = nil
|
s.prefetcher = nil
|
||||||
}
|
}
|
||||||
if s.readPrefetcher != nil {
|
|
||||||
s.readPrefetcher.wait()
|
|
||||||
s.readPrefetcher.close()
|
|
||||||
s.readPrefetcher = nil
|
|
||||||
}
|
|
||||||
if s.snap != nil {
|
if s.snap != nil {
|
||||||
s.prefetcher = newTriePrefetcher(s.db, s.originalRoot, namespace)
|
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.
|
// from the gathered metrics.
|
||||||
func (s *StateDB) StopPrefetcher() {
|
func (s *StateDB) StopPrefetcher() {
|
||||||
if s.prefetcher != nil {
|
if s.prefetcher != nil {
|
||||||
s.prefetcher.wait()
|
|
||||||
s.prefetcher.close()
|
s.prefetcher.close()
|
||||||
s.prefetcher = nil
|
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.
|
// 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)
|
s.SnapshotAccountReads += time.Since(start)
|
||||||
}
|
}
|
||||||
if err == nil {
|
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 {
|
if acc == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -634,15 +622,9 @@ func (s *StateDB) getDeletedStateObject(addr common.Address) *stateObject {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert into the live set
|
// Insert into the live set
|
||||||
obj := newObject(s, addr, data)
|
obj := newObject(s, addr, data)
|
||||||
s.setStateObject(obj)
|
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
|
return obj
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -719,7 +701,10 @@ func (s *StateDB) CreateAccount(addr common.Address) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy creates a deep, independent copy of the state.
|
// 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 {
|
func (s *StateDB) Copy() *StateDB {
|
||||||
// Copy all the basic fields, initialize the memory ones
|
// Copy all the basic fields, initialize the memory ones
|
||||||
state := &StateDB{
|
state := &StateDB{
|
||||||
|
|
@ -816,12 +801,6 @@ func (s *StateDB) Copy() *StateDB {
|
||||||
state.accessList = s.accessList.Copy()
|
state.accessList = s.accessList.Copy()
|
||||||
state.transientStorage = s.transientStorage.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
|
return state
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -909,7 +888,7 @@ func (s *StateDB) collectReadStorageAccessLists() {
|
||||||
for _, obj := range s.stateObjects {
|
for _, obj := range s.stateObjects {
|
||||||
// load read storage slots from the finished trie in the prefetcher as these continue to be prefetched
|
// load read storage slots from the finished trie in the prefetcher as these continue to be prefetched
|
||||||
// until commit.
|
// until commit.
|
||||||
tr := s.readPrefetcher.trie(obj.addrHash, obj.data.Root)
|
tr := s.prefetcher.trie(obj.addrHash, obj.data.Root)
|
||||||
if tr == nil {
|
if tr == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
@ -921,9 +900,9 @@ func (s *StateDB) collectReadStorageAccessLists() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StateDB) collectReadAccountsAccessLists() {
|
func (s *StateDB) collectReadAccountsAccessLists() {
|
||||||
tr := s.readPrefetcher.trie(common.Hash{}, s.originalRoot)
|
tr := s.prefetcher.trie(common.Hash{}, s.originalRoot)
|
||||||
if tr == nil {
|
if tr == nil {
|
||||||
// TODO: ensure this case is b/c of empty block
|
// empty block
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
accessList := tr.AccessList()
|
accessList := tr.AccessList()
|
||||||
|
|
@ -942,21 +921,14 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
|
||||||
prefetcher := s.prefetcher
|
prefetcher := s.prefetcher
|
||||||
if s.prefetcher != nil {
|
if s.prefetcher != nil {
|
||||||
defer func() {
|
defer func() {
|
||||||
// TODO: need to wait for read accounts to be resolved in prefetcher main trie?
|
|
||||||
s.prefetcher.wait()
|
|
||||||
s.prefetcher.close()
|
s.prefetcher.close()
|
||||||
|
if s.witness != nil {
|
||||||
|
s.collectReadStorageAccessLists()
|
||||||
|
s.collectReadAccountsAccessLists()
|
||||||
|
}
|
||||||
s.prefetcher = nil
|
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
|
// Although naively it makes sense to retrieve the account trie and then do
|
||||||
// the contract storage and account updates sequentially, that short circuits
|
// the contract storage and account updates sequentially, that short circuits
|
||||||
// the account prefetcher. Instead, let's process all the storage updates
|
// 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))
|
usedAddrs := make([][]byte, 0, len(s.stateObjectsPending))
|
||||||
|
|
||||||
// perform updates before deletions. In the case where a full node
|
// Perform updates before deletions. This is needed for stateless execution in MPT:
|
||||||
// has two children, one of them selfdestructs and makes the recipient
|
//
|
||||||
// another non-existing sibling, applying deletion before update would
|
// Take value nodes 1, 2 who share the same full node parent 3 and have no other siblings.
|
||||||
// result in the unecessary premature collapse of the full node into a short node
|
// 1 self-destructs specifying a non-existing recipient account which would be a child of 3.
|
||||||
// for the untouched third sibling.
|
// 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
|
var deletedObjects []*stateObject
|
||||||
for addr := range s.stateObjectsPending {
|
for addr := range s.stateObjectsPending {
|
||||||
if obj := s.stateObjects[addr]; !obj.deleted {
|
if obj := s.stateObjects[addr]; !obj.deleted {
|
||||||
|
|
@ -1250,22 +1223,6 @@ func (s *StateDB) Witness() *Witness {
|
||||||
return s.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.
|
// Commit writes the state to the underlying in-memory trie database.
|
||||||
// Once the state is committed, tries cached in stateDB (including account
|
// Once the state is committed, tries cached in stateDB (including account
|
||||||
// trie, storage tries) will no longer be functional. A new state instance
|
// 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
|
// 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.
|
// 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.
|
// 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 {
|
for addr := range s.stateObjects {
|
||||||
obj := s.stateObjects[addr]
|
obj := s.stateObjects[addr]
|
||||||
if _, ok := s.stateObjectsDirty[addr]; ok && !obj.deleted {
|
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
|
continue
|
||||||
}
|
}
|
||||||
if obj.trie != nil {
|
if obj.trie != nil {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue