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