mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-18 09:53:48 +00:00
core/state: polish
This commit is contained in:
parent
9f9b209277
commit
05ee450f2d
7 changed files with 64 additions and 61 deletions
|
|
@ -399,10 +399,7 @@ func (dl *diffLayer) flatten() snapshot {
|
|||
continue
|
||||
}
|
||||
// Storage exists in both parent and child, merge the slots
|
||||
comboData := parent.storageData[accountHash]
|
||||
for storageHash, data := range storage {
|
||||
comboData[storageHash] = data
|
||||
}
|
||||
maps.Copy(parent.storageData[accountHash], storage)
|
||||
}
|
||||
// Return the combo parent
|
||||
return &diffLayer{
|
||||
|
|
|
|||
|
|
@ -67,20 +67,17 @@ func (dl *diffLayer) initBinaryAccountIterator(seek common.Hash) Iterator {
|
|||
func (dl *diffLayer) initBinaryStorageIterator(account, seek common.Hash) Iterator {
|
||||
parent, ok := dl.parent.(*diffLayer)
|
||||
if !ok {
|
||||
a := dl.StorageIterator(account, seek)
|
||||
b := dl.Parent().StorageIterator(account, seek)
|
||||
l := &binaryIterator{
|
||||
a: a,
|
||||
b: b,
|
||||
a: dl.StorageIterator(account, seek),
|
||||
b: dl.Parent().StorageIterator(account, seek),
|
||||
account: account,
|
||||
}
|
||||
l.aDone = !l.a.Next()
|
||||
l.bDone = !l.b.Next()
|
||||
return l
|
||||
}
|
||||
a := dl.StorageIterator(account, seek)
|
||||
l := &binaryIterator{
|
||||
a: a,
|
||||
a: dl.StorageIterator(account, seek),
|
||||
b: parent.initBinaryStorageIterator(account, seek),
|
||||
account: account,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -543,10 +543,14 @@ func diffToDisk(bottom *diffLayer) *diskLayer {
|
|||
continue
|
||||
}
|
||||
// Push the account to disk
|
||||
if len(data) != 0 {
|
||||
rawdb.WriteAccountSnapshot(batch, hash, data)
|
||||
base.cache.Set(hash[:], data)
|
||||
snapshotCleanAccountWriteMeter.Mark(int64(len(data)))
|
||||
|
||||
} else {
|
||||
rawdb.DeleteAccountSnapshot(batch, hash)
|
||||
base.cache.Set(hash[:], nil)
|
||||
}
|
||||
snapshotFlushAccountItemMeter.Mark(1)
|
||||
snapshotFlushAccountSizeMeter.Mark(int64(len(data)))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -932,16 +932,17 @@ func (s *StateDB) clearJournalAndRefund() {
|
|||
// of a specific account. It leverages the associated state snapshot for fast
|
||||
// storage iteration and constructs trie node deletion markers by creating
|
||||
// stack trie with iterated slots.
|
||||
func (s *StateDB) fastDeleteStorage(snaps *snapshot.Tree, addrHash common.Hash, root common.Hash) (map[common.Hash][]byte, *trienode.NodeSet, error) {
|
||||
func (s *StateDB) fastDeleteStorage(snaps *snapshot.Tree, addrHash common.Hash, root common.Hash) (map[common.Hash][]byte, map[common.Hash][]byte, *trienode.NodeSet, error) {
|
||||
iter, err := snaps.StorageIterator(s.originalRoot, addrHash, common.Hash{})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
defer iter.Release()
|
||||
|
||||
var (
|
||||
nodes = trienode.NewNodeSet(addrHash)
|
||||
slots = make(map[common.Hash][]byte)
|
||||
deletes = make(map[common.Hash][]byte)
|
||||
)
|
||||
stack := trie.NewStackTrie(func(path []byte, hash common.Hash, blob []byte) {
|
||||
nodes.AddNode(path, trienode.NewDeleted())
|
||||
|
|
@ -949,42 +950,47 @@ func (s *StateDB) fastDeleteStorage(snaps *snapshot.Tree, addrHash common.Hash,
|
|||
for iter.Next() {
|
||||
slot := common.CopyBytes(iter.Slot())
|
||||
if err := iter.Error(); err != nil { // error might occur after Slot function
|
||||
return nil, nil, err
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
slots[iter.Hash()] = slot
|
||||
key := iter.Hash()
|
||||
slots[key] = slot
|
||||
deletes[key] = nil
|
||||
|
||||
if err := stack.Update(iter.Hash().Bytes(), slot); err != nil {
|
||||
return nil, nil, err
|
||||
if err := stack.Update(key.Bytes(), slot); err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
}
|
||||
if err := iter.Error(); err != nil { // error might occur during iteration
|
||||
return nil, nil, err
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
if stack.Hash() != root {
|
||||
return nil, nil, fmt.Errorf("snapshot is not matched, exp %x, got %x", root, stack.Hash())
|
||||
return nil, nil, nil, fmt.Errorf("snapshot is not matched, exp %x, got %x", root, stack.Hash())
|
||||
}
|
||||
return slots, nodes, nil
|
||||
return deletes, slots, nodes, nil
|
||||
}
|
||||
|
||||
// slowDeleteStorage serves as a less-efficient alternative to "fastDeleteStorage,"
|
||||
// employed when the associated state snapshot is not available. It iterates the
|
||||
// storage slots along with all internal trie nodes via trie directly.
|
||||
func (s *StateDB) slowDeleteStorage(addr common.Address, addrHash common.Hash, root common.Hash) (map[common.Hash][]byte, *trienode.NodeSet, error) {
|
||||
func (s *StateDB) slowDeleteStorage(addr common.Address, addrHash common.Hash, root common.Hash) (map[common.Hash][]byte, map[common.Hash][]byte, *trienode.NodeSet, error) {
|
||||
tr, err := s.db.OpenStorageTrie(s.originalRoot, addr, root, s.trie)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to open storage trie, err: %w", err)
|
||||
return nil, nil, nil, fmt.Errorf("failed to open storage trie, err: %w", err)
|
||||
}
|
||||
it, err := tr.NodeIterator(nil)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to open storage iterator, err: %w", err)
|
||||
return nil, nil, nil, fmt.Errorf("failed to open storage iterator, err: %w", err)
|
||||
}
|
||||
var (
|
||||
nodes = trienode.NewNodeSet(addrHash)
|
||||
slots = make(map[common.Hash][]byte)
|
||||
deletes = make(map[common.Hash][]byte)
|
||||
)
|
||||
for it.Next(true) {
|
||||
if it.Leaf() {
|
||||
slots[common.BytesToHash(it.LeafKey())] = common.CopyBytes(it.LeafBlob())
|
||||
key := common.BytesToHash(it.LeafKey())
|
||||
slots[key] = common.CopyBytes(it.LeafBlob())
|
||||
deletes[key] = nil
|
||||
continue
|
||||
}
|
||||
if it.Hash() == (common.Hash{}) {
|
||||
|
|
@ -993,19 +999,20 @@ func (s *StateDB) slowDeleteStorage(addr common.Address, addrHash common.Hash, r
|
|||
nodes.AddNode(it.Path(), trienode.NewDeleted())
|
||||
}
|
||||
if err := it.Error(); err != nil {
|
||||
return nil, nil, err
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
return slots, nodes, nil
|
||||
return deletes, slots, nodes, nil
|
||||
}
|
||||
|
||||
// deleteStorage is designed to delete the storage trie of a designated account.
|
||||
// The function will make an attempt to utilize an efficient strategy if the
|
||||
// associated state snapshot is reachable; otherwise, it will resort to a less
|
||||
// efficient approach.
|
||||
func (s *StateDB) deleteStorage(addr common.Address, addrHash common.Hash, root common.Hash) (map[common.Hash][]byte, *trienode.NodeSet, error) {
|
||||
func (s *StateDB) deleteStorage(addr common.Address, addrHash common.Hash, root common.Hash) (map[common.Hash][]byte, map[common.Hash][]byte, *trienode.NodeSet, error) {
|
||||
var (
|
||||
err error
|
||||
slots map[common.Hash][]byte
|
||||
deletes map[common.Hash][]byte
|
||||
nodes *trienode.NodeSet
|
||||
)
|
||||
// The fast approach can be failed if the snapshot is not fully
|
||||
|
|
@ -1013,15 +1020,15 @@ func (s *StateDB) deleteStorage(addr common.Address, addrHash common.Hash, root
|
|||
// one just in case.
|
||||
snaps := s.db.Snapshot()
|
||||
if snaps != nil {
|
||||
slots, nodes, err = s.fastDeleteStorage(snaps, addrHash, root)
|
||||
deletes, slots, nodes, err = s.fastDeleteStorage(snaps, addrHash, root)
|
||||
}
|
||||
if snaps == nil || err != nil {
|
||||
slots, nodes, err = s.slowDeleteStorage(addr, addrHash, root)
|
||||
deletes, slots, nodes, err = s.slowDeleteStorage(addr, addrHash, root)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
return slots, nodes, nil
|
||||
return deletes, slots, nodes, nil
|
||||
}
|
||||
|
||||
// handleDestruction processes all destruction markers and deletes the account
|
||||
|
|
@ -1072,11 +1079,12 @@ func (s *StateDB) handleDestruction() (map[common.Hash]*accountDelete, []*trieno
|
|||
continue
|
||||
}
|
||||
// Remove storage slots belonging to the account.
|
||||
slots, set, err := s.deleteStorage(addr, addrHash, prev.Root)
|
||||
storages, storagesOrigin, set, err := s.deleteStorage(addr, addrHash, prev.Root)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to delete storage, err: %w", err)
|
||||
}
|
||||
op.storagesOrigin = slots
|
||||
op.storages = storages
|
||||
op.storagesOrigin = storagesOrigin
|
||||
|
||||
// Aggregate the associated trie node changes.
|
||||
nodes = append(nodes, set)
|
||||
|
|
|
|||
|
|
@ -353,8 +353,8 @@ func (test *stateTest) verifyAccountUpdate(next common.Hash, db *triedb.Database
|
|||
if !bytes.Equal(full, oBlob) {
|
||||
return fmt.Errorf("account value is not matched, %x", addrHash)
|
||||
}
|
||||
if len(account) == 0 {
|
||||
if len(nBlob) != 0 {
|
||||
if len(nBlob) == 0 {
|
||||
if len(account) != 0 {
|
||||
return errors.New("unexpected account data")
|
||||
}
|
||||
} else {
|
||||
|
|
@ -363,7 +363,6 @@ func (test *stateTest) verifyAccountUpdate(next common.Hash, db *triedb.Database
|
|||
return fmt.Errorf("unexpected account data, %x, want %v, got: %v", addrHash, full, nBlob)
|
||||
}
|
||||
}
|
||||
|
||||
// Decode accounts
|
||||
var (
|
||||
oAcct types.StateAccount
|
||||
|
|
|
|||
|
|
@ -1305,12 +1305,12 @@ func TestDeleteStorage(t *testing.T) {
|
|||
obj := fastState.getOrNewStateObject(addr)
|
||||
storageRoot := obj.data.Root
|
||||
|
||||
_, fastNodes, err := fastState.deleteStorage(addr, crypto.Keccak256Hash(addr[:]), storageRoot)
|
||||
_, _, fastNodes, err := fastState.deleteStorage(addr, crypto.Keccak256Hash(addr[:]), storageRoot)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, slowNodes, err := slowState.deleteStorage(addr, crypto.Keccak256Hash(addr[:]), storageRoot)
|
||||
_, _, slowNodes, err := slowState.deleteStorage(addr, crypto.Keccak256Hash(addr[:]), storageRoot)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ type contractCode struct {
|
|||
type accountDelete struct {
|
||||
address common.Address // address is the unique account identifier
|
||||
origin []byte // origin is the original value of account data in slim-RLP encoding.
|
||||
storages map[common.Hash][]byte // storages stores mutated slots, the value should be nil.
|
||||
storagesOrigin map[common.Hash][]byte // storagesOrigin stores the original values of mutated slots in prefix-zero-trimmed RLP format.
|
||||
}
|
||||
|
||||
|
|
@ -85,12 +86,10 @@ func newStateUpdate(originRoot common.Hash, root common.Hash, deletes map[common
|
|||
accounts[addrHash] = nil
|
||||
accountsOrigin[addr] = op.origin
|
||||
|
||||
if len(op.storagesOrigin) > 0 {
|
||||
subset := make(map[common.Hash][]byte, len(op.storagesOrigin))
|
||||
for key := range op.storagesOrigin {
|
||||
subset[key] = nil
|
||||
if len(op.storages) > 0 {
|
||||
storages[addrHash] = op.storages
|
||||
}
|
||||
storages[addrHash] = subset
|
||||
if len(op.storagesOrigin) > 0 {
|
||||
storagesOrigin[addr] = op.storagesOrigin
|
||||
}
|
||||
}
|
||||
|
|
@ -121,17 +120,16 @@ func newStateUpdate(originRoot common.Hash, root common.Hash, deletes map[common
|
|||
// Aggregate the storage original values. If the slot is already present
|
||||
// in aggregated storagesOrigin set, skip it.
|
||||
if len(op.storagesOrigin) > 0 {
|
||||
origin := storagesOrigin[addr]
|
||||
if origin == nil {
|
||||
origin, exist := storagesOrigin[addr]
|
||||
if !exist {
|
||||
storagesOrigin[addr] = op.storagesOrigin
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
for key, slot := range op.storagesOrigin {
|
||||
if _, found := origin[key]; !found {
|
||||
origin[key] = slot
|
||||
}
|
||||
}
|
||||
storagesOrigin[addr] = origin
|
||||
}
|
||||
}
|
||||
}
|
||||
return &stateUpdate{
|
||||
|
|
|
|||
Loading…
Reference in a new issue