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

     1  // Copyright 2023 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 trienode
    18  
    19  import (
    20  	"fmt"
    21  	"maps"
    22  	"sort"
    23  	"strings"
    24  
    25  	"github.com/ethereum/go-ethereum/common"
    26  )
    27  
    28  // Node is a wrapper which contains the encoded blob of the trie node and its
    29  // node hash. It is general enough that can be used to represent trie node
    30  // corresponding to different trie implementations.
    31  type Node struct {
    32  	Hash common.Hash // Node hash, empty for deleted node
    33  	Blob []byte      // Encoded node blob, nil for the deleted node
    34  }
    35  
    36  // Size returns the total memory size used by this node.
    37  func (n *Node) Size() int {
    38  	return len(n.Blob) + common.HashLength
    39  }
    40  
    41  // IsDeleted returns the indicator if the node is marked as deleted.
    42  func (n *Node) IsDeleted() bool {
    43  	return len(n.Blob) == 0
    44  }
    45  
    46  // New constructs a node with provided node information.
    47  func New(hash common.Hash, blob []byte) *Node {
    48  	return &Node{Hash: hash, Blob: blob}
    49  }
    50  
    51  // NewDeleted constructs a node which is deleted.
    52  func NewDeleted() *Node { return New(common.Hash{}, nil) }
    53  
    54  // leaf represents a trie leaf node
    55  type leaf struct {
    56  	Blob   []byte      // raw blob of leaf
    57  	Parent common.Hash // the hash of parent node
    58  }
    59  
    60  // NodeSet contains a set of nodes collected during the commit operation.
    61  // Each node is keyed by path. It's not thread-safe to use.
    62  type NodeSet struct {
    63  	Owner   common.Hash
    64  	Leaves  []*leaf
    65  	Nodes   map[string]*Node
    66  	updates int // the count of updated and inserted nodes
    67  	deletes int // the count of deleted nodes
    68  }
    69  
    70  // NewNodeSet initializes a node set. The owner is zero for the account trie and
    71  // the owning account address hash for storage tries.
    72  func NewNodeSet(owner common.Hash) *NodeSet {
    73  	return &NodeSet{
    74  		Owner: owner,
    75  		Nodes: make(map[string]*Node),
    76  	}
    77  }
    78  
    79  // ForEachWithOrder iterates the nodes with the order from bottom to top,
    80  // right to left, nodes with the longest path will be iterated first.
    81  func (set *NodeSet) ForEachWithOrder(callback func(path string, n *Node)) {
    82  	paths := make([]string, 0, len(set.Nodes))
    83  	for path := range set.Nodes {
    84  		paths = append(paths, path)
    85  	}
    86  	// Bottom-up, the longest path first
    87  	sort.Sort(sort.Reverse(sort.StringSlice(paths)))
    88  	for _, path := range paths {
    89  		callback(path, set.Nodes[path])
    90  	}
    91  }
    92  
    93  // AddNode adds the provided node into set.
    94  func (set *NodeSet) AddNode(path []byte, n *Node) {
    95  	if n.IsDeleted() {
    96  		set.deletes += 1
    97  	} else {
    98  		set.updates += 1
    99  	}
   100  	set.Nodes[string(path)] = n
   101  }
   102  
   103  // MergeSet merges this 'set' with 'other'. It assumes that the sets are disjoint,
   104  // and thus does not deduplicate data (count deletes, dedup leaves etc).
   105  func (set *NodeSet) MergeSet(other *NodeSet) error {
   106  	if set.Owner != other.Owner {
   107  		return fmt.Errorf("nodesets belong to different owner are not mergeable %x-%x", set.Owner, other.Owner)
   108  	}
   109  	maps.Copy(set.Nodes, other.Nodes)
   110  
   111  	set.deletes += other.deletes
   112  	set.updates += other.updates
   113  
   114  	// Since we assume the sets are disjoint, we can safely append leaves
   115  	// like this without deduplication.
   116  	set.Leaves = append(set.Leaves, other.Leaves...)
   117  	return nil
   118  }
   119  
   120  // Merge adds a set of nodes into the set.
   121  func (set *NodeSet) Merge(owner common.Hash, nodes map[string]*Node) error {
   122  	if set.Owner != owner {
   123  		return fmt.Errorf("nodesets belong to different owner are not mergeable %x-%x", set.Owner, owner)
   124  	}
   125  	for path, node := range nodes {
   126  		prev, ok := set.Nodes[path]
   127  		if ok {
   128  			// overwrite happens, revoke the counter
   129  			if prev.IsDeleted() {
   130  				set.deletes -= 1
   131  			} else {
   132  				set.updates -= 1
   133  			}
   134  		}
   135  		if node.IsDeleted() {
   136  			set.deletes += 1
   137  		} else {
   138  			set.updates += 1
   139  		}
   140  		set.Nodes[path] = node
   141  	}
   142  	return nil
   143  }
   144  
   145  // AddLeaf adds the provided leaf node into set. TODO(rjl493456442) how can
   146  // we get rid of it?
   147  func (set *NodeSet) AddLeaf(parent common.Hash, blob []byte) {
   148  	set.Leaves = append(set.Leaves, &leaf{Blob: blob, Parent: parent})
   149  }
   150  
   151  // Size returns the number of dirty nodes in set.
   152  func (set *NodeSet) Size() (int, int) {
   153  	return set.updates, set.deletes
   154  }
   155  
   156  // HashSet returns a set of trie nodes keyed by node hash.
   157  func (set *NodeSet) HashSet() map[common.Hash][]byte {
   158  	ret := make(map[common.Hash][]byte, len(set.Nodes))
   159  	for _, n := range set.Nodes {
   160  		ret[n.Hash] = n.Blob
   161  	}
   162  	return ret
   163  }
   164  
   165  // Summary returns a string-representation of the NodeSet.
   166  func (set *NodeSet) Summary() string {
   167  	var out = new(strings.Builder)
   168  	fmt.Fprintf(out, "nodeset owner: %v\n", set.Owner)
   169  	for path, n := range set.Nodes {
   170  		// Deletion
   171  		if n.IsDeleted() {
   172  			fmt.Fprintf(out, "  [-]: %x\n", path)
   173  			continue
   174  		}
   175  		// Insertion or update
   176  		fmt.Fprintf(out, "  [+/*]: %x -> %v \n", path, n.Hash)
   177  	}
   178  	for _, n := range set.Leaves {
   179  		fmt.Fprintf(out, "[leaf]: %v\n", n)
   180  	}
   181  	return out.String()
   182  }
   183  
   184  // MergedNodeSet represents a merged node set for a group of tries.
   185  type MergedNodeSet struct {
   186  	Sets map[common.Hash]*NodeSet
   187  }
   188  
   189  // NewMergedNodeSet initializes an empty merged set.
   190  func NewMergedNodeSet() *MergedNodeSet {
   191  	return &MergedNodeSet{Sets: make(map[common.Hash]*NodeSet)}
   192  }
   193  
   194  // NewWithNodeSet constructs a merged nodeset with the provided single set.
   195  func NewWithNodeSet(set *NodeSet) *MergedNodeSet {
   196  	merged := NewMergedNodeSet()
   197  	merged.Merge(set)
   198  	return merged
   199  }
   200  
   201  // Merge merges the provided dirty nodes of a trie into the set. The assumption
   202  // is held that no duplicated set belonging to the same trie will be merged twice.
   203  func (set *MergedNodeSet) Merge(other *NodeSet) error {
   204  	subset, present := set.Sets[other.Owner]
   205  	if present {
   206  		return subset.Merge(other.Owner, other.Nodes)
   207  	}
   208  	set.Sets[other.Owner] = other
   209  	return nil
   210  }
   211  
   212  // Flatten returns a two-dimensional map for internal nodes.
   213  func (set *MergedNodeSet) Flatten() map[common.Hash]map[string]*Node {
   214  	nodes := make(map[common.Hash]map[string]*Node, len(set.Sets))
   215  	for owner, set := range set.Sets {
   216  		nodes[owner] = set.Nodes
   217  	}
   218  	return nodes
   219  }