github.com/ethereum/go-ethereum@v1.16.1/trie/stacktrie.go (about)

     1  // Copyright 2020 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package trie
    18  
    19  import (
    20  	"bytes"
    21  	"errors"
    22  	"sync"
    23  
    24  	"github.com/ethereum/go-ethereum/common"
    25  	"github.com/ethereum/go-ethereum/core/types"
    26  )
    27  
    28  var (
    29  	stPool = sync.Pool{New: func() any { return new(stNode) }}
    30  	bPool  = newBytesPool(32, 100)
    31  	_      = types.TrieHasher((*StackTrie)(nil))
    32  )
    33  
    34  // OnTrieNode is a callback method invoked when a trie node is committed
    35  // by the stack trie. The node is only committed if it's considered complete.
    36  //
    37  // The caller should not modify the contents of the returned path and blob
    38  // slice, and their contents may be changed after the call. It is up to the
    39  // `onTrieNode` receiver function to deep-copy the data if it wants to retain
    40  // it after the call ends.
    41  type OnTrieNode func(path []byte, hash common.Hash, blob []byte)
    42  
    43  // StackTrie is a trie implementation that expects keys to be inserted
    44  // in order. Once it determines that a subtree will no longer be inserted
    45  // into, it will hash it and free up the memory it uses.
    46  type StackTrie struct {
    47  	root       *stNode
    48  	h          *hasher
    49  	last       []byte
    50  	onTrieNode OnTrieNode
    51  	kBuf       []byte // buf space used for hex-key during insertions
    52  	pBuf       []byte // buf space used for path during insertions
    53  }
    54  
    55  // NewStackTrie allocates and initializes an empty trie. The committed nodes
    56  // will be discarded immediately if no callback is configured.
    57  func NewStackTrie(onTrieNode OnTrieNode) *StackTrie {
    58  	return &StackTrie{
    59  		root:       stPool.Get().(*stNode),
    60  		h:          newHasher(false),
    61  		onTrieNode: onTrieNode,
    62  		kBuf:       make([]byte, 64),
    63  		pBuf:       make([]byte, 64),
    64  	}
    65  }
    66  
    67  func (t *StackTrie) grow(key []byte) {
    68  	if cap(t.kBuf) < 2*len(key) {
    69  		t.kBuf = make([]byte, 2*len(key))
    70  	}
    71  	if cap(t.pBuf) < 2*len(key) {
    72  		t.pBuf = make([]byte, 2*len(key))
    73  	}
    74  }
    75  
    76  // Update inserts a (key, value) pair into the stack trie.
    77  func (t *StackTrie) Update(key, value []byte) error {
    78  	if len(value) == 0 {
    79  		return errors.New("trying to insert empty (deletion)")
    80  	}
    81  	t.grow(key)
    82  	k := writeHexKey(t.kBuf, key)
    83  	if bytes.Compare(t.last, k) >= 0 {
    84  		return errors.New("non-ascending key order")
    85  	}
    86  	if t.last == nil {
    87  		t.last = append([]byte{}, k...) // allocate key slice
    88  	} else {
    89  		t.last = append(t.last[:0], k...) // reuse key slice
    90  	}
    91  	t.insert(t.root, k, value, t.pBuf[:0])
    92  	return nil
    93  }
    94  
    95  // Reset resets the stack trie object to empty state.
    96  func (t *StackTrie) Reset() {
    97  	t.root = stPool.Get().(*stNode)
    98  	t.last = nil
    99  }
   100  
   101  // TrieKey returns the internal key representation for the given user key.
   102  func (t *StackTrie) TrieKey(key []byte) []byte {
   103  	k := keybytesToHex(key)
   104  	k = k[:len(k)-1] // chop the termination flag
   105  	return k
   106  }
   107  
   108  // stNode represents a node within a StackTrie
   109  type stNode struct {
   110  	typ      uint8       // node type (as in branch, ext, leaf)
   111  	key      []byte      // key chunk covered by this (leaf|ext) node
   112  	val      []byte      // value contained by this node if it's a leaf
   113  	children [16]*stNode // list of children (for branch and exts)
   114  }
   115  
   116  // newLeaf constructs a leaf node with provided node key and value. The key
   117  // will be deep-copied in the function and safe to modify afterwards, but
   118  // value is not.
   119  func newLeaf(key, val []byte) *stNode {
   120  	st := stPool.Get().(*stNode)
   121  	st.typ = leafNode
   122  	st.key = append(st.key, key...)
   123  	st.val = val
   124  	return st
   125  }
   126  
   127  // newExt constructs an extension node with provided node key and child. The
   128  // key will be deep-copied in the function and safe to modify afterwards.
   129  func newExt(key []byte, child *stNode) *stNode {
   130  	st := stPool.Get().(*stNode)
   131  	st.typ = extNode
   132  	st.key = append(st.key, key...)
   133  	st.children[0] = child
   134  	return st
   135  }
   136  
   137  // List all values that stNode#nodeType can hold
   138  const (
   139  	emptyNode = iota
   140  	branchNode
   141  	extNode
   142  	leafNode
   143  	hashedNode
   144  )
   145  
   146  func (n *stNode) reset() *stNode {
   147  	if n.typ == hashedNode {
   148  		// On hashnodes, we 'own' the val: it is guaranteed to be not held
   149  		// by external caller. Hence, when we arrive here, we can put it back
   150  		// into the pool
   151  		bPool.Put(n.val)
   152  	}
   153  	n.key = n.key[:0]
   154  	n.val = nil
   155  	for i := range n.children {
   156  		n.children[i] = nil
   157  	}
   158  	n.typ = emptyNode
   159  	return n
   160  }
   161  
   162  // Helper function that, given a full key, determines the index
   163  // at which the chunk pointed by st.keyOffset is different from
   164  // the same chunk in the full key.
   165  func (n *stNode) getDiffIndex(key []byte) int {
   166  	for idx, nibble := range n.key {
   167  		if nibble != key[idx] {
   168  			return idx
   169  		}
   170  	}
   171  	return len(n.key)
   172  }
   173  
   174  // Helper function to that inserts a (key, value) pair into the trie.
   175  //
   176  //   - The key is not retained by this method, but always copied if needed.
   177  //   - The value is retained by this method, as long as the leaf that it represents
   178  //     remains unhashed. However: it is never modified.
   179  //   - The path is not retained by this method.
   180  func (t *StackTrie) insert(st *stNode, key, value []byte, path []byte) {
   181  	switch st.typ {
   182  	case branchNode: /* Branch */
   183  		idx := int(key[0])
   184  
   185  		// Unresolve elder siblings
   186  		for i := idx - 1; i >= 0; i-- {
   187  			if st.children[i] != nil {
   188  				if st.children[i].typ != hashedNode {
   189  					t.hash(st.children[i], append(path, byte(i)))
   190  				}
   191  				break
   192  			}
   193  		}
   194  
   195  		// Add new child
   196  		if st.children[idx] == nil {
   197  			st.children[idx] = newLeaf(key[1:], value)
   198  		} else {
   199  			t.insert(st.children[idx], key[1:], value, append(path, key[0]))
   200  		}
   201  
   202  	case extNode: /* Ext */
   203  		// Compare both key chunks and see where they differ
   204  		diffidx := st.getDiffIndex(key)
   205  
   206  		// Check if chunks are identical. If so, recurse into
   207  		// the child node. Otherwise, the key has to be split
   208  		// into 1) an optional common prefix, 2) the fullnode
   209  		// representing the two differing path, and 3) a leaf
   210  		// for each of the differentiated subtrees.
   211  		if diffidx == len(st.key) {
   212  			// Ext key and key segment are identical, recurse into
   213  			// the child node.
   214  			t.insert(st.children[0], key[diffidx:], value, append(path, key[:diffidx]...))
   215  			return
   216  		}
   217  		// Save the original part. Depending if the break is
   218  		// at the extension's last byte or not, create an
   219  		// intermediate extension or use the extension's child
   220  		// node directly.
   221  		var n *stNode
   222  		if diffidx < len(st.key)-1 {
   223  			// Break on the non-last byte, insert an intermediate
   224  			// extension. The path prefix of the newly-inserted
   225  			// extension should also contain the different byte.
   226  			n = newExt(st.key[diffidx+1:], st.children[0])
   227  			t.hash(n, append(path, st.key[:diffidx+1]...))
   228  		} else {
   229  			// Break on the last byte, no need to insert
   230  			// an extension node: reuse the current node.
   231  			// The path prefix of the original part should
   232  			// still be same.
   233  			n = st.children[0]
   234  			t.hash(n, append(path, st.key...))
   235  		}
   236  		var p *stNode
   237  		if diffidx == 0 {
   238  			// the break is on the first byte, so
   239  			// the current node is converted into
   240  			// a branch node.
   241  			st.children[0] = nil
   242  			p = st
   243  			st.typ = branchNode
   244  		} else {
   245  			// the common prefix is at least one byte
   246  			// long, insert a new intermediate branch
   247  			// node.
   248  			st.children[0] = stPool.Get().(*stNode)
   249  			st.children[0].typ = branchNode
   250  			p = st.children[0]
   251  		}
   252  		// Create a leaf for the inserted part
   253  		o := newLeaf(key[diffidx+1:], value)
   254  
   255  		// Insert both child leaves where they belong:
   256  		origIdx := st.key[diffidx]
   257  		newIdx := key[diffidx]
   258  		p.children[origIdx] = n
   259  		p.children[newIdx] = o
   260  		st.key = st.key[:diffidx]
   261  
   262  	case leafNode: /* Leaf */
   263  		// Compare both key chunks and see where they differ
   264  		diffidx := st.getDiffIndex(key)
   265  
   266  		// Overwriting a key isn't supported, which means that
   267  		// the current leaf is expected to be split into 1) an
   268  		// optional extension for the common prefix of these 2
   269  		// keys, 2) a fullnode selecting the path on which the
   270  		// keys differ, and 3) one leaf for the differentiated
   271  		// component of each key.
   272  		if diffidx >= len(st.key) {
   273  			panic("Trying to insert into existing key")
   274  		}
   275  
   276  		// Check if the split occurs at the first nibble of the
   277  		// chunk. In that case, no prefix extnode is necessary.
   278  		// Otherwise, create that
   279  		var p *stNode
   280  		if diffidx == 0 {
   281  			// Convert current leaf into a branch
   282  			st.typ = branchNode
   283  			p = st
   284  			st.children[0] = nil
   285  		} else {
   286  			// Convert current node into an ext,
   287  			// and insert a child branch node.
   288  			st.typ = extNode
   289  			st.children[0] = stPool.Get().(*stNode)
   290  			st.children[0].typ = branchNode
   291  			p = st.children[0]
   292  		}
   293  
   294  		// Create the two child leaves: one containing the original
   295  		// value and another containing the new value. The child leaf
   296  		// is hashed directly in order to free up some memory.
   297  		origIdx := st.key[diffidx]
   298  		p.children[origIdx] = newLeaf(st.key[diffidx+1:], st.val)
   299  		t.hash(p.children[origIdx], append(path, st.key[:diffidx+1]...))
   300  
   301  		newIdx := key[diffidx]
   302  		p.children[newIdx] = newLeaf(key[diffidx+1:], value)
   303  
   304  		// Finally, cut off the key part that has been passed
   305  		// over to the children.
   306  		st.key = st.key[:diffidx]
   307  		st.val = nil
   308  
   309  	case emptyNode: /* Empty */
   310  		st.typ = leafNode
   311  		st.key = append(st.key, key...) // deep-copy the key as it's volatile
   312  		st.val = value
   313  
   314  	case hashedNode:
   315  		panic("trying to insert into hash")
   316  
   317  	default:
   318  		panic("invalid type")
   319  	}
   320  }
   321  
   322  // hash converts st into a 'hashedNode', if possible. Possible outcomes:
   323  //
   324  // 1. The rlp-encoded value was >= 32 bytes:
   325  //   - Then the 32-byte `hash` will be accessible in `st.val`.
   326  //   - And the 'st.type' will be 'hashedNode'
   327  //
   328  // 2. The rlp-encoded value was < 32 bytes
   329  //   - Then the <32 byte rlp-encoded value will be accessible in 'st.val'.
   330  //   - And the 'st.type' will be 'hashedNode' AGAIN
   331  //
   332  // This method also sets 'st.type' to hashedNode, and clears 'st.key'.
   333  func (t *StackTrie) hash(st *stNode, path []byte) {
   334  	var blob []byte // RLP-encoded node blob
   335  	switch st.typ {
   336  	case hashedNode:
   337  		return
   338  
   339  	case emptyNode:
   340  		st.val = types.EmptyRootHash.Bytes()
   341  		st.key = st.key[:0]
   342  		st.typ = hashedNode
   343  		return
   344  
   345  	case branchNode:
   346  		var nodes fullnodeEncoder
   347  		for i, child := range st.children {
   348  			if child == nil {
   349  				continue
   350  			}
   351  			t.hash(child, append(path, byte(i)))
   352  			nodes.Children[i] = child.val
   353  		}
   354  		nodes.encode(t.h.encbuf)
   355  		blob = t.h.encodedBytes()
   356  
   357  		for i, child := range st.children {
   358  			if child == nil {
   359  				continue
   360  			}
   361  			st.children[i] = nil
   362  			stPool.Put(child.reset()) // Release child back to pool.
   363  		}
   364  
   365  	case extNode:
   366  		// recursively hash and commit child as the first step
   367  		t.hash(st.children[0], append(path, st.key...))
   368  
   369  		// encode the extension node
   370  		n := extNodeEncoder{
   371  			Key: hexToCompactInPlace(st.key),
   372  			Val: st.children[0].val,
   373  		}
   374  		n.encode(t.h.encbuf)
   375  		blob = t.h.encodedBytes()
   376  
   377  		stPool.Put(st.children[0].reset()) // Release child back to pool.
   378  		st.children[0] = nil
   379  
   380  	case leafNode:
   381  		st.key = append(st.key, byte(16))
   382  		n := leafNodeEncoder{
   383  			Key: hexToCompactInPlace(st.key),
   384  			Val: st.val,
   385  		}
   386  		n.encode(t.h.encbuf)
   387  		blob = t.h.encodedBytes()
   388  
   389  	default:
   390  		panic("invalid node type")
   391  	}
   392  	// Convert the node type to hashNode and reset the key slice.
   393  	st.typ = hashedNode
   394  	st.key = st.key[:0]
   395  
   396  	st.val = nil // Release reference to potentially externally held slice.
   397  
   398  	// Skip committing the non-root node if the size is smaller than 32 bytes
   399  	// as tiny nodes are always embedded in their parent except root node.
   400  	if len(blob) < 32 && len(path) > 0 {
   401  		st.val = bPool.GetWithSize(len(blob))
   402  		copy(st.val, blob)
   403  		return
   404  	}
   405  	// Write the hash to the 'val'. We allocate a new val here to not mutate
   406  	// input values.
   407  	st.val = bPool.GetWithSize(32)
   408  	t.h.hashDataTo(st.val, blob)
   409  
   410  	// Invoke the callback it's provided. Notably, the path and blob slices are
   411  	// volatile, please deep-copy the slices in callback if the contents need
   412  	// to be retained.
   413  	if t.onTrieNode != nil {
   414  		t.onTrieNode(path, common.BytesToHash(st.val), blob)
   415  	}
   416  }
   417  
   418  // Hash will firstly hash the entire trie if it's still not hashed and then commit
   419  // all leftover nodes to the associated database. Actually most of the trie nodes
   420  // have been committed already. The main purpose here is to commit the nodes on
   421  // right boundary.
   422  func (t *StackTrie) Hash() common.Hash {
   423  	n := t.root
   424  	t.hash(n, nil)
   425  	return common.BytesToHash(n.val)
   426  }