diff --git a/core/state/state_object.go b/core/state/state_object.go index 26e0b08f5..0833f2b0a 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -204,6 +204,15 @@ func (s *stateObject) GetCommittedState(db Database, key common.Hash) common.Has if metrics.EnabledExpensive { defer func(start time.Time) { s.db.SnapshotStorageReads += time.Since(start) }(time.Now()) } + // If the object was destructed in *this* block (and potentially resurrected), + // the storage has been cleared out, and we should *not* consult the previous + // snapshot about any storage values. The only possible alternatives are: + // 1) resurrect happened, and new slot values were set -- those should + // have been handles via pendingStorage above. + // 2) we don't have new values, and can deliver empty response back + if _, destructed := s.db.snapDestructs[s.addrHash]; destructed { + return common.Hash{} + } enc, err = s.db.snap.Storage(s.addrHash, crypto.Keccak256Hash(key[:])) } // If snapshot unavailable or reading from it failed, load from the database diff --git a/core/state/statedb.go b/core/state/statedb.go index ff2c6dac2..038005685 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -595,6 +595,9 @@ func (s *StateDB) CreateAccount(addr common.Address) { if prev != nil { newObj.setBalance(prev.data.Balance) } + if s.snap != nil && prev != nil { + s.snapDestructs[prev.addrHash] = struct{}{} + } } func (db *StateDB) ForEachStorage(addr common.Address, cb func(key, value common.Hash) bool) error { @@ -855,7 +858,7 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { log.Warn("Failed to cap snapshot tree", "root", root, "layers", 127, "err", err) } } - s.snap, s.snapAccounts, s.snapStorage = nil, nil, nil + s.snap, s.snapDestructs, s.snapAccounts, s.snapStorage = nil, nil, nil, nil } return root, err }