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 }