github.com/MetalBlockchain/metalgo@v1.11.9/x/merkledb/proof.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  	"bytes"
     8  	"context"
     9  	"errors"
    10  	"fmt"
    11  	"math"
    12  
    13  	"github.com/MetalBlockchain/metalgo/database"
    14  	"github.com/MetalBlockchain/metalgo/database/memdb"
    15  	"github.com/MetalBlockchain/metalgo/ids"
    16  	"github.com/MetalBlockchain/metalgo/trace"
    17  	"github.com/MetalBlockchain/metalgo/utils/maybe"
    18  
    19  	pb "github.com/MetalBlockchain/metalgo/proto/pb/sync"
    20  )
    21  
    22  const verificationCacheSize = math.MaxUint16
    23  
    24  var (
    25  	ErrInvalidProof                = errors.New("proof obtained an invalid root ID")
    26  	ErrInvalidMaxLength            = errors.New("expected max length to be > 0")
    27  	ErrNonIncreasingValues         = errors.New("keys sent are not in increasing order")
    28  	ErrStateFromOutsideOfRange     = errors.New("state key falls outside of the start->end range")
    29  	ErrNonIncreasingProofNodes     = errors.New("each proof node key must be a strict prefix of the next")
    30  	ErrExtraProofNodes             = errors.New("extra proof nodes in path")
    31  	ErrDataInMissingRootProof      = errors.New("there should be no state or deleted keys in a change proof that had a missing root")
    32  	ErrEmptyProof                  = errors.New("proof is empty")
    33  	ErrNoMerkleProof               = errors.New("empty key response must include merkle proof")
    34  	ErrShouldJustBeRoot            = errors.New("end proof should only contain root")
    35  	ErrNoStartProof                = errors.New("no start proof")
    36  	ErrNoEndProof                  = errors.New("no end proof")
    37  	ErrProofNodeNotForKey          = errors.New("the provided node has a key that is not a prefix of the specified key")
    38  	ErrProofValueDoesntMatch       = errors.New("the provided value does not match the proof node for the provided key's value")
    39  	ErrProofNodeHasUnincludedValue = errors.New("the provided proof has a value for a key within the range that is not present in the provided key/values")
    40  	ErrInvalidMaybe                = errors.New("maybe is nothing but has value")
    41  	ErrNilProofNode                = errors.New("proof node is nil")
    42  	ErrNilValueOrHash              = errors.New("proof node's valueOrHash field is nil")
    43  	ErrNilKey                      = errors.New("key is nil")
    44  	ErrInvalidKeyLength            = errors.New("key length doesn't match bytes length, check specified branchFactor")
    45  	ErrNilRangeProof               = errors.New("range proof is nil")
    46  	ErrNilChangeProof              = errors.New("change proof is nil")
    47  	ErrNilMaybeBytes               = errors.New("maybe bytes is nil")
    48  	ErrNilProof                    = errors.New("proof is nil")
    49  	ErrNilValue                    = errors.New("value is nil")
    50  	ErrUnexpectedEndProof          = errors.New("end proof should be empty")
    51  )
    52  
    53  type ProofNode struct {
    54  	Key Key
    55  	// Nothing if this is an intermediate node.
    56  	// The value in this node if its length < [HashLen].
    57  	// The hash of the value in this node otherwise.
    58  	ValueOrHash maybe.Maybe[[]byte]
    59  	Children    map[byte]ids.ID
    60  }
    61  
    62  // ToProto converts the ProofNode into the protobuf version of a proof node
    63  // Assumes [node.Key.Key.length] <= math.MaxUint64.
    64  func (node *ProofNode) ToProto() *pb.ProofNode {
    65  	pbNode := &pb.ProofNode{
    66  		Key: &pb.Key{
    67  			Length: uint64(node.Key.length),
    68  			Value:  node.Key.Bytes(),
    69  		},
    70  		ValueOrHash: &pb.MaybeBytes{
    71  			Value:     node.ValueOrHash.Value(),
    72  			IsNothing: node.ValueOrHash.IsNothing(),
    73  		},
    74  		Children: make(map[uint32][]byte, len(node.Children)),
    75  	}
    76  
    77  	for childIndex, childID := range node.Children {
    78  		childID := childID
    79  		pbNode.Children[uint32(childIndex)] = childID[:]
    80  	}
    81  
    82  	return pbNode
    83  }
    84  
    85  func (node *ProofNode) UnmarshalProto(pbNode *pb.ProofNode) error {
    86  	switch {
    87  	case pbNode == nil:
    88  		return ErrNilProofNode
    89  	case pbNode.ValueOrHash == nil:
    90  		return ErrNilValueOrHash
    91  	case pbNode.ValueOrHash.IsNothing && len(pbNode.ValueOrHash.Value) != 0:
    92  		return ErrInvalidMaybe
    93  	case pbNode.Key == nil:
    94  		return ErrNilKey
    95  	case len(pbNode.Key.Value) != bytesNeeded(int(pbNode.Key.Length)):
    96  		return ErrInvalidKeyLength
    97  	}
    98  	node.Key = ToKey(pbNode.Key.Value).Take(int(pbNode.Key.Length))
    99  	node.Children = make(map[byte]ids.ID, len(pbNode.Children))
   100  	for childIndex, childIDBytes := range pbNode.Children {
   101  		if childIndex > math.MaxUint8 {
   102  			return errChildIndexTooLarge
   103  		}
   104  		childID, err := ids.ToID(childIDBytes)
   105  		if err != nil {
   106  			return err
   107  		}
   108  		node.Children[byte(childIndex)] = childID
   109  	}
   110  
   111  	if !pbNode.ValueOrHash.IsNothing {
   112  		node.ValueOrHash = maybe.Some(pbNode.ValueOrHash.Value)
   113  	}
   114  
   115  	return nil
   116  }
   117  
   118  // Proof represents an inclusion/exclusion proof of a key.
   119  type Proof struct {
   120  	// Nodes in the proof path from root --> target key
   121  	// (or node that would be where key is if it doesn't exist).
   122  	// Always contains at least the root.
   123  	Path []ProofNode
   124  	// This is a proof that [key] exists/doesn't exist.
   125  	Key Key
   126  
   127  	// Nothing if [Key] isn't in the trie.
   128  	// Otherwise, the value corresponding to [Key].
   129  	Value maybe.Maybe[[]byte]
   130  }
   131  
   132  // Verify returns nil if the trie given in [proof] has root [expectedRootID].
   133  // That is, this is a valid proof that [proof.Key] exists/doesn't exist
   134  // in the trie with root [expectedRootID].
   135  func (proof *Proof) Verify(
   136  	ctx context.Context,
   137  	expectedRootID ids.ID,
   138  	tokenSize int,
   139  	hasher Hasher,
   140  ) error {
   141  	// Make sure the proof is well-formed.
   142  	if len(proof.Path) == 0 {
   143  		return ErrEmptyProof
   144  	}
   145  
   146  	if err := verifyProofPath(proof.Path, maybe.Some(proof.Key)); err != nil {
   147  		return err
   148  	}
   149  
   150  	// Confirm that the last proof node's value matches the claimed proof value
   151  	lastNode := proof.Path[len(proof.Path)-1]
   152  
   153  	// If the last proof node's key is [proof.Key] (i.e. this is an inclusion proof)
   154  	// then the value of the last proof node must match [proof.Value].
   155  	// Note partial byte length keys can never match the [proof.Key] since it's bytes,
   156  	// and thus has a whole number of bytes
   157  	if !lastNode.Key.hasPartialByte() &&
   158  		proof.Key == lastNode.Key &&
   159  		!valueOrHashMatches(hasher, proof.Value, lastNode.ValueOrHash) {
   160  		return ErrProofValueDoesntMatch
   161  	}
   162  
   163  	// If the last proof node has a length not evenly divisible into bytes or a different key than [proof.Key]
   164  	// then this is an exclusion proof and should prove that [proof.Key] isn't in the trie.
   165  	// Note length not evenly divisible into bytes can never match the [proof.Key] since it's bytes,
   166  	// and thus an exact number of bytes.
   167  	if (lastNode.Key.hasPartialByte() || proof.Key != lastNode.Key) &&
   168  		proof.Value.HasValue() {
   169  		return ErrProofValueDoesntMatch
   170  	}
   171  
   172  	// Don't bother locking [view] -- nobody else has a reference to it.
   173  	view, err := getStandaloneView(ctx, nil, tokenSize)
   174  	if err != nil {
   175  		return err
   176  	}
   177  
   178  	// Insert all proof nodes.
   179  	// [provenKey] is the key that we are proving exists, or the key
   180  	// that is the next key along the node path, proving that [proof.Key] doesn't exist in the trie.
   181  	provenKey := maybe.Some(lastNode.Key)
   182  
   183  	if err = addPathInfo(view, proof.Path, provenKey, provenKey); err != nil {
   184  		return err
   185  	}
   186  
   187  	gotRootID, err := view.GetMerkleRoot(ctx)
   188  	if err != nil {
   189  		return err
   190  	}
   191  	if expectedRootID != gotRootID {
   192  		return fmt.Errorf("%w:[%s], expected:[%s]", ErrInvalidProof, gotRootID, expectedRootID)
   193  	}
   194  	return nil
   195  }
   196  
   197  func (proof *Proof) ToProto() *pb.Proof {
   198  	value := &pb.MaybeBytes{
   199  		Value:     proof.Value.Value(),
   200  		IsNothing: proof.Value.IsNothing(),
   201  	}
   202  
   203  	pbProof := &pb.Proof{
   204  		Key:   proof.Key.Bytes(),
   205  		Value: value,
   206  	}
   207  
   208  	pbProof.Proof = make([]*pb.ProofNode, len(proof.Path))
   209  	for i, node := range proof.Path {
   210  		pbProof.Proof[i] = node.ToProto()
   211  	}
   212  
   213  	return pbProof
   214  }
   215  
   216  func (proof *Proof) UnmarshalProto(pbProof *pb.Proof) error {
   217  	switch {
   218  	case pbProof == nil:
   219  		return ErrNilProof
   220  	case pbProof.Value == nil:
   221  		return ErrNilValue
   222  	case pbProof.Value.IsNothing && len(pbProof.Value.Value) != 0:
   223  		return ErrInvalidMaybe
   224  	}
   225  
   226  	proof.Key = ToKey(pbProof.Key)
   227  
   228  	if !pbProof.Value.IsNothing {
   229  		proof.Value = maybe.Some(pbProof.Value.Value)
   230  	}
   231  
   232  	proof.Path = make([]ProofNode, len(pbProof.Proof))
   233  	for i, pbNode := range pbProof.Proof {
   234  		if err := proof.Path[i].UnmarshalProto(pbNode); err != nil {
   235  			return err
   236  		}
   237  	}
   238  
   239  	return nil
   240  }
   241  
   242  type KeyValue struct {
   243  	Key   []byte
   244  	Value []byte
   245  }
   246  
   247  // RangeProof is a proof that a given set of key-value pairs are in a trie.
   248  type RangeProof struct {
   249  	// Invariant: At least one of [StartProof], [EndProof], [KeyValues] is non-empty.
   250  
   251  	// A proof that the smallest key in the requested range does/doesn't exist.
   252  	// Note that this may not be an entire proof -- nodes are omitted if
   253  	// they are also in [EndProof].
   254  	StartProof []ProofNode
   255  
   256  	// If no upper range bound was given and [KeyValues] is empty, this is empty.
   257  	//
   258  	// If no upper range bound was given and [KeyValues] is non-empty, this is
   259  	// a proof for the largest key in [KeyValues].
   260  	//
   261  	// Otherwise this is a proof for the upper range bound.
   262  	EndProof []ProofNode
   263  
   264  	// This proof proves that the key-value pairs in [KeyValues] are in the trie.
   265  	// Sorted by increasing key.
   266  	KeyValues []KeyValue
   267  }
   268  
   269  // Verify returns nil iff all the following hold:
   270  //   - The invariants of RangeProof hold.
   271  //   - [start] <= [end].
   272  //   - [proof] proves the key-value pairs in [proof.KeyValues] are in the trie
   273  //     whose root is [expectedRootID].
   274  //
   275  // All keys in [proof.KeyValues] are in the range [start, end].
   276  //
   277  //	If [start] is Nothing, all keys are considered > [start].
   278  //	If [end] is Nothing, all keys are considered < [end].
   279  func (proof *RangeProof) Verify(
   280  	ctx context.Context,
   281  	start maybe.Maybe[[]byte],
   282  	end maybe.Maybe[[]byte],
   283  	expectedRootID ids.ID,
   284  	tokenSize int,
   285  	hasher Hasher,
   286  ) error {
   287  	switch {
   288  	case start.HasValue() && end.HasValue() && bytes.Compare(start.Value(), end.Value()) > 0:
   289  		return ErrStartAfterEnd
   290  	case len(proof.KeyValues) == 0 && len(proof.StartProof) == 0 && len(proof.EndProof) == 0:
   291  		return ErrEmptyProof
   292  	case end.IsNothing() && len(proof.KeyValues) == 0 && len(proof.EndProof) != 0:
   293  		return ErrUnexpectedEndProof
   294  	case len(proof.EndProof) == 0 && (end.HasValue() || len(proof.KeyValues) > 0):
   295  		return ErrNoEndProof
   296  	}
   297  
   298  	// Make sure the key-value pairs are sorted and in [start, end].
   299  	if err := verifyKeyValues(proof.KeyValues, start, end); err != nil {
   300  		return err
   301  	}
   302  
   303  	// [proof] allegedly provides and proves all key-value
   304  	// pairs in [smallestProvenKey, largestProvenKey].
   305  	// If [smallestProvenKey] is Nothing, [proof] should
   306  	// provide and prove all keys < [largestProvenKey].
   307  	// If [largestProvenKey] is Nothing, [proof] should
   308  	// provide and prove all keys > [smallestProvenKey].
   309  	// If both are Nothing, [proof] should prove the entire trie.
   310  	smallestProvenKey := maybe.Bind(start, ToKey)
   311  
   312  	largestProvenKey := maybe.Bind(end, ToKey)
   313  
   314  	if len(proof.KeyValues) > 0 {
   315  		// If [proof] has key-value pairs, we should insert children
   316  		// greater than [largestProvenKey] to ancestors of the node containing
   317  		// [largestProvenKey] so that we get the expected root ID.
   318  		largestProvenKey = maybe.Some(ToKey(proof.KeyValues[len(proof.KeyValues)-1].Key))
   319  	}
   320  
   321  	// The key-value pairs (allegedly) proven by [proof].
   322  	keyValues := make(map[Key][]byte, len(proof.KeyValues))
   323  	for _, keyValue := range proof.KeyValues {
   324  		keyValues[ToKey(keyValue.Key)] = keyValue.Value
   325  	}
   326  
   327  	// Ensure that the start proof is valid and contains values that
   328  	// match the key/values that were sent.
   329  	if err := verifyProofPath(proof.StartProof, smallestProvenKey); err != nil {
   330  		return err
   331  	}
   332  	if err := verifyAllRangeProofKeyValuesPresent(
   333  		hasher,
   334  		proof.StartProof,
   335  		smallestProvenKey,
   336  		largestProvenKey,
   337  		keyValues,
   338  	); err != nil {
   339  		return err
   340  	}
   341  
   342  	// Ensure that the end proof is valid and contains values that
   343  	// match the key/values that were sent.
   344  	if err := verifyProofPath(proof.EndProof, largestProvenKey); err != nil {
   345  		return err
   346  	}
   347  	if err := verifyAllRangeProofKeyValuesPresent(
   348  		hasher,
   349  		proof.EndProof,
   350  		smallestProvenKey,
   351  		largestProvenKey,
   352  		keyValues,
   353  	); err != nil {
   354  		return err
   355  	}
   356  
   357  	// Insert all key-value pairs into the trie.
   358  	ops := make([]database.BatchOp, len(proof.KeyValues))
   359  	for i, kv := range proof.KeyValues {
   360  		ops[i] = database.BatchOp{
   361  			Key:   kv.Key,
   362  			Value: kv.Value,
   363  		}
   364  	}
   365  
   366  	// Don't need to lock [view] because nobody else has a reference to it.
   367  	view, err := getStandaloneView(ctx, ops, tokenSize)
   368  	if err != nil {
   369  		return err
   370  	}
   371  
   372  	// For all the nodes along the edges of the proof, insert children
   373  	// < [smallestProvenKey] and > [largestProvenKey]
   374  	// into the trie so that we get the expected root ID (if this proof is valid).
   375  	// By inserting all children < [smallestProvenKey], we prove that there are no keys
   376  	// > [smallestProvenKey] but less than the first key given.
   377  	// That is, the peer who gave us this proof is not omitting nodes.
   378  	if err := addPathInfo(
   379  		view,
   380  		proof.StartProof,
   381  		smallestProvenKey,
   382  		largestProvenKey,
   383  	); err != nil {
   384  		return err
   385  	}
   386  	if err := addPathInfo(
   387  		view,
   388  		proof.EndProof,
   389  		smallestProvenKey,
   390  		largestProvenKey,
   391  	); err != nil {
   392  		return err
   393  	}
   394  
   395  	calculatedRoot, err := view.GetMerkleRoot(ctx)
   396  	if err != nil {
   397  		return err
   398  	}
   399  	if expectedRootID != calculatedRoot {
   400  		return fmt.Errorf("%w:[%s], expected:[%s]", ErrInvalidProof, calculatedRoot, expectedRootID)
   401  	}
   402  	return nil
   403  }
   404  
   405  func (proof *RangeProof) ToProto() *pb.RangeProof {
   406  	startProof := make([]*pb.ProofNode, len(proof.StartProof))
   407  	for i, node := range proof.StartProof {
   408  		startProof[i] = node.ToProto()
   409  	}
   410  
   411  	endProof := make([]*pb.ProofNode, len(proof.EndProof))
   412  	for i, node := range proof.EndProof {
   413  		endProof[i] = node.ToProto()
   414  	}
   415  
   416  	keyValues := make([]*pb.KeyValue, len(proof.KeyValues))
   417  	for i, kv := range proof.KeyValues {
   418  		keyValues[i] = &pb.KeyValue{
   419  			Key:   kv.Key,
   420  			Value: kv.Value,
   421  		}
   422  	}
   423  
   424  	return &pb.RangeProof{
   425  		StartProof: startProof,
   426  		EndProof:   endProof,
   427  		KeyValues:  keyValues,
   428  	}
   429  }
   430  
   431  func (proof *RangeProof) UnmarshalProto(pbProof *pb.RangeProof) error {
   432  	if pbProof == nil {
   433  		return ErrNilRangeProof
   434  	}
   435  
   436  	proof.StartProof = make([]ProofNode, len(pbProof.StartProof))
   437  	for i, protoNode := range pbProof.StartProof {
   438  		if err := proof.StartProof[i].UnmarshalProto(protoNode); err != nil {
   439  			return err
   440  		}
   441  	}
   442  
   443  	proof.EndProof = make([]ProofNode, len(pbProof.EndProof))
   444  	for i, protoNode := range pbProof.EndProof {
   445  		if err := proof.EndProof[i].UnmarshalProto(protoNode); err != nil {
   446  			return err
   447  		}
   448  	}
   449  
   450  	proof.KeyValues = make([]KeyValue, len(pbProof.KeyValues))
   451  	for i, kv := range pbProof.KeyValues {
   452  		proof.KeyValues[i] = KeyValue{
   453  			Key:   kv.Key,
   454  			Value: kv.Value,
   455  		}
   456  	}
   457  
   458  	return nil
   459  }
   460  
   461  // Verify that all non-intermediate nodes in [proof] which have keys
   462  // in [[start], [end]] have the value given for that key in [keysValues].
   463  func verifyAllRangeProofKeyValuesPresent(
   464  	hasher Hasher,
   465  	proof []ProofNode,
   466  	start maybe.Maybe[Key],
   467  	end maybe.Maybe[Key],
   468  	keysValues map[Key][]byte,
   469  ) error {
   470  	for i := 0; i < len(proof); i++ {
   471  		var (
   472  			node    = proof[i]
   473  			nodeKey = node.Key
   474  		)
   475  
   476  		// Skip keys that cannot have a value (enforced by [verifyProofPath]).
   477  		if !nodeKey.hasPartialByte() && (start.IsNothing() || !nodeKey.Less(start.Value())) && (end.IsNothing() || !nodeKey.Greater(end.Value())) {
   478  			value, ok := keysValues[nodeKey]
   479  			if !ok && node.ValueOrHash.HasValue() {
   480  				// We didn't get a key-value pair for this key, but the proof node has a value.
   481  				return ErrProofNodeHasUnincludedValue
   482  			}
   483  			if ok && !valueOrHashMatches(hasher, maybe.Some(value), node.ValueOrHash) {
   484  				// We got a key-value pair for this key, but the value in the proof
   485  				// node doesn't match the value we got for this key.
   486  				return ErrProofValueDoesntMatch
   487  			}
   488  		}
   489  	}
   490  	return nil
   491  }
   492  
   493  type KeyChange struct {
   494  	Key   []byte
   495  	Value maybe.Maybe[[]byte]
   496  }
   497  
   498  // ChangeProof proves that a set of key-value changes occurred
   499  // between two trie roots, where each key-value pair's key is
   500  // between some lower and upper bound (inclusive).
   501  type ChangeProof struct {
   502  	// Invariant: At least one of [StartProof], [EndProof], or
   503  	// [KeyChanges] is non-empty.
   504  
   505  	// A proof that the smallest key in the requested range does/doesn't
   506  	// exist in the trie with the requested start root.
   507  	// Empty if no lower bound on the requested range was given.
   508  	// Note that this may not be an entire proof -- nodes are omitted if
   509  	// they are also in [EndProof].
   510  	StartProof []ProofNode
   511  
   512  	// If [KeyChanges] is non-empty, this is a proof of the largest key
   513  	// in [KeyChanges].
   514  	//
   515  	// If [KeyChanges] is empty and an upper range bound was given,
   516  	// this is a proof of the upper range bound.
   517  	//
   518  	// If [KeyChanges] is empty and no upper range bound was given,
   519  	// this is empty.
   520  	EndProof []ProofNode
   521  
   522  	// A subset of key-values that were added, removed, or had their values
   523  	// modified between the requested start root (exclusive) and the requested
   524  	// end root (inclusive).
   525  	// Each key is in the requested range (inclusive).
   526  	// The first key-value is the first key-value at/after the range start.
   527  	// The key-value pairs are consecutive. That is, if keys k1 and k2 are
   528  	// in [KeyChanges] then there is no k3 that was modified between the start and
   529  	// end roots such that k1 < k3 < k2.
   530  	// This is a subset of the requested key-value range, rather than the entire
   531  	// range, because otherwise the proof may be too large.
   532  	// Sorted by increasing key and with no duplicate keys.
   533  	//
   534  	// Example: Suppose that between the start root and the end root, the following
   535  	// key-value pairs were added, removed, or modified:
   536  	//
   537  	// [kv1, kv2, kv3, kv4, kv5]
   538  	// where start <= kv1 < ... < kv5 <= end.
   539  	//
   540  	// The following are possible values of [KeyChanges]:
   541  	//
   542  	// []
   543  	// [kv1]
   544  	// [kv1, kv2]
   545  	// [kv1, kv2, kv3]
   546  	// [kv1, kv2, kv3, kv4]
   547  	// [kv1, kv2, kv3, kv4, kv5]
   548  	//
   549  	// The following values of [KeyChanges] are always invalid, for example:
   550  	//
   551  	// [kv2] (Doesn't include kv1, the first key-value at/after the range start)
   552  	// [kv1, kv3] (Doesn't include kv2, the key-value between kv1 and kv3)
   553  	// [kv1, kv3, kv2] (Not sorted by increasing key)
   554  	// [kv1, kv1] (Duplicate key-value pairs)
   555  	// [kv0, kv1] (For some kv1 < start)
   556  	// [kv1, kv2, kv3, kv4, kv5, kv6] (For some kv6 > end)
   557  	KeyChanges []KeyChange
   558  }
   559  
   560  func (proof *ChangeProof) ToProto() *pb.ChangeProof {
   561  	startProof := make([]*pb.ProofNode, len(proof.StartProof))
   562  	for i, node := range proof.StartProof {
   563  		startProof[i] = node.ToProto()
   564  	}
   565  
   566  	endProof := make([]*pb.ProofNode, len(proof.EndProof))
   567  	for i, node := range proof.EndProof {
   568  		endProof[i] = node.ToProto()
   569  	}
   570  
   571  	keyChanges := make([]*pb.KeyChange, len(proof.KeyChanges))
   572  	for i, kv := range proof.KeyChanges {
   573  		keyChanges[i] = &pb.KeyChange{
   574  			Key: kv.Key,
   575  			Value: &pb.MaybeBytes{
   576  				Value:     kv.Value.Value(),
   577  				IsNothing: kv.Value.IsNothing(),
   578  			},
   579  		}
   580  	}
   581  
   582  	return &pb.ChangeProof{
   583  		StartProof: startProof,
   584  		EndProof:   endProof,
   585  		KeyChanges: keyChanges,
   586  	}
   587  }
   588  
   589  func (proof *ChangeProof) UnmarshalProto(pbProof *pb.ChangeProof) error {
   590  	if pbProof == nil {
   591  		return ErrNilChangeProof
   592  	}
   593  
   594  	proof.StartProof = make([]ProofNode, len(pbProof.StartProof))
   595  	for i, protoNode := range pbProof.StartProof {
   596  		if err := proof.StartProof[i].UnmarshalProto(protoNode); err != nil {
   597  			return err
   598  		}
   599  	}
   600  
   601  	proof.EndProof = make([]ProofNode, len(pbProof.EndProof))
   602  	for i, protoNode := range pbProof.EndProof {
   603  		if err := proof.EndProof[i].UnmarshalProto(protoNode); err != nil {
   604  			return err
   605  		}
   606  	}
   607  
   608  	proof.KeyChanges = make([]KeyChange, len(pbProof.KeyChanges))
   609  	for i, kv := range pbProof.KeyChanges {
   610  		if kv.Value == nil {
   611  			return ErrNilMaybeBytes
   612  		}
   613  
   614  		if kv.Value.IsNothing && len(kv.Value.Value) != 0 {
   615  			return ErrInvalidMaybe
   616  		}
   617  
   618  		value := maybe.Nothing[[]byte]()
   619  		if !kv.Value.IsNothing {
   620  			value = maybe.Some(kv.Value.Value)
   621  		}
   622  		proof.KeyChanges[i] = KeyChange{
   623  			Key:   kv.Key,
   624  			Value: value,
   625  		}
   626  	}
   627  
   628  	return nil
   629  }
   630  
   631  // Verifies that all values present in the [proof]:
   632  // - Are nothing when deleted, not in the db, or the node has key partial byte length
   633  // - if the node's key is within the key range, that has a value that matches the value passed in the change list or in the db
   634  func verifyAllChangeProofKeyValuesPresent(
   635  	ctx context.Context,
   636  	db *merkleDB,
   637  	proof []ProofNode,
   638  	start maybe.Maybe[Key],
   639  	end maybe.Maybe[Key],
   640  	keysValues map[Key]maybe.Maybe[[]byte],
   641  ) error {
   642  	for i := 0; i < len(proof); i++ {
   643  		var (
   644  			node    = proof[i]
   645  			nodeKey = node.Key
   646  		)
   647  
   648  		// Check the value of any node with a key that is within the range.
   649  		// Skip keys that cannot have a value (enforced by [verifyProofPath]).
   650  		if !nodeKey.hasPartialByte() && (start.IsNothing() || !nodeKey.Less(start.Value())) && (end.IsNothing() || !nodeKey.Greater(end.Value())) {
   651  			value, ok := keysValues[nodeKey]
   652  			if !ok {
   653  				// This value isn't in the list of key-value pairs we got.
   654  				dbValue, err := db.GetValue(ctx, nodeKey.Bytes())
   655  				if err != nil {
   656  					if !errors.Is(err, database.ErrNotFound) {
   657  						return err
   658  					}
   659  					// This key isn't in the database so proof node should have Nothing.
   660  					value = maybe.Nothing[[]byte]()
   661  				} else {
   662  					// This key is in the database so proof node should have matching value.
   663  					value = maybe.Some(dbValue)
   664  				}
   665  			}
   666  			if !valueOrHashMatches(db.hasher, value, node.ValueOrHash) {
   667  				return ErrProofValueDoesntMatch
   668  			}
   669  		}
   670  	}
   671  	return nil
   672  }
   673  
   674  func (proof *ChangeProof) Empty() bool {
   675  	return len(proof.KeyChanges) == 0 &&
   676  		len(proof.StartProof) == 0 && len(proof.EndProof) == 0
   677  }
   678  
   679  // ChangeOrRangeProof has exactly one of [ChangeProof] or [RangeProof] is non-nil.
   680  type ChangeOrRangeProof struct {
   681  	ChangeProof *ChangeProof
   682  	RangeProof  *RangeProof
   683  }
   684  
   685  // Returns nil iff both hold:
   686  // 1. [kvs] is sorted by key in increasing order.
   687  // 2. All keys in [kvs] are in the range [start, end].
   688  // If [start] is Nothing, there is no lower bound on acceptable keys.
   689  // If [end] is Nothing, there is no upper bound on acceptable keys.
   690  // If [kvs] is empty, returns nil.
   691  func verifyKeyChanges(kvs []KeyChange, start maybe.Maybe[[]byte], end maybe.Maybe[[]byte]) error {
   692  	if len(kvs) == 0 {
   693  		return nil
   694  	}
   695  
   696  	// ensure that the keys are in increasing order
   697  	for i := 0; i < len(kvs)-1; i++ {
   698  		if bytes.Compare(kvs[i].Key, kvs[i+1].Key) >= 0 {
   699  			return ErrNonIncreasingValues
   700  		}
   701  	}
   702  
   703  	// ensure that the keys are within the range [start, end]
   704  	if (start.HasValue() && bytes.Compare(kvs[0].Key, start.Value()) < 0) ||
   705  		(end.HasValue() && bytes.Compare(kvs[len(kvs)-1].Key, end.Value()) > 0) {
   706  		return ErrStateFromOutsideOfRange
   707  	}
   708  
   709  	return nil
   710  }
   711  
   712  // Returns nil iff both hold:
   713  // 1. [kvs] is sorted by key in increasing order.
   714  // 2. All keys in [kvs] are in the range [start, end].
   715  // If [start] is nil, there is no lower bound on acceptable keys.
   716  // If [end] is nothing, there is no upper bound on acceptable keys.
   717  // If [kvs] is empty, returns nil.
   718  func verifyKeyValues(kvs []KeyValue, start maybe.Maybe[[]byte], end maybe.Maybe[[]byte]) error {
   719  	hasLowerBound := start.HasValue()
   720  	hasUpperBound := end.HasValue()
   721  	for i := 0; i < len(kvs); i++ {
   722  		if i < len(kvs)-1 && bytes.Compare(kvs[i].Key, kvs[i+1].Key) >= 0 {
   723  			return ErrNonIncreasingValues
   724  		}
   725  		if (hasLowerBound && bytes.Compare(kvs[i].Key, start.Value()) < 0) ||
   726  			(hasUpperBound && bytes.Compare(kvs[i].Key, end.Value()) > 0) {
   727  			return ErrStateFromOutsideOfRange
   728  		}
   729  	}
   730  	return nil
   731  }
   732  
   733  // Returns nil iff all the following hold:
   734  //   - Any node with a partial byte length, should not have a value associated with it
   735  //     since all keys with values are written in complete bytes([]byte).
   736  //   - Each key in [proof] is a strict prefix of the following key.
   737  //   - Each key in [proof] is a strict prefix of [keyBytes], except possibly the last.
   738  //   - If the last element in [proof] is [Key], this is an inclusion proof.
   739  //     Otherwise, this is an exclusion proof and [keyBytes] must not be in [proof].
   740  func verifyProofPath(proof []ProofNode, key maybe.Maybe[Key]) error {
   741  	if len(proof) == 0 {
   742  		return nil
   743  	}
   744  
   745  	// loop over all but the last node since it will not have the prefix in exclusion proofs
   746  	for i := 0; i < len(proof)-1; i++ {
   747  		currentProofNode := proof[i]
   748  		nodeKey := currentProofNode.Key
   749  
   750  		// Because the interface only supports []byte keys,
   751  		// a key with a partial byte may not store a value
   752  		if nodeKey.hasPartialByte() && proof[i].ValueOrHash.HasValue() {
   753  			return ErrPartialByteLengthWithValue
   754  		}
   755  
   756  		// each node should have a key that has the proven key as a prefix
   757  		if key.HasValue() && !key.Value().HasStrictPrefix(nodeKey) {
   758  			return ErrProofNodeNotForKey
   759  		}
   760  
   761  		// each node should have a key that has a matching TokenConfig and is a prefix of the next node's key
   762  		nextKey := proof[i+1].Key
   763  		if !nextKey.HasStrictPrefix(nodeKey) {
   764  			return ErrNonIncreasingProofNodes
   765  		}
   766  	}
   767  
   768  	// check the last node for a value since the above loop doesn't check the last node
   769  	if len(proof) > 0 {
   770  		lastNode := proof[len(proof)-1]
   771  		if lastNode.Key.hasPartialByte() && !lastNode.ValueOrHash.IsNothing() {
   772  			return ErrPartialByteLengthWithValue
   773  		}
   774  	}
   775  
   776  	return nil
   777  }
   778  
   779  // Returns true if [value] and [valueDigest] match.
   780  // [valueOrHash] should be the [ValueOrHash] field of a [ProofNode].
   781  func valueOrHashMatches(
   782  	hasher Hasher,
   783  	value maybe.Maybe[[]byte],
   784  	valueOrHash maybe.Maybe[[]byte],
   785  ) bool {
   786  	var (
   787  		valueIsNothing  = value.IsNothing()
   788  		digestIsNothing = valueOrHash.IsNothing()
   789  	)
   790  
   791  	switch {
   792  	case valueIsNothing != digestIsNothing:
   793  		// One is nothing and the other isn't -- no match.
   794  		return false
   795  	case valueIsNothing:
   796  		// Both are nothing -- match.
   797  		return true
   798  	case len(value.Value()) < HashLength:
   799  		return bytes.Equal(value.Value(), valueOrHash.Value())
   800  	default:
   801  		valueHash := hasher.HashValue(value.Value())
   802  		return bytes.Equal(valueHash[:], valueOrHash.Value())
   803  	}
   804  }
   805  
   806  // Adds each key/value pair in [proofPath] to [t].
   807  // For each proof node, adds the children that are
   808  // < [insertChildrenLessThan] or > [insertChildrenGreaterThan].
   809  // If [insertChildrenLessThan] is Nothing, no children are < [insertChildrenLessThan].
   810  // If [insertChildrenGreaterThan] is Nothing, no children are > [insertChildrenGreaterThan].
   811  // Assumes [v.lock] is held.
   812  func addPathInfo(
   813  	v *view,
   814  	proofPath []ProofNode,
   815  	insertChildrenLessThan maybe.Maybe[Key],
   816  	insertChildrenGreaterThan maybe.Maybe[Key],
   817  ) error {
   818  	var (
   819  		shouldInsertLeftChildren  = insertChildrenLessThan.HasValue()
   820  		shouldInsertRightChildren = insertChildrenGreaterThan.HasValue()
   821  	)
   822  
   823  	for i := len(proofPath) - 1; i >= 0; i-- {
   824  		proofNode := proofPath[i]
   825  		key := proofNode.Key
   826  
   827  		if key.hasPartialByte() && !proofNode.ValueOrHash.IsNothing() {
   828  			return ErrPartialByteLengthWithValue
   829  		}
   830  
   831  		// load the node associated with the key or create a new one
   832  		// pass nothing because we are going to overwrite the value digest below
   833  		n, err := v.insert(key, maybe.Nothing[[]byte]())
   834  		if err != nil {
   835  			return err
   836  		}
   837  		// We overwrite the valueDigest to be the hash provided in the proof
   838  		// node because we may not know the pre-image of the valueDigest.
   839  		n.valueDigest = proofNode.ValueOrHash
   840  
   841  		if !shouldInsertLeftChildren && !shouldInsertRightChildren {
   842  			// No children of proof nodes are outside the range.
   843  			// No need to add any children to [n].
   844  			continue
   845  		}
   846  
   847  		// Add [proofNode]'s children which are outside the range
   848  		// [insertChildrenLessThan, insertChildrenGreaterThan].
   849  		for index, childID := range proofNode.Children {
   850  			var compressedKey Key
   851  			if existingChild, ok := n.children[index]; ok {
   852  				compressedKey = existingChild.compressedKey
   853  			}
   854  			childKey := key.Extend(ToToken(index, v.tokenSize), compressedKey)
   855  			if (shouldInsertLeftChildren && childKey.Less(insertChildrenLessThan.Value())) ||
   856  				(shouldInsertRightChildren && childKey.Greater(insertChildrenGreaterThan.Value())) {
   857  				// We don't set the [hasValue] field of the child but that's OK.
   858  				// We only need the compressed key and ID to be correct so that the
   859  				// calculated hash is correct.
   860  				n.setChildEntry(
   861  					index,
   862  					&child{
   863  						id:            childID,
   864  						compressedKey: compressedKey,
   865  					})
   866  			}
   867  		}
   868  	}
   869  
   870  	return nil
   871  }
   872  
   873  // getStandaloneView returns a new view that has nothing in it besides the changes due to [ops]
   874  func getStandaloneView(ctx context.Context, ops []database.BatchOp, size int) (*view, error) {
   875  	db, err := newDatabase(
   876  		ctx,
   877  		memdb.New(),
   878  		Config{
   879  			BranchFactor:                tokenSizeToBranchFactor[size],
   880  			Tracer:                      trace.Noop,
   881  			ValueNodeCacheSize:          verificationCacheSize,
   882  			IntermediateNodeCacheSize:   verificationCacheSize,
   883  			IntermediateWriteBufferSize: verificationCacheSize,
   884  			IntermediateWriteBatchSize:  verificationCacheSize,
   885  		},
   886  		&mockMetrics{},
   887  	)
   888  	if err != nil {
   889  		return nil, err
   890  	}
   891  
   892  	return newView(db, db, ViewChanges{BatchOps: ops, ConsumeBytes: true})
   893  }