From 8011fcd49f0bc0b3dba3c5f0f35867ff7e728c30 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Sat, 4 Jan 2020 13:56:26 +0100 Subject: [PATCH] core/state, trie: avoid unnecessary storage trie load+commit --- core/state/state_object.go | 18 ++++++++++++++---- core/state/statedb.go | 3 ++- trie/pure_committer.go | 6 ++++++ trie/trie.go | 6 ++++++ 4 files changed, 28 insertions(+), 5 deletions(-) diff --git a/core/state/state_object.go b/core/state/state_object.go index 8680de021f..2ab9d7ec46 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -272,10 +272,15 @@ func (s *stateObject) finalise() { } // updateTrie writes cached storage modifications into the object's storage trie. +// It will return nil if the trie has not been loaded and no changes have been made +// Note: It may return non-nil if the trie is already loaded due to previous changes +// in the same block func (s *stateObject) updateTrie(db Database) Trie { // Make sure all dirty slots are finalized into the pending storage area s.finalise() - + if len(s.pendingStorage) == 0{ + return s.trie + } // Track the amount of time wasted on updating the storge trie if metrics.EnabledExpensive { defer func(start time.Time) { s.db.StorageUpdates += time.Since(start) }(time.Now()) @@ -305,8 +310,10 @@ func (s *stateObject) updateTrie(db Database) Trie { // UpdateRoot sets the trie root to the current root hash of func (s *stateObject) updateRoot(db Database) { - s.updateTrie(db) - + if s.updateTrie(db) == nil{ + // No changes, storage trie is not even loaded + return + } // Track the amount of time wasted on hashing the storge trie if metrics.EnabledExpensive { defer func(start time.Time) { s.db.StorageHashes += time.Since(start) }(time.Now()) @@ -317,7 +324,10 @@ func (s *stateObject) updateRoot(db Database) { // CommitTrie the storage trie of the object to db. // This updates the trie root. func (s *stateObject) CommitTrie(db Database) error { - s.updateTrie(db) + if s.updateTrie(db) == nil{ + // No changes, storage trie is not even loaded + return nil + } if s.dbErr != nil { return s.dbErr } diff --git a/core/state/statedb.go b/core/state/statedb.go index 8399f1bab9..2ec0c3613d 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -330,7 +330,8 @@ func (s *StateDB) StorageTrie(addr common.Address) Trie { return nil } cpy := stateObject.deepCopy(s) - return cpy.updateTrie(s.db) + cpy.updateTrie(s.db) + return cpy.getTrie(s.db) } func (s *StateDB) HasSuicided(addr common.Address) bool { diff --git a/trie/pure_committer.go b/trie/pure_committer.go index 30404b217d..d74fc0d4c8 100644 --- a/trie/pure_committer.go +++ b/trie/pure_committer.go @@ -67,6 +67,12 @@ func returnCommitterToPool(h *committer) { committerPool.Put(h) } +// commitNeeded returns 'false' if the given node is already in sync with db +func (h *committer) commitNeeded(n node) bool { + hash, dirty := n.cache() + return hash == nil || dirty +} + // hash collapses a node down into a hash node, also returning a copy of the // original node initialized with the computed hash to replace the original one. func (h *committer) commit(n node, db *Database, force bool) (node, error) { diff --git a/trie/trie.go b/trie/trie.go index a5d09f292b..74666fbdda 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -441,6 +441,12 @@ func (t *Trie) Commit(onleaf LeafCallback) (root common.Hash, err error) { rootHash := t.Hash() h := newCommitter(onleaf) defer returnCommitterToPool(h) + // Do a quick check if we really need to commit, before we spin + // up goroutines. This can happen e.g. if we load a trie for reading storage + // values, but don't write to it. + if !h.commitNeeded(t.root) { + return rootHash, nil + } var wg sync.WaitGroup if onleaf != nil { wg.Add(1)