core/state: clear out cached state data when reset occurs (#27376)
* core/state: remove cached snap data if reset occurs * core/state: address comment from peter * core/state: skip revert in case data is nil
This commit is contained in:
parent
78f7a6b7f2
commit
380fb4e249
@ -93,6 +93,8 @@ type (
|
||||
account *common.Address
|
||||
prev *stateObject
|
||||
prevdestruct bool
|
||||
prevAccount []byte
|
||||
prevStorage map[common.Hash][]byte
|
||||
}
|
||||
suicideChange struct {
|
||||
account *common.Address
|
||||
@ -160,6 +162,12 @@ func (ch resetObjectChange) revert(s *StateDB) {
|
||||
if !ch.prevdestruct {
|
||||
delete(s.stateObjectsDestruct, ch.prev.address)
|
||||
}
|
||||
if ch.prevAccount != nil {
|
||||
s.snapAccounts[ch.prev.addrHash] = ch.prevAccount
|
||||
}
|
||||
if ch.prevStorage != nil {
|
||||
s.snapStorage[ch.prev.addrHash] = ch.prevStorage
|
||||
}
|
||||
}
|
||||
|
||||
func (ch resetObjectChange) dirtied() *common.Address {
|
||||
|
@ -627,11 +627,34 @@ func (s *StateDB) createObject(addr common.Address) (newobj, prev *stateObject)
|
||||
if prev == nil {
|
||||
s.journal.append(createObjectChange{account: &addr})
|
||||
} else {
|
||||
// The original account should be marked as destructed and all cached
|
||||
// account and storage data should be cleared as well. Note, it must
|
||||
// be done here, otherwise the destruction event of original one will
|
||||
// be lost.
|
||||
_, prevdestruct := s.stateObjectsDestruct[prev.address]
|
||||
if !prevdestruct {
|
||||
s.stateObjectsDestruct[prev.address] = struct{}{}
|
||||
}
|
||||
s.journal.append(resetObjectChange{account: &addr, prev: prev, prevdestruct: prevdestruct})
|
||||
var (
|
||||
account []byte
|
||||
storage map[common.Hash][]byte
|
||||
)
|
||||
// There may be some cached account/storage data already since IntermediateRoot
|
||||
// will be called for each transaction before byzantium fork which will always
|
||||
// cache the latest account/storage data.
|
||||
if s.snap != nil {
|
||||
account = s.snapAccounts[prev.addrHash]
|
||||
storage = s.snapStorage[prev.addrHash]
|
||||
delete(s.snapAccounts, prev.addrHash)
|
||||
delete(s.snapStorage, prev.addrHash)
|
||||
}
|
||||
s.journal.append(resetObjectChange{
|
||||
account: &addr,
|
||||
prev: prev,
|
||||
prevdestruct: prevdestruct,
|
||||
prevAccount: account,
|
||||
prevStorage: storage,
|
||||
})
|
||||
}
|
||||
s.setStateObject(newobj)
|
||||
if prev != nil && !prev.deleted {
|
||||
|
@ -31,7 +31,10 @@ import (
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/state/snapshot"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
)
|
||||
|
||||
// Tests that updating a state trie does not leak any database writes prior to
|
||||
@ -998,3 +1001,37 @@ func TestStateDBTransientStorage(t *testing.T) {
|
||||
t.Fatalf("transient storage mismatch: have %x, want %x", got, value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResetObject(t *testing.T) {
|
||||
var (
|
||||
disk = rawdb.NewMemoryDatabase()
|
||||
tdb = trie.NewDatabase(disk)
|
||||
db = NewDatabaseWithNodeDB(disk, tdb)
|
||||
snaps, _ = snapshot.New(snapshot.Config{CacheSize: 10}, disk, tdb, types.EmptyRootHash)
|
||||
state, _ = New(types.EmptyRootHash, db, snaps)
|
||||
addr = common.HexToAddress("0x1")
|
||||
slotA = common.HexToHash("0x1")
|
||||
slotB = common.HexToHash("0x2")
|
||||
)
|
||||
// Initialize account with balance and storage in first transaction.
|
||||
state.SetBalance(addr, big.NewInt(1))
|
||||
state.SetState(addr, slotA, common.BytesToHash([]byte{0x1}))
|
||||
state.IntermediateRoot(true)
|
||||
|
||||
// Reset account and mutate balance and storages
|
||||
state.CreateAccount(addr)
|
||||
state.SetBalance(addr, big.NewInt(2))
|
||||
state.SetState(addr, slotB, common.BytesToHash([]byte{0x2}))
|
||||
root, _ := state.Commit(true)
|
||||
|
||||
// Ensure the original account is wiped properly
|
||||
snap := snaps.Snapshot(root)
|
||||
slot, _ := snap.Storage(crypto.Keccak256Hash(addr.Bytes()), crypto.Keccak256Hash(slotA.Bytes()))
|
||||
if len(slot) != 0 {
|
||||
t.Fatalf("Unexpected storage slot")
|
||||
}
|
||||
slot, _ = snap.Storage(crypto.Keccak256Hash(addr.Bytes()), crypto.Keccak256Hash(slotB.Bytes()))
|
||||
if !bytes.Equal(slot, []byte{0x2}) {
|
||||
t.Fatalf("Unexpected storage slot value %v", slot)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user