diff --git a/core/state/state_object.go b/core/state/state_object.go index 97d9cd4ebb..8902dcbe3c 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -21,6 +21,7 @@ import ( "fmt" "io" "math/big" + "sync" "time" "github.com/ethereum/go-ethereum/common" @@ -73,6 +74,7 @@ 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 + storageMutex sync.Mutex originStorage Storage // Storage cache of original entries to dedup rewrites pendingStorage Storage // Storage entries that need to be flushed to disk, at the end of an entire block dirtyStorage Storage // Storage entries that have been modified in the current transaction execution, reset for every transaction @@ -176,13 +178,18 @@ func (s *stateObject) GetState(key common.Hash) common.Hash { // GetCommittedState retrieves a value from the committed account storage trie. func (s *stateObject) GetCommittedState(key common.Hash) common.Hash { // If we have a pending write or clean cached, return that + s.storageMutex.Lock() if value, pending := s.pendingStorage[key]; pending { + s.storageMutex.Unlock() return value } + s.storageMutex.Lock() if value, cached := s.originStorage[key]; cached { + s.storageMutex.Unlock() return value } + // If the object was destructed in *this* block (and potentially resurrected), // the storage has been cleared out, and we should *not* consult the previous // database about any storage values. The only possible alternatives are: @@ -234,7 +241,9 @@ func (s *stateObject) GetCommittedState(key common.Hash) common.Hash { value.SetBytes(val) } + s.storageMutex.Lock() s.originStorage[key] = value + s.storageMutex.Unlock() return value }