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 }