173 lines
5.3 KiB
Go
173 lines
5.3 KiB
Go
// Package trie implements Merkle Patricia Tries.
|
|
package trie
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/crypto"
|
|
|
|
"github.com/ethereum/go-ethereum/statediff/indexer/ipld"
|
|
)
|
|
|
|
var (
|
|
// emptyRoot is the known root hash of an empty trie.
|
|
emptyRoot = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
|
|
|
|
// emptyState is the known hash of an empty state trie entry.
|
|
emptyState = crypto.Keccak256Hash(nil)
|
|
)
|
|
|
|
// Trie is a Merkle Patricia Trie. Use New to create a trie that sits on
|
|
// top of a database. Whenever trie performs a commit operation, the generated
|
|
// nodes will be gathered and returned in a set. Once the trie is committed,
|
|
// it's not usable anymore. Callers have to re-create the trie with new root
|
|
// based on the updated trie database.
|
|
//
|
|
// Trie is not safe for concurrent use.
|
|
type Trie struct {
|
|
root node
|
|
owner common.Hash
|
|
|
|
// Keep track of the number leaves which have been inserted since the last
|
|
// hashing operation. This number will not directly map to the number of
|
|
// actually unhashed nodes.
|
|
unhashed int
|
|
|
|
// db is the handler trie can retrieve nodes from. It's
|
|
// only for reading purpose and not available for writing.
|
|
db *Database
|
|
|
|
// Multihash codec for key encoding
|
|
codec uint64
|
|
}
|
|
|
|
// New creates a trie with an existing root node from db and an assigned
|
|
// owner for storage proximity.
|
|
//
|
|
// If root is the zero hash or the sha3 hash of an empty string, the
|
|
// trie is initially empty and does not require a database. Otherwise,
|
|
// New will panic if db is nil and returns a MissingNodeError if root does
|
|
// not exist in the database. Accessing the trie loads nodes from db on demand.
|
|
func New(owner common.Hash, root common.Hash, db *Database, codec uint64) (*Trie, error) {
|
|
trie := &Trie{
|
|
owner: owner,
|
|
db: db,
|
|
codec: codec,
|
|
}
|
|
if root != (common.Hash{}) && root != emptyRoot {
|
|
rootnode, err := trie.resolveHash(root[:], nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
trie.root = rootnode
|
|
}
|
|
return trie, nil
|
|
}
|
|
|
|
// NewEmpty is a shortcut to create empty tree. It's mostly used in tests.
|
|
func NewEmpty(db *Database) *Trie {
|
|
tr, _ := New(common.Hash{}, common.Hash{}, db, ipld.MEthStateTrie)
|
|
return tr
|
|
}
|
|
|
|
// NodeIterator returns an iterator that returns nodes of the trie. Iteration starts at
|
|
// the key after the given start key.
|
|
func (t *Trie) NodeIterator(start []byte) NodeIterator {
|
|
return newNodeIterator(t, start)
|
|
}
|
|
|
|
// TryGet returns the value for key stored in the trie.
|
|
// The value bytes must not be modified by the caller.
|
|
// If a node was not found in the database, a MissingNodeError is returned.
|
|
func (t *Trie) TryGet(key []byte) ([]byte, error) {
|
|
value, newroot, didResolve, err := t.tryGet(t.root, keybytesToHex(key), 0)
|
|
if err == nil && didResolve {
|
|
t.root = newroot
|
|
}
|
|
return value, err
|
|
}
|
|
|
|
func (t *Trie) tryGet(origNode node, key []byte, pos int) (value []byte, newnode node, didResolve bool, err error) {
|
|
switch n := (origNode).(type) {
|
|
case nil:
|
|
return nil, nil, false, nil
|
|
case valueNode:
|
|
return n, n, false, nil
|
|
case *shortNode:
|
|
if len(key)-pos < len(n.Key) || !bytes.Equal(n.Key, key[pos:pos+len(n.Key)]) {
|
|
// key not found in trie
|
|
return nil, n, false, nil
|
|
}
|
|
value, newnode, didResolve, err = t.tryGet(n.Val, key, pos+len(n.Key))
|
|
if err == nil && didResolve {
|
|
n = n.copy()
|
|
n.Val = newnode
|
|
}
|
|
return value, n, didResolve, err
|
|
case *fullNode:
|
|
value, newnode, didResolve, err = t.tryGet(n.Children[key[pos]], key, pos+1)
|
|
if err == nil && didResolve {
|
|
n = n.copy()
|
|
n.Children[key[pos]] = newnode
|
|
}
|
|
return value, n, didResolve, err
|
|
case hashNode:
|
|
child, err := t.resolveHash(n, key[:pos])
|
|
if err != nil {
|
|
return nil, n, true, err
|
|
}
|
|
value, newnode, _, err := t.tryGet(child, key, pos)
|
|
return value, newnode, true, err
|
|
default:
|
|
panic(fmt.Sprintf("%T: invalid node: %v", origNode, origNode))
|
|
}
|
|
}
|
|
|
|
// resolveHash loads node from the underlying database with the provided
|
|
// node hash and path prefix.
|
|
func (t *Trie) resolveHash(n hashNode, prefix []byte) (node, error) {
|
|
cid := ipld.Keccak256ToCid(t.codec, n)
|
|
node, err := t.db.node(cid.Bytes())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if node != nil {
|
|
return node, nil
|
|
}
|
|
return nil, &MissingNodeError{Owner: t.owner, NodeHash: n, Path: prefix}
|
|
}
|
|
|
|
// resolveHash loads rlp-encoded node blob from the underlying database
|
|
// with the provided node hash and path prefix.
|
|
func (t *Trie) resolveBlob(n hashNode, prefix []byte) ([]byte, error) {
|
|
cid := ipld.Keccak256ToCid(t.codec, n)
|
|
blob, _ := t.db.Node(cid.Bytes())
|
|
if len(blob) != 0 {
|
|
return blob, nil
|
|
}
|
|
return nil, &MissingNodeError{Owner: t.owner, NodeHash: n, Path: prefix}
|
|
}
|
|
|
|
// Hash returns the root hash of the trie. It does not write to the
|
|
// database and can be used even if the trie doesn't have one.
|
|
func (t *Trie) Hash() common.Hash {
|
|
hash, cached, _ := t.hashRoot()
|
|
t.root = cached
|
|
return common.BytesToHash(hash.(hashNode))
|
|
}
|
|
|
|
// hashRoot calculates the root hash of the given trie
|
|
func (t *Trie) hashRoot() (node, node, error) {
|
|
if t.root == nil {
|
|
return hashNode(emptyRoot.Bytes()), nil, nil
|
|
}
|
|
// If the number of changes is below 100, we let one thread handle it
|
|
h := newHasher(t.unhashed >= 100)
|
|
defer returnHasherToPool(h)
|
|
hashed, cached := h.hash(t.root, true)
|
|
t.unhashed = 0
|
|
return hashed, cached, nil
|
|
}
|