|
@@ -20,6 +20,7 @@ package state
|
|
|
import (
|
|
import (
|
|
|
"fmt"
|
|
"fmt"
|
|
|
"math/big"
|
|
"math/big"
|
|
|
|
|
+ "sort"
|
|
|
"sync"
|
|
"sync"
|
|
|
|
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/common"
|
|
@@ -40,12 +41,17 @@ var StartingNonce uint64
|
|
|
const (
|
|
const (
|
|
|
// Number of past tries to keep. The arbitrarily chosen value here
|
|
// Number of past tries to keep. The arbitrarily chosen value here
|
|
|
// is max uncle depth + 1.
|
|
// is max uncle depth + 1.
|
|
|
- maxJournalLength = 8
|
|
|
|
|
|
|
+ maxTrieCacheLength = 8
|
|
|
|
|
|
|
|
// Number of codehash->size associations to keep.
|
|
// Number of codehash->size associations to keep.
|
|
|
codeSizeCacheSize = 100000
|
|
codeSizeCacheSize = 100000
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
|
|
+type revision struct {
|
|
|
|
|
+ id int
|
|
|
|
|
+ journalIndex int
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
// StateDBs within the ethereum protocol are used to store anything
|
|
// StateDBs within the ethereum protocol are used to store anything
|
|
|
// within the merkle trie. StateDBs take care of caching and storing
|
|
// within the merkle trie. StateDBs take care of caching and storing
|
|
|
// nested states. It's the general query interface to retrieve:
|
|
// nested states. It's the general query interface to retrieve:
|
|
@@ -69,6 +75,12 @@ type StateDB struct {
|
|
|
logs map[common.Hash]vm.Logs
|
|
logs map[common.Hash]vm.Logs
|
|
|
logSize uint
|
|
logSize uint
|
|
|
|
|
|
|
|
|
|
+ // Journal of state modifications. This is the backbone of
|
|
|
|
|
+ // Snapshot and RevertToSnapshot.
|
|
|
|
|
+ journal journal
|
|
|
|
|
+ validRevisions []revision
|
|
|
|
|
+ nextRevisionId int
|
|
|
|
|
+
|
|
|
lock sync.Mutex
|
|
lock sync.Mutex
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -124,12 +136,12 @@ func (self *StateDB) Reset(root common.Hash) error {
|
|
|
self.trie = tr
|
|
self.trie = tr
|
|
|
self.stateObjects = make(map[common.Address]*StateObject)
|
|
self.stateObjects = make(map[common.Address]*StateObject)
|
|
|
self.stateObjectsDirty = make(map[common.Address]struct{})
|
|
self.stateObjectsDirty = make(map[common.Address]struct{})
|
|
|
- self.refund = new(big.Int)
|
|
|
|
|
self.thash = common.Hash{}
|
|
self.thash = common.Hash{}
|
|
|
self.bhash = common.Hash{}
|
|
self.bhash = common.Hash{}
|
|
|
self.txIndex = 0
|
|
self.txIndex = 0
|
|
|
self.logs = make(map[common.Hash]vm.Logs)
|
|
self.logs = make(map[common.Hash]vm.Logs)
|
|
|
self.logSize = 0
|
|
self.logSize = 0
|
|
|
|
|
+ self.clearJournalAndRefund()
|
|
|
|
|
|
|
|
return nil
|
|
return nil
|
|
|
}
|
|
}
|
|
@@ -150,7 +162,7 @@ func (self *StateDB) pushTrie(t *trie.SecureTrie) {
|
|
|
self.lock.Lock()
|
|
self.lock.Lock()
|
|
|
defer self.lock.Unlock()
|
|
defer self.lock.Unlock()
|
|
|
|
|
|
|
|
- if len(self.pastTries) >= maxJournalLength {
|
|
|
|
|
|
|
+ if len(self.pastTries) >= maxTrieCacheLength {
|
|
|
copy(self.pastTries, self.pastTries[1:])
|
|
copy(self.pastTries, self.pastTries[1:])
|
|
|
self.pastTries[len(self.pastTries)-1] = t
|
|
self.pastTries[len(self.pastTries)-1] = t
|
|
|
} else {
|
|
} else {
|
|
@@ -165,6 +177,8 @@ func (self *StateDB) StartRecord(thash, bhash common.Hash, ti int) {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
func (self *StateDB) AddLog(log *vm.Log) {
|
|
func (self *StateDB) AddLog(log *vm.Log) {
|
|
|
|
|
+ self.journal = append(self.journal, addLogChange{txhash: self.thash})
|
|
|
|
|
+
|
|
|
log.TxHash = self.thash
|
|
log.TxHash = self.thash
|
|
|
log.BlockHash = self.bhash
|
|
log.BlockHash = self.bhash
|
|
|
log.TxIndex = uint(self.txIndex)
|
|
log.TxIndex = uint(self.txIndex)
|
|
@@ -186,13 +200,12 @@ func (self *StateDB) Logs() vm.Logs {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
func (self *StateDB) AddRefund(gas *big.Int) {
|
|
func (self *StateDB) AddRefund(gas *big.Int) {
|
|
|
|
|
+ self.journal = append(self.journal, refundChange{prev: new(big.Int).Set(self.refund)})
|
|
|
self.refund.Add(self.refund, gas)
|
|
self.refund.Add(self.refund, gas)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-func (self *StateDB) HasAccount(addr common.Address) bool {
|
|
|
|
|
- return self.GetStateObject(addr) != nil
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
|
|
+// Exist reports whether the given account address exists in the state.
|
|
|
|
|
+// Notably this also returns true for suicided accounts.
|
|
|
func (self *StateDB) Exist(addr common.Address) bool {
|
|
func (self *StateDB) Exist(addr common.Address) bool {
|
|
|
return self.GetStateObject(addr) != nil
|
|
return self.GetStateObject(addr) != nil
|
|
|
}
|
|
}
|
|
@@ -207,7 +220,6 @@ func (self *StateDB) GetBalance(addr common.Address) *big.Int {
|
|
|
if stateObject != nil {
|
|
if stateObject != nil {
|
|
|
return stateObject.Balance()
|
|
return stateObject.Balance()
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
return common.Big0
|
|
return common.Big0
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -282,6 +294,13 @@ func (self *StateDB) AddBalance(addr common.Address, amount *big.Int) {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+func (self *StateDB) SetBalance(addr common.Address, amount *big.Int) {
|
|
|
|
|
+ stateObject := self.GetOrNewStateObject(addr)
|
|
|
|
|
+ if stateObject != nil {
|
|
|
|
|
+ stateObject.SetBalance(amount)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
func (self *StateDB) SetNonce(addr common.Address, nonce uint64) {
|
|
func (self *StateDB) SetNonce(addr common.Address, nonce uint64) {
|
|
|
stateObject := self.GetOrNewStateObject(addr)
|
|
stateObject := self.GetOrNewStateObject(addr)
|
|
|
if stateObject != nil {
|
|
if stateObject != nil {
|
|
@@ -299,27 +318,36 @@ func (self *StateDB) SetCode(addr common.Address, code []byte) {
|
|
|
func (self *StateDB) SetState(addr common.Address, key common.Hash, value common.Hash) {
|
|
func (self *StateDB) SetState(addr common.Address, key common.Hash, value common.Hash) {
|
|
|
stateObject := self.GetOrNewStateObject(addr)
|
|
stateObject := self.GetOrNewStateObject(addr)
|
|
|
if stateObject != nil {
|
|
if stateObject != nil {
|
|
|
- stateObject.SetState(key, value)
|
|
|
|
|
|
|
+ stateObject.SetState(self.db, key, value)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+// Delete marks the given account as suicided.
|
|
|
|
|
+// This clears the account balance.
|
|
|
|
|
+//
|
|
|
|
|
+// The account's state object is still available until the state is committed,
|
|
|
|
|
+// GetStateObject will return a non-nil account after Delete.
|
|
|
func (self *StateDB) Delete(addr common.Address) bool {
|
|
func (self *StateDB) Delete(addr common.Address) bool {
|
|
|
stateObject := self.GetStateObject(addr)
|
|
stateObject := self.GetStateObject(addr)
|
|
|
- if stateObject != nil {
|
|
|
|
|
- stateObject.MarkForDeletion()
|
|
|
|
|
- stateObject.data.Balance = new(big.Int)
|
|
|
|
|
- return true
|
|
|
|
|
|
|
+ if stateObject == nil {
|
|
|
|
|
+ return false
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- return false
|
|
|
|
|
|
|
+ self.journal = append(self.journal, deleteAccountChange{
|
|
|
|
|
+ account: &addr,
|
|
|
|
|
+ prev: stateObject.remove,
|
|
|
|
|
+ prevbalance: new(big.Int).Set(stateObject.Balance()),
|
|
|
|
|
+ })
|
|
|
|
|
+ stateObject.markForDeletion()
|
|
|
|
|
+ stateObject.data.Balance = new(big.Int)
|
|
|
|
|
+ return true
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//
|
|
//
|
|
|
// Setting, updating & deleting state object methods
|
|
// Setting, updating & deleting state object methods
|
|
|
//
|
|
//
|
|
|
|
|
|
|
|
-// Update the given state object and apply it to state trie
|
|
|
|
|
-func (self *StateDB) UpdateStateObject(stateObject *StateObject) {
|
|
|
|
|
|
|
+// updateStateObject writes the given object to the trie.
|
|
|
|
|
+func (self *StateDB) updateStateObject(stateObject *StateObject) {
|
|
|
addr := stateObject.Address()
|
|
addr := stateObject.Address()
|
|
|
data, err := rlp.EncodeToBytes(stateObject)
|
|
data, err := rlp.EncodeToBytes(stateObject)
|
|
|
if err != nil {
|
|
if err != nil {
|
|
@@ -328,10 +356,9 @@ func (self *StateDB) UpdateStateObject(stateObject *StateObject) {
|
|
|
self.trie.Update(addr[:], data)
|
|
self.trie.Update(addr[:], data)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// Delete the given state object and delete it from the state trie
|
|
|
|
|
-func (self *StateDB) DeleteStateObject(stateObject *StateObject) {
|
|
|
|
|
|
|
+// deleteStateObject removes the given object from the state trie.
|
|
|
|
|
+func (self *StateDB) deleteStateObject(stateObject *StateObject) {
|
|
|
stateObject.deleted = true
|
|
stateObject.deleted = true
|
|
|
-
|
|
|
|
|
addr := stateObject.Address()
|
|
addr := stateObject.Address()
|
|
|
self.trie.Delete(addr[:])
|
|
self.trie.Delete(addr[:])
|
|
|
}
|
|
}
|
|
@@ -357,12 +384,12 @@ func (self *StateDB) GetStateObject(addr common.Address) (stateObject *StateObje
|
|
|
return nil
|
|
return nil
|
|
|
}
|
|
}
|
|
|
// Insert into the live set.
|
|
// Insert into the live set.
|
|
|
- obj := NewObject(addr, data, self.MarkStateObjectDirty)
|
|
|
|
|
- self.SetStateObject(obj)
|
|
|
|
|
|
|
+ obj := newObject(self, addr, data, self.MarkStateObjectDirty)
|
|
|
|
|
+ self.setStateObject(obj)
|
|
|
return obj
|
|
return obj
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-func (self *StateDB) SetStateObject(object *StateObject) {
|
|
|
|
|
|
|
+func (self *StateDB) setStateObject(object *StateObject) {
|
|
|
self.stateObjects[object.Address()] = object
|
|
self.stateObjects[object.Address()] = object
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -370,52 +397,55 @@ func (self *StateDB) SetStateObject(object *StateObject) {
|
|
|
func (self *StateDB) GetOrNewStateObject(addr common.Address) *StateObject {
|
|
func (self *StateDB) GetOrNewStateObject(addr common.Address) *StateObject {
|
|
|
stateObject := self.GetStateObject(addr)
|
|
stateObject := self.GetStateObject(addr)
|
|
|
if stateObject == nil || stateObject.deleted {
|
|
if stateObject == nil || stateObject.deleted {
|
|
|
- stateObject = self.CreateStateObject(addr)
|
|
|
|
|
|
|
+ stateObject, _ = self.createObject(addr)
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
return stateObject
|
|
return stateObject
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// NewStateObject create a state object whether it exist in the trie or not
|
|
|
|
|
-func (self *StateDB) newStateObject(addr common.Address) *StateObject {
|
|
|
|
|
- if glog.V(logger.Core) {
|
|
|
|
|
- glog.Infof("(+) %x\n", addr)
|
|
|
|
|
- }
|
|
|
|
|
- obj := NewObject(addr, Account{}, self.MarkStateObjectDirty)
|
|
|
|
|
- obj.SetNonce(StartingNonce) // sets the object to dirty
|
|
|
|
|
- self.stateObjects[addr] = obj
|
|
|
|
|
- return obj
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
// MarkStateObjectDirty adds the specified object to the dirty map to avoid costly
|
|
// MarkStateObjectDirty adds the specified object to the dirty map to avoid costly
|
|
|
// state object cache iteration to find a handful of modified ones.
|
|
// state object cache iteration to find a handful of modified ones.
|
|
|
func (self *StateDB) MarkStateObjectDirty(addr common.Address) {
|
|
func (self *StateDB) MarkStateObjectDirty(addr common.Address) {
|
|
|
self.stateObjectsDirty[addr] = struct{}{}
|
|
self.stateObjectsDirty[addr] = struct{}{}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// Creates creates a new state object and takes ownership.
|
|
|
|
|
-func (self *StateDB) CreateStateObject(addr common.Address) *StateObject {
|
|
|
|
|
- // Get previous (if any)
|
|
|
|
|
- so := self.GetStateObject(addr)
|
|
|
|
|
- // Create a new one
|
|
|
|
|
- newSo := self.newStateObject(addr)
|
|
|
|
|
-
|
|
|
|
|
- // If it existed set the balance to the new account
|
|
|
|
|
- if so != nil {
|
|
|
|
|
- newSo.data.Balance = so.data.Balance
|
|
|
|
|
|
|
+// createObject creates a new state object. If there is an existing account with
|
|
|
|
|
+// the given address, it is overwritten and returned as the second return value.
|
|
|
|
|
+func (self *StateDB) createObject(addr common.Address) (newobj, prev *StateObject) {
|
|
|
|
|
+ prev = self.GetStateObject(addr)
|
|
|
|
|
+ newobj = newObject(self, addr, Account{}, self.MarkStateObjectDirty)
|
|
|
|
|
+ newobj.setNonce(StartingNonce) // sets the object to dirty
|
|
|
|
|
+ if prev == nil {
|
|
|
|
|
+ if glog.V(logger.Core) {
|
|
|
|
|
+ glog.Infof("(+) %x\n", addr)
|
|
|
|
|
+ }
|
|
|
|
|
+ self.journal = append(self.journal, createObjectChange{account: &addr})
|
|
|
|
|
+ } else {
|
|
|
|
|
+ self.journal = append(self.journal, resetObjectChange{prev: prev})
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- return newSo
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-func (self *StateDB) CreateAccount(addr common.Address) vm.Account {
|
|
|
|
|
- return self.CreateStateObject(addr)
|
|
|
|
|
|
|
+ self.setStateObject(newobj)
|
|
|
|
|
+ return newobj, prev
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+// CreateAccount explicitly creates a state object. If a state object with the address
|
|
|
|
|
+// already exists the balance is carried over to the new account.
|
|
|
|
|
+//
|
|
|
|
|
+// CreateAccount is called during the EVM CREATE operation. The situation might arise that
|
|
|
|
|
+// a contract does the following:
|
|
|
//
|
|
//
|
|
|
-// Setting, copying of the state methods
|
|
|
|
|
|
|
+// 1. sends funds to sha(account ++ (nonce + 1))
|
|
|
|
|
+// 2. tx_create(sha(account ++ nonce)) (note that this gets the address of 1)
|
|
|
//
|
|
//
|
|
|
|
|
+// Carrying over the balance ensures that Ether doesn't disappear.
|
|
|
|
|
+func (self *StateDB) CreateAccount(addr common.Address) vm.Account {
|
|
|
|
|
+ new, prev := self.createObject(addr)
|
|
|
|
|
+ if prev != nil {
|
|
|
|
|
+ new.setBalance(prev.data.Balance)
|
|
|
|
|
+ }
|
|
|
|
|
+ return new
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
|
|
+// Copy creates a deep, independent copy of the state.
|
|
|
|
|
+// Snapshots of the copied state cannot be applied to the copy.
|
|
|
func (self *StateDB) Copy() *StateDB {
|
|
func (self *StateDB) Copy() *StateDB {
|
|
|
self.lock.Lock()
|
|
self.lock.Lock()
|
|
|
defer self.lock.Unlock()
|
|
defer self.lock.Unlock()
|
|
@@ -434,7 +464,7 @@ func (self *StateDB) Copy() *StateDB {
|
|
|
}
|
|
}
|
|
|
// Copy the dirty states and logs
|
|
// Copy the dirty states and logs
|
|
|
for addr, _ := range self.stateObjectsDirty {
|
|
for addr, _ := range self.stateObjectsDirty {
|
|
|
- state.stateObjects[addr] = self.stateObjects[addr].Copy(self.db, state.MarkStateObjectDirty)
|
|
|
|
|
|
|
+ state.stateObjects[addr] = self.stateObjects[addr].deepCopy(state, state.MarkStateObjectDirty)
|
|
|
state.stateObjectsDirty[addr] = struct{}{}
|
|
state.stateObjectsDirty[addr] = struct{}{}
|
|
|
}
|
|
}
|
|
|
for hash, logs := range self.logs {
|
|
for hash, logs := range self.logs {
|
|
@@ -444,21 +474,38 @@ func (self *StateDB) Copy() *StateDB {
|
|
|
return state
|
|
return state
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-func (self *StateDB) Set(state *StateDB) {
|
|
|
|
|
- self.lock.Lock()
|
|
|
|
|
- defer self.lock.Unlock()
|
|
|
|
|
|
|
+// Snapshot returns an identifier for the current revision of the state.
|
|
|
|
|
+func (self *StateDB) Snapshot() int {
|
|
|
|
|
+ id := self.nextRevisionId
|
|
|
|
|
+ self.nextRevisionId++
|
|
|
|
|
+ self.validRevisions = append(self.validRevisions, revision{id, len(self.journal)})
|
|
|
|
|
+ return id
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// RevertToSnapshot reverts all state changes made since the given revision.
|
|
|
|
|
+func (self *StateDB) RevertToSnapshot(revid int) {
|
|
|
|
|
+ // Find the snapshot in the stack of valid snapshots.
|
|
|
|
|
+ idx := sort.Search(len(self.validRevisions), func(i int) bool {
|
|
|
|
|
+ return self.validRevisions[i].id >= revid
|
|
|
|
|
+ })
|
|
|
|
|
+ if idx == len(self.validRevisions) || self.validRevisions[idx].id != revid {
|
|
|
|
|
+ panic(fmt.Errorf("revision id %v cannot be reverted", revid))
|
|
|
|
|
+ }
|
|
|
|
|
+ snapshot := self.validRevisions[idx].journalIndex
|
|
|
|
|
+
|
|
|
|
|
+ // Replay the journal to undo changes.
|
|
|
|
|
+ for i := len(self.journal) - 1; i >= snapshot; i-- {
|
|
|
|
|
+ self.journal[i].undo(self)
|
|
|
|
|
+ }
|
|
|
|
|
+ self.journal = self.journal[:snapshot]
|
|
|
|
|
|
|
|
- self.db = state.db
|
|
|
|
|
- self.trie = state.trie
|
|
|
|
|
- self.pastTries = state.pastTries
|
|
|
|
|
- self.stateObjects = state.stateObjects
|
|
|
|
|
- self.stateObjectsDirty = state.stateObjectsDirty
|
|
|
|
|
- self.codeSizeCache = state.codeSizeCache
|
|
|
|
|
- self.refund = state.refund
|
|
|
|
|
- self.logs = state.logs
|
|
|
|
|
- self.logSize = state.logSize
|
|
|
|
|
|
|
+ // Remove invalidated snapshots from the stack.
|
|
|
|
|
+ self.validRevisions = self.validRevisions[:idx]
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+// GetRefund returns the current value of the refund counter.
|
|
|
|
|
+// The return value must not be modified by the caller and will become
|
|
|
|
|
+// invalid at the next call to AddRefund.
|
|
|
func (self *StateDB) GetRefund() *big.Int {
|
|
func (self *StateDB) GetRefund() *big.Int {
|
|
|
return self.refund
|
|
return self.refund
|
|
|
}
|
|
}
|
|
@@ -467,16 +514,17 @@ func (self *StateDB) GetRefund() *big.Int {
|
|
|
// It is called in between transactions to get the root hash that
|
|
// It is called in between transactions to get the root hash that
|
|
|
// goes into transaction receipts.
|
|
// goes into transaction receipts.
|
|
|
func (s *StateDB) IntermediateRoot() common.Hash {
|
|
func (s *StateDB) IntermediateRoot() common.Hash {
|
|
|
- s.refund = new(big.Int)
|
|
|
|
|
for addr, _ := range s.stateObjectsDirty {
|
|
for addr, _ := range s.stateObjectsDirty {
|
|
|
stateObject := s.stateObjects[addr]
|
|
stateObject := s.stateObjects[addr]
|
|
|
if stateObject.remove {
|
|
if stateObject.remove {
|
|
|
- s.DeleteStateObject(stateObject)
|
|
|
|
|
|
|
+ s.deleteStateObject(stateObject)
|
|
|
} else {
|
|
} else {
|
|
|
- stateObject.UpdateRoot(s.db)
|
|
|
|
|
- s.UpdateStateObject(stateObject)
|
|
|
|
|
|
|
+ stateObject.updateRoot(s.db)
|
|
|
|
|
+ s.updateStateObject(stateObject)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+ // Invalidate journal because reverting across transactions is not allowed.
|
|
|
|
|
+ s.clearJournalAndRefund()
|
|
|
return s.trie.Hash()
|
|
return s.trie.Hash()
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -486,9 +534,9 @@ func (s *StateDB) IntermediateRoot() common.Hash {
|
|
|
// DeleteSuicides should not be used for consensus related updates
|
|
// DeleteSuicides should not be used for consensus related updates
|
|
|
// under any circumstances.
|
|
// under any circumstances.
|
|
|
func (s *StateDB) DeleteSuicides() {
|
|
func (s *StateDB) DeleteSuicides() {
|
|
|
- // Reset refund so that any used-gas calculations can use
|
|
|
|
|
- // this method.
|
|
|
|
|
- s.refund = new(big.Int)
|
|
|
|
|
|
|
+ // Reset refund so that any used-gas calculations can use this method.
|
|
|
|
|
+ s.clearJournalAndRefund()
|
|
|
|
|
+
|
|
|
for addr, _ := range s.stateObjectsDirty {
|
|
for addr, _ := range s.stateObjectsDirty {
|
|
|
stateObject := s.stateObjects[addr]
|
|
stateObject := s.stateObjects[addr]
|
|
|
|
|
|
|
@@ -516,15 +564,21 @@ func (s *StateDB) CommitBatch() (root common.Hash, batch ethdb.Batch) {
|
|
|
return root, batch
|
|
return root, batch
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-func (s *StateDB) commit(dbw trie.DatabaseWriter) (root common.Hash, err error) {
|
|
|
|
|
|
|
+func (s *StateDB) clearJournalAndRefund() {
|
|
|
|
|
+ s.journal = nil
|
|
|
|
|
+ s.validRevisions = s.validRevisions[:0]
|
|
|
s.refund = new(big.Int)
|
|
s.refund = new(big.Int)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func (s *StateDB) commit(dbw trie.DatabaseWriter) (root common.Hash, err error) {
|
|
|
|
|
+ defer s.clearJournalAndRefund()
|
|
|
|
|
|
|
|
// Commit objects to the trie.
|
|
// Commit objects to the trie.
|
|
|
for addr, stateObject := range s.stateObjects {
|
|
for addr, stateObject := range s.stateObjects {
|
|
|
if stateObject.remove {
|
|
if stateObject.remove {
|
|
|
// If the object has been removed, don't bother syncing it
|
|
// If the object has been removed, don't bother syncing it
|
|
|
// and just mark it for deletion in the trie.
|
|
// and just mark it for deletion in the trie.
|
|
|
- s.DeleteStateObject(stateObject)
|
|
|
|
|
|
|
+ s.deleteStateObject(stateObject)
|
|
|
} else if _, ok := s.stateObjectsDirty[addr]; ok {
|
|
} else if _, ok := s.stateObjectsDirty[addr]; ok {
|
|
|
// Write any contract code associated with the state object
|
|
// Write any contract code associated with the state object
|
|
|
if stateObject.code != nil && stateObject.dirtyCode {
|
|
if stateObject.code != nil && stateObject.dirtyCode {
|
|
@@ -538,7 +592,7 @@ func (s *StateDB) commit(dbw trie.DatabaseWriter) (root common.Hash, err error)
|
|
|
return common.Hash{}, err
|
|
return common.Hash{}, err
|
|
|
}
|
|
}
|
|
|
// Update the object in the main account trie.
|
|
// Update the object in the main account trie.
|
|
|
- s.UpdateStateObject(stateObject)
|
|
|
|
|
|
|
+ s.updateStateObject(stateObject)
|
|
|
}
|
|
}
|
|
|
delete(s.stateObjectsDirty, addr)
|
|
delete(s.stateObjectsDirty, addr)
|
|
|
}
|
|
}
|
|
@@ -549,7 +603,3 @@ func (s *StateDB) commit(dbw trie.DatabaseWriter) (root common.Hash, err error)
|
|
|
}
|
|
}
|
|
|
return root, err
|
|
return root, err
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
-func (self *StateDB) Refunds() *big.Int {
|
|
|
|
|
- return self.refund
|
|
|
|
|
-}
|
|
|