github.com/electroneum/electroneum-sc@v0.0.0-20230105223411-3bc1d078281e/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 "bufio" 21 "bytes" 22 "encoding/gob" 23 "errors" 24 "fmt" 25 "io" 26 "sync" 27 28 "github.com/electroneum/electroneum-sc/common" 29 "github.com/electroneum/electroneum-sc/ethdb" 30 "github.com/electroneum/electroneum-sc/log" 31 ) 32 33 var ErrCommitDisabled = errors.New("no database for committing") 34 35 var stPool = sync.Pool{ 36 New: func() interface{} { 37 return NewStackTrie(nil) 38 }, 39 } 40 41 func stackTrieFromPool(db ethdb.KeyValueWriter) *StackTrie { 42 st := stPool.Get().(*StackTrie) 43 st.db = db 44 return st 45 } 46 47 func returnToPool(st *StackTrie) { 48 st.Reset() 49 stPool.Put(st) 50 } 51 52 // StackTrie is a trie implementation that expects keys to be inserted 53 // in order. Once it determines that a subtree will no longer be inserted 54 // into, it will hash it and free up the memory it uses. 55 type StackTrie struct { 56 nodeType uint8 // node type (as in branch, ext, leaf) 57 val []byte // value contained by this node if it's a leaf 58 key []byte // key chunk covered by this (leaf|ext) node 59 children [16]*StackTrie // list of children (for branch and exts) 60 db ethdb.KeyValueWriter // Pointer to the commit db, can be nil 61 } 62 63 // NewStackTrie allocates and initializes an empty trie. 64 func NewStackTrie(db ethdb.KeyValueWriter) *StackTrie { 65 return &StackTrie{ 66 nodeType: emptyNode, 67 db: db, 68 } 69 } 70 71 // NewFromBinary initialises a serialized stacktrie with the given db. 72 func NewFromBinary(data []byte, db ethdb.KeyValueWriter) (*StackTrie, error) { 73 var st StackTrie 74 if err := st.UnmarshalBinary(data); err != nil { 75 return nil, err 76 } 77 // If a database is used, we need to recursively add it to every child 78 if db != nil { 79 st.setDb(db) 80 } 81 return &st, nil 82 } 83 84 // MarshalBinary implements encoding.BinaryMarshaler 85 func (st *StackTrie) MarshalBinary() (data []byte, err error) { 86 var ( 87 b bytes.Buffer 88 w = bufio.NewWriter(&b) 89 ) 90 if err := gob.NewEncoder(w).Encode(struct { 91 Nodetype uint8 92 Val []byte 93 Key []byte 94 }{ 95 st.nodeType, 96 st.val, 97 st.key, 98 }); err != nil { 99 return nil, err 100 } 101 for _, child := range st.children { 102 if child == nil { 103 w.WriteByte(0) 104 continue 105 } 106 w.WriteByte(1) 107 if childData, err := child.MarshalBinary(); err != nil { 108 return nil, err 109 } else { 110 w.Write(childData) 111 } 112 } 113 w.Flush() 114 return b.Bytes(), nil 115 } 116 117 // UnmarshalBinary implements encoding.BinaryUnmarshaler 118 func (st *StackTrie) UnmarshalBinary(data []byte) error { 119 r := bytes.NewReader(data) 120 return st.unmarshalBinary(r) 121 } 122 123 func (st *StackTrie) unmarshalBinary(r io.Reader) error { 124 var dec struct { 125 Nodetype uint8 126 Val []byte 127 Key []byte 128 } 129 gob.NewDecoder(r).Decode(&dec) 130 st.nodeType = dec.Nodetype 131 st.val = dec.Val 132 st.key = dec.Key 133 134 var hasChild = make([]byte, 1) 135 for i := range st.children { 136 if _, err := r.Read(hasChild); err != nil { 137 return err 138 } else if hasChild[0] == 0 { 139 continue 140 } 141 var child StackTrie 142 child.unmarshalBinary(r) 143 st.children[i] = &child 144 } 145 return nil 146 } 147 148 func (st *StackTrie) setDb(db ethdb.KeyValueWriter) { 149 st.db = db 150 for _, child := range st.children { 151 if child != nil { 152 child.setDb(db) 153 } 154 } 155 } 156 157 func newLeaf(key, val []byte, db ethdb.KeyValueWriter) *StackTrie { 158 st := stackTrieFromPool(db) 159 st.nodeType = leafNode 160 st.key = append(st.key, key...) 161 st.val = val 162 return st 163 } 164 165 func newExt(key []byte, child *StackTrie, db ethdb.KeyValueWriter) *StackTrie { 166 st := stackTrieFromPool(db) 167 st.nodeType = extNode 168 st.key = append(st.key, key...) 169 st.children[0] = child 170 return st 171 } 172 173 // List all values that StackTrie#nodeType can hold 174 const ( 175 emptyNode = iota 176 branchNode 177 extNode 178 leafNode 179 hashedNode 180 ) 181 182 // TryUpdate inserts a (key, value) pair into the stack trie 183 func (st *StackTrie) TryUpdate(key, value []byte) error { 184 k := keybytesToHex(key) 185 if len(value) == 0 { 186 panic("deletion not supported") 187 } 188 st.insert(k[:len(k)-1], value) 189 return nil 190 } 191 192 func (st *StackTrie) Update(key, value []byte) { 193 if err := st.TryUpdate(key, value); err != nil { 194 log.Error(fmt.Sprintf("Unhandled trie error: %v", err)) 195 } 196 } 197 198 func (st *StackTrie) Reset() { 199 st.db = nil 200 st.key = st.key[:0] 201 st.val = nil 202 for i := range st.children { 203 st.children[i] = nil 204 } 205 st.nodeType = emptyNode 206 } 207 208 // Helper function that, given a full key, determines the index 209 // at which the chunk pointed by st.keyOffset is different from 210 // the same chunk in the full key. 211 func (st *StackTrie) getDiffIndex(key []byte) int { 212 for idx, nibble := range st.key { 213 if nibble != key[idx] { 214 return idx 215 } 216 } 217 return len(st.key) 218 } 219 220 // Helper function to that inserts a (key, value) pair into 221 // the trie. 222 func (st *StackTrie) insert(key, value []byte) { 223 switch st.nodeType { 224 case branchNode: /* Branch */ 225 idx := int(key[0]) 226 227 // Unresolve elder siblings 228 for i := idx - 1; i >= 0; i-- { 229 if st.children[i] != nil { 230 if st.children[i].nodeType != hashedNode { 231 st.children[i].hash() 232 } 233 break 234 } 235 } 236 237 // Add new child 238 if st.children[idx] == nil { 239 st.children[idx] = newLeaf(key[1:], value, st.db) 240 } else { 241 st.children[idx].insert(key[1:], value) 242 } 243 244 case extNode: /* Ext */ 245 // Compare both key chunks and see where they differ 246 diffidx := st.getDiffIndex(key) 247 248 // Check if chunks are identical. If so, recurse into 249 // the child node. Otherwise, the key has to be split 250 // into 1) an optional common prefix, 2) the fullnode 251 // representing the two differing path, and 3) a leaf 252 // for each of the differentiated subtrees. 253 if diffidx == len(st.key) { 254 // Ext key and key segment are identical, recurse into 255 // the child node. 256 st.children[0].insert(key[diffidx:], value) 257 return 258 } 259 // Save the original part. Depending if the break is 260 // at the extension's last byte or not, create an 261 // intermediate extension or use the extension's child 262 // node directly. 263 var n *StackTrie 264 if diffidx < len(st.key)-1 { 265 n = newExt(st.key[diffidx+1:], st.children[0], st.db) 266 } else { 267 // Break on the last byte, no need to insert 268 // an extension node: reuse the current node 269 n = st.children[0] 270 } 271 // Convert to hash 272 n.hash() 273 var p *StackTrie 274 if diffidx == 0 { 275 // the break is on the first byte, so 276 // the current node is converted into 277 // a branch node. 278 st.children[0] = nil 279 p = st 280 st.nodeType = branchNode 281 } else { 282 // the common prefix is at least one byte 283 // long, insert a new intermediate branch 284 // node. 285 st.children[0] = stackTrieFromPool(st.db) 286 st.children[0].nodeType = branchNode 287 p = st.children[0] 288 } 289 // Create a leaf for the inserted part 290 o := newLeaf(key[diffidx+1:], value, st.db) 291 292 // Insert both child leaves where they belong: 293 origIdx := st.key[diffidx] 294 newIdx := key[diffidx] 295 p.children[origIdx] = n 296 p.children[newIdx] = o 297 st.key = st.key[:diffidx] 298 299 case leafNode: /* Leaf */ 300 // Compare both key chunks and see where they differ 301 diffidx := st.getDiffIndex(key) 302 303 // Overwriting a key isn't supported, which means that 304 // the current leaf is expected to be split into 1) an 305 // optional extension for the common prefix of these 2 306 // keys, 2) a fullnode selecting the path on which the 307 // keys differ, and 3) one leaf for the differentiated 308 // component of each key. 309 if diffidx >= len(st.key) { 310 panic("Trying to insert into existing key") 311 } 312 313 // Check if the split occurs at the first nibble of the 314 // chunk. In that case, no prefix extnode is necessary. 315 // Otherwise, create that 316 var p *StackTrie 317 if diffidx == 0 { 318 // Convert current leaf into a branch 319 st.nodeType = branchNode 320 p = st 321 st.children[0] = nil 322 } else { 323 // Convert current node into an ext, 324 // and insert a child branch node. 325 st.nodeType = extNode 326 st.children[0] = NewStackTrie(st.db) 327 st.children[0].nodeType = branchNode 328 p = st.children[0] 329 } 330 331 // Create the two child leaves: one containing the original 332 // value and another containing the new value. The child leaf 333 // is hashed directly in order to free up some memory. 334 origIdx := st.key[diffidx] 335 p.children[origIdx] = newLeaf(st.key[diffidx+1:], st.val, st.db) 336 p.children[origIdx].hash() 337 338 newIdx := key[diffidx] 339 p.children[newIdx] = newLeaf(key[diffidx+1:], value, st.db) 340 341 // Finally, cut off the key part that has been passed 342 // over to the children. 343 st.key = st.key[:diffidx] 344 st.val = nil 345 346 case emptyNode: /* Empty */ 347 st.nodeType = leafNode 348 st.key = key 349 st.val = value 350 351 case hashedNode: 352 panic("trying to insert into hash") 353 354 default: 355 panic("invalid type") 356 } 357 } 358 359 // hash converts st into a 'hashedNode', if possible. Possible outcomes: 360 // 361 // 1. The rlp-encoded value was >= 32 bytes: 362 // - Then the 32-byte `hash` will be accessible in `st.val`. 363 // - And the 'st.type' will be 'hashedNode' 364 // 365 // 2. The rlp-encoded value was < 32 bytes 366 // - Then the <32 byte rlp-encoded value will be accessible in 'st.val'. 367 // - And the 'st.type' will be 'hashedNode' AGAIN 368 // 369 // This method also sets 'st.type' to hashedNode, and clears 'st.key'. 370 func (st *StackTrie) hash() { 371 h := newHasher(false) 372 defer returnHasherToPool(h) 373 374 st.hashRec(h) 375 } 376 377 func (st *StackTrie) hashRec(hasher *hasher) { 378 // The switch below sets this to the RLP-encoding of this node. 379 var encodedNode []byte 380 381 switch st.nodeType { 382 case hashedNode: 383 return 384 385 case emptyNode: 386 st.val = emptyRoot.Bytes() 387 st.key = st.key[:0] 388 st.nodeType = hashedNode 389 return 390 391 case branchNode: 392 var nodes rawFullNode 393 for i, child := range st.children { 394 if child == nil { 395 nodes[i] = nilValueNode 396 continue 397 } 398 399 child.hashRec(hasher) 400 if len(child.val) < 32 { 401 nodes[i] = rawNode(child.val) 402 } else { 403 nodes[i] = hashNode(child.val) 404 } 405 406 // Release child back to pool. 407 st.children[i] = nil 408 returnToPool(child) 409 } 410 411 nodes.encode(hasher.encbuf) 412 encodedNode = hasher.encodedBytes() 413 414 case extNode: 415 st.children[0].hashRec(hasher) 416 417 sz := hexToCompactInPlace(st.key) 418 n := rawShortNode{Key: st.key[:sz]} 419 if len(st.children[0].val) < 32 { 420 n.Val = rawNode(st.children[0].val) 421 } else { 422 n.Val = hashNode(st.children[0].val) 423 } 424 425 n.encode(hasher.encbuf) 426 encodedNode = hasher.encodedBytes() 427 428 // Release child back to pool. 429 returnToPool(st.children[0]) 430 st.children[0] = nil 431 432 case leafNode: 433 st.key = append(st.key, byte(16)) 434 sz := hexToCompactInPlace(st.key) 435 n := rawShortNode{Key: st.key[:sz], Val: valueNode(st.val)} 436 437 n.encode(hasher.encbuf) 438 encodedNode = hasher.encodedBytes() 439 440 default: 441 panic("invalid node type") 442 } 443 444 st.nodeType = hashedNode 445 st.key = st.key[:0] 446 if len(encodedNode) < 32 { 447 st.val = common.CopyBytes(encodedNode) 448 return 449 } 450 451 // Write the hash to the 'val'. We allocate a new val here to not mutate 452 // input values 453 st.val = hasher.hashData(encodedNode) 454 if st.db != nil { 455 // TODO! Is it safe to Put the slice here? 456 // Do all db implementations copy the value provided? 457 st.db.Put(st.val, encodedNode) 458 } 459 } 460 461 // Hash returns the hash of the current node. 462 func (st *StackTrie) Hash() (h common.Hash) { 463 hasher := newHasher(false) 464 defer returnHasherToPool(hasher) 465 466 st.hashRec(hasher) 467 if len(st.val) == 32 { 468 copy(h[:], st.val) 469 return h 470 } 471 472 // If the node's RLP isn't 32 bytes long, the node will not 473 // be hashed, and instead contain the rlp-encoding of the 474 // node. For the top level node, we need to force the hashing. 475 hasher.sha.Reset() 476 hasher.sha.Write(st.val) 477 hasher.sha.Read(h[:]) 478 return h 479 } 480 481 // Commit will firstly hash the entrie trie if it's still not hashed 482 // and then commit all nodes to the associated database. Actually most 483 // of the trie nodes MAY have been committed already. The main purpose 484 // here is to commit the root node. 485 // 486 // The associated database is expected, otherwise the whole commit 487 // functionality should be disabled. 488 func (st *StackTrie) Commit() (h common.Hash, err error) { 489 if st.db == nil { 490 return common.Hash{}, ErrCommitDisabled 491 } 492 493 hasher := newHasher(false) 494 defer returnHasherToPool(hasher) 495 496 st.hashRec(hasher) 497 if len(st.val) == 32 { 498 copy(h[:], st.val) 499 return h, nil 500 } 501 502 // If the node's RLP isn't 32 bytes long, the node will not 503 // be hashed (and committed), and instead contain the rlp-encoding of the 504 // node. For the top level node, we need to force the hashing+commit. 505 hasher.sha.Reset() 506 hasher.sha.Write(st.val) 507 hasher.sha.Read(h[:]) 508 st.db.Put(h[:], st.val) 509 return h, nil 510 }