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 }