mirror of
https://gitlab.com/pulsechaincom/erigon-pulse.git
synced 2024-12-22 19:50:36 +00:00
de60e03f03
Added trie findpath to support bor receipt format. This requires testing against the polygon deployed contracts to confirm parent path format
1232 lines
32 KiB
Go
1232 lines
32 KiB
Go
// Copyright 2019 The go-ethereum Authors
|
|
// This file is part of the go-ethereum library.
|
|
//
|
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Lesser General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty off
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Lesser General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Lesser General Public License
|
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
// Package trie implements Merkle Patricia Tries.
|
|
package trie
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"fmt"
|
|
|
|
libcommon "github.com/ledgerwatch/erigon-lib/common"
|
|
"github.com/ledgerwatch/erigon-lib/common/cmp"
|
|
|
|
"github.com/ledgerwatch/erigon/core/types/accounts"
|
|
"github.com/ledgerwatch/erigon/crypto"
|
|
"github.com/ledgerwatch/erigon/ethdb"
|
|
)
|
|
|
|
var (
|
|
// EmptyRoot is the known root hash of an empty trie.
|
|
// DESCRIBED: docs/programmers_guide/guide.md#root
|
|
EmptyRoot = libcommon.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
|
|
|
|
// emptyState is the known hash of an empty state trie entry.
|
|
emptyState = crypto.Keccak256Hash(nil)
|
|
)
|
|
|
|
// Trie is a Merkle Patricia Trie.
|
|
// The zero value is an empty trie with no database.
|
|
// Use New to create a trie that sits on top of a database.
|
|
//
|
|
// Trie is not safe for concurrent use.
|
|
// Deprecated
|
|
// use package turbo/trie
|
|
type Trie struct {
|
|
root node
|
|
valueNodesRLPEncoded bool
|
|
|
|
newHasherFunc func() *hasher
|
|
}
|
|
|
|
// New creates a trie with an existing root node from db.
|
|
//
|
|
// 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.
|
|
// Deprecated
|
|
// use package turbo/trie
|
|
func New(root libcommon.Hash) *Trie {
|
|
trie := &Trie{
|
|
newHasherFunc: func() *hasher { return newHasher( /*valueNodesRlpEncoded = */ false) },
|
|
}
|
|
if (root != libcommon.Hash{}) && root != EmptyRoot {
|
|
trie.root = hashNode{hash: root[:]}
|
|
}
|
|
return trie
|
|
}
|
|
|
|
// NewTestRLPTrie treats all the data provided to `Update` function as rlp-encoded.
|
|
// it is usually used for testing purposes.
|
|
func NewTestRLPTrie(root libcommon.Hash) *Trie {
|
|
trie := &Trie{
|
|
valueNodesRLPEncoded: true,
|
|
newHasherFunc: func() *hasher { return newHasher( /*valueNodesRlpEncoded = */ true) },
|
|
}
|
|
if (root != libcommon.Hash{}) && root != EmptyRoot {
|
|
trie.root = hashNode{hash: root[:]}
|
|
}
|
|
return trie
|
|
}
|
|
|
|
// Get returns the value for key stored in the trie.
|
|
func (t *Trie) Get(key []byte) (value []byte, gotValue bool) {
|
|
if t.root == nil {
|
|
return nil, true
|
|
}
|
|
|
|
hex := keybytesToHex(key)
|
|
return t.get(t.root, hex, 0)
|
|
}
|
|
|
|
func (t *Trie) FindPath(key []byte) (value []byte, parents [][]byte, gotValue bool) {
|
|
if t.root == nil {
|
|
return nil, nil, true
|
|
}
|
|
|
|
hex := keybytesToHex(key)
|
|
return t.getPath(t.root, nil, hex, 0)
|
|
}
|
|
|
|
func (t *Trie) GetAccount(key []byte) (value *accounts.Account, gotValue bool) {
|
|
if t.root == nil {
|
|
return nil, true
|
|
}
|
|
|
|
hex := keybytesToHex(key)
|
|
|
|
accNode, gotValue := t.getAccount(t.root, hex, 0)
|
|
if accNode != nil {
|
|
var value accounts.Account
|
|
value.Copy(&accNode.Account)
|
|
return &value, gotValue
|
|
}
|
|
return nil, gotValue
|
|
}
|
|
|
|
func (t *Trie) GetAccountCode(key []byte) (value []byte, gotValue bool) {
|
|
if t.root == nil {
|
|
return nil, false
|
|
}
|
|
|
|
hex := keybytesToHex(key)
|
|
|
|
accNode, gotValue := t.getAccount(t.root, hex, 0)
|
|
if accNode != nil {
|
|
if bytes.Equal(accNode.Account.CodeHash[:], EmptyCodeHash[:]) {
|
|
return nil, gotValue
|
|
}
|
|
|
|
if accNode.code == nil {
|
|
return nil, false
|
|
}
|
|
|
|
return accNode.code, gotValue
|
|
}
|
|
return nil, gotValue
|
|
}
|
|
|
|
func (t *Trie) GetAccountCodeSize(key []byte) (value int, gotValue bool) {
|
|
if t.root == nil {
|
|
return 0, false
|
|
}
|
|
|
|
hex := keybytesToHex(key)
|
|
|
|
accNode, gotValue := t.getAccount(t.root, hex, 0)
|
|
if accNode != nil {
|
|
if bytes.Equal(accNode.Account.CodeHash[:], EmptyCodeHash[:]) {
|
|
return 0, gotValue
|
|
}
|
|
|
|
if accNode.codeSize == codeSizeUncached {
|
|
return 0, false
|
|
}
|
|
|
|
return accNode.codeSize, gotValue
|
|
}
|
|
return 0, gotValue
|
|
}
|
|
|
|
func (t *Trie) getAccount(origNode node, key []byte, pos int) (value *accountNode, gotValue bool) {
|
|
switch n := (origNode).(type) {
|
|
case nil:
|
|
return nil, true
|
|
case *shortNode:
|
|
matchlen := prefixLen(key[pos:], n.Key)
|
|
if matchlen == len(n.Key) {
|
|
if v, ok := n.Val.(*accountNode); ok {
|
|
return v, true
|
|
} else {
|
|
return t.getAccount(n.Val, key, pos+matchlen)
|
|
}
|
|
} else {
|
|
return nil, true
|
|
}
|
|
case *duoNode:
|
|
i1, i2 := n.childrenIdx()
|
|
switch key[pos] {
|
|
case i1:
|
|
return t.getAccount(n.child1, key, pos+1)
|
|
case i2:
|
|
return t.getAccount(n.child2, key, pos+1)
|
|
default:
|
|
return nil, true
|
|
}
|
|
case *fullNode:
|
|
child := n.Children[key[pos]]
|
|
return t.getAccount(child, key, pos+1)
|
|
case hashNode:
|
|
return nil, false
|
|
|
|
case *accountNode:
|
|
return n, true
|
|
default:
|
|
panic(fmt.Sprintf("%T: invalid node: %v", origNode, origNode))
|
|
}
|
|
}
|
|
|
|
func (t *Trie) get(origNode node, key []byte, pos int) (value []byte, gotValue bool) {
|
|
switch n := (origNode).(type) {
|
|
case nil:
|
|
return nil, true
|
|
case valueNode:
|
|
return n, true
|
|
case *accountNode:
|
|
return t.get(n.storage, key, pos)
|
|
case *shortNode:
|
|
matchlen := prefixLen(key[pos:], n.Key)
|
|
if matchlen == len(n.Key) || n.Key[matchlen] == 16 {
|
|
value, gotValue = t.get(n.Val, key, pos+matchlen)
|
|
} else {
|
|
value, gotValue = nil, true
|
|
}
|
|
return
|
|
case *duoNode:
|
|
i1, i2 := n.childrenIdx()
|
|
switch key[pos] {
|
|
case i1:
|
|
value, gotValue = t.get(n.child1, key, pos+1)
|
|
case i2:
|
|
value, gotValue = t.get(n.child2, key, pos+1)
|
|
default:
|
|
value, gotValue = nil, true
|
|
}
|
|
return
|
|
case *fullNode:
|
|
child := n.Children[key[pos]]
|
|
if child == nil {
|
|
return nil, true
|
|
}
|
|
return t.get(child, key, pos+1)
|
|
case hashNode:
|
|
return n.hash, false
|
|
|
|
default:
|
|
panic(fmt.Sprintf("%T: invalid node: %v", origNode, origNode))
|
|
}
|
|
}
|
|
|
|
func (t *Trie) getPath(origNode node, parents [][]byte, key []byte, pos int) ([]byte, [][]byte, bool) {
|
|
switch n := (origNode).(type) {
|
|
case nil:
|
|
return nil, parents, true
|
|
case valueNode:
|
|
return n, parents, true
|
|
case *accountNode:
|
|
return t.getPath(n.storage, append(parents, n.reference()), key, pos)
|
|
case *shortNode:
|
|
matchlen := prefixLen(key[pos:], n.Key)
|
|
if matchlen == len(n.Key) || n.Key[matchlen] == 16 {
|
|
return t.getPath(n.Val, append(parents, n.reference()), key, pos+matchlen)
|
|
} else {
|
|
return nil, parents, true
|
|
}
|
|
|
|
case *duoNode:
|
|
i1, i2 := n.childrenIdx()
|
|
switch key[pos] {
|
|
case i1:
|
|
return t.getPath(n.child1, append(parents, n.reference()), key, pos+1)
|
|
case i2:
|
|
return t.getPath(n.child2, append(parents, n.reference()), key, pos+1)
|
|
default:
|
|
return nil, parents, true
|
|
}
|
|
case *fullNode:
|
|
child := n.Children[key[pos]]
|
|
if child == nil {
|
|
return nil, parents, true
|
|
}
|
|
return t.getPath(child, append(parents, n.reference()), key, pos+1)
|
|
case hashNode:
|
|
return n.hash, parents, false
|
|
|
|
default:
|
|
panic(fmt.Sprintf("%T: invalid node: %v", origNode, origNode))
|
|
}
|
|
}
|
|
|
|
// Update associates key with value in the trie. Subsequent calls to
|
|
// Get will return value. If value has length zero, any existing value
|
|
// is deleted from the trie and calls to Get will return nil.
|
|
//
|
|
// The value bytes must not be modified by the caller while they are
|
|
// stored in the trie.
|
|
// DESCRIBED: docs/programmers_guide/guide.md#root
|
|
func (t *Trie) Update(key, value []byte) {
|
|
hex := keybytesToHex(key)
|
|
|
|
newnode := valueNode(value)
|
|
|
|
if t.root == nil {
|
|
t.root = NewShortNode(hex, newnode)
|
|
} else {
|
|
_, t.root = t.insert(t.root, hex, valueNode(value))
|
|
}
|
|
}
|
|
|
|
func (t *Trie) UpdateAccount(key []byte, acc *accounts.Account) {
|
|
//make account copy. There are some pointer into big.Int
|
|
value := new(accounts.Account)
|
|
value.Copy(acc)
|
|
|
|
hex := keybytesToHex(key)
|
|
|
|
var newnode *accountNode
|
|
if value.Root == EmptyRoot || value.Root == (libcommon.Hash{}) {
|
|
newnode = &accountNode{*value, nil, true, nil, codeSizeUncached}
|
|
} else {
|
|
newnode = &accountNode{*value, hashNode{hash: value.Root[:]}, true, nil, codeSizeUncached}
|
|
}
|
|
|
|
if t.root == nil {
|
|
t.root = NewShortNode(hex, newnode)
|
|
} else {
|
|
_, t.root = t.insert(t.root, hex, newnode)
|
|
}
|
|
}
|
|
|
|
// UpdateAccountCode attaches the code node to an account at specified key
|
|
func (t *Trie) UpdateAccountCode(key []byte, code codeNode) error {
|
|
if t.root == nil {
|
|
return nil
|
|
}
|
|
|
|
hex := keybytesToHex(key)
|
|
|
|
accNode, gotValue := t.getAccount(t.root, hex, 0)
|
|
if accNode == nil || !gotValue {
|
|
return fmt.Errorf("account not found with key: %x, %w", key, ethdb.ErrKeyNotFound)
|
|
}
|
|
|
|
actualCodeHash := crypto.Keccak256(code)
|
|
if !bytes.Equal(accNode.CodeHash[:], actualCodeHash) {
|
|
return fmt.Errorf("inserted code mismatch account hash (acc.CodeHash=%x codeHash=%x)", accNode.CodeHash[:], actualCodeHash)
|
|
}
|
|
|
|
accNode.code = code
|
|
accNode.codeSize = len(code)
|
|
|
|
// t.insert will call the observer methods itself
|
|
_, t.root = t.insert(t.root, hex, accNode)
|
|
return nil
|
|
}
|
|
|
|
// UpdateAccountCodeSize attaches the code size to the account
|
|
func (t *Trie) UpdateAccountCodeSize(key []byte, codeSize int) error {
|
|
if t.root == nil {
|
|
return nil
|
|
}
|
|
|
|
hex := keybytesToHex(key)
|
|
|
|
accNode, gotValue := t.getAccount(t.root, hex, 0)
|
|
if accNode == nil || !gotValue {
|
|
return fmt.Errorf("account not found with key: %x, %w", key, ethdb.ErrKeyNotFound)
|
|
}
|
|
|
|
accNode.codeSize = codeSize
|
|
|
|
// t.insert will call the observer methods itself
|
|
_, t.root = t.insert(t.root, hex, accNode)
|
|
return nil
|
|
}
|
|
|
|
// LoadRequestForCode Code expresses the need to fetch code from the DB (by its hash) and attach
|
|
// to a specific account leaf in the trie.
|
|
type LoadRequestForCode struct {
|
|
t *Trie
|
|
addrHash libcommon.Hash // contract address hash
|
|
codeHash libcommon.Hash
|
|
bytecode bool // include the bytecode too
|
|
}
|
|
|
|
func (lrc *LoadRequestForCode) String() string {
|
|
return fmt.Sprintf("rr_code{addrHash:%x,codeHash:%x,bytecode:%v}", lrc.addrHash, lrc.codeHash, lrc.bytecode)
|
|
}
|
|
|
|
func (t *Trie) NewLoadRequestForCode(addrHash libcommon.Hash, codeHash libcommon.Hash, bytecode bool) *LoadRequestForCode {
|
|
return &LoadRequestForCode{t, addrHash, codeHash, bytecode}
|
|
}
|
|
|
|
func (t *Trie) NeedLoadCode(addrHash libcommon.Hash, codeHash libcommon.Hash, bytecode bool) (bool, *LoadRequestForCode) {
|
|
if bytes.Equal(codeHash[:], EmptyCodeHash[:]) {
|
|
return false, nil
|
|
}
|
|
|
|
var ok bool
|
|
if bytecode {
|
|
_, ok = t.GetAccountCode(addrHash[:])
|
|
} else {
|
|
_, ok = t.GetAccountCodeSize(addrHash[:])
|
|
}
|
|
if !ok {
|
|
return true, t.NewLoadRequestForCode(addrHash, codeHash, bytecode)
|
|
}
|
|
|
|
return false, nil
|
|
}
|
|
|
|
// FindSubTriesToLoad walks over the trie and creates the list of DB prefixes and
|
|
// corresponding list of valid bits in the prefix (for the cases when prefix contains an
|
|
// odd number of nibbles) that would allow loading the missing information from the database
|
|
// It also create list of `hooks`, the paths in the trie (in nibbles) where the loaded
|
|
// sub-tries need to be inserted.
|
|
func (t *Trie) FindSubTriesToLoad(rl RetainDecider) (prefixes [][]byte, fixedbits []int, hooks [][]byte) {
|
|
return findSubTriesToLoad(t.root, nil, nil, rl, nil, 0, nil, nil, nil)
|
|
}
|
|
|
|
var bytes8 [8]byte
|
|
var bytes16 [16]byte
|
|
|
|
func findSubTriesToLoad(nd node, nibblePath []byte, hook []byte, rl RetainDecider, dbPrefix []byte, bits int, prefixes [][]byte, fixedbits []int, hooks [][]byte) (newPrefixes [][]byte, newFixedBits []int, newHooks [][]byte) {
|
|
switch n := nd.(type) {
|
|
case *shortNode:
|
|
nKey := n.Key
|
|
if nKey[len(nKey)-1] == 16 {
|
|
nKey = nKey[:len(nKey)-1]
|
|
}
|
|
nibblePath = append(nibblePath, nKey...)
|
|
hook = append(hook, nKey...)
|
|
if !rl.Retain(nibblePath) {
|
|
return prefixes, fixedbits, hooks
|
|
}
|
|
for _, b := range nKey {
|
|
if bits%8 == 0 {
|
|
dbPrefix = append(dbPrefix, b<<4)
|
|
} else {
|
|
dbPrefix[len(dbPrefix)-1] &= 0xf0
|
|
dbPrefix[len(dbPrefix)-1] |= b & 0xf
|
|
}
|
|
bits += 4
|
|
}
|
|
return findSubTriesToLoad(n.Val, nibblePath, hook, rl, dbPrefix, bits, prefixes, fixedbits, hooks)
|
|
case *duoNode:
|
|
i1, i2 := n.childrenIdx()
|
|
newPrefixes = prefixes
|
|
newFixedBits = fixedbits
|
|
newHooks = hooks
|
|
newNibblePath := append(nibblePath, i1)
|
|
newHook := append(hook, i1)
|
|
if rl.Retain(newNibblePath) {
|
|
var newDbPrefix []byte
|
|
if bits%8 == 0 {
|
|
newDbPrefix = append(dbPrefix, i1<<4)
|
|
} else {
|
|
newDbPrefix = dbPrefix
|
|
newDbPrefix[len(newDbPrefix)-1] &= 0xf0
|
|
newDbPrefix[len(newDbPrefix)-1] |= i1 & 0xf
|
|
}
|
|
newPrefixes, newFixedBits, newHooks = findSubTriesToLoad(n.child1, newNibblePath, newHook, rl, newDbPrefix, bits+4, newPrefixes, newFixedBits, newHooks)
|
|
}
|
|
newNibblePath = append(nibblePath, i2)
|
|
newHook = append(hook, i2)
|
|
if rl.Retain(newNibblePath) {
|
|
var newDbPrefix []byte
|
|
if bits%8 == 0 {
|
|
newDbPrefix = append(dbPrefix, i2<<4)
|
|
} else {
|
|
newDbPrefix = dbPrefix
|
|
newDbPrefix[len(newDbPrefix)-1] &= 0xf0
|
|
newDbPrefix[len(newDbPrefix)-1] |= i2 & 0xf
|
|
}
|
|
newPrefixes, newFixedBits, newHooks = findSubTriesToLoad(n.child2, newNibblePath, newHook, rl, newDbPrefix, bits+4, newPrefixes, newFixedBits, newHooks)
|
|
}
|
|
return newPrefixes, newFixedBits, newHooks
|
|
case *fullNode:
|
|
newPrefixes = prefixes
|
|
newFixedBits = fixedbits
|
|
newHooks = hooks
|
|
var newNibblePath []byte
|
|
var newHook []byte
|
|
for i, child := range n.Children {
|
|
if child != nil {
|
|
newNibblePath = append(nibblePath, byte(i))
|
|
newHook = append(hook, byte(i))
|
|
if rl.Retain(newNibblePath) {
|
|
var newDbPrefix []byte
|
|
if bits%8 == 0 {
|
|
newDbPrefix = append(dbPrefix, byte(i)<<4)
|
|
} else {
|
|
newDbPrefix = dbPrefix
|
|
newDbPrefix[len(newDbPrefix)-1] &= 0xf0
|
|
newDbPrefix[len(newDbPrefix)-1] |= byte(i) & 0xf
|
|
}
|
|
newPrefixes, newFixedBits, newHooks = findSubTriesToLoad(child, newNibblePath, newHook, rl, newDbPrefix, bits+4, newPrefixes, newFixedBits, newHooks)
|
|
}
|
|
}
|
|
}
|
|
return newPrefixes, newFixedBits, newHooks
|
|
case *accountNode:
|
|
if n.storage == nil {
|
|
return prefixes, fixedbits, hooks
|
|
}
|
|
binary.BigEndian.PutUint64(bytes8[:], n.Incarnation)
|
|
dbPrefix = append(dbPrefix, bytes8[:]...)
|
|
// Add decompressed incarnation to the nibblePath
|
|
for i, b := range bytes8[:] {
|
|
bytes16[i*2] = b / 16
|
|
bytes16[i*2+1] = b % 16
|
|
}
|
|
nibblePath = append(nibblePath, bytes16[:]...)
|
|
newPrefixes = prefixes
|
|
newFixedBits = fixedbits
|
|
newHooks = hooks
|
|
if rl.Retain(nibblePath) {
|
|
newPrefixes, newFixedBits, newHooks = findSubTriesToLoad(n.storage, nibblePath, hook, rl, dbPrefix, bits+64, prefixes, fixedbits, hooks)
|
|
}
|
|
return newPrefixes, newFixedBits, newHooks
|
|
case hashNode:
|
|
newPrefixes = append(prefixes, libcommon.Copy(dbPrefix))
|
|
newFixedBits = append(fixedbits, bits)
|
|
newHooks = append(hooks, libcommon.Copy(hook))
|
|
return newPrefixes, newFixedBits, newHooks
|
|
}
|
|
return prefixes, fixedbits, hooks
|
|
}
|
|
|
|
// can pass incarnation=0 if start from root, method internally will
|
|
// put incarnation from accountNode when pass it by traverse
|
|
func (t *Trie) insert(origNode node, key []byte, value node) (updated bool, newNode node) {
|
|
return t.insertRecursive(origNode, key, 0, value)
|
|
}
|
|
|
|
func (t *Trie) insertRecursive(origNode node, key []byte, pos int, value node) (updated bool, newNode node) {
|
|
if len(key) == pos {
|
|
origN, origNok := origNode.(valueNode)
|
|
vn, vnok := value.(valueNode)
|
|
if origNok && vnok {
|
|
updated = !bytes.Equal(origN, vn)
|
|
if updated {
|
|
newNode = value
|
|
} else {
|
|
newNode = origN
|
|
}
|
|
return
|
|
}
|
|
origAccN, origNok := origNode.(*accountNode)
|
|
vAccN, vnok := value.(*accountNode)
|
|
if origNok && vnok {
|
|
updated = !origAccN.Equals(&vAccN.Account)
|
|
if updated {
|
|
if !bytes.Equal(origAccN.CodeHash[:], vAccN.CodeHash[:]) {
|
|
origAccN.code = nil
|
|
} else if vAccN.code != nil {
|
|
origAccN.code = vAccN.code
|
|
}
|
|
origAccN.Account.Copy(&vAccN.Account)
|
|
origAccN.codeSize = vAccN.codeSize
|
|
origAccN.rootCorrect = false
|
|
}
|
|
newNode = origAccN
|
|
return
|
|
}
|
|
|
|
// replacing nodes except accounts
|
|
if !origNok {
|
|
return true, value
|
|
}
|
|
}
|
|
|
|
var nn node
|
|
switch n := origNode.(type) {
|
|
case nil:
|
|
return true, NewShortNode(libcommon.Copy(key[pos:]), value)
|
|
case *accountNode:
|
|
updated, nn = t.insertRecursive(n.storage, key, pos, value)
|
|
if updated {
|
|
n.storage = nn
|
|
n.rootCorrect = false
|
|
}
|
|
return updated, n
|
|
case *shortNode:
|
|
matchlen := prefixLen(key[pos:], n.Key)
|
|
// If the whole key matches, keep this short node as is
|
|
// and only update the value.
|
|
if matchlen == len(n.Key) || n.Key[matchlen] == 16 {
|
|
updated, nn = t.insertRecursive(n.Val, key, pos+matchlen, value)
|
|
if updated {
|
|
n.Val = nn
|
|
n.ref.len = 0
|
|
}
|
|
newNode = n
|
|
} else {
|
|
// Otherwise branch out at the index where they differ.
|
|
var c1 node
|
|
if len(n.Key) == matchlen+1 {
|
|
c1 = n.Val
|
|
} else {
|
|
c1 = NewShortNode(libcommon.Copy(n.Key[matchlen+1:]), n.Val)
|
|
}
|
|
var c2 node
|
|
if len(key) == pos+matchlen+1 {
|
|
c2 = value
|
|
} else {
|
|
c2 = NewShortNode(libcommon.Copy(key[pos+matchlen+1:]), value)
|
|
}
|
|
branch := &duoNode{}
|
|
if n.Key[matchlen] < key[pos+matchlen] {
|
|
branch.child1 = c1
|
|
branch.child2 = c2
|
|
} else {
|
|
branch.child1 = c2
|
|
branch.child2 = c1
|
|
}
|
|
branch.mask = (1 << (n.Key[matchlen])) | (1 << (key[pos+matchlen]))
|
|
|
|
// Replace this shortNode with the branch if it occurs at index 0.
|
|
if matchlen == 0 {
|
|
newNode = branch // current node leaves the generation, but new node branch joins it
|
|
} else {
|
|
// Otherwise, replace it with a short node leading up to the branch.
|
|
n.Key = libcommon.Copy(key[pos : pos+matchlen])
|
|
n.Val = branch
|
|
n.ref.len = 0
|
|
newNode = n
|
|
}
|
|
updated = true
|
|
}
|
|
return
|
|
|
|
case *duoNode:
|
|
i1, i2 := n.childrenIdx()
|
|
switch key[pos] {
|
|
case i1:
|
|
updated, nn = t.insertRecursive(n.child1, key, pos+1, value)
|
|
if updated {
|
|
n.child1 = nn
|
|
n.ref.len = 0
|
|
}
|
|
newNode = n
|
|
case i2:
|
|
updated, nn = t.insertRecursive(n.child2, key, pos+1, value)
|
|
if updated {
|
|
n.child2 = nn
|
|
n.ref.len = 0
|
|
}
|
|
newNode = n
|
|
default:
|
|
var child node
|
|
if len(key) == pos+1 {
|
|
child = value
|
|
} else {
|
|
child = NewShortNode(libcommon.Copy(key[pos+1:]), value)
|
|
}
|
|
newnode := &fullNode{}
|
|
newnode.Children[i1] = n.child1
|
|
newnode.Children[i2] = n.child2
|
|
newnode.Children[key[pos]] = child
|
|
updated = true
|
|
// current node leaves the generation but newnode joins it
|
|
newNode = newnode
|
|
}
|
|
return
|
|
|
|
case *fullNode:
|
|
child := n.Children[key[pos]]
|
|
if child == nil {
|
|
if len(key) == pos+1 {
|
|
n.Children[key[pos]] = value
|
|
} else {
|
|
n.Children[key[pos]] = NewShortNode(libcommon.Copy(key[pos+1:]), value)
|
|
}
|
|
updated = true
|
|
n.ref.len = 0
|
|
} else {
|
|
updated, nn = t.insertRecursive(child, key, pos+1, value)
|
|
if updated {
|
|
n.Children[key[pos]] = nn
|
|
n.ref.len = 0
|
|
}
|
|
}
|
|
newNode = n
|
|
return
|
|
default:
|
|
panic(fmt.Sprintf("%T: invalid node: %v. Searched by: key=%x, pos=%d", n, n, key, pos))
|
|
}
|
|
}
|
|
|
|
// non-recursive version of get and returns: node and parent node
|
|
func (t *Trie) getNode(hex []byte, doTouch bool) (node, node, bool, uint64) {
|
|
var nd = t.root
|
|
var parent node
|
|
pos := 0
|
|
var account bool
|
|
var incarnation uint64
|
|
for pos < len(hex) || account {
|
|
switch n := nd.(type) {
|
|
case nil:
|
|
return nil, nil, false, incarnation
|
|
case *shortNode:
|
|
matchlen := prefixLen(hex[pos:], n.Key)
|
|
if matchlen == len(n.Key) || n.Key[matchlen] == 16 {
|
|
parent = n
|
|
nd = n.Val
|
|
pos += matchlen
|
|
if _, ok := nd.(*accountNode); ok {
|
|
account = true
|
|
}
|
|
} else {
|
|
return nil, nil, false, incarnation
|
|
}
|
|
case *duoNode:
|
|
i1, i2 := n.childrenIdx()
|
|
switch hex[pos] {
|
|
case i1:
|
|
parent = n
|
|
nd = n.child1
|
|
pos++
|
|
case i2:
|
|
parent = n
|
|
nd = n.child2
|
|
pos++
|
|
default:
|
|
return nil, nil, false, incarnation
|
|
}
|
|
case *fullNode:
|
|
child := n.Children[hex[pos]]
|
|
if child == nil {
|
|
return nil, nil, false, incarnation
|
|
}
|
|
parent = n
|
|
nd = child
|
|
pos++
|
|
case *accountNode:
|
|
parent = n
|
|
nd = n.storage
|
|
incarnation = n.Incarnation
|
|
account = false
|
|
case valueNode:
|
|
return nd, parent, true, incarnation
|
|
case hashNode:
|
|
return nd, parent, true, incarnation
|
|
default:
|
|
panic(fmt.Sprintf("Unknown node: %T", n))
|
|
}
|
|
}
|
|
return nd, parent, true, incarnation
|
|
}
|
|
|
|
func (t *Trie) HookSubTries(subTries SubTries, hooks [][]byte) error {
|
|
for i, hookNibbles := range hooks {
|
|
root := subTries.roots[i]
|
|
hash := subTries.Hashes[i]
|
|
if root == nil {
|
|
return fmt.Errorf("root==nil for hook %x", hookNibbles)
|
|
}
|
|
if err := t.hook(hookNibbles, root, hash[:]); err != nil {
|
|
return fmt.Errorf("hook %x: %w", hookNibbles, err)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (t *Trie) hook(hex []byte, n node, hash []byte) error {
|
|
nd, parent, ok, incarnation := t.getNode(hex, true)
|
|
if !ok {
|
|
return nil
|
|
}
|
|
if _, ok := nd.(valueNode); ok {
|
|
return nil
|
|
}
|
|
if hn, ok := nd.(hashNode); ok {
|
|
if !bytes.Equal(hn.hash, hash) {
|
|
return fmt.Errorf("wrong hash when hooking, expected %s, sub-tree hash %x", hn, hash)
|
|
}
|
|
} else if nd != nil {
|
|
return fmt.Errorf("expected hash node at %x, got %T", hex, nd)
|
|
}
|
|
|
|
t.touchAll(n, hex, false, incarnation)
|
|
switch p := parent.(type) {
|
|
case nil:
|
|
t.root = n
|
|
case *shortNode:
|
|
p.Val = n
|
|
case *duoNode:
|
|
i1, i2 := p.childrenIdx()
|
|
switch hex[len(hex)-1] {
|
|
case i1:
|
|
p.child1 = n
|
|
case i2:
|
|
p.child2 = n
|
|
}
|
|
case *fullNode:
|
|
idx := hex[len(hex)-1]
|
|
p.Children[idx] = n
|
|
case *accountNode:
|
|
p.storage = n
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (t *Trie) touchAll(n node, hex []byte, del bool, incarnation uint64) {
|
|
switch n := n.(type) {
|
|
case *shortNode:
|
|
if _, ok := n.Val.(valueNode); !ok {
|
|
// Don't need to compute prefix for a leaf
|
|
h := n.Key
|
|
// Remove terminator
|
|
if h[len(h)-1] == 16 {
|
|
h = h[:len(h)-1]
|
|
}
|
|
hexVal := concat(hex, h...)
|
|
t.touchAll(n.Val, hexVal, del, incarnation)
|
|
}
|
|
case *duoNode:
|
|
i1, i2 := n.childrenIdx()
|
|
hex1 := make([]byte, len(hex)+1)
|
|
copy(hex1, hex)
|
|
hex1[len(hex)] = i1
|
|
hex2 := make([]byte, len(hex)+1)
|
|
copy(hex2, hex)
|
|
hex2[len(hex)] = i2
|
|
t.touchAll(n.child1, hex1, del, incarnation)
|
|
t.touchAll(n.child2, hex2, del, incarnation)
|
|
case *fullNode:
|
|
for i, child := range n.Children {
|
|
if child != nil {
|
|
t.touchAll(child, concat(hex, byte(i)), del, incarnation)
|
|
}
|
|
}
|
|
case *accountNode:
|
|
if n.storage != nil {
|
|
t.touchAll(n.storage, hex, del, n.Incarnation)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Delete removes any existing value for key from the trie.
|
|
// DESCRIBED: docs/programmers_guide/guide.md#root
|
|
func (t *Trie) Delete(key []byte) {
|
|
hex := keybytesToHex(key)
|
|
_, t.root = t.delete(t.root, hex, false)
|
|
}
|
|
|
|
func (t *Trie) convertToShortNode(child node, pos uint) node {
|
|
if pos != 16 {
|
|
// If the remaining entry is a short node, it replaces
|
|
// n and its key gets the missing nibble tacked to the
|
|
// front. This avoids creating an invalid
|
|
// shortNode{..., shortNode{...}}. Since the entry
|
|
// might not be loaded yet, resolve it just for this
|
|
// check.
|
|
if short, ok := child.(*shortNode); ok {
|
|
k := make([]byte, len(short.Key)+1)
|
|
k[0] = byte(pos)
|
|
copy(k[1:], short.Key)
|
|
return NewShortNode(k, short.Val)
|
|
}
|
|
}
|
|
// Otherwise, n is replaced by a one-nibble short node
|
|
// containing the child.
|
|
return NewShortNode([]byte{byte(pos)}, child)
|
|
}
|
|
|
|
func (t *Trie) delete(origNode node, key []byte, preserveAccountNode bool) (updated bool, newNode node) {
|
|
return t.deleteRecursive(origNode, key, 0, preserveAccountNode, 0)
|
|
}
|
|
|
|
// delete returns the new root of the trie with key deleted.
|
|
// It reduces the trie to minimal form by simplifying
|
|
// nodes on the way up after deleting recursively.
|
|
//
|
|
// can pass incarnation=0 if start from root, method internally will
|
|
// put incarnation from accountNode when pass it by traverse
|
|
func (t *Trie) deleteRecursive(origNode node, key []byte, keyStart int, preserveAccountNode bool, incarnation uint64) (updated bool, newNode node) {
|
|
var nn node
|
|
switch n := origNode.(type) {
|
|
case *shortNode:
|
|
matchlen := prefixLen(key[keyStart:], n.Key)
|
|
if matchlen == cmp.Min(len(n.Key), len(key[keyStart:])) || n.Key[matchlen] == 16 || key[keyStart+matchlen] == 16 {
|
|
fullMatch := matchlen == len(key)-keyStart
|
|
removeNodeEntirely := fullMatch
|
|
if preserveAccountNode {
|
|
removeNodeEntirely = len(key) == keyStart || matchlen == len(key[keyStart:])-1
|
|
}
|
|
|
|
if removeNodeEntirely {
|
|
updated = true
|
|
touchKey := key[:keyStart+matchlen]
|
|
if touchKey[len(touchKey)-1] == 16 {
|
|
touchKey = touchKey[:len(touchKey)-1]
|
|
}
|
|
t.touchAll(n.Val, touchKey, true, incarnation)
|
|
newNode = nil
|
|
} else {
|
|
// The key is longer than n.Key. Remove the remaining suffix
|
|
// from the subtrie. Child can never be nil here since the
|
|
// subtrie must contain at least two other values with keys
|
|
// longer than n.Key.
|
|
updated, nn = t.deleteRecursive(n.Val, key, keyStart+matchlen, preserveAccountNode, incarnation)
|
|
if !updated {
|
|
newNode = n
|
|
} else {
|
|
if nn == nil {
|
|
newNode = nil
|
|
} else {
|
|
if shortChild, ok := nn.(*shortNode); ok {
|
|
// Deleting from the subtrie reduced it to another
|
|
// short node. Merge the nodes to avoid creating a
|
|
// shortNode{..., shortNode{...}}. Use concat (which
|
|
// always creates a new slice) instead of append to
|
|
// avoid modifying n.Key since it might be shared with
|
|
// other nodes.
|
|
newNode = NewShortNode(concat(n.Key, shortChild.Key...), shortChild.Val)
|
|
} else {
|
|
n.Val = nn
|
|
newNode = n
|
|
n.ref.len = 0
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
updated = false
|
|
newNode = n // don't replace n on mismatch
|
|
}
|
|
return
|
|
|
|
case *duoNode:
|
|
i1, i2 := n.childrenIdx()
|
|
switch key[keyStart] {
|
|
case i1:
|
|
updated, nn = t.deleteRecursive(n.child1, key, keyStart+1, preserveAccountNode, incarnation)
|
|
if !updated {
|
|
newNode = n
|
|
} else {
|
|
if nn == nil {
|
|
newNode = t.convertToShortNode(n.child2, uint(i2))
|
|
} else {
|
|
n.child1 = nn
|
|
n.ref.len = 0
|
|
newNode = n
|
|
}
|
|
}
|
|
case i2:
|
|
updated, nn = t.deleteRecursive(n.child2, key, keyStart+1, preserveAccountNode, incarnation)
|
|
if !updated {
|
|
newNode = n
|
|
} else {
|
|
if nn == nil {
|
|
newNode = t.convertToShortNode(n.child1, uint(i1))
|
|
} else {
|
|
n.child2 = nn
|
|
n.ref.len = 0
|
|
newNode = n
|
|
}
|
|
}
|
|
default:
|
|
updated = false
|
|
newNode = n
|
|
}
|
|
return
|
|
|
|
case *fullNode:
|
|
child := n.Children[key[keyStart]]
|
|
updated, nn = t.deleteRecursive(child, key, keyStart+1, preserveAccountNode, incarnation)
|
|
if !updated {
|
|
newNode = n
|
|
} else {
|
|
n.Children[key[keyStart]] = nn
|
|
// Check how many non-nil entries are left after deleting and
|
|
// reduce the full node to a short node if only one entry is
|
|
// left. Since n must've contained at least two children
|
|
// before deletion (otherwise it would not be a full node) n
|
|
// can never be reduced to nil.
|
|
//
|
|
// When the loop is done, pos contains the index of the single
|
|
// value that is left in n or -2 if n contains at least two
|
|
// values.
|
|
var pos1, pos2 int
|
|
count := 0
|
|
for i, cld := range n.Children {
|
|
if cld != nil {
|
|
if count == 0 {
|
|
pos1 = i
|
|
}
|
|
if count == 1 {
|
|
pos2 = i
|
|
}
|
|
count++
|
|
if count > 2 {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
if count == 1 {
|
|
newNode = t.convertToShortNode(n.Children[pos1], uint(pos1))
|
|
} else if count == 2 {
|
|
duo := &duoNode{}
|
|
if pos1 == int(key[keyStart]) {
|
|
duo.child1 = nn
|
|
} else {
|
|
duo.child1 = n.Children[pos1]
|
|
}
|
|
if pos2 == int(key[keyStart]) {
|
|
duo.child2 = nn
|
|
} else {
|
|
duo.child2 = n.Children[pos2]
|
|
}
|
|
duo.mask = (1 << uint(pos1)) | (uint32(1) << uint(pos2))
|
|
newNode = duo
|
|
} else if count > 2 {
|
|
// n still contains at least three values and cannot be reduced.
|
|
n.ref.len = 0
|
|
newNode = n
|
|
}
|
|
}
|
|
return
|
|
|
|
case valueNode:
|
|
updated = true
|
|
newNode = nil
|
|
return
|
|
|
|
case *accountNode:
|
|
if keyStart >= len(key) || key[keyStart] == 16 {
|
|
// Key terminates here
|
|
h := key[:keyStart]
|
|
if h[len(h)-1] == 16 {
|
|
h = h[:len(h)-1]
|
|
}
|
|
if n.storage != nil {
|
|
// Mark all the storage nodes as deleted
|
|
t.touchAll(n.storage, h, true, n.Incarnation)
|
|
}
|
|
if preserveAccountNode {
|
|
n.storage = nil
|
|
n.code = nil
|
|
n.Root = EmptyRoot
|
|
n.rootCorrect = true
|
|
return true, n
|
|
}
|
|
|
|
return true, nil
|
|
}
|
|
updated, nn = t.deleteRecursive(n.storage, key, keyStart, preserveAccountNode, n.Incarnation)
|
|
if updated {
|
|
n.storage = nn
|
|
n.rootCorrect = false
|
|
}
|
|
newNode = n
|
|
return
|
|
|
|
case nil:
|
|
updated = false
|
|
newNode = nil
|
|
return
|
|
|
|
default:
|
|
panic(fmt.Sprintf("%T: invalid node: %v (%v)", n, n, key[:keyStart]))
|
|
}
|
|
}
|
|
|
|
// DeleteSubtree removes any existing value for key from the trie.
|
|
// The only difference between Delete and DeleteSubtree is that Delete would delete accountNode too,
|
|
// wherewas DeleteSubtree will keep the accountNode, but will make the storage sub-trie empty
|
|
func (t *Trie) DeleteSubtree(keyPrefix []byte) {
|
|
hexPrefix := keybytesToHex(keyPrefix)
|
|
|
|
_, t.root = t.delete(t.root, hexPrefix, true)
|
|
|
|
}
|
|
|
|
func concat(s1 []byte, s2 ...byte) []byte {
|
|
r := make([]byte, len(s1)+len(s2))
|
|
copy(r, s1)
|
|
copy(r[len(s1):], s2)
|
|
return r
|
|
}
|
|
|
|
// Root returns the root hash of the trie.
|
|
// Deprecated: use Hash instead.
|
|
func (t *Trie) Root() []byte { return t.Hash().Bytes() }
|
|
|
|
// 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.
|
|
// DESCRIBED: docs/programmers_guide/guide.md#root
|
|
func (t *Trie) Hash() libcommon.Hash {
|
|
if t == nil || t.root == nil {
|
|
return EmptyRoot
|
|
}
|
|
|
|
h := t.getHasher()
|
|
defer returnHasherToPool(h)
|
|
|
|
var result libcommon.Hash
|
|
_, _ = h.hash(t.root, true, result[:])
|
|
|
|
return result
|
|
}
|
|
|
|
func (t *Trie) Reset() {
|
|
resetRefs(t.root)
|
|
}
|
|
|
|
func (t *Trie) getHasher() *hasher {
|
|
return t.newHasherFunc()
|
|
}
|
|
|
|
// DeepHash returns internal hash of a node reachable by the specified key prefix.
|
|
// Note that if the prefix points into the middle of a key for a leaf node or of an extension
|
|
// node, it will return the hash of a modified leaf node or extension node, where the
|
|
// key prefix is removed from the key.
|
|
// First returned value is `true` if the node with the specified prefix is found.
|
|
func (t *Trie) DeepHash(keyPrefix []byte) (bool, libcommon.Hash) {
|
|
hexPrefix := keybytesToHex(keyPrefix)
|
|
accNode, gotValue := t.getAccount(t.root, hexPrefix, 0)
|
|
if !gotValue {
|
|
return false, libcommon.Hash{}
|
|
}
|
|
if accNode.rootCorrect {
|
|
return true, accNode.Root
|
|
}
|
|
if accNode.storage == nil {
|
|
accNode.Root = EmptyRoot
|
|
accNode.rootCorrect = true
|
|
} else {
|
|
h := t.getHasher()
|
|
defer returnHasherToPool(h)
|
|
h.hash(accNode.storage, true, accNode.Root[:])
|
|
}
|
|
return true, accNode.Root
|
|
}
|
|
|
|
func (t *Trie) EvictNode(hex []byte) {
|
|
isCode := IsPointingToCode(hex)
|
|
if isCode {
|
|
hex = AddrHashFromCodeKey(hex)
|
|
}
|
|
|
|
nd, parent, ok, incarnation := t.getNode(hex, false)
|
|
if !ok {
|
|
return
|
|
}
|
|
if accNode, ok := parent.(*accountNode); isCode && ok {
|
|
// add special treatment to code nodes
|
|
accNode.code = nil
|
|
return
|
|
}
|
|
|
|
switch nd.(type) {
|
|
case valueNode, hashNode:
|
|
return
|
|
default:
|
|
// can work with other nodes type
|
|
}
|
|
|
|
var hn libcommon.Hash
|
|
if nd == nil {
|
|
fmt.Printf("nd == nil, hex %x, parent node: %T\n", hex, parent)
|
|
return
|
|
}
|
|
copy(hn[:], nd.reference())
|
|
hnode := hashNode{hash: hn[:]}
|
|
|
|
t.notifyUnloadRecursive(hex, incarnation, nd)
|
|
|
|
switch p := parent.(type) {
|
|
case nil:
|
|
t.root = hnode
|
|
case *shortNode:
|
|
p.Val = hnode
|
|
case *duoNode:
|
|
i1, i2 := p.childrenIdx()
|
|
switch hex[len(hex)-1] {
|
|
case i1:
|
|
p.child1 = hnode
|
|
case i2:
|
|
p.child2 = hnode
|
|
}
|
|
case *fullNode:
|
|
idx := hex[len(hex)-1]
|
|
p.Children[idx] = hnode
|
|
case *accountNode:
|
|
p.storage = hnode
|
|
}
|
|
}
|
|
|
|
func (t *Trie) notifyUnloadRecursive(hex []byte, incarnation uint64, nd node) {
|
|
switch n := nd.(type) {
|
|
case *shortNode:
|
|
hex = append(hex, n.Key...)
|
|
if hex[len(hex)-1] == 16 {
|
|
hex = hex[:len(hex)-1]
|
|
}
|
|
t.notifyUnloadRecursive(hex, incarnation, n.Val)
|
|
case *accountNode:
|
|
if n.storage == nil {
|
|
return
|
|
}
|
|
if _, ok := n.storage.(hashNode); ok {
|
|
return
|
|
}
|
|
t.notifyUnloadRecursive(hex, n.Incarnation, n.storage)
|
|
case *fullNode:
|
|
for i := range n.Children {
|
|
if n.Children[i] == nil {
|
|
continue
|
|
}
|
|
if _, ok := n.Children[i].(hashNode); ok {
|
|
continue
|
|
}
|
|
t.notifyUnloadRecursive(append(hex, uint8(i)), incarnation, n.Children[i])
|
|
}
|
|
case *duoNode:
|
|
i1, i2 := n.childrenIdx()
|
|
if n.child1 != nil {
|
|
t.notifyUnloadRecursive(append(hex, i1), incarnation, n.child1)
|
|
}
|
|
if n.child2 != nil {
|
|
t.notifyUnloadRecursive(append(hex, i2), incarnation, n.child2)
|
|
}
|
|
default:
|
|
// nothing to do
|
|
}
|
|
}
|
|
|
|
func (t *Trie) TrieSize() int {
|
|
return calcSubtreeSize(t.root)
|
|
}
|
|
|
|
func (t *Trie) NumberOfAccounts() int {
|
|
return calcSubtreeNodes(t.root)
|
|
}
|