// Package trie implements Merkle Patricia Tries. package trie import ( "bytes" "errors" "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)) } } // TryGetNode attempts to retrieve a trie node by compact-encoded path. It is not // possible to use keybyte-encoding as the path might contain odd nibbles. func (t *Trie) TryGetNode(path []byte) ([]byte, int, error) { item, newroot, resolved, err := t.tryGetNode(t.root, CompactToHex(path), 0) if err != nil { return nil, resolved, err } if resolved > 0 { t.root = newroot } if item == nil { return nil, resolved, nil } return item, resolved, err } func (t *Trie) tryGetNode(origNode node, path []byte, pos int) (item []byte, newnode node, resolved int, err error) { // If non-existent path requested, abort if origNode == nil { return nil, nil, 0, nil } // If we reached the requested path, return the current node if pos >= len(path) { // Although we most probably have the original node expanded, encoding // that into consensus form can be nasty (needs to cascade down) and // time consuming. Instead, just pull the hash up from disk directly. var hash hashNode if node, ok := origNode.(hashNode); ok { hash = node } else { hash, _ = origNode.cache() } if hash == nil { return nil, origNode, 0, errors.New("non-consensus node") } blob, err := t.db.Node(hash) return blob, origNode, 1, err } // Path still needs to be traversed, descend into children switch n := (origNode).(type) { case valueNode: // Path prematurely ended, abort return nil, nil, 0, nil case *shortNode: if len(path)-pos < len(n.Key) || !bytes.Equal(n.Key, path[pos:pos+len(n.Key)]) { // Path branches off from short node return nil, n, 0, nil } item, newnode, resolved, err = t.tryGetNode(n.Val, path, pos+len(n.Key)) if err == nil && resolved > 0 { n = n.copy() n.Val = newnode } return item, n, resolved, err case *fullNode: item, newnode, resolved, err = t.tryGetNode(n.Children[path[pos]], path, pos+1) if err == nil && resolved > 0 { n = n.copy() n.Children[path[pos]] = newnode } return item, n, resolved, err case hashNode: child, err := t.resolveHash(n, path[:pos]) if err != nil { return nil, n, 1, err } item, newnode, resolved, err := t.tryGetNode(child, path, pos) return item, newnode, resolved + 1, 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 }