github.com/MetalBlockchain/metalgo@v1.11.9/x/merkledb/node.go (about)

     1  // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package merkledb
     5  
     6  import (
     7  	"slices"
     8  
     9  	"github.com/MetalBlockchain/metalgo/ids"
    10  	"github.com/MetalBlockchain/metalgo/utils/maybe"
    11  )
    12  
    13  // Representation of a node stored in the database.
    14  type dbNode struct {
    15  	value    maybe.Maybe[[]byte]
    16  	children map[byte]*child
    17  }
    18  
    19  type child struct {
    20  	compressedKey Key
    21  	id            ids.ID
    22  	hasValue      bool
    23  }
    24  
    25  // node holds additional information on top of the dbNode that makes calculations easier to do
    26  type node struct {
    27  	dbNode
    28  	key         Key
    29  	valueDigest maybe.Maybe[[]byte]
    30  }
    31  
    32  // Returns a new node with the given [key] and no value.
    33  func newNode(key Key) *node {
    34  	return &node{
    35  		dbNode: dbNode{
    36  			children: make(map[byte]*child, 2),
    37  		},
    38  		key: key,
    39  	}
    40  }
    41  
    42  // Parse [nodeBytes] to a node and set its key to [key].
    43  func parseNode(hasher Hasher, key Key, nodeBytes []byte) (*node, error) {
    44  	n := dbNode{}
    45  	if err := decodeDBNode(nodeBytes, &n); err != nil {
    46  		return nil, err
    47  	}
    48  	result := &node{
    49  		dbNode: n,
    50  		key:    key,
    51  	}
    52  
    53  	result.setValueDigest(hasher)
    54  	return result, nil
    55  }
    56  
    57  // Returns true iff this node has a value.
    58  func (n *node) hasValue() bool {
    59  	return !n.value.IsNothing()
    60  }
    61  
    62  // Returns the byte representation of this node.
    63  func (n *node) bytes() []byte {
    64  	return encodeDBNode(&n.dbNode)
    65  }
    66  
    67  // Set [n]'s value to [val].
    68  func (n *node) setValue(hasher Hasher, val maybe.Maybe[[]byte]) {
    69  	n.value = val
    70  	n.setValueDigest(hasher)
    71  }
    72  
    73  func (n *node) setValueDigest(hasher Hasher) {
    74  	if n.value.IsNothing() || len(n.value.Value()) < HashLength {
    75  		n.valueDigest = n.value
    76  	} else {
    77  		hash := hasher.HashValue(n.value.Value())
    78  		n.valueDigest = maybe.Some(hash[:])
    79  	}
    80  }
    81  
    82  // Adds [child] as a child of [n].
    83  // Assumes [child]'s key is valid as a child of [n].
    84  // That is, [n.key] is a prefix of [child.key].
    85  func (n *node) addChild(childNode *node, tokenSize int) {
    86  	n.addChildWithID(childNode, tokenSize, ids.Empty)
    87  }
    88  
    89  func (n *node) addChildWithID(childNode *node, tokenSize int, childID ids.ID) {
    90  	n.setChildEntry(
    91  		childNode.key.Token(n.key.length, tokenSize),
    92  		&child{
    93  			compressedKey: childNode.key.Skip(n.key.length + tokenSize),
    94  			id:            childID,
    95  			hasValue:      childNode.hasValue(),
    96  		},
    97  	)
    98  }
    99  
   100  // Adds a child to [n] without a reference to the child node.
   101  func (n *node) setChildEntry(index byte, childEntry *child) {
   102  	n.children[index] = childEntry
   103  }
   104  
   105  // Removes [child] from [n]'s children.
   106  func (n *node) removeChild(child *node, tokenSize int) {
   107  	delete(n.children, child.key.Token(n.key.length, tokenSize))
   108  }
   109  
   110  // clone Returns a copy of [n].
   111  // Note: value isn't cloned because it is never edited, only overwritten
   112  // if this ever changes, value will need to be copied as well
   113  // it is safe to clone all fields because they are only written/read while one or both of the db locks are held
   114  func (n *node) clone() *node {
   115  	result := &node{
   116  		key: n.key,
   117  		dbNode: dbNode{
   118  			value:    n.value,
   119  			children: make(map[byte]*child, len(n.children)),
   120  		},
   121  		valueDigest: n.valueDigest,
   122  	}
   123  	for key, existing := range n.children {
   124  		result.children[key] = &child{
   125  			compressedKey: existing.compressedKey,
   126  			id:            existing.id,
   127  			hasValue:      existing.hasValue,
   128  		}
   129  	}
   130  	return result
   131  }
   132  
   133  // Returns the ProofNode representation of this node.
   134  func (n *node) asProofNode() ProofNode {
   135  	pn := ProofNode{
   136  		Key:         n.key,
   137  		Children:    make(map[byte]ids.ID, len(n.children)),
   138  		ValueOrHash: maybe.Bind(n.valueDigest, slices.Clone[[]byte]),
   139  	}
   140  	for index, entry := range n.children {
   141  		pn.Children[index] = entry.id
   142  	}
   143  	return pn
   144  }