github.com/MetalBlockchain/metalgo@v1.11.9/x/merkledb/view.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 "context" 8 "errors" 9 "slices" 10 "sync" 11 12 "go.opentelemetry.io/otel/attribute" 13 14 "github.com/MetalBlockchain/metalgo/database" 15 "github.com/MetalBlockchain/metalgo/ids" 16 "github.com/MetalBlockchain/metalgo/utils" 17 "github.com/MetalBlockchain/metalgo/utils/maybe" 18 19 oteltrace "go.opentelemetry.io/otel/trace" 20 ) 21 22 const ( 23 initKeyValuesSize = 256 24 defaultPreallocationSize = 100 25 ) 26 27 var ( 28 _ View = (*view)(nil) 29 30 ErrCommitted = errors.New("view has been committed") 31 ErrInvalid = errors.New("the trie this view was based on has changed, rendering this view invalid") 32 ErrPartialByteLengthWithValue = errors.New( 33 "the underlying db only supports whole number of byte keys, so cannot record changes with partial byte lengths", 34 ) 35 ErrVisitPathToKey = errors.New("failed to visit expected node during insertion") 36 ErrStartAfterEnd = errors.New("start key > end key") 37 ErrNoChanges = errors.New("no changes provided") 38 ErrParentNotDatabase = errors.New("parent trie is not database") 39 ErrNodesAlreadyCalculated = errors.New("cannot modify the trie after the node changes have been calculated") 40 ) 41 42 type view struct { 43 // If true, this view has been committed. 44 // [commitLock] must be held while accessing this field. 45 committed bool 46 commitLock sync.RWMutex 47 48 // valueChangesApplied is used to enforce that no changes are made to the 49 // trie after the nodes have been calculated 50 valueChangesApplied utils.Atomic[bool] 51 52 // applyValueChangesOnce prevents node calculation from occurring multiple 53 // times 54 applyValueChangesOnce sync.Once 55 56 // Controls the view's validity related fields. 57 // Must be held while reading/writing [childViews], [invalidated], and [parentTrie]. 58 // Only use to lock current view or descendants of the current view 59 // DO NOT grab the [validityTrackingLock] of any ancestor trie while this is held. 60 validityTrackingLock sync.RWMutex 61 62 // If true, this view has been invalidated and can't be used. 63 // 64 // Invariant: This view is marked as invalid before any of its ancestors change. 65 // Since we ensure that all subviews are marked invalid before making an invalidating change 66 // then if we are still valid at the end of the function, then no corrupting changes could have 67 // occurred during execution. 68 // Namely, if we have a method with: 69 // 70 // *Code Accessing Ancestor State* 71 // 72 // if v.isInvalid() { 73 // return ErrInvalid 74 // } 75 // return [result] 76 // 77 // If the invalidated check passes, then we're guaranteed that no ancestor changes occurred 78 // during the code that accessed ancestor state and the result of that work is still valid 79 // 80 // [validityTrackingLock] must be held when reading/writing this field. 81 invalidated bool 82 83 // the uncommitted parent trie of this view 84 // [validityTrackingLock] must be held when reading/writing this field. 85 parentTrie View 86 87 // The valid children of this view. 88 // [validityTrackingLock] must be held when reading/writing this field. 89 childViews []*view 90 91 // Changes made to this view. 92 // May include nodes that haven't been updated 93 // but will when their ID is recalculated. 94 changes *changeSummary 95 96 db *merkleDB 97 98 // The root of the trie represented by this view. 99 root maybe.Maybe[*node] 100 101 tokenSize int 102 } 103 104 // NewView returns a new view on top of this view where the passed changes 105 // have been applied. 106 // Adds the new view to [v.childViews]. 107 // Assumes [v.commitLock] isn't held. 108 func (v *view) NewView( 109 ctx context.Context, 110 changes ViewChanges, 111 ) (View, error) { 112 if v.isInvalid() { 113 return nil, ErrInvalid 114 } 115 v.commitLock.RLock() 116 defer v.commitLock.RUnlock() 117 118 if v.committed { 119 return v.getParentTrie().NewView(ctx, changes) 120 } 121 122 if err := v.applyValueChanges(ctx); err != nil { 123 return nil, err 124 } 125 126 childView, err := newView(v.db, v, changes) 127 if err != nil { 128 return nil, err 129 } 130 131 v.validityTrackingLock.Lock() 132 defer v.validityTrackingLock.Unlock() 133 134 if v.invalidated { 135 return nil, ErrInvalid 136 } 137 v.childViews = append(v.childViews, childView) 138 139 return childView, nil 140 } 141 142 // Creates a new view with the given [parentTrie]. 143 func newView( 144 db *merkleDB, 145 parentTrie View, 146 changes ViewChanges, 147 ) (*view, error) { 148 v := &view{ 149 root: maybe.Bind(parentTrie.getRoot(), (*node).clone), 150 db: db, 151 parentTrie: parentTrie, 152 changes: newChangeSummary(len(changes.BatchOps) + len(changes.MapOps)), 153 tokenSize: db.tokenSize, 154 } 155 156 for _, op := range changes.BatchOps { 157 key := op.Key 158 if !changes.ConsumeBytes { 159 key = slices.Clone(op.Key) 160 } 161 162 newVal := maybe.Nothing[[]byte]() 163 if !op.Delete { 164 newVal = maybe.Some(op.Value) 165 if !changes.ConsumeBytes { 166 newVal = maybe.Some(slices.Clone(op.Value)) 167 } 168 } 169 if err := v.recordValueChange(toKey(key), newVal); err != nil { 170 return nil, err 171 } 172 } 173 for key, val := range changes.MapOps { 174 if !changes.ConsumeBytes { 175 val = maybe.Bind(val, slices.Clone[[]byte]) 176 } 177 if err := v.recordValueChange(toKey(stringToByteSlice(key)), val); err != nil { 178 return nil, err 179 } 180 } 181 return v, nil 182 } 183 184 // Creates a view of the db at a historical root using the provided [changes]. 185 // Returns ErrNoChanges if [changes] is empty. 186 func newViewWithChanges( 187 db *merkleDB, 188 changes *changeSummary, 189 ) (*view, error) { 190 if changes == nil { 191 return nil, ErrNoChanges 192 } 193 194 v := &view{ 195 root: changes.rootChange.after, 196 db: db, 197 parentTrie: db, 198 changes: changes, 199 tokenSize: db.tokenSize, 200 } 201 // since this is a set of historical changes, all nodes have already been calculated 202 // since no new changes have occurred, no new calculations need to be done 203 v.applyValueChangesOnce.Do(func() {}) 204 v.valueChangesApplied.Set(true) 205 return v, nil 206 } 207 208 func (v *view) getTokenSize() int { 209 return v.tokenSize 210 } 211 212 func (v *view) getRoot() maybe.Maybe[*node] { 213 return v.root 214 } 215 216 // applyValueChanges generates the node changes from the value changes. It then 217 // hashes the changed nodes to calculate the new trie. 218 // 219 // Cancelling [ctx] doesn't cancel the operation. It's used only for tracing. 220 func (v *view) applyValueChanges(ctx context.Context) error { 221 var err error 222 v.applyValueChangesOnce.Do(func() { 223 // Create the span inside the once wrapper to make traces more useful. 224 // Otherwise, spans would be created during calls where the IDs are not 225 // re-calculated. 226 ctx, span := v.db.infoTracer.Start(ctx, "MerkleDB.view.applyValueChanges") 227 defer span.End() 228 229 if v.isInvalid() { 230 err = ErrInvalid 231 return 232 } 233 defer v.valueChangesApplied.Set(true) 234 235 oldRoot := maybe.Bind(v.root, (*node).clone) 236 237 // Note we're setting [err] defined outside this function. 238 if err = v.calculateNodeChanges(ctx); err != nil { 239 return 240 } 241 v.hashChangedNodes(ctx) 242 243 v.changes.rootChange = change[maybe.Maybe[*node]]{ 244 before: oldRoot, 245 after: v.root, 246 } 247 248 // ensure no ancestor changes occurred during execution 249 if v.isInvalid() { 250 err = ErrInvalid 251 return 252 } 253 }) 254 return err 255 } 256 257 func (v *view) calculateNodeChanges(ctx context.Context) error { 258 _, span := v.db.infoTracer.Start(ctx, "MerkleDB.view.calculateNodeChanges") 259 defer span.End() 260 261 // Add all the changed key/values to the nodes of the trie 262 for key, change := range v.changes.values { 263 if change.after.IsNothing() { 264 if err := v.remove(key); err != nil { 265 return err 266 } 267 } else if _, err := v.insert(key, change.after); err != nil { 268 return err 269 } 270 } 271 272 return nil 273 } 274 275 func (v *view) hashChangedNodes(ctx context.Context) { 276 _, span := v.db.infoTracer.Start(ctx, "MerkleDB.view.hashChangedNodes") 277 defer span.End() 278 279 if v.root.IsNothing() { 280 v.changes.rootID = ids.Empty 281 return 282 } 283 284 // If there are no children, we can avoid allocating [keyBuffer]. 285 root := v.root.Value() 286 if len(root.children) == 0 { 287 v.changes.rootID = v.db.hasher.HashNode(root) 288 v.db.metrics.HashCalculated() 289 return 290 } 291 292 // Allocate [keyBuffer] and populate it with the root node's key. 293 keyBuffer := v.db.hashNodesKeyPool.Acquire() 294 keyBuffer = v.setKeyBuffer(root, keyBuffer) 295 v.changes.rootID, keyBuffer = v.hashChangedNode(root, keyBuffer) 296 v.db.hashNodesKeyPool.Release(keyBuffer) 297 } 298 299 // Calculates the ID of all descendants of [n] which need to be recalculated, 300 // and then calculates the ID of [n] itself. 301 // 302 // Returns a potentially expanded [keyBuffer]. By returning this value this 303 // function is able to have a maximum total number of allocations shared across 304 // multiple invocations. 305 // 306 // Invariant: [keyBuffer] must be populated with [n]'s key and have sufficient 307 // length to contain any of [n]'s child keys. 308 func (v *view) hashChangedNode(n *node, keyBuffer []byte) (ids.ID, []byte) { 309 var ( 310 // childBuffer is allocated on the stack. 311 childBuffer = make([]byte, 1) 312 dualIndex = dualBitIndex(v.tokenSize) 313 bytesForKey = bytesNeeded(n.key.length) 314 // We track the last byte of [n.key] so that we can reset the value for 315 // each key. This is needed because the child buffer may get ORed at 316 // this byte. 317 lastKeyByte byte 318 319 // We use [wg] to wait until all descendants of [n] have been updated. 320 wg waitGroup 321 ) 322 if bytesForKey > 0 { 323 lastKeyByte = keyBuffer[bytesForKey-1] 324 } 325 326 // This loop is optimized to avoid allocations when calculating the 327 // [childKey] by reusing [keyBuffer] and leaving the first [bytesForKey-1] 328 // bytes unmodified. 329 for childIndex, childEntry := range n.children { 330 childBuffer[0] = childIndex << dualIndex 331 childIndexAsKey := Key{ 332 // It is safe to use byteSliceToString because [childBuffer] is not 333 // modified while [childIndexAsKey] is in use. 334 value: byteSliceToString(childBuffer), 335 length: v.tokenSize, 336 } 337 338 totalBitLength := n.key.length + v.tokenSize + childEntry.compressedKey.length 339 // Because [keyBuffer] may have been modified in a prior iteration of 340 // this loop, it is not guaranteed that its length is at least 341 // [bytesNeeded(totalBitLength)]. However, that's fine. The below 342 // slicing would only panic if the buffer didn't have sufficient 343 // capacity. 344 keyBuffer = keyBuffer[:bytesNeeded(totalBitLength)] 345 // We don't need to copy this node's key. It's assumed to already be 346 // correct; except for the last byte. We must make sure the last byte of 347 // the key is set correctly because extendIntoBuffer may OR bits from 348 // the extension and overwrite the last byte. However, extendIntoBuffer 349 // does not modify the first [bytesForKey-1] bytes of [keyBuffer]. 350 if bytesForKey > 0 { 351 keyBuffer[bytesForKey-1] = lastKeyByte 352 } 353 extendIntoBuffer(keyBuffer, childIndexAsKey, n.key.length) 354 extendIntoBuffer(keyBuffer, childEntry.compressedKey, n.key.length+v.tokenSize) 355 childKey := Key{ 356 // It is safe to use byteSliceToString because [keyBuffer] is not 357 // modified while [childKey] is in use. 358 value: byteSliceToString(keyBuffer), 359 length: totalBitLength, 360 } 361 362 childNodeChange, ok := v.changes.nodes[childKey] 363 if !ok { 364 // This child wasn't changed. 365 continue 366 } 367 368 childNode := childNodeChange.after 369 childEntry.hasValue = childNode.hasValue() 370 371 // If there are no children of the childNode, we can avoid constructing 372 // the buffer for the child keys. 373 if len(childNode.children) == 0 { 374 childEntry.id = v.db.hasher.HashNode(childNode) 375 v.db.metrics.HashCalculated() 376 continue 377 } 378 379 // Try updating the child and its descendants in a goroutine. 380 if childKeyBuffer, ok := v.db.hashNodesKeyPool.TryAcquire(); ok { 381 wg.Add(1) 382 go func(wg *sync.WaitGroup, childEntry *child, childNode *node, childKeyBuffer []byte) { 383 childKeyBuffer = v.setKeyBuffer(childNode, childKeyBuffer) 384 childEntry.id, childKeyBuffer = v.hashChangedNode(childNode, childKeyBuffer) 385 v.db.hashNodesKeyPool.Release(childKeyBuffer) 386 wg.Done() 387 }(wg.wg, childEntry, childNode, childKeyBuffer) 388 } else { 389 // We're at the goroutine limit; do the work in this goroutine. 390 // 391 // We can skip copying the key here because [keyBuffer] is already 392 // constructed to be childNode's key. 393 keyBuffer = v.setLengthForChildren(childNode, keyBuffer) 394 childEntry.id, keyBuffer = v.hashChangedNode(childNode, keyBuffer) 395 } 396 } 397 398 // Wait until all descendants of [n] have been updated. 399 wg.Wait() 400 401 // The IDs [n]'s descendants are up to date so we can calculate [n]'s ID. 402 v.db.metrics.HashCalculated() 403 return v.db.hasher.HashNode(n), keyBuffer 404 } 405 406 // setKeyBuffer expands [keyBuffer] to have sufficient size for any of [n]'s 407 // child keys and populates [n]'s key into [keyBuffer]. If [keyBuffer] already 408 // has sufficient size, this function will not perform any memory allocations. 409 func (v *view) setKeyBuffer(n *node, keyBuffer []byte) []byte { 410 keyBuffer = v.setLengthForChildren(n, keyBuffer) 411 copy(keyBuffer, n.key.value) 412 return keyBuffer 413 } 414 415 // setLengthForChildren expands [keyBuffer] to have sufficient size for any of 416 // [n]'s child keys. 417 func (v *view) setLengthForChildren(n *node, keyBuffer []byte) []byte { 418 // Calculate the size of the largest child key of this node. 419 var maxBitLength int 420 for _, childEntry := range n.children { 421 maxBitLength = max(maxBitLength, childEntry.compressedKey.length) 422 } 423 maxBytesNeeded := bytesNeeded(n.key.length + v.tokenSize + maxBitLength) 424 return setBytesLength(keyBuffer, maxBytesNeeded) 425 } 426 427 func setBytesLength(b []byte, size int) []byte { 428 if size <= cap(b) { 429 return b[:size] 430 } 431 return append(b[:cap(b)], make([]byte, size-cap(b))...) 432 } 433 434 // GetProof returns a proof that [bytesPath] is in or not in trie [t]. 435 func (v *view) GetProof(ctx context.Context, key []byte) (*Proof, error) { 436 _, span := v.db.infoTracer.Start(ctx, "MerkleDB.view.GetProof") 437 defer span.End() 438 439 if err := v.applyValueChanges(ctx); err != nil { 440 return nil, err 441 } 442 443 result, err := getProof(v, key) 444 if err != nil { 445 return nil, err 446 } 447 if v.isInvalid() { 448 return nil, ErrInvalid 449 } 450 return result, nil 451 } 452 453 // GetRangeProof returns a range proof for (at least part of) the key range [start, end]. 454 // The returned proof's [KeyValues] has at most [maxLength] values. 455 // [maxLength] must be > 0. 456 func (v *view) GetRangeProof( 457 ctx context.Context, 458 start maybe.Maybe[[]byte], 459 end maybe.Maybe[[]byte], 460 maxLength int, 461 ) (*RangeProof, error) { 462 _, span := v.db.infoTracer.Start(ctx, "MerkleDB.view.GetRangeProof") 463 defer span.End() 464 465 if err := v.applyValueChanges(ctx); err != nil { 466 return nil, err 467 } 468 result, err := getRangeProof(v, start, end, maxLength) 469 if err != nil { 470 return nil, err 471 } 472 if v.isInvalid() { 473 return nil, ErrInvalid 474 } 475 return result, nil 476 } 477 478 // CommitToDB commits changes from this view to the underlying DB. 479 func (v *view) CommitToDB(ctx context.Context) error { 480 ctx, span := v.db.infoTracer.Start(ctx, "MerkleDB.view.CommitToDB") 481 defer span.End() 482 483 v.db.commitLock.Lock() 484 defer v.db.commitLock.Unlock() 485 486 return v.commitToDB(ctx) 487 } 488 489 // Commits the changes from [trieToCommit] to this view, 490 // this view to its parent, and so on until committing to the db. 491 // Assumes [v.db.commitLock] is held. 492 func (v *view) commitToDB(ctx context.Context) error { 493 v.commitLock.Lock() 494 defer v.commitLock.Unlock() 495 496 ctx, span := v.db.infoTracer.Start(ctx, "MerkleDB.view.commitToDB", oteltrace.WithAttributes( 497 attribute.Int("changeCount", len(v.changes.values)), 498 )) 499 defer span.End() 500 501 // Call this here instead of in [v.db.commitView] because doing so there 502 // would be a deadlock. 503 if err := v.applyValueChanges(ctx); err != nil { 504 return err 505 } 506 507 if err := v.db.commitView(ctx, v); err != nil { 508 return err 509 } 510 511 v.committed = true 512 513 return nil 514 } 515 516 // Assumes [v.validityTrackingLock] isn't held. 517 func (v *view) isInvalid() bool { 518 v.validityTrackingLock.RLock() 519 defer v.validityTrackingLock.RUnlock() 520 521 return v.invalidated 522 } 523 524 // Invalidates this view and all descendants. 525 // Assumes [v.validityTrackingLock] isn't held. 526 func (v *view) invalidate() { 527 v.validityTrackingLock.Lock() 528 defer v.validityTrackingLock.Unlock() 529 530 v.invalidated = true 531 532 for _, childView := range v.childViews { 533 childView.invalidate() 534 } 535 536 // after invalidating the children, they no longer need to be tracked 537 v.childViews = make([]*view, 0, defaultPreallocationSize) 538 } 539 540 func (v *view) updateParent(newParent View) { 541 v.validityTrackingLock.Lock() 542 defer v.validityTrackingLock.Unlock() 543 544 v.parentTrie = newParent 545 } 546 547 // GetMerkleRoot returns the ID of the root of this view. 548 func (v *view) GetMerkleRoot(ctx context.Context) (ids.ID, error) { 549 if err := v.applyValueChanges(ctx); err != nil { 550 return ids.Empty, err 551 } 552 return v.changes.rootID, nil 553 } 554 555 func (v *view) GetValues(ctx context.Context, keys [][]byte) ([][]byte, []error) { 556 _, span := v.db.debugTracer.Start(ctx, "MerkleDB.view.GetValues", oteltrace.WithAttributes( 557 attribute.Int("keyCount", len(keys)), 558 )) 559 defer span.End() 560 561 results := make([][]byte, len(keys)) 562 valueErrors := make([]error, len(keys)) 563 564 for i, key := range keys { 565 results[i], valueErrors[i] = v.getValueCopy(ToKey(key)) 566 } 567 return results, valueErrors 568 } 569 570 // GetValue returns the value for the given [key]. 571 // Returns database.ErrNotFound if it doesn't exist. 572 func (v *view) GetValue(ctx context.Context, key []byte) ([]byte, error) { 573 _, span := v.db.debugTracer.Start(ctx, "MerkleDB.view.GetValue") 574 defer span.End() 575 576 return v.getValueCopy(ToKey(key)) 577 } 578 579 // getValueCopy returns a copy of the value for the given [key]. 580 // Returns database.ErrNotFound if it doesn't exist. 581 func (v *view) getValueCopy(key Key) ([]byte, error) { 582 val, err := v.getValue(key) 583 if err != nil { 584 return nil, err 585 } 586 return slices.Clone(val), nil 587 } 588 589 func (v *view) getValue(key Key) ([]byte, error) { 590 if v.isInvalid() { 591 return nil, ErrInvalid 592 } 593 594 if change, ok := v.changes.values[key]; ok { 595 v.db.metrics.ViewChangesValueHit() 596 if change.after.IsNothing() { 597 return nil, database.ErrNotFound 598 } 599 return change.after.Value(), nil 600 } 601 v.db.metrics.ViewChangesValueMiss() 602 603 // if we don't have local copy of the value, then grab a copy from the parent trie 604 value, err := v.getParentTrie().getValue(key) 605 if err != nil { 606 return nil, err 607 } 608 609 // ensure no ancestor changes occurred during execution 610 if v.isInvalid() { 611 return nil, ErrInvalid 612 } 613 614 return value, nil 615 } 616 617 // Must not be called after [applyValueChanges] has returned. 618 func (v *view) remove(key Key) error { 619 if v.valueChangesApplied.Get() { 620 return ErrNodesAlreadyCalculated 621 } 622 623 // confirm a node exists with a value 624 keyNode, err := v.getNode(key, true) 625 if err != nil { 626 if errors.Is(err, database.ErrNotFound) { 627 // [key] isn't in the trie. 628 return nil 629 } 630 return err 631 } 632 633 if !keyNode.hasValue() { 634 // [key] doesn't have a value. 635 return nil 636 } 637 638 // if the node exists and contains a value 639 // mark all ancestor for change 640 // grab parent and grandparent nodes for path compression 641 var grandParent, parent, nodeToDelete *node 642 if err := visitPathToKey(v, key, func(n *node) error { 643 grandParent = parent 644 parent = nodeToDelete 645 nodeToDelete = n 646 return v.recordNodeChange(n) 647 }); err != nil { 648 return err 649 } 650 651 hadValue := nodeToDelete.hasValue() 652 nodeToDelete.setValue(v.db.hasher, maybe.Nothing[[]byte]()) 653 654 // if the removed node has no children, the node can be removed from the trie 655 if len(nodeToDelete.children) == 0 { 656 if err := v.recordNodeDeleted(nodeToDelete, hadValue); err != nil { 657 return err 658 } 659 660 if nodeToDelete.key == v.root.Value().key { 661 // We deleted the root. The trie is empty now. 662 v.root = maybe.Nothing[*node]() 663 return nil 664 } 665 666 // Note [parent] != nil since [nodeToDelete.key] != [v.root.key]. 667 // i.e. There's the root and at least one more node. 668 parent.removeChild(nodeToDelete, v.tokenSize) 669 670 // merge the parent node and its child into a single node if possible 671 return v.compressNodePath(grandParent, parent) 672 } 673 674 // merge this node and its parent into a single node if possible 675 return v.compressNodePath(parent, nodeToDelete) 676 } 677 678 // Merges [n] with its [parent] if [n] has only one child and no value. 679 // If [parent] is nil, [n] is the root node and [v.root] is updated to [n]. 680 // Assumes at least one of the following is true: 681 // * [n] has a value. 682 // * [n] has children. 683 // Must not be called after [applyValueChanges] has returned. 684 func (v *view) compressNodePath(parent, n *node) error { 685 if v.valueChangesApplied.Get() { 686 return ErrNodesAlreadyCalculated 687 } 688 689 if len(n.children) != 1 || n.hasValue() { 690 return nil 691 } 692 693 // We know from above that [n] has no value. 694 if err := v.recordNodeDeleted(n, false /* hasValue */); err != nil { 695 return err 696 } 697 698 var ( 699 childEntry *child 700 childKey Key 701 ) 702 // There is only one child, but we don't know the index. 703 // "Cycle" over the key/values to find the only child. 704 // Note this iteration once because len(node.children) == 1. 705 for index, entry := range n.children { 706 childKey = n.key.Extend(ToToken(index, v.tokenSize), entry.compressedKey) 707 childEntry = entry 708 } 709 710 if parent == nil { 711 root, err := v.getNode(childKey, childEntry.hasValue) 712 if err != nil { 713 return err 714 } 715 v.root = maybe.Some(root) 716 return nil 717 } 718 719 parent.setChildEntry(childKey.Token(parent.key.length, v.tokenSize), 720 &child{ 721 compressedKey: childKey.Skip(parent.key.length + v.tokenSize), 722 id: childEntry.id, 723 hasValue: childEntry.hasValue, 724 }) 725 return v.recordNodeChange(parent) 726 } 727 728 // Get a copy of the node matching the passed key from the view. 729 // Used by views to get nodes from their ancestors. 730 func (v *view) getEditableNode(key Key, hadValue bool) (*node, error) { 731 if v.isInvalid() { 732 return nil, ErrInvalid 733 } 734 735 // grab the node in question 736 n, err := v.getNode(key, hadValue) 737 if err != nil { 738 return nil, err 739 } 740 741 // ensure no ancestor changes occurred during execution 742 if v.isInvalid() { 743 return nil, ErrInvalid 744 } 745 746 // return a clone of the node, so it can be edited without affecting this view 747 return n.clone(), nil 748 } 749 750 // insert a key/value pair into the correct node of the trie. 751 // Must not be called after [applyValueChanges] has returned. 752 func (v *view) insert( 753 key Key, 754 value maybe.Maybe[[]byte], 755 ) (*node, error) { 756 if v.valueChangesApplied.Get() { 757 return nil, ErrNodesAlreadyCalculated 758 } 759 760 if v.root.IsNothing() { 761 // the trie is empty, so create a new root node. 762 root := newNode(key) 763 root.setValue(v.db.hasher, value) 764 v.root = maybe.Some(root) 765 return root, v.recordNewNode(root) 766 } 767 768 // Find the node that most closely matches [key]. 769 var closestNode *node 770 if err := visitPathToKey(v, key, func(n *node) error { 771 closestNode = n 772 // Need to recalculate ID for all nodes on path to [key]. 773 return v.recordNodeChange(n) 774 }); err != nil { 775 return nil, err 776 } 777 778 if closestNode == nil { 779 // [v.root.key] isn't a prefix of [key]. 780 var ( 781 oldRoot = v.root.Value() 782 commonPrefixLength = getLengthOfCommonPrefix(oldRoot.key, key, 0 /*offset*/, v.tokenSize) 783 commonPrefix = oldRoot.key.Take(commonPrefixLength) 784 newRoot = newNode(commonPrefix) 785 oldRootID = v.db.hasher.HashNode(oldRoot) 786 ) 787 v.db.metrics.HashCalculated() 788 789 // Call addChildWithID instead of addChild so the old root is added 790 // to the new root with the correct ID. 791 // TODO: 792 // [oldRootID] shouldn't need to be calculated here. 793 // Either oldRootID should already be calculated or will be calculated at the end with the other nodes 794 // Initialize the v.changes.rootID during newView and then use that here instead of oldRootID 795 newRoot.addChildWithID(oldRoot, v.tokenSize, oldRootID) 796 if err := v.recordNewNode(newRoot); err != nil { 797 return nil, err 798 } 799 v.root = maybe.Some(newRoot) 800 801 closestNode = newRoot 802 } 803 804 // a node with that exact key already exists so update its value 805 if closestNode.key == key { 806 closestNode.setValue(v.db.hasher, value) 807 // closestNode was already marked as changed in the ancestry loop above 808 return closestNode, nil 809 } 810 811 // A node with the exact key doesn't exist so determine the portion of the 812 // key that hasn't been matched yet 813 // Note that [key] has prefix [closestNode.key], so [key] must be longer 814 // and the following index won't OOB. 815 existingChildEntry, hasChild := closestNode.children[key.Token(closestNode.key.length, v.tokenSize)] 816 if !hasChild { 817 // there are no existing nodes along the key [key], so create a new node to insert [value] 818 newNode := newNode(key) 819 newNode.setValue(v.db.hasher, value) 820 closestNode.addChild(newNode, v.tokenSize) 821 return newNode, v.recordNewNode(newNode) 822 } 823 824 // if we have reached this point, then the [key] we are trying to insert and 825 // the existing path node have some common prefix. 826 // a new branching node will be created that will represent this common prefix and 827 // have the existing path node and the value being inserted as children. 828 829 // generate the new branch node 830 // find how many tokens are common between the existing child's compressed key and 831 // the current key(offset by the closest node's key), 832 // then move all the common tokens into the branch node 833 commonPrefixLength := getLengthOfCommonPrefix( 834 existingChildEntry.compressedKey, 835 key, 836 closestNode.key.length+v.tokenSize, 837 v.tokenSize, 838 ) 839 840 if existingChildEntry.compressedKey.length <= commonPrefixLength { 841 // Since the compressed key is shorter than the common prefix, 842 // we should have visited [existingChildEntry] in [visitPathToKey]. 843 return nil, ErrVisitPathToKey 844 } 845 846 branchNode := newNode(key.Take(closestNode.key.length + v.tokenSize + commonPrefixLength)) 847 closestNode.addChild(branchNode, v.tokenSize) 848 nodeWithValue := branchNode 849 850 if key.length == branchNode.key.length { 851 // the branch node has exactly the key to be inserted as its key, so set the value on the branch node 852 branchNode.setValue(v.db.hasher, value) 853 } else { 854 // the key to be inserted is a child of the branch node 855 // create a new node and add the value to it 856 newNode := newNode(key) 857 newNode.setValue(v.db.hasher, value) 858 branchNode.addChild(newNode, v.tokenSize) 859 if err := v.recordNewNode(newNode); err != nil { 860 return nil, err 861 } 862 nodeWithValue = newNode 863 } 864 865 // add the existing child onto the branch node 866 branchNode.setChildEntry( 867 existingChildEntry.compressedKey.Token(commonPrefixLength, v.tokenSize), 868 &child{ 869 compressedKey: existingChildEntry.compressedKey.Skip(commonPrefixLength + v.tokenSize), 870 id: existingChildEntry.id, 871 hasValue: existingChildEntry.hasValue, 872 }) 873 874 return nodeWithValue, v.recordNewNode(branchNode) 875 } 876 877 func getLengthOfCommonPrefix(first, second Key, secondOffset int, tokenSize int) int { 878 commonIndex := 0 879 for first.length > commonIndex && second.length > commonIndex+secondOffset && 880 first.Token(commonIndex, tokenSize) == second.Token(commonIndex+secondOffset, tokenSize) { 881 commonIndex += tokenSize 882 } 883 return commonIndex 884 } 885 886 // Records that a node has been created. 887 // Must not be called after [applyValueChanges] has returned. 888 func (v *view) recordNewNode(after *node) error { 889 return v.recordKeyChange(after.key, after, after.hasValue(), true /* newNode */) 890 } 891 892 // Records that an existing node has been changed. 893 // Must not be called after [applyValueChanges] has returned. 894 func (v *view) recordNodeChange(after *node) error { 895 return v.recordKeyChange(after.key, after, after.hasValue(), false /* newNode */) 896 } 897 898 // Records that the node associated with the given key has been deleted. 899 // Must not be called after [applyValueChanges] has returned. 900 func (v *view) recordNodeDeleted(after *node, hadValue bool) error { 901 return v.recordKeyChange(after.key, nil, hadValue, false /* newNode */) 902 } 903 904 // Records that the node associated with the given key has been changed. 905 // If it is an existing node, record what its value was before it was changed. 906 // Must not be called after [applyValueChanges] has returned. 907 func (v *view) recordKeyChange(key Key, after *node, hadValue bool, newNode bool) error { 908 if v.valueChangesApplied.Get() { 909 return ErrNodesAlreadyCalculated 910 } 911 912 if existing, ok := v.changes.nodes[key]; ok { 913 existing.after = after 914 return nil 915 } 916 917 if newNode { 918 v.changes.nodes[key] = &change[*node]{ 919 after: after, 920 } 921 return nil 922 } 923 924 before, err := v.getParentTrie().getEditableNode(key, hadValue) 925 if err != nil { 926 return err 927 } 928 v.changes.nodes[key] = &change[*node]{ 929 before: before, 930 after: after, 931 } 932 return nil 933 } 934 935 // Records that a key's value has been added or updated. 936 // Doesn't actually change the trie data structure. 937 // That's deferred until we call [applyValueChanges]. 938 // Must not be called after [applyValueChanges] has returned. 939 func (v *view) recordValueChange(key Key, value maybe.Maybe[[]byte]) error { 940 if v.valueChangesApplied.Get() { 941 return ErrNodesAlreadyCalculated 942 } 943 944 // update the existing change if it exists 945 if existing, ok := v.changes.values[key]; ok { 946 existing.after = value 947 return nil 948 } 949 950 // grab the before value 951 var beforeMaybe maybe.Maybe[[]byte] 952 before, err := v.getParentTrie().getValue(key) 953 switch err { 954 case nil: 955 beforeMaybe = maybe.Some(before) 956 case database.ErrNotFound: 957 beforeMaybe = maybe.Nothing[[]byte]() 958 default: 959 return err 960 } 961 962 v.changes.values[key] = &change[maybe.Maybe[[]byte]]{ 963 before: beforeMaybe, 964 after: value, 965 } 966 return nil 967 } 968 969 // Retrieves a node with the given [key]. 970 // If the node is fetched from [v.parentTrie] and [id] isn't empty, 971 // sets the node's ID to [id]. 972 // If the node is loaded from the baseDB, [hasValue] determines which database the node is stored in. 973 // Returns database.ErrNotFound if the node doesn't exist. 974 func (v *view) getNode(key Key, hasValue bool) (*node, error) { 975 // check for the key within the changed nodes 976 if nodeChange, isChanged := v.changes.nodes[key]; isChanged { 977 v.db.metrics.ViewChangesNodeHit() 978 if nodeChange.after == nil { 979 return nil, database.ErrNotFound 980 } 981 return nodeChange.after, nil 982 } 983 v.db.metrics.ViewChangesNodeMiss() 984 985 // get the node from the parent trie and store a local copy 986 return v.getParentTrie().getEditableNode(key, hasValue) 987 } 988 989 // Get the parent trie of the view 990 func (v *view) getParentTrie() View { 991 v.validityTrackingLock.RLock() 992 defer v.validityTrackingLock.RUnlock() 993 return v.parentTrie 994 }