From bab696378c359c56640fae48dfd3132763dbc64b Mon Sep 17 00:00:00 2001 From: Vadim Macagon Date: Tue, 2 Oct 2018 18:04:52 +0700 Subject: [PATCH] Force stateObject to update storage trie deterministically --- core/state/state_object.go | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/core/state/state_object.go b/core/state/state_object.go index f41ab04092..b120ea7018 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -77,8 +77,9 @@ type stateObject struct { trie Trie // storage trie, which becomes non-nil on first access code Code // contract bytecode, which gets set when code is loaded - originStorage Storage // Storage cache of original entries to dedup rewrites - dirtyStorage Storage // Storage entries that need to be flushed to disk + originStorage Storage // Storage cache of original entries to dedup rewrites + dirtyStorage Storage // Storage entries that need to be flushed to disk + dirtyStorageKeys []common.Hash // Dirty storage keys in order of insertion into dirtyStorage // Cache flags. // When an object is marked suicided it will be delete from the trie @@ -111,12 +112,13 @@ func newObject(db *StateDB, address common.Address, data Account) *stateObject { data.CodeHash = emptyCodeHash } return &stateObject{ - db: db, - address: address, - addrHash: crypto.Keccak256Hash(address[:]), - data: data, - originStorage: make(Storage), - dirtyStorage: make(Storage), + db: db, + address: address, + addrHash: crypto.Keccak256Hash(address[:]), + data: data, + originStorage: make(Storage), + dirtyStorage: make(Storage), + dirtyStorageKeys: nil, } } @@ -212,12 +214,21 @@ func (self *stateObject) SetState(db Database, key, value common.Hash) { func (self *stateObject) setState(key, value common.Hash) { self.dirtyStorage[key] = value + for _, k := range self.dirtyStorageKeys { + if k == key { + return + } + } + self.dirtyStorageKeys = append(self.dirtyStorageKeys, key) } // updateTrie writes cached storage modifications into the object's storage trie. func (self *stateObject) updateTrie(db Database) Trie { tr := self.getTrie(db) - for key, value := range self.dirtyStorage { + // Iterate through the storage keys in deterministic order to ensure the storage trie is + // identical across machines + for _, key := range self.dirtyStorageKeys { + value := self.dirtyStorage[key] delete(self.dirtyStorage, key) // Skip noop changes, persist actual changes @@ -303,6 +314,7 @@ func (self *stateObject) deepCopy(db *StateDB) *stateObject { } stateObject.code = self.code stateObject.dirtyStorage = self.dirtyStorage.Copy() + stateObject.dirtyStorageKeys = append([]common.Hash{}, self.dirtyStorageKeys...) stateObject.originStorage = self.originStorage.Copy() stateObject.suicided = self.suicided stateObject.dirtyCode = self.dirtyCode