core: fix two snapshot iterator flaws, decollide snap storage prefix

* core/state/snapshot/iterator: fix two disk iterator flaws

* core/rawdb: change SnapshotStoragePrefix to avoid prefix collision with preimagePrefix
This commit is contained in:
Martin Holst Swende
2020-03-06 13:05:44 +01:00
committed by Péter Szilágyi
parent fab0ee3bfa
commit 074efe6c8d
5 changed files with 149 additions and 12 deletions

View File

@ -90,7 +90,8 @@ type (
account *common.Address
}
resetObjectChange struct {
prev *stateObject
prev *stateObject
prevdestruct bool
}
suicideChange struct {
account *common.Address
@ -142,6 +143,9 @@ func (ch createObjectChange) dirtied() *common.Address {
func (ch resetObjectChange) revert(s *StateDB) {
s.setStateObject(ch.prev)
if !ch.prevdestruct && s.snap != nil {
delete(s.snapDestructs, ch.prev.addrHash)
}
}
func (ch resetObjectChange) dirtied() *common.Address {

View File

@ -148,9 +148,10 @@ type diskAccountIterator struct {
// AccountIterator creates an account iterator over a disk layer.
func (dl *diskLayer) AccountIterator(seek common.Hash) AccountIterator {
// TODO: Fix seek position, or remove seek parameter
return &diskAccountIterator{
layer: dl,
it: dl.diskdb.NewIteratorWithPrefix(append(rawdb.SnapshotAccountPrefix, seek[:]...)),
it: dl.diskdb.NewIteratorWithPrefix(rawdb.SnapshotAccountPrefix),
}
}
@ -160,11 +161,16 @@ func (it *diskAccountIterator) Next() bool {
if it.it == nil {
return false
}
// Try to advance the iterator and release it if we reahed the end
if !it.it.Next() || !bytes.HasPrefix(it.it.Key(), rawdb.SnapshotAccountPrefix) {
it.it.Release()
it.it = nil
return false
// Try to advance the iterator and release it if we reached the end
for {
if !it.it.Next() || !bytes.HasPrefix(it.it.Key(), rawdb.SnapshotAccountPrefix) {
it.it.Release()
it.it = nil
return false
}
if len(it.it.Key()) == len(rawdb.SnapshotAccountPrefix)+common.HashLength {
break
}
}
return true
}

View File

@ -569,12 +569,19 @@ func (s *StateDB) GetOrNewStateObject(addr common.Address) *stateObject {
func (s *StateDB) createObject(addr common.Address) (newobj, prev *stateObject) {
prev = s.getDeletedStateObject(addr) // Note, prev might have been deleted, we need that!
var prevdestruct bool
if s.snap != nil && prev != nil {
_, prevdestruct = s.snapDestructs[prev.addrHash]
if !prevdestruct {
s.snapDestructs[prev.addrHash] = struct{}{}
}
}
newobj = newObject(s, addr, Account{})
newobj.setNonce(0) // sets the object to dirty
if prev == nil {
s.journal.append(createObjectChange{account: &addr})
} else {
s.journal.append(resetObjectChange{prev: prev})
s.journal.append(resetObjectChange{prev: prev, prevdestruct: prevdestruct})
}
s.setStateObject(newobj)
return newobj, prev
@ -595,9 +602,6 @@ 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 {