diff --git a/trie/database.go b/trie/database.go index b0fd787444..6f4c379689 100644 --- a/trie/database.go +++ b/trie/database.go @@ -314,24 +314,24 @@ func (db *Database) InsertBlob(hash common.Hash, blob []byte) { db.lock.Lock() defer db.lock.Unlock() - db.insert(hash, blob, rawNode(blob)) + db.insert(hash, len(blob), rawNode(blob)) } // insert inserts a collapsed trie node into the memory database. This method is // a more generic version of InsertBlob, supporting both raw blob insertions as -// well ex trie node insertions. The blob must always be specified to allow proper +// well ex trie node insertions. The blob size must be specified to allow proper // size tracking. -func (db *Database) insert(hash common.Hash, blob []byte, node node) { +func (db *Database) insert(hash common.Hash, size int, node node) { // If the node's already cached, skip if _, ok := db.dirties[hash]; ok { return } - memcacheDirtyWriteMeter.Mark(int64(len(blob))) + memcacheDirtyWriteMeter.Mark(int64(size)) // Create the cached entry for this node entry := &cachedNode{ node: simplifyNode(node), - size: uint16(len(blob)), + size: uint16(size), flushPrev: db.newest, } for _, child := range entry.childs() { diff --git a/trie/hasher.go b/trie/hasher.go index 54f6a9de2b..649705ada8 100644 --- a/trie/hasher.go +++ b/trie/hasher.go @@ -184,7 +184,7 @@ func (h *hasher) store(n node, db *Database, force bool) (node, error) { hash := common.BytesToHash(hash) db.lock.Lock() - db.insert(hash, h.tmp, n) + db.insert(hash, len(h.tmp), n) db.lock.Unlock() // Track external references from account->storage trie diff --git a/trie/trie_test.go b/trie/trie_test.go index 5286c490ca..08a3740810 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -512,14 +512,34 @@ func BenchmarkHash(b *testing.B) { trie.Hash() } +type account struct { + Nonce uint64 + Balance *big.Int + Root common.Hash + Code []byte +} + // Benchmarks the trie Commit following a Hash. Since the trie caches the result of any operation, // we cannot use b.N as the number of hashing rouns, since all rounds apart from // the first one will be NOOP. As such, we'll use b.N as the number of account to // insert into the trie before measuring the hashing. func BenchmarkCommitAfterHash(b *testing.B) { + b.Run("no-onleaf", func(b *testing.B) { + benchmarkCommitAfterHash(b, nil) + }) + onleaf := func(leaf []byte, parent common.Hash) error { + var a account + rlp.DecodeBytes(leaf, &a) + return nil + } + b.Run("with-onleaf", func(b *testing.B) { + benchmarkCommitAfterHash(b, onleaf) + }) +} + +func benchmarkCommitAfterHash(b *testing.B, onleaf LeafCallback) { // Make the random benchmark deterministic random := rand.New(rand.NewSource(0)) - // Create a realistic account trie to hash addresses := make([][20]byte, b.N) for i := 0; i < len(addresses); i++ { @@ -535,17 +555,17 @@ func BenchmarkCommitAfterHash(b *testing.B) { root = emptyRoot code = crypto.Keccak256(nil) ) - accounts[i], _ = rlp.EncodeToBytes([]interface{}{nonce, balance, root, code}) + accounts[i], _ = rlp.EncodeToBytes(&account{nonce, balance, root, code}) } - // Insert the accounts into the trie and hash it trie := newEmpty() for i := 0; i < len(addresses); i++ { trie.Update(crypto.Keccak256(addresses[i][:]), accounts[i]) } + // Insert the accounts into the trie and hash it trie.Hash() b.ResetTimer() b.ReportAllocs() - trie.Commit(nil) + trie.Commit(onleaf) } func tempDB() (string, *Database) {