diff --git a/x/evm/types/statedb.go b/x/evm/types/statedb.go index 1d47f39db..44df93cb8 100644 --- a/x/evm/types/statedb.go +++ b/x/evm/types/statedb.go @@ -471,7 +471,7 @@ func (csdb *CommitStateDB) Finalise(deleteEmptyObjects bool) error { } } - csdb.stateObjectsDirty[dirty.address] = struct{}{} + delete(csdb.stateObjectsDirty, dirty.address) } // invalidate journal because reverting across transactions is not allowed @@ -702,9 +702,9 @@ func (csdb *CommitStateDB) Copy() *CommitStateDB { storeKey: csdb.storeKey, paramSpace: csdb.paramSpace, accountKeeper: csdb.accountKeeper, - stateObjects: make([]stateEntry, len(csdb.journal.dirties)), - addressToObjectIndex: make(map[ethcmn.Address]int, len(csdb.journal.dirties)), - stateObjectsDirty: make(map[ethcmn.Address]struct{}, len(csdb.journal.dirties)), + stateObjects: []stateEntry{}, + addressToObjectIndex: make(map[ethcmn.Address]int), + stateObjectsDirty: make(map[ethcmn.Address]struct{}), refund: csdb.refund, logSize: csdb.logSize, preimages: make(map[ethcmn.Hash][]byte), @@ -712,18 +712,19 @@ func (csdb *CommitStateDB) Copy() *CommitStateDB { } // copy the dirty states, logs, and preimages - for i, dirty := range csdb.journal.dirties { + for _, dirty := range csdb.journal.dirties { // There is a case where an object is in the journal but not in the // stateObjects: OOG after touch on ripeMD prior to Byzantium. Thus, we // need to check for nil. // // Ref: https://github.com/ethereum/go-ethereum/pull/16485#issuecomment-380438527 if idx, exist := csdb.addressToObjectIndex[dirty.address]; exist { - state.stateObjects[i] = stateEntry{ + state.stateObjects = append(state.stateObjects, stateEntry{ address: dirty.address, stateObject: csdb.stateObjects[idx].stateObject.deepCopy(state), - } - state.stateObjectsDirty[dirty.address] = struct{}{} + }) + delete(state.stateObjectsDirty, dirty.address) + state.addressToObjectIndex[dirty.address] = len(state.stateObjects) - 1 } } @@ -731,9 +732,11 @@ func (csdb *CommitStateDB) Copy() *CommitStateDB { // copied, the loop above will be a no-op, since the copy's journal is empty. // Thus, here we iterate over stateObjects, to enable copies of copies. for addr := range csdb.stateObjectsDirty { - if idx, exist := state.addressToObjectIndex[addr]; !exist { - state.setStateObject(csdb.stateObjects[idx].stateObject.deepCopy(state)) - state.stateObjectsDirty[addr] = struct{}{} + if _, exist := state.addressToObjectIndex[addr]; !exist { + if idx, ok := csdb.addressToObjectIndex[addr]; ok { + state.setStateObject(csdb.stateObjects[idx].stateObject.deepCopy(state)) + delete(state.stateObjectsDirty, addr) + } } } @@ -821,8 +824,7 @@ func (csdb *CommitStateDB) setError(err error) { // getStateObject attempts to retrieve a state object given by the address. // Returns nil and sets an error if not found. func (csdb *CommitStateDB) getStateObject(addr ethcmn.Address) (stateObject *stateObject) { - idx, found := csdb.addressToObjectIndex[addr] - if found { + if idx, found := csdb.addressToObjectIndex[addr]; found && idx < len(csdb.stateObjects) { // prefer 'live' (cached) objects if so := csdb.stateObjects[idx].stateObject; so != nil { if so.deleted { @@ -848,8 +850,7 @@ func (csdb *CommitStateDB) getStateObject(addr ethcmn.Address) (stateObject *sta } func (csdb *CommitStateDB) setStateObject(so *stateObject) { - idx, found := csdb.addressToObjectIndex[so.Address()] - if found { + if idx, found := csdb.addressToObjectIndex[so.Address()]; found && idx < len(csdb.stateObjects) { // update the existing object csdb.stateObjects[idx].stateObject = so return