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  }