mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-18 10:50:44 +00:00
Merge f674fdc18f into dddbaa4bf3
This commit is contained in:
commit
d6f37a3363
8 changed files with 44 additions and 13 deletions
|
|
@ -149,8 +149,18 @@ func (c *committer) store(path []byte, n node) node {
|
|||
return n
|
||||
}
|
||||
// Collect the dirty node to nodeset for return.
|
||||
var blob []byte
|
||||
switch n := n.(type) {
|
||||
case *shortNode:
|
||||
blob = n.flags.blob
|
||||
case *fullNode:
|
||||
blob = n.flags.blob
|
||||
}
|
||||
if len(blob) == 0 {
|
||||
blob = nodeToBytes(n)
|
||||
}
|
||||
nhash := common.BytesToHash(hash)
|
||||
c.nodes.AddNode(path, trienode.NewNodeWithPrev(nhash, nodeToBytes(n), c.tracer.Get(path)))
|
||||
c.nodes.AddNode(path, trienode.NewNodeWithPrev(nhash, blob, c.tracer.Get(path)))
|
||||
|
||||
// Collect the corresponding leaf node if it's required. We don't check
|
||||
// full node since it's impossible to store value in fullNode. The key
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import (
|
|||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
)
|
||||
|
|
@ -28,10 +29,11 @@ import (
|
|||
// hasher is a type used for the trie Hash operation. A hasher has some
|
||||
// internal preallocated temp space
|
||||
type hasher struct {
|
||||
sha crypto.KeccakState
|
||||
tmp []byte
|
||||
encbuf rlp.EncoderBuffer
|
||||
parallel bool // Whether to use parallel threads when hashing
|
||||
sha crypto.KeccakState
|
||||
tmp []byte
|
||||
encbuf rlp.EncoderBuffer
|
||||
parallel bool // Whether to use parallel threads when hashing
|
||||
cacheBlob bool // Whether to stash each node's encoding for the committer
|
||||
}
|
||||
|
||||
// hasherPool holds pureHashers
|
||||
|
|
@ -45,9 +47,10 @@ var hasherPool = sync.Pool{
|
|||
},
|
||||
}
|
||||
|
||||
func newHasher(parallel bool) *hasher {
|
||||
func newHasher(parallel, cacheBlob bool) *hasher {
|
||||
h := hasherPool.Get().(*hasher)
|
||||
h.parallel = parallel
|
||||
h.cacheBlob = cacheBlob
|
||||
return h
|
||||
}
|
||||
|
||||
|
|
@ -76,6 +79,9 @@ func (h *hasher) hash(n node, force bool) []byte {
|
|||
}
|
||||
hash := h.hashData(enc)
|
||||
n.flags.hash = hash
|
||||
if h.cacheBlob {
|
||||
n.flags.blob = common.CopyBytes(enc)
|
||||
}
|
||||
return hash
|
||||
|
||||
case *fullNode:
|
||||
|
|
@ -91,6 +97,9 @@ func (h *hasher) hash(n node, force bool) []byte {
|
|||
}
|
||||
hash := h.hashData(enc)
|
||||
n.flags.hash = hash
|
||||
if h.cacheBlob {
|
||||
n.flags.blob = common.CopyBytes(enc)
|
||||
}
|
||||
return hash
|
||||
|
||||
case hashNode:
|
||||
|
|
@ -148,9 +157,9 @@ func (h *hasher) encodeFullNode(n *fullNode) []byte {
|
|||
go func(i int) {
|
||||
defer wg.Done()
|
||||
|
||||
h := newHasher(false)
|
||||
fn.Children[i] = h.hash(n.Children[i], false)
|
||||
returnHasherToPool(h)
|
||||
h2 := newHasher(false, h.cacheBlob)
|
||||
fn.Children[i] = h2.hash(n.Children[i], false)
|
||||
returnHasherToPool(h2)
|
||||
}(i)
|
||||
}
|
||||
wg.Wait()
|
||||
|
|
|
|||
|
|
@ -234,7 +234,7 @@ func (it *nodeIterator) LeafBlob() []byte {
|
|||
func (it *nodeIterator) LeafProof() [][]byte {
|
||||
if len(it.stack) > 0 {
|
||||
if _, ok := it.stack[len(it.stack)-1].node.(valueNode); ok {
|
||||
hasher := newHasher(false)
|
||||
hasher := newHasher(false, false)
|
||||
defer returnHasherToPool(hasher)
|
||||
proofs := make([][]byte, 0, len(it.stack))
|
||||
|
||||
|
|
|
|||
|
|
@ -80,12 +80,14 @@ func (n *fullNode) EncodeRLP(w io.Writer) error {
|
|||
// nodeFlag contains caching-related metadata about a node.
|
||||
type nodeFlag struct {
|
||||
hash hashNode // cached hash of the node (may be nil)
|
||||
blob []byte // cached rlp encoding of the node, set along with the hash (may be nil)
|
||||
dirty bool // whether the node has changes that must be written to the database
|
||||
}
|
||||
|
||||
func (n nodeFlag) copy() nodeFlag {
|
||||
return nodeFlag{
|
||||
hash: common.CopyBytes(n.hash),
|
||||
blob: common.CopyBytes(n.blob),
|
||||
dirty: n.dirty,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ func (t *Trie) Prove(key []byte, proofDb ethdb.KeyValueWriter) error {
|
|||
panic(fmt.Sprintf("%T: invalid node: %v", tn, tn))
|
||||
}
|
||||
}
|
||||
hasher := newHasher(false)
|
||||
hasher := newHasher(false, false)
|
||||
defer returnHasherToPool(hasher)
|
||||
|
||||
for i, n := range nodes {
|
||||
|
|
|
|||
|
|
@ -83,6 +83,10 @@ func NewStateTrie(id *ID, db database.NodeDatabase) (*StateTrie, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// State tries always follow a hash-then-commit lifecycle, so cache the node
|
||||
// encodings produced during hashing for reuse by the subsequent commit.
|
||||
trie.cacheBlob = true
|
||||
|
||||
tr := &StateTrie{
|
||||
trie: *trie,
|
||||
db: db,
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ type StackTrie struct {
|
|||
func NewStackTrie(onTrieNode OnTrieNode) *StackTrie {
|
||||
return &StackTrie{
|
||||
root: stPool.Get().(*stNode),
|
||||
h: newHasher(false),
|
||||
h: newHasher(false, false),
|
||||
onTrieNode: onTrieNode,
|
||||
kBuf: make([]byte, 64),
|
||||
pBuf: make([]byte, 64),
|
||||
|
|
|
|||
|
|
@ -54,6 +54,11 @@ type Trie struct {
|
|||
// uncommitted is the number of updates since last commit.
|
||||
uncommitted int
|
||||
|
||||
// cacheBlob makes the hasher cache encoded trie nodes.
|
||||
// Saves re-encoding on commit. Can be turned off for
|
||||
// Trie's that are never committed (e.g. for snap sync).
|
||||
cacheBlob bool
|
||||
|
||||
// reader is the handler trie can retrieve nodes from.
|
||||
reader *Reader
|
||||
|
||||
|
|
@ -75,6 +80,7 @@ func (t *Trie) Copy() *Trie {
|
|||
committed: t.committed,
|
||||
unhashed: t.unhashed,
|
||||
uncommitted: t.uncommitted,
|
||||
cacheBlob: t.cacheBlob,
|
||||
reader: t.reader,
|
||||
opTracer: t.opTracer.copy(),
|
||||
prevalueTracer: t.prevalueTracer.Copy(),
|
||||
|
|
@ -860,7 +866,7 @@ func (t *Trie) hashRoot() []byte {
|
|||
return types.EmptyRootHash.Bytes()
|
||||
}
|
||||
// If the number of changes is below 100, we let one thread handle it
|
||||
h := newHasher(t.unhashed >= 100)
|
||||
h := newHasher(t.unhashed >= 100, t.cacheBlob)
|
||||
defer func() {
|
||||
returnHasherToPool(h)
|
||||
t.unhashed = 0
|
||||
|
|
|
|||
Loading…
Reference in a new issue