diff --git a/tests/testdata b/tests/testdata index b5eb9900ee..25f480521d 160000 --- a/tests/testdata +++ b/tests/testdata @@ -1 +1 @@ -Subproject commit b5eb9900ee2147b40d3e681fe86efa4fd693959a +Subproject commit 25f480521dae1937841bbcb034e862c4dfd53256 diff --git a/trie/hasher.go b/trie/hasher.go index 649705ada8..816a29857c 100644 --- a/trie/hasher.go +++ b/trie/hasher.go @@ -25,10 +25,17 @@ import ( "golang.org/x/crypto/sha3" ) +type Leaf struct { + size int + hash common.Hash + node node +} + type hasher struct { tmp sliceBuffer sha keccakState onleaf LeafCallback + leafCh chan *Leaf } // keccakState wraps sha3.state. In addition to the usual hash methods, it also supports @@ -178,16 +185,37 @@ func (h *hasher) store(n node, db *Database, force bool) (node, error) { if hash == nil { hash = h.makeHashNode(h.tmp) } - if db != nil { + h.leafCh <- &Leaf{ + size: len(h.tmp), + hash: common.BytesToHash(hash), + node: n, + } + } + return hash, nil +} + +func (h *hasher) makeHashNode(data []byte) hashNode { + n := make(hashNode, h.sha.Size()) + h.sha.Reset() + h.sha.Write(data) + h.sha.Read(n) + return n +} + +// commitLoop does the actual insert + leaf callback for nodes +func (h *hasher) commitLoop(db *Database, wg *sync.WaitGroup) { + defer wg.Done() + for item := range h.leafCh { + var ( + hash = item.hash + size = item.size + n = item.node + ) // We are pooling the trie nodes into an intermediate memory cache - hash := common.BytesToHash(hash) - db.lock.Lock() - db.insert(hash, len(h.tmp), n) + db.insert(hash, size, n) db.lock.Unlock() - - // Track external references from account->storage trie if h.onleaf != nil { switch n := n.(type) { case *shortNode: @@ -203,13 +231,4 @@ func (h *hasher) store(n node, db *Database, force bool) (node, error) { } } } - return hash, nil -} - -func (h *hasher) makeHashNode(data []byte) hashNode { - n := make(hashNode, h.sha.Size()) - h.sha.Reset() - h.sha.Write(data) - h.sha.Read(n) - return n } diff --git a/trie/trie.go b/trie/trie.go index 920e331fd6..9efc8657a3 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -20,6 +20,7 @@ package trie import ( "bytes" "fmt" + "sync" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" @@ -415,7 +416,18 @@ func (t *Trie) Commit(onleaf LeafCallback) (root common.Hash, err error) { if t.db == nil { panic("commit called on trie with nil database") } - hash, cached, err := t.hashRoot(t.db, onleaf) + if t.root == nil { + return emptyRoot, nil + } + h := newHasher(onleaf) + h.leafCh = make(chan *Leaf, 200) // arbitrary number + defer returnHasherToPool(h) + var wg sync.WaitGroup + wg.Add(1) + go h.commitLoop(t.db, &wg) + hash, cached, err := h.hash(t.root, t.db, true) + close(h.leafCh) + wg.Wait() if err != nil { return common.Hash{}, err } @@ -431,3 +443,4 @@ func (t *Trie) hashRoot(db *Database, onleaf LeafCallback) (node, node, error) { defer returnHasherToPool(h) return h.hash(t.root, db, true) } +