github.com/MetalBlockchain/metalgo@v1.11.9/x/merkledb/proof_test.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 "math/rand" 10 "testing" 11 "time" 12 13 "github.com/stretchr/testify/require" 14 15 "github.com/MetalBlockchain/metalgo/database" 16 "github.com/MetalBlockchain/metalgo/ids" 17 "github.com/MetalBlockchain/metalgo/utils/hashing" 18 "github.com/MetalBlockchain/metalgo/utils/maybe" 19 "github.com/MetalBlockchain/metalgo/utils/set" 20 21 pb "github.com/MetalBlockchain/metalgo/proto/pb/sync" 22 ) 23 24 func Test_Proof_Empty(t *testing.T) { 25 proof := &Proof{} 26 err := proof.Verify(context.Background(), ids.Empty, 4, DefaultHasher) 27 require.ErrorIs(t, err, ErrEmptyProof) 28 } 29 30 func Test_Proof_Simple(t *testing.T) { 31 require := require.New(t) 32 33 db, err := getBasicDB() 34 require.NoError(err) 35 36 ctx := context.Background() 37 require.NoError(db.PutContext(ctx, []byte{}, []byte{1})) 38 require.NoError(db.PutContext(ctx, []byte{0}, []byte{2})) 39 40 expectedRoot, err := db.GetMerkleRoot(ctx) 41 require.NoError(err) 42 43 proof, err := db.GetProof(ctx, []byte{}) 44 require.NoError(err) 45 46 require.NoError(proof.Verify(ctx, expectedRoot, db.tokenSize, db.hasher)) 47 } 48 49 func Test_Proof_Verify_Bad_Data(t *testing.T) { 50 type test struct { 51 name string 52 malform func(proof *Proof) 53 expectedErr error 54 } 55 56 tests := []test{ 57 { 58 name: "happyPath", 59 malform: func(*Proof) {}, 60 expectedErr: nil, 61 }, 62 { 63 name: "empty", 64 malform: func(proof *Proof) { 65 proof.Path = nil 66 }, 67 expectedErr: ErrEmptyProof, 68 }, 69 { 70 name: "odd length key path with value", 71 malform: func(proof *Proof) { 72 proof.Path[0].ValueOrHash = maybe.Some([]byte{1, 2}) 73 }, 74 expectedErr: ErrPartialByteLengthWithValue, 75 }, 76 { 77 name: "last proof node has missing value", 78 malform: func(proof *Proof) { 79 proof.Path[len(proof.Path)-1].ValueOrHash = maybe.Nothing[[]byte]() 80 }, 81 expectedErr: ErrProofValueDoesntMatch, 82 }, 83 { 84 name: "missing value on proof", 85 malform: func(proof *Proof) { 86 proof.Value = maybe.Nothing[[]byte]() 87 }, 88 expectedErr: ErrProofValueDoesntMatch, 89 }, 90 { 91 name: "mismatched value on proof", 92 malform: func(proof *Proof) { 93 proof.Value = maybe.Some([]byte{10}) 94 }, 95 expectedErr: ErrProofValueDoesntMatch, 96 }, 97 { 98 name: "value of exclusion proof", 99 malform: func(proof *Proof) { 100 // remove the value node to make it look like it is an exclusion proof 101 proof.Path = proof.Path[:len(proof.Path)-1] 102 }, 103 expectedErr: ErrProofValueDoesntMatch, 104 }, 105 } 106 107 for _, tt := range tests { 108 t.Run(tt.name, func(t *testing.T) { 109 require := require.New(t) 110 111 db, err := getBasicDB() 112 require.NoError(err) 113 114 writeBasicBatch(t, db) 115 116 proof, err := db.GetProof(context.Background(), []byte{2}) 117 require.NoError(err) 118 require.NotNil(proof) 119 120 tt.malform(proof) 121 122 err = proof.Verify(context.Background(), db.getMerkleRoot(), db.tokenSize, db.hasher) 123 require.ErrorIs(err, tt.expectedErr) 124 }) 125 } 126 } 127 128 func Test_Proof_ValueOrHashMatches(t *testing.T) { 129 require := require.New(t) 130 131 require.True(valueOrHashMatches(SHA256Hasher, maybe.Some([]byte{0}), maybe.Some([]byte{0}))) 132 require.False(valueOrHashMatches(SHA256Hasher, maybe.Nothing[[]byte](), maybe.Some(hashing.ComputeHash256([]byte{0})))) 133 require.True(valueOrHashMatches(SHA256Hasher, maybe.Nothing[[]byte](), maybe.Nothing[[]byte]())) 134 135 require.False(valueOrHashMatches(SHA256Hasher, maybe.Some([]byte{0}), maybe.Nothing[[]byte]())) 136 require.False(valueOrHashMatches(SHA256Hasher, maybe.Nothing[[]byte](), maybe.Some([]byte{0}))) 137 require.False(valueOrHashMatches(SHA256Hasher, maybe.Nothing[[]byte](), maybe.Some(hashing.ComputeHash256([]byte{1})))) 138 require.False(valueOrHashMatches(SHA256Hasher, maybe.Some(hashing.ComputeHash256([]byte{0})), maybe.Nothing[[]byte]())) 139 } 140 141 func Test_RangeProof_Extra_Value(t *testing.T) { 142 require := require.New(t) 143 144 db, err := getBasicDB() 145 require.NoError(err) 146 writeBasicBatch(t, db) 147 148 val, err := db.Get([]byte{2}) 149 require.NoError(err) 150 require.Equal([]byte{2}, val) 151 152 proof, err := db.GetRangeProof(context.Background(), maybe.Some([]byte{1}), maybe.Some([]byte{5, 5}), 10) 153 require.NoError(err) 154 require.NotNil(proof) 155 156 require.NoError(proof.Verify( 157 context.Background(), 158 maybe.Some([]byte{1}), 159 maybe.Some([]byte{5, 5}), 160 db.rootID, 161 db.tokenSize, 162 db.hasher, 163 )) 164 165 proof.KeyValues = append(proof.KeyValues, KeyValue{Key: []byte{5}, Value: []byte{5}}) 166 167 err = proof.Verify( 168 context.Background(), 169 maybe.Some([]byte{1}), 170 maybe.Some([]byte{5, 5}), 171 db.rootID, 172 db.tokenSize, 173 db.hasher, 174 ) 175 require.ErrorIs(err, ErrInvalidProof) 176 } 177 178 func Test_RangeProof_Verify_Bad_Data(t *testing.T) { 179 type test struct { 180 name string 181 malform func(proof *RangeProof) 182 expectedErr error 183 } 184 185 tests := []test{ 186 { 187 name: "happyPath", 188 malform: func(*RangeProof) {}, 189 expectedErr: nil, 190 }, 191 { 192 name: "empty", 193 malform: func(proof *RangeProof) { 194 proof.KeyValues = nil 195 proof.StartProof = nil 196 proof.EndProof = nil 197 }, 198 expectedErr: ErrEmptyProof, 199 }, 200 { 201 name: "StartProof: last proof node has missing value", 202 malform: func(proof *RangeProof) { 203 proof.StartProof[len(proof.StartProof)-1].ValueOrHash = maybe.Nothing[[]byte]() 204 }, 205 expectedErr: ErrProofValueDoesntMatch, 206 }, 207 { 208 name: "EndProof: odd length key path with value", 209 malform: func(proof *RangeProof) { 210 proof.EndProof[0].ValueOrHash = maybe.Some([]byte{1, 2}) 211 }, 212 expectedErr: ErrPartialByteLengthWithValue, 213 }, 214 { 215 name: "EndProof: last proof node has missing value", 216 malform: func(proof *RangeProof) { 217 proof.EndProof[len(proof.EndProof)-1].ValueOrHash = maybe.Nothing[[]byte]() 218 }, 219 expectedErr: ErrProofValueDoesntMatch, 220 }, 221 { 222 name: "missing key/value", 223 malform: func(proof *RangeProof) { 224 proof.KeyValues = proof.KeyValues[1:] 225 }, 226 expectedErr: ErrProofNodeHasUnincludedValue, 227 }, 228 } 229 230 for _, tt := range tests { 231 t.Run(tt.name, func(t *testing.T) { 232 require := require.New(t) 233 234 db, err := getBasicDB() 235 require.NoError(err) 236 writeBasicBatch(t, db) 237 238 proof, err := db.GetRangeProof(context.Background(), maybe.Some([]byte{2}), maybe.Some([]byte{3, 0}), 50) 239 require.NoError(err) 240 require.NotNil(proof) 241 242 tt.malform(proof) 243 244 err = proof.Verify(context.Background(), maybe.Some([]byte{2}), maybe.Some([]byte{3, 0}), db.getMerkleRoot(), db.tokenSize, db.hasher) 245 require.ErrorIs(err, tt.expectedErr) 246 }) 247 } 248 } 249 250 func Test_RangeProof_MaxLength(t *testing.T) { 251 require := require.New(t) 252 253 dbTrie, err := getBasicDB() 254 require.NoError(err) 255 require.NotNil(dbTrie) 256 trie, err := dbTrie.NewView(context.Background(), ViewChanges{}) 257 require.NoError(err) 258 259 _, err = trie.GetRangeProof(context.Background(), maybe.Nothing[[]byte](), maybe.Nothing[[]byte](), -1) 260 require.ErrorIs(err, ErrInvalidMaxLength) 261 262 _, err = trie.GetRangeProof(context.Background(), maybe.Nothing[[]byte](), maybe.Nothing[[]byte](), 0) 263 require.ErrorIs(err, ErrInvalidMaxLength) 264 } 265 266 func Test_Proof(t *testing.T) { 267 require := require.New(t) 268 269 dbTrie, err := getBasicDB() 270 require.NoError(err) 271 require.NotNil(dbTrie) 272 trie, err := dbTrie.NewView( 273 context.Background(), 274 ViewChanges{ 275 BatchOps: []database.BatchOp{ 276 {Key: []byte("key"), Value: []byte("value")}, 277 {Key: []byte("key0"), Value: []byte("value0")}, 278 {Key: []byte("key1"), Value: []byte("value1")}, 279 {Key: []byte("key2"), Value: []byte("value2")}, 280 {Key: []byte("key3"), Value: []byte("value3")}, 281 {Key: []byte("key4"), Value: []byte("value4")}, 282 }, 283 }, 284 ) 285 require.NoError(err) 286 287 _, err = trie.GetMerkleRoot(context.Background()) 288 require.NoError(err) 289 proof, err := trie.GetProof(context.Background(), []byte("key1")) 290 require.NoError(err) 291 require.NotNil(proof) 292 293 require.Len(proof.Path, 3) 294 295 require.Equal(ToKey([]byte("key")), proof.Path[0].Key) 296 require.Equal(maybe.Some([]byte("value")), proof.Path[0].ValueOrHash) 297 require.Equal(ToKey([]byte("key0")).Take(28), proof.Path[1].Key) 298 require.True(proof.Path[1].ValueOrHash.IsNothing()) // intermediate node 299 require.Equal(ToKey([]byte("key1")), proof.Path[2].Key) 300 require.Equal(maybe.Some([]byte("value1")), proof.Path[2].ValueOrHash) 301 302 expectedRootID, err := trie.GetMerkleRoot(context.Background()) 303 require.NoError(err) 304 require.NoError(proof.Verify(context.Background(), expectedRootID, dbTrie.tokenSize, dbTrie.hasher)) 305 306 proof.Path[0].Key = ToKey([]byte("key1")) 307 err = proof.Verify(context.Background(), expectedRootID, dbTrie.tokenSize, dbTrie.hasher) 308 require.ErrorIs(err, ErrProofNodeNotForKey) 309 } 310 311 func Test_RangeProof_Syntactic_Verify(t *testing.T) { 312 type test struct { 313 name string 314 start maybe.Maybe[[]byte] 315 end maybe.Maybe[[]byte] 316 proof *RangeProof 317 expectedErr error 318 } 319 320 tests := []test{ 321 { 322 name: "start > end", 323 start: maybe.Some([]byte{1}), 324 end: maybe.Some([]byte{0}), 325 proof: &RangeProof{}, 326 expectedErr: ErrStartAfterEnd, 327 }, 328 { 329 name: "empty", 330 start: maybe.Some([]byte{1}), 331 end: maybe.Nothing[[]byte](), 332 proof: &RangeProof{}, 333 expectedErr: ErrEmptyProof, 334 }, 335 { 336 name: "unexpected end proof", 337 start: maybe.Some([]byte{1}), 338 end: maybe.Nothing[[]byte](), 339 proof: &RangeProof{ 340 StartProof: []ProofNode{{}}, 341 EndProof: []ProofNode{{}}, 342 }, 343 expectedErr: ErrUnexpectedEndProof, 344 }, 345 { 346 name: "no end proof; has end bound", 347 start: maybe.Some([]byte{1}), 348 end: maybe.Some([]byte{1}), 349 proof: &RangeProof{ 350 StartProof: []ProofNode{{}}, 351 }, 352 expectedErr: ErrNoEndProof, 353 }, 354 { 355 name: "no end proof; has key-values", 356 start: maybe.Some([]byte{1}), 357 end: maybe.Nothing[[]byte](), 358 proof: &RangeProof{ 359 KeyValues: []KeyValue{{}}, 360 }, 361 expectedErr: ErrNoEndProof, 362 }, 363 { 364 name: "unsorted key values", 365 start: maybe.Some([]byte{1}), 366 end: maybe.Nothing[[]byte](), 367 proof: &RangeProof{ 368 KeyValues: []KeyValue{ 369 {Key: []byte{1}, Value: []byte{1}}, 370 {Key: []byte{0}, Value: []byte{0}}, 371 }, 372 EndProof: []ProofNode{{Key: Key{}}}, 373 }, 374 expectedErr: ErrNonIncreasingValues, 375 }, 376 { 377 name: "key lower than start", 378 start: maybe.Some([]byte{1}), 379 end: maybe.Nothing[[]byte](), 380 proof: &RangeProof{ 381 KeyValues: []KeyValue{ 382 {Key: []byte{0}, Value: []byte{0}}, 383 }, 384 EndProof: []ProofNode{{Key: Key{}}}, 385 }, 386 expectedErr: ErrStateFromOutsideOfRange, 387 }, 388 { 389 name: "key greater than end", 390 start: maybe.Some([]byte{1}), 391 end: maybe.Some([]byte{1}), 392 proof: &RangeProof{ 393 KeyValues: []KeyValue{ 394 {Key: []byte{2}, Value: []byte{0}}, 395 }, 396 EndProof: []ProofNode{{Key: Key{}}}, 397 }, 398 expectedErr: ErrStateFromOutsideOfRange, 399 }, 400 { 401 name: "start proof nodes in wrong order", 402 start: maybe.Some([]byte{1, 2}), 403 end: maybe.Nothing[[]byte](), 404 proof: &RangeProof{ 405 KeyValues: []KeyValue{ 406 {Key: []byte{1, 2}, Value: []byte{1}}, 407 }, 408 StartProof: []ProofNode{ 409 { 410 Key: ToKey([]byte{2}), 411 }, 412 { 413 Key: ToKey([]byte{1}), 414 }, 415 }, 416 EndProof: []ProofNode{{Key: Key{}}}, 417 }, 418 expectedErr: ErrProofNodeNotForKey, 419 }, 420 { 421 name: "start proof has node for wrong key", 422 start: maybe.Some([]byte{1, 2}), 423 end: maybe.Nothing[[]byte](), 424 proof: &RangeProof{ 425 KeyValues: []KeyValue{ 426 {Key: []byte{1, 2}, Value: []byte{1}}, 427 }, 428 StartProof: []ProofNode{ 429 { 430 Key: ToKey([]byte{1}), 431 }, 432 { 433 Key: ToKey([]byte{1, 2, 3}), // Not a prefix of [1, 2] 434 }, 435 { 436 Key: ToKey([]byte{1, 2, 3, 4}), 437 }, 438 }, 439 EndProof: []ProofNode{{Key: Key{}}}, 440 }, 441 expectedErr: ErrProofNodeNotForKey, 442 }, 443 { 444 name: "end proof nodes in wrong order", 445 start: maybe.Nothing[[]byte](), 446 end: maybe.Some([]byte{1, 2}), 447 proof: &RangeProof{ 448 KeyValues: []KeyValue{ 449 {Key: []byte{1, 2}, Value: []byte{1}}, 450 }, 451 EndProof: []ProofNode{ 452 { 453 Key: ToKey([]byte{2}), 454 }, 455 { 456 Key: ToKey([]byte{1}), 457 }, 458 }, 459 }, 460 expectedErr: ErrProofNodeNotForKey, 461 }, 462 { 463 name: "end proof has node for wrong key", 464 start: maybe.Nothing[[]byte](), 465 end: maybe.Some([]byte{1, 2}), 466 proof: &RangeProof{ 467 KeyValues: []KeyValue{ 468 {Key: []byte{1, 2}, Value: []byte{1}}, 469 }, 470 EndProof: []ProofNode{ 471 { 472 Key: ToKey([]byte{1}), 473 }, 474 { 475 Key: ToKey([]byte{1, 2, 3}), // Not a prefix of [1, 2] 476 }, 477 { 478 Key: ToKey([]byte{1, 2, 3, 4}), 479 }, 480 }, 481 }, 482 expectedErr: ErrProofNodeNotForKey, 483 }, 484 } 485 486 for _, tt := range tests { 487 t.Run(tt.name, func(t *testing.T) { 488 err := tt.proof.Verify(context.Background(), tt.start, tt.end, ids.Empty, 4, DefaultHasher) 489 require.ErrorIs(t, err, tt.expectedErr) 490 }) 491 } 492 } 493 494 func Test_RangeProof(t *testing.T) { 495 require := require.New(t) 496 497 db, err := getBasicDB() 498 require.NoError(err) 499 writeBasicBatch(t, db) 500 501 proof, err := db.GetRangeProof(context.Background(), maybe.Some([]byte{1}), maybe.Some([]byte{3, 5}), 10) 502 require.NoError(err) 503 require.NotNil(proof) 504 require.Len(proof.KeyValues, 3) 505 506 require.Equal([]byte{1}, proof.KeyValues[0].Key) 507 require.Equal([]byte{2}, proof.KeyValues[1].Key) 508 require.Equal([]byte{3}, proof.KeyValues[2].Key) 509 510 require.Equal([]byte{1}, proof.KeyValues[0].Value) 511 require.Equal([]byte{2}, proof.KeyValues[1].Value) 512 require.Equal([]byte{3}, proof.KeyValues[2].Value) 513 514 require.Len(proof.EndProof, 2) 515 require.Equal([]byte{0}, proof.EndProof[0].Key.Bytes()) 516 require.Len(proof.EndProof[0].Children, 5) // 0,1,2,3,4 517 require.Equal([]byte{3}, proof.EndProof[1].Key.Bytes()) 518 519 // only a single node here since others are duplicates in endproof 520 require.Equal([]byte{1}, proof.StartProof[0].Key.Bytes()) 521 522 require.NoError(proof.Verify( 523 context.Background(), 524 maybe.Some([]byte{1}), 525 maybe.Some([]byte{3, 5}), 526 db.rootID, 527 db.tokenSize, 528 db.hasher, 529 )) 530 } 531 532 func Test_RangeProof_BadBounds(t *testing.T) { 533 require := require.New(t) 534 535 db, err := getBasicDB() 536 require.NoError(err) 537 538 require.NoError(db.Put(nil, nil)) 539 540 // non-nil start/end 541 proof, err := db.GetRangeProof(context.Background(), maybe.Some([]byte{4}), maybe.Some([]byte{3}), 50) 542 require.ErrorIs(err, ErrStartAfterEnd) 543 require.Nil(proof) 544 } 545 546 func Test_RangeProof_NilStart(t *testing.T) { 547 require := require.New(t) 548 549 db, err := getBasicDB() 550 require.NoError(err) 551 batch := db.NewBatch() 552 require.NoError(batch.Put([]byte("key1"), []byte("value1"))) 553 require.NoError(batch.Put([]byte("key2"), []byte("value2"))) 554 require.NoError(batch.Put([]byte("key3"), []byte("value3"))) 555 require.NoError(batch.Put([]byte("key4"), []byte("value4"))) 556 require.NoError(batch.Write()) 557 558 val, err := db.Get([]byte("key1")) 559 require.NoError(err) 560 require.Equal([]byte("value1"), val) 561 562 proof, err := db.GetRangeProof(context.Background(), maybe.Nothing[[]byte](), maybe.Some([]byte("key35")), 2) 563 require.NoError(err) 564 require.NotNil(proof) 565 566 require.Len(proof.KeyValues, 2) 567 568 require.Equal([]byte("key1"), proof.KeyValues[0].Key) 569 require.Equal([]byte("key2"), proof.KeyValues[1].Key) 570 571 require.Equal([]byte("value1"), proof.KeyValues[0].Value) 572 require.Equal([]byte("value2"), proof.KeyValues[1].Value) 573 574 require.Equal(ToKey([]byte("key2")), proof.EndProof[1].Key, db.tokenSize) 575 require.Equal(ToKey([]byte("key2")).Take(28), proof.EndProof[0].Key) 576 577 require.NoError(proof.Verify( 578 context.Background(), 579 maybe.Nothing[[]byte](), 580 maybe.Some([]byte("key35")), 581 db.rootID, 582 db.tokenSize, 583 db.hasher, 584 )) 585 } 586 587 func Test_RangeProof_NilEnd(t *testing.T) { 588 require := require.New(t) 589 590 db, err := getBasicDB() 591 require.NoError(err) 592 593 writeBasicBatch(t, db) 594 require.NoError(err) 595 596 proof, err := db.GetRangeProof( // Should have keys [1], [2] 597 context.Background(), 598 maybe.Some([]byte{1}), 599 maybe.Nothing[[]byte](), 600 2, 601 ) 602 require.NoError(err) 603 require.NotNil(proof) 604 605 require.Len(proof.KeyValues, 2) 606 607 require.Equal([]byte{1}, proof.KeyValues[0].Key) 608 require.Equal([]byte{2}, proof.KeyValues[1].Key) 609 610 require.Equal([]byte{1}, proof.KeyValues[0].Value) 611 require.Equal([]byte{2}, proof.KeyValues[1].Value) 612 613 require.Equal([]byte{1}, proof.StartProof[0].Key.Bytes()) 614 615 require.Equal(db.root.Value().key, proof.EndProof[0].Key) 616 require.Equal([]byte{2}, proof.EndProof[1].Key.Bytes()) 617 618 require.NoError(proof.Verify( 619 context.Background(), 620 maybe.Some([]byte{1}), 621 maybe.Nothing[[]byte](), 622 db.rootID, 623 db.tokenSize, 624 db.hasher, 625 )) 626 } 627 628 func Test_RangeProof_EmptyValues(t *testing.T) { 629 require := require.New(t) 630 631 db, err := getBasicDB() 632 require.NoError(err) 633 batch := db.NewBatch() 634 require.NoError(batch.Put([]byte("key1"), nil)) 635 require.NoError(batch.Put([]byte("key12"), []byte("value1"))) 636 require.NoError(batch.Put([]byte("key2"), []byte{})) 637 require.NoError(batch.Write()) 638 639 val, err := db.Get([]byte("key12")) 640 require.NoError(err) 641 require.Equal([]byte("value1"), val) 642 643 proof, err := db.GetRangeProof(context.Background(), maybe.Some([]byte("key1")), maybe.Some([]byte("key2")), 10) 644 require.NoError(err) 645 require.NotNil(proof) 646 647 require.Len(proof.KeyValues, 3) 648 require.Equal([]byte("key1"), proof.KeyValues[0].Key) 649 require.Empty(proof.KeyValues[0].Value) 650 require.Equal([]byte("key12"), proof.KeyValues[1].Key) 651 require.Equal([]byte("value1"), proof.KeyValues[1].Value) 652 require.Equal([]byte("key2"), proof.KeyValues[2].Key) 653 require.Empty(proof.KeyValues[2].Value) 654 655 require.Len(proof.StartProof, 1) 656 require.Equal(ToKey([]byte("key1")), proof.StartProof[0].Key) 657 658 require.Len(proof.EndProof, 2) 659 require.Equal(ToKey([]byte("key1")).Take(28), proof.EndProof[0].Key, db.tokenSize) // root 660 require.Equal(ToKey([]byte("key2")), proof.EndProof[1].Key, db.tokenSize) 661 662 require.NoError(proof.Verify( 663 context.Background(), 664 maybe.Some([]byte("key1")), 665 maybe.Some([]byte("key2")), 666 db.rootID, 667 db.tokenSize, 668 db.hasher, 669 )) 670 } 671 672 func Test_ChangeProof_Missing_History_For_EndRoot(t *testing.T) { 673 require := require.New(t) 674 seed := time.Now().UnixNano() 675 t.Logf("Seed: %d", seed) 676 rand := rand.New(rand.NewSource(seed)) // #nosec G404 677 678 db, err := getBasicDB() 679 require.NoError(err) 680 681 roots := []ids.ID{} 682 for i := 0; i < defaultHistoryLength+1; i++ { 683 key := make([]byte, 16) 684 _, _ = rand.Read(key) 685 require.NoError(db.Put(key, nil)) 686 root, err := db.GetMerkleRoot(context.Background()) 687 require.NoError(err) 688 roots = append(roots, root) 689 } 690 691 _, err = db.GetChangeProof( 692 context.Background(), 693 roots[len(roots)-1], 694 ids.GenerateTestID(), 695 maybe.Nothing[[]byte](), 696 maybe.Nothing[[]byte](), 697 50, 698 ) 699 require.ErrorIs(err, ErrNoEndRoot) 700 require.ErrorIs(err, ErrInsufficientHistory) 701 702 _, err = db.GetChangeProof( 703 context.Background(), 704 roots[0], 705 roots[len(roots)-1], 706 maybe.Nothing[[]byte](), 707 maybe.Nothing[[]byte](), 708 50, 709 ) 710 require.NotErrorIs(err, ErrNoEndRoot) 711 require.ErrorIs(err, ErrInsufficientHistory) 712 713 _, err = db.GetChangeProof( 714 context.Background(), 715 roots[1], 716 roots[len(roots)-1], 717 maybe.Nothing[[]byte](), 718 maybe.Nothing[[]byte](), 719 50, 720 ) 721 require.NoError(err) 722 } 723 724 func Test_ChangeProof_BadBounds(t *testing.T) { 725 require := require.New(t) 726 727 db, err := getBasicDB() 728 require.NoError(err) 729 730 startRoot, err := db.GetMerkleRoot(context.Background()) 731 require.NoError(err) 732 733 require.NoError(db.PutContext(context.Background(), []byte{0}, []byte{0})) 734 735 endRoot, err := db.GetMerkleRoot(context.Background()) 736 require.NoError(err) 737 738 // non-nil start/end 739 proof, err := db.GetChangeProof(context.Background(), startRoot, endRoot, maybe.Some([]byte("key4")), maybe.Some([]byte("key3")), 50) 740 require.ErrorIs(err, ErrStartAfterEnd) 741 require.Nil(proof) 742 } 743 744 func Test_ChangeProof_Verify(t *testing.T) { 745 require := require.New(t) 746 747 db, err := getBasicDB() 748 require.NoError(err) 749 batch := db.NewBatch() 750 require.NoError(batch.Put([]byte("key20"), []byte("value0"))) 751 require.NoError(batch.Put([]byte("key21"), []byte("value1"))) 752 require.NoError(batch.Put([]byte("key22"), []byte("value2"))) 753 require.NoError(batch.Put([]byte("key23"), []byte("value3"))) 754 require.NoError(batch.Put([]byte("key24"), []byte("value4"))) 755 require.NoError(batch.Write()) 756 startRoot, err := db.GetMerkleRoot(context.Background()) 757 require.NoError(err) 758 759 // create a second db that has "synced" to the start root 760 dbClone, err := getBasicDB() 761 require.NoError(err) 762 batch = dbClone.NewBatch() 763 require.NoError(batch.Put([]byte("key20"), []byte("value0"))) 764 require.NoError(batch.Put([]byte("key21"), []byte("value1"))) 765 require.NoError(batch.Put([]byte("key22"), []byte("value2"))) 766 require.NoError(batch.Put([]byte("key23"), []byte("value3"))) 767 require.NoError(batch.Put([]byte("key24"), []byte("value4"))) 768 require.NoError(batch.Write()) 769 770 // the second db has started to sync some of the range outside of the range proof 771 batch = dbClone.NewBatch() 772 require.NoError(batch.Put([]byte("key31"), []byte("value1"))) 773 require.NoError(batch.Write()) 774 775 batch = db.NewBatch() 776 require.NoError(batch.Put([]byte("key25"), []byte("value0"))) 777 require.NoError(batch.Put([]byte("key26"), []byte("value1"))) 778 require.NoError(batch.Put([]byte("key27"), []byte("value2"))) 779 require.NoError(batch.Put([]byte("key28"), []byte("value3"))) 780 require.NoError(batch.Put([]byte("key29"), []byte("value4"))) 781 require.NoError(batch.Write()) 782 783 batch = db.NewBatch() 784 require.NoError(batch.Put([]byte("key30"), []byte("value0"))) 785 require.NoError(batch.Put([]byte("key31"), []byte("value1"))) 786 require.NoError(batch.Put([]byte("key32"), []byte("value2"))) 787 require.NoError(batch.Delete([]byte("key21"))) 788 require.NoError(batch.Delete([]byte("key22"))) 789 require.NoError(batch.Write()) 790 791 endRoot, err := db.GetMerkleRoot(context.Background()) 792 require.NoError(err) 793 794 // non-nil start/end 795 proof, err := db.GetChangeProof(context.Background(), startRoot, endRoot, maybe.Some([]byte("key21")), maybe.Some([]byte("key30")), 50) 796 require.NoError(err) 797 require.NotNil(proof) 798 799 require.NoError(dbClone.VerifyChangeProof(context.Background(), proof, maybe.Some([]byte("key21")), maybe.Some([]byte("key30")), db.getMerkleRoot())) 800 801 // low maxLength 802 proof, err = db.GetChangeProof(context.Background(), startRoot, endRoot, maybe.Nothing[[]byte](), maybe.Nothing[[]byte](), 5) 803 require.NoError(err) 804 require.NotNil(proof) 805 806 require.NoError(dbClone.VerifyChangeProof(context.Background(), proof, maybe.Nothing[[]byte](), maybe.Nothing[[]byte](), db.getMerkleRoot())) 807 808 // nil start/end 809 proof, err = db.GetChangeProof(context.Background(), startRoot, endRoot, maybe.Nothing[[]byte](), maybe.Nothing[[]byte](), 50) 810 require.NoError(err) 811 require.NotNil(proof) 812 813 require.NoError(dbClone.VerifyChangeProof(context.Background(), proof, maybe.Nothing[[]byte](), maybe.Nothing[[]byte](), endRoot)) 814 require.NoError(dbClone.CommitChangeProof(context.Background(), proof)) 815 816 newRoot, err := dbClone.GetMerkleRoot(context.Background()) 817 require.NoError(err) 818 require.Equal(endRoot, newRoot) 819 820 proof, err = db.GetChangeProof(context.Background(), startRoot, endRoot, maybe.Some([]byte("key20")), maybe.Some([]byte("key30")), 50) 821 require.NoError(err) 822 require.NotNil(proof) 823 824 require.NoError(dbClone.VerifyChangeProof(context.Background(), proof, maybe.Some([]byte("key20")), maybe.Some([]byte("key30")), db.getMerkleRoot())) 825 } 826 827 func Test_ChangeProof_Verify_Bad_Data(t *testing.T) { 828 type test struct { 829 name string 830 malform func(proof *ChangeProof) 831 expectedErr error 832 } 833 834 tests := []test{ 835 { 836 name: "happyPath", 837 malform: func(*ChangeProof) {}, 838 expectedErr: nil, 839 }, 840 { 841 name: "odd length key path with value", 842 malform: func(proof *ChangeProof) { 843 proof.EndProof[0].ValueOrHash = maybe.Some([]byte{1, 2}) 844 }, 845 expectedErr: ErrPartialByteLengthWithValue, 846 }, 847 { 848 name: "last proof node has missing value", 849 malform: func(proof *ChangeProof) { 850 proof.EndProof[len(proof.EndProof)-1].ValueOrHash = maybe.Nothing[[]byte]() 851 }, 852 expectedErr: ErrProofValueDoesntMatch, 853 }, 854 { 855 name: "missing key/value", 856 malform: func(proof *ChangeProof) { 857 proof.KeyChanges = proof.KeyChanges[1:] 858 }, 859 expectedErr: ErrProofValueDoesntMatch, 860 }, 861 } 862 863 for _, tt := range tests { 864 t.Run(tt.name, func(t *testing.T) { 865 require := require.New(t) 866 867 db, err := getBasicDB() 868 require.NoError(err) 869 870 startRoot, err := db.GetMerkleRoot(context.Background()) 871 require.NoError(err) 872 873 writeBasicBatch(t, db) 874 875 endRoot, err := db.GetMerkleRoot(context.Background()) 876 require.NoError(err) 877 878 // create a second db that will be synced to the first db 879 dbClone, err := getBasicDB() 880 require.NoError(err) 881 882 proof, err := db.GetChangeProof( 883 context.Background(), 884 startRoot, 885 endRoot, 886 maybe.Some([]byte{2}), 887 maybe.Some([]byte{3, 0}), 888 50, 889 ) 890 require.NoError(err) 891 require.NotNil(proof) 892 893 tt.malform(proof) 894 895 err = dbClone.VerifyChangeProof( 896 context.Background(), 897 proof, 898 maybe.Some([]byte{2}), 899 maybe.Some([]byte{3, 0}), 900 db.getMerkleRoot(), 901 ) 902 require.ErrorIs(err, tt.expectedErr) 903 }) 904 } 905 } 906 907 func Test_ChangeProof_Syntactic_Verify(t *testing.T) { 908 type test struct { 909 name string 910 proof *ChangeProof 911 start maybe.Maybe[[]byte] 912 end maybe.Maybe[[]byte] 913 expectedErr error 914 } 915 916 tests := []test{ 917 { 918 name: "start after end", 919 proof: nil, 920 start: maybe.Some([]byte{1}), 921 end: maybe.Some([]byte{0}), 922 expectedErr: ErrStartAfterEnd, 923 }, 924 { 925 name: "empty", 926 proof: &ChangeProof{}, 927 start: maybe.Nothing[[]byte](), 928 end: maybe.Nothing[[]byte](), 929 expectedErr: ErrEmptyProof, 930 }, 931 { 932 name: "no end proof", 933 proof: &ChangeProof{ 934 StartProof: []ProofNode{{}}, 935 }, 936 start: maybe.Nothing[[]byte](), 937 end: maybe.Some([]byte{1}), 938 expectedErr: ErrNoEndProof, 939 }, 940 { 941 name: "no start proof", 942 proof: &ChangeProof{ 943 KeyChanges: []KeyChange{{Key: []byte{1}}}, 944 }, 945 start: maybe.Some([]byte{1}), 946 end: maybe.Nothing[[]byte](), 947 expectedErr: ErrNoStartProof, 948 }, 949 { 950 name: "non-increasing key-values", 951 proof: &ChangeProof{ 952 KeyChanges: []KeyChange{ 953 {Key: []byte{1}}, 954 {Key: []byte{0}}, 955 }, 956 }, 957 start: maybe.Nothing[[]byte](), 958 end: maybe.Nothing[[]byte](), 959 expectedErr: ErrNonIncreasingValues, 960 }, 961 { 962 name: "key-value too low", 963 proof: &ChangeProof{ 964 StartProof: []ProofNode{{}}, 965 KeyChanges: []KeyChange{ 966 {Key: []byte{0}}, 967 }, 968 }, 969 start: maybe.Some([]byte{1}), 970 end: maybe.Nothing[[]byte](), 971 expectedErr: ErrStateFromOutsideOfRange, 972 }, 973 { 974 name: "key-value too great", 975 proof: &ChangeProof{ 976 EndProof: []ProofNode{{}}, 977 KeyChanges: []KeyChange{ 978 {Key: []byte{2}}, 979 }, 980 }, 981 start: maybe.Nothing[[]byte](), 982 end: maybe.Some([]byte{1}), 983 expectedErr: ErrStateFromOutsideOfRange, 984 }, 985 { 986 name: "duplicate key", 987 proof: &ChangeProof{ 988 KeyChanges: []KeyChange{ 989 {Key: []byte{1}}, 990 {Key: []byte{1}}, 991 }, 992 }, 993 start: maybe.Nothing[[]byte](), 994 end: maybe.Nothing[[]byte](), 995 expectedErr: ErrNonIncreasingValues, 996 }, 997 { 998 name: "start proof node has wrong prefix", 999 proof: &ChangeProof{ 1000 StartProof: []ProofNode{ 1001 {Key: ToKey([]byte{2})}, 1002 {Key: ToKey([]byte{2, 3})}, 1003 }, 1004 }, 1005 start: maybe.Some([]byte{1, 2, 3}), 1006 end: maybe.Nothing[[]byte](), 1007 expectedErr: ErrProofNodeNotForKey, 1008 }, 1009 { 1010 name: "start proof non-increasing", 1011 proof: &ChangeProof{ 1012 StartProof: []ProofNode{ 1013 {Key: ToKey([]byte{1})}, 1014 {Key: ToKey([]byte{2, 3})}, 1015 }, 1016 }, 1017 start: maybe.Some([]byte{1, 2, 3}), 1018 end: maybe.Nothing[[]byte](), 1019 expectedErr: ErrNonIncreasingProofNodes, 1020 }, 1021 { 1022 name: "end proof node has wrong prefix", 1023 proof: &ChangeProof{ 1024 KeyChanges: []KeyChange{ 1025 {Key: []byte{1, 2}, Value: maybe.Some([]byte{0})}, 1026 }, 1027 EndProof: []ProofNode{ 1028 {Key: ToKey([]byte{2})}, 1029 {Key: ToKey([]byte{2, 3})}, 1030 }, 1031 }, 1032 start: maybe.Nothing[[]byte](), 1033 end: maybe.Nothing[[]byte](), 1034 expectedErr: ErrProofNodeNotForKey, 1035 }, 1036 { 1037 name: "end proof non-increasing", 1038 proof: &ChangeProof{ 1039 KeyChanges: []KeyChange{ 1040 {Key: []byte{1, 2, 3}}, 1041 }, 1042 EndProof: []ProofNode{ 1043 {Key: ToKey([]byte{1})}, 1044 {Key: ToKey([]byte{2, 3})}, 1045 }, 1046 }, 1047 start: maybe.Nothing[[]byte](), 1048 end: maybe.Nothing[[]byte](), 1049 expectedErr: ErrNonIncreasingProofNodes, 1050 }, 1051 } 1052 1053 for _, tt := range tests { 1054 t.Run(tt.name, func(t *testing.T) { 1055 require := require.New(t) 1056 1057 db, err := getBasicDB() 1058 require.NoError(err) 1059 err = db.VerifyChangeProof(context.Background(), tt.proof, tt.start, tt.end, ids.Empty) 1060 require.ErrorIs(err, tt.expectedErr) 1061 }) 1062 } 1063 } 1064 1065 func TestVerifyKeyValues(t *testing.T) { 1066 type test struct { 1067 name string 1068 start maybe.Maybe[[]byte] 1069 end maybe.Maybe[[]byte] 1070 kvs []KeyValue 1071 expectedErr error 1072 } 1073 1074 tests := []test{ 1075 { 1076 name: "empty", 1077 start: maybe.Nothing[[]byte](), 1078 end: maybe.Nothing[[]byte](), 1079 kvs: nil, 1080 expectedErr: nil, 1081 }, 1082 { 1083 name: "1 key", 1084 start: maybe.Nothing[[]byte](), 1085 end: maybe.Nothing[[]byte](), 1086 kvs: []KeyValue{ 1087 {Key: []byte{0}}, 1088 }, 1089 expectedErr: nil, 1090 }, 1091 { 1092 name: "non-increasing keys", 1093 start: maybe.Nothing[[]byte](), 1094 end: maybe.Nothing[[]byte](), 1095 kvs: []KeyValue{ 1096 {Key: []byte{0}}, 1097 {Key: []byte{0}}, 1098 }, 1099 expectedErr: ErrNonIncreasingValues, 1100 }, 1101 { 1102 name: "key before start", 1103 start: maybe.Some([]byte{1, 2}), 1104 end: maybe.Nothing[[]byte](), 1105 kvs: []KeyValue{ 1106 {Key: []byte{1}}, 1107 {Key: []byte{1, 2}}, 1108 }, 1109 expectedErr: ErrStateFromOutsideOfRange, 1110 }, 1111 { 1112 name: "key after end", 1113 start: maybe.Nothing[[]byte](), 1114 end: maybe.Some([]byte{1, 2}), 1115 kvs: []KeyValue{ 1116 {Key: []byte{1}}, 1117 {Key: []byte{1, 2}}, 1118 {Key: []byte{1, 2, 3}}, 1119 }, 1120 expectedErr: ErrStateFromOutsideOfRange, 1121 }, 1122 { 1123 name: "happy path", 1124 start: maybe.Nothing[[]byte](), 1125 end: maybe.Some([]byte{1, 2, 3}), 1126 kvs: []KeyValue{ 1127 {Key: []byte{1}}, 1128 {Key: []byte{1, 2}}, 1129 }, 1130 expectedErr: nil, 1131 }, 1132 } 1133 1134 for _, tt := range tests { 1135 t.Run(tt.name, func(t *testing.T) { 1136 err := verifyKeyValues(tt.kvs, tt.start, tt.end) 1137 require.ErrorIs(t, err, tt.expectedErr) 1138 }) 1139 } 1140 } 1141 1142 func TestVerifyProofPath(t *testing.T) { 1143 type test struct { 1144 name string 1145 path []ProofNode 1146 proofKey maybe.Maybe[Key] 1147 expectedErr error 1148 } 1149 1150 tests := []test{ 1151 { 1152 name: "empty", 1153 path: nil, 1154 proofKey: maybe.Nothing[Key](), 1155 expectedErr: nil, 1156 }, 1157 { 1158 name: "1 element", 1159 path: []ProofNode{{Key: ToKey([]byte{1})}}, 1160 proofKey: maybe.Nothing[Key](), 1161 expectedErr: nil, 1162 }, 1163 { 1164 name: "non-increasing keys", 1165 path: []ProofNode{ 1166 {Key: ToKey([]byte{1})}, 1167 {Key: ToKey([]byte{1, 2})}, 1168 {Key: ToKey([]byte{1, 3})}, 1169 }, 1170 proofKey: maybe.Some(ToKey([]byte{1, 2, 3})), 1171 expectedErr: ErrNonIncreasingProofNodes, 1172 }, 1173 { 1174 name: "invalid key", 1175 path: []ProofNode{ 1176 {Key: ToKey([]byte{1})}, 1177 {Key: ToKey([]byte{1, 2})}, 1178 {Key: ToKey([]byte{1, 2, 4})}, 1179 {Key: ToKey([]byte{1, 2, 3})}, 1180 }, 1181 proofKey: maybe.Some(ToKey([]byte{1, 2, 3})), 1182 expectedErr: ErrProofNodeNotForKey, 1183 }, 1184 { 1185 name: "extra node inclusion proof", 1186 path: []ProofNode{ 1187 {Key: ToKey([]byte{1})}, 1188 {Key: ToKey([]byte{1, 2})}, 1189 {Key: ToKey([]byte{1, 2, 3})}, 1190 }, 1191 proofKey: maybe.Some(ToKey([]byte{1, 2})), 1192 expectedErr: ErrProofNodeNotForKey, 1193 }, 1194 { 1195 name: "extra node exclusion proof", 1196 path: []ProofNode{ 1197 {Key: ToKey([]byte{1})}, 1198 {Key: ToKey([]byte{1, 3})}, 1199 {Key: ToKey([]byte{1, 3, 4})}, 1200 }, 1201 proofKey: maybe.Some(ToKey([]byte{1, 2})), 1202 expectedErr: ErrProofNodeNotForKey, 1203 }, 1204 { 1205 name: "happy path exclusion proof", 1206 path: []ProofNode{ 1207 {Key: ToKey([]byte{1})}, 1208 {Key: ToKey([]byte{1, 2})}, 1209 {Key: ToKey([]byte{1, 2, 4})}, 1210 }, 1211 proofKey: maybe.Some(ToKey([]byte{1, 2, 3})), 1212 expectedErr: nil, 1213 }, 1214 { 1215 name: "happy path inclusion proof", 1216 path: []ProofNode{ 1217 {Key: ToKey([]byte{1})}, 1218 {Key: ToKey([]byte{1, 2})}, 1219 {Key: ToKey([]byte{1, 2, 3})}, 1220 }, 1221 proofKey: maybe.Some(ToKey([]byte{1, 2, 3})), 1222 expectedErr: nil, 1223 }, 1224 { 1225 name: "repeat nodes", 1226 path: []ProofNode{ 1227 {Key: ToKey([]byte{1})}, 1228 {Key: ToKey([]byte{1})}, 1229 {Key: ToKey([]byte{1, 2})}, 1230 {Key: ToKey([]byte{1, 2, 3})}, 1231 }, 1232 proofKey: maybe.Some(ToKey([]byte{1, 2, 3})), 1233 expectedErr: ErrNonIncreasingProofNodes, 1234 }, 1235 { 1236 name: "repeat nodes 2", 1237 path: []ProofNode{ 1238 {Key: ToKey([]byte{1})}, 1239 {Key: ToKey([]byte{1, 2})}, 1240 {Key: ToKey([]byte{1, 2})}, 1241 {Key: ToKey([]byte{1, 2, 3})}, 1242 }, 1243 proofKey: maybe.Some(ToKey([]byte{1, 2, 3})), 1244 expectedErr: ErrNonIncreasingProofNodes, 1245 }, 1246 { 1247 name: "repeat nodes 3", 1248 path: []ProofNode{ 1249 {Key: ToKey([]byte{1})}, 1250 {Key: ToKey([]byte{1, 2})}, 1251 {Key: ToKey([]byte{1, 2, 3})}, 1252 {Key: ToKey([]byte{1, 2, 3})}, 1253 }, 1254 proofKey: maybe.Some(ToKey([]byte{1, 2, 3})), 1255 expectedErr: ErrProofNodeNotForKey, 1256 }, 1257 { 1258 name: "oddLength key with value", 1259 path: []ProofNode{ 1260 {Key: ToKey([]byte{1})}, 1261 {Key: ToKey([]byte{1, 2})}, 1262 { 1263 Key: Key{ 1264 value: string([]byte{1, 2, 240}), 1265 length: 20, 1266 }, 1267 ValueOrHash: maybe.Some([]byte{1}), 1268 }, 1269 }, 1270 proofKey: maybe.Some(ToKey([]byte{1, 2, 3})), 1271 expectedErr: ErrPartialByteLengthWithValue, 1272 }, 1273 } 1274 1275 for _, tt := range tests { 1276 t.Run(tt.name, func(t *testing.T) { 1277 err := verifyProofPath(tt.path, tt.proofKey) 1278 require.ErrorIs(t, err, tt.expectedErr) 1279 }) 1280 } 1281 } 1282 1283 func TestProofNodeUnmarshalProtoInvalidMaybe(t *testing.T) { 1284 now := time.Now().UnixNano() 1285 t.Logf("seed: %d", now) 1286 rand := rand.New(rand.NewSource(now)) // #nosec G404 1287 1288 node := newRandomProofNode(rand) 1289 protoNode := node.ToProto() 1290 1291 // It's invalid to have a value and be nothing. 1292 protoNode.ValueOrHash = &pb.MaybeBytes{ 1293 Value: []byte{1, 2, 3}, 1294 IsNothing: true, 1295 } 1296 1297 var unmarshaledNode ProofNode 1298 err := unmarshaledNode.UnmarshalProto(protoNode) 1299 require.ErrorIs(t, err, ErrInvalidMaybe) 1300 } 1301 1302 func TestProofNodeUnmarshalProtoInvalidChildBytes(t *testing.T) { 1303 now := time.Now().UnixNano() 1304 t.Logf("seed: %d", now) 1305 rand := rand.New(rand.NewSource(now)) // #nosec G404 1306 1307 node := newRandomProofNode(rand) 1308 protoNode := node.ToProto() 1309 1310 protoNode.Children = map[uint32][]byte{ 1311 1: []byte("not 32 bytes"), 1312 } 1313 1314 var unmarshaledNode ProofNode 1315 err := unmarshaledNode.UnmarshalProto(protoNode) 1316 require.ErrorIs(t, err, hashing.ErrInvalidHashLen) 1317 } 1318 1319 func TestProofNodeUnmarshalProtoInvalidChildIndex(t *testing.T) { 1320 now := time.Now().UnixNano() 1321 t.Logf("seed: %d", now) 1322 rand := rand.New(rand.NewSource(now)) // #nosec G404 1323 1324 node := newRandomProofNode(rand) 1325 protoNode := node.ToProto() 1326 1327 childID := ids.GenerateTestID() 1328 protoNode.Children[256] = childID[:] 1329 1330 var unmarshaledNode ProofNode 1331 err := unmarshaledNode.UnmarshalProto(protoNode) 1332 require.ErrorIs(t, err, errChildIndexTooLarge) 1333 } 1334 1335 func TestProofNodeUnmarshalProtoMissingFields(t *testing.T) { 1336 now := time.Now().UnixNano() 1337 t.Logf("seed: %d", now) 1338 rand := rand.New(rand.NewSource(now)) // #nosec G404 1339 1340 type test struct { 1341 name string 1342 nodeFunc func() *pb.ProofNode 1343 expectedErr error 1344 } 1345 1346 tests := []test{ 1347 { 1348 name: "nil node", 1349 nodeFunc: func() *pb.ProofNode { 1350 return nil 1351 }, 1352 expectedErr: ErrNilProofNode, 1353 }, 1354 { 1355 name: "nil ValueOrHash", 1356 nodeFunc: func() *pb.ProofNode { 1357 node := newRandomProofNode(rand) 1358 protoNode := node.ToProto() 1359 protoNode.ValueOrHash = nil 1360 return protoNode 1361 }, 1362 expectedErr: ErrNilValueOrHash, 1363 }, 1364 { 1365 name: "nil key", 1366 nodeFunc: func() *pb.ProofNode { 1367 node := newRandomProofNode(rand) 1368 protoNode := node.ToProto() 1369 protoNode.Key = nil 1370 return protoNode 1371 }, 1372 expectedErr: ErrNilKey, 1373 }, 1374 } 1375 1376 for _, tt := range tests { 1377 t.Run(tt.name, func(t *testing.T) { 1378 var node ProofNode 1379 err := node.UnmarshalProto(tt.nodeFunc()) 1380 require.ErrorIs(t, err, tt.expectedErr) 1381 }) 1382 } 1383 } 1384 1385 func FuzzProofNodeProtoMarshalUnmarshal(f *testing.F) { 1386 f.Fuzz(func( 1387 t *testing.T, 1388 randSeed int64, 1389 ) { 1390 require := require.New(t) 1391 rand := rand.New(rand.NewSource(randSeed)) // #nosec G404 1392 node := newRandomProofNode(rand) 1393 1394 // Marshal and unmarshal it. 1395 // Assert the unmarshaled one is the same as the original. 1396 protoNode := node.ToProto() 1397 var unmarshaledNode ProofNode 1398 require.NoError(unmarshaledNode.UnmarshalProto(protoNode)) 1399 require.Equal(node, unmarshaledNode) 1400 1401 // Marshaling again should yield same result. 1402 protoUnmarshaledNode := unmarshaledNode.ToProto() 1403 require.Equal(protoNode, protoUnmarshaledNode) 1404 }) 1405 } 1406 1407 func FuzzRangeProofProtoMarshalUnmarshal(f *testing.F) { 1408 f.Fuzz(func( 1409 t *testing.T, 1410 randSeed int64, 1411 ) { 1412 require := require.New(t) 1413 rand := rand.New(rand.NewSource(randSeed)) // #nosec G404 1414 1415 // Make a random range proof. 1416 startProofLen := rand.Intn(32) 1417 startProof := make([]ProofNode, startProofLen) 1418 for i := 0; i < startProofLen; i++ { 1419 startProof[i] = newRandomProofNode(rand) 1420 } 1421 1422 endProofLen := rand.Intn(32) 1423 endProof := make([]ProofNode, endProofLen) 1424 for i := 0; i < endProofLen; i++ { 1425 endProof[i] = newRandomProofNode(rand) 1426 } 1427 1428 numKeyValues := rand.Intn(128) 1429 keyValues := make([]KeyValue, numKeyValues) 1430 for i := 0; i < numKeyValues; i++ { 1431 keyLen := rand.Intn(32) 1432 key := make([]byte, keyLen) 1433 _, _ = rand.Read(key) 1434 1435 valueLen := rand.Intn(32) 1436 value := make([]byte, valueLen) 1437 _, _ = rand.Read(value) 1438 1439 keyValues[i] = KeyValue{ 1440 Key: key, 1441 Value: value, 1442 } 1443 } 1444 1445 proof := RangeProof{ 1446 StartProof: startProof, 1447 EndProof: endProof, 1448 KeyValues: keyValues, 1449 } 1450 1451 // Marshal and unmarshal it. 1452 // Assert the unmarshaled one is the same as the original. 1453 var unmarshaledProof RangeProof 1454 protoProof := proof.ToProto() 1455 require.NoError(unmarshaledProof.UnmarshalProto(protoProof)) 1456 require.Equal(proof, unmarshaledProof) 1457 1458 // Marshaling again should yield same result. 1459 protoUnmarshaledProof := unmarshaledProof.ToProto() 1460 require.Equal(protoProof, protoUnmarshaledProof) 1461 }) 1462 } 1463 1464 func FuzzChangeProofProtoMarshalUnmarshal(f *testing.F) { 1465 f.Fuzz(func( 1466 t *testing.T, 1467 randSeed int64, 1468 ) { 1469 require := require.New(t) 1470 rand := rand.New(rand.NewSource(randSeed)) // #nosec G404 1471 1472 // Make a random change proof. 1473 startProofLen := rand.Intn(32) 1474 startProof := make([]ProofNode, startProofLen) 1475 for i := 0; i < startProofLen; i++ { 1476 startProof[i] = newRandomProofNode(rand) 1477 } 1478 1479 endProofLen := rand.Intn(32) 1480 endProof := make([]ProofNode, endProofLen) 1481 for i := 0; i < endProofLen; i++ { 1482 endProof[i] = newRandomProofNode(rand) 1483 } 1484 1485 numKeyChanges := rand.Intn(128) 1486 keyChanges := make([]KeyChange, numKeyChanges) 1487 for i := 0; i < numKeyChanges; i++ { 1488 keyLen := rand.Intn(32) 1489 key := make([]byte, keyLen) 1490 _, _ = rand.Read(key) 1491 1492 value := maybe.Nothing[[]byte]() 1493 hasValue := rand.Intn(2) == 0 1494 if hasValue { 1495 valueLen := rand.Intn(32) 1496 valueBytes := make([]byte, valueLen) 1497 _, _ = rand.Read(valueBytes) 1498 value = maybe.Some(valueBytes) 1499 } 1500 1501 keyChanges[i] = KeyChange{ 1502 Key: key, 1503 Value: value, 1504 } 1505 } 1506 1507 proof := ChangeProof{ 1508 StartProof: startProof, 1509 EndProof: endProof, 1510 KeyChanges: keyChanges, 1511 } 1512 1513 // Marshal and unmarshal it. 1514 // Assert the unmarshaled one is the same as the original. 1515 var unmarshaledProof ChangeProof 1516 protoProof := proof.ToProto() 1517 require.NoError(unmarshaledProof.UnmarshalProto(protoProof)) 1518 require.Equal(proof, unmarshaledProof) 1519 1520 // Marshaling again should yield same result. 1521 protoUnmarshaledProof := unmarshaledProof.ToProto() 1522 require.Equal(protoProof, protoUnmarshaledProof) 1523 }) 1524 } 1525 1526 func TestChangeProofUnmarshalProtoNil(t *testing.T) { 1527 var proof ChangeProof 1528 err := proof.UnmarshalProto(nil) 1529 require.ErrorIs(t, err, ErrNilChangeProof) 1530 } 1531 1532 func TestChangeProofUnmarshalProtoNilValue(t *testing.T) { 1533 now := time.Now().UnixNano() 1534 t.Logf("seed: %d", now) 1535 rand := rand.New(rand.NewSource(now)) // #nosec G404 1536 1537 // Make a random change proof. 1538 startProofLen := rand.Intn(32) 1539 startProof := make([]ProofNode, startProofLen) 1540 for i := 0; i < startProofLen; i++ { 1541 startProof[i] = newRandomProofNode(rand) 1542 } 1543 1544 endProofLen := rand.Intn(32) 1545 endProof := make([]ProofNode, endProofLen) 1546 for i := 0; i < endProofLen; i++ { 1547 endProof[i] = newRandomProofNode(rand) 1548 } 1549 1550 numKeyChanges := rand.Intn(128) + 1 1551 keyChanges := make([]KeyChange, numKeyChanges) 1552 for i := 0; i < numKeyChanges; i++ { 1553 keyLen := rand.Intn(32) 1554 key := make([]byte, keyLen) 1555 _, _ = rand.Read(key) 1556 1557 value := maybe.Nothing[[]byte]() 1558 hasValue := rand.Intn(2) == 0 1559 if hasValue { 1560 valueLen := rand.Intn(32) 1561 valueBytes := make([]byte, valueLen) 1562 _, _ = rand.Read(valueBytes) 1563 value = maybe.Some(valueBytes) 1564 } 1565 1566 keyChanges[i] = KeyChange{ 1567 Key: key, 1568 Value: value, 1569 } 1570 } 1571 1572 proof := ChangeProof{ 1573 StartProof: startProof, 1574 EndProof: endProof, 1575 KeyChanges: keyChanges, 1576 } 1577 protoProof := proof.ToProto() 1578 // Make a value nil 1579 protoProof.KeyChanges[0].Value = nil 1580 1581 var unmarshaledProof ChangeProof 1582 err := unmarshaledProof.UnmarshalProto(protoProof) 1583 require.ErrorIs(t, err, ErrNilMaybeBytes) 1584 } 1585 1586 func TestChangeProofUnmarshalProtoInvalidMaybe(t *testing.T) { 1587 protoProof := &pb.ChangeProof{ 1588 KeyChanges: []*pb.KeyChange{ 1589 { 1590 Key: []byte{1}, 1591 Value: &pb.MaybeBytes{ 1592 Value: []byte{1}, 1593 IsNothing: true, 1594 }, 1595 }, 1596 }, 1597 } 1598 1599 var proof ChangeProof 1600 err := proof.UnmarshalProto(protoProof) 1601 require.ErrorIs(t, err, ErrInvalidMaybe) 1602 } 1603 1604 func FuzzProofProtoMarshalUnmarshal(f *testing.F) { 1605 f.Fuzz(func( 1606 t *testing.T, 1607 randSeed int64, 1608 ) { 1609 require := require.New(t) 1610 rand := rand.New(rand.NewSource(randSeed)) // #nosec G404 1611 1612 // Make a random proof. 1613 proofLen := rand.Intn(32) 1614 proofPath := make([]ProofNode, proofLen) 1615 for i := 0; i < proofLen; i++ { 1616 proofPath[i] = newRandomProofNode(rand) 1617 } 1618 1619 keyLen := rand.Intn(32) 1620 key := make([]byte, keyLen) 1621 _, _ = rand.Read(key) 1622 1623 hasValue := rand.Intn(2) == 1 1624 value := maybe.Nothing[[]byte]() 1625 if hasValue { 1626 valueLen := rand.Intn(32) 1627 valueBytes := make([]byte, valueLen) 1628 _, _ = rand.Read(valueBytes) 1629 value = maybe.Some(valueBytes) 1630 } 1631 1632 proof := Proof{ 1633 Key: ToKey(key), 1634 Value: value, 1635 Path: proofPath, 1636 } 1637 1638 // Marshal and unmarshal it. 1639 // Assert the unmarshaled one is the same as the original. 1640 var unmarshaledProof Proof 1641 protoProof := proof.ToProto() 1642 require.NoError(unmarshaledProof.UnmarshalProto(protoProof)) 1643 require.Equal(proof, unmarshaledProof) 1644 1645 // Marshaling again should yield same result. 1646 protoUnmarshaledProof := unmarshaledProof.ToProto() 1647 require.Equal(protoProof, protoUnmarshaledProof) 1648 }) 1649 } 1650 1651 func TestProofProtoUnmarshal(t *testing.T) { 1652 type test struct { 1653 name string 1654 proof *pb.Proof 1655 expectedErr error 1656 } 1657 1658 tests := []test{ 1659 { 1660 name: "nil", 1661 proof: nil, 1662 expectedErr: ErrNilProof, 1663 }, 1664 { 1665 name: "nil value", 1666 proof: &pb.Proof{}, 1667 expectedErr: ErrNilValue, 1668 }, 1669 { 1670 name: "invalid maybe", 1671 proof: &pb.Proof{ 1672 Value: &pb.MaybeBytes{ 1673 Value: []byte{1}, 1674 IsNothing: true, 1675 }, 1676 }, 1677 expectedErr: ErrInvalidMaybe, 1678 }, 1679 } 1680 1681 for _, tt := range tests { 1682 t.Run(tt.name, func(t *testing.T) { 1683 var proof Proof 1684 err := proof.UnmarshalProto(tt.proof) 1685 require.ErrorIs(t, err, tt.expectedErr) 1686 }) 1687 } 1688 } 1689 1690 func FuzzRangeProofInvariants(f *testing.F) { 1691 deletePortion := 0.25 1692 f.Fuzz(func( 1693 t *testing.T, 1694 randSeed int64, 1695 startBytes []byte, 1696 endBytes []byte, 1697 maxProofLen uint, 1698 numKeyValues uint, 1699 ) { 1700 require := require.New(t) 1701 1702 // Make sure proof length is valid 1703 if maxProofLen == 0 { 1704 t.SkipNow() 1705 } 1706 if numKeyValues == 0 { 1707 t.SkipNow() 1708 } 1709 1710 // Make sure proof bounds are valid 1711 if len(endBytes) != 0 && bytes.Compare(startBytes, endBytes) > 0 { 1712 t.SkipNow() 1713 } 1714 1715 rand := rand.New(rand.NewSource(randSeed)) // #nosec G404 1716 1717 db, err := getBasicDB() 1718 require.NoError(err) 1719 1720 // Insert a bunch of random key values. 1721 insertRandomKeyValues( 1722 require, 1723 rand, 1724 []database.Database{db}, 1725 numKeyValues, 1726 deletePortion, 1727 ) 1728 1729 start := maybe.Nothing[[]byte]() 1730 if len(startBytes) != 0 { 1731 start = maybe.Some(startBytes) 1732 } 1733 1734 end := maybe.Nothing[[]byte]() 1735 if len(endBytes) != 0 { 1736 end = maybe.Some(endBytes) 1737 } 1738 1739 rootID, err := db.GetMerkleRoot(context.Background()) 1740 require.NoError(err) 1741 1742 rangeProof, err := db.GetRangeProof( 1743 context.Background(), 1744 start, 1745 end, 1746 int(maxProofLen), 1747 ) 1748 if rootID == ids.Empty { 1749 require.ErrorIs(err, ErrEmptyProof) 1750 return 1751 } 1752 require.NoError(err) 1753 1754 require.NoError(rangeProof.Verify( 1755 context.Background(), 1756 start, 1757 end, 1758 rootID, 1759 db.tokenSize, 1760 db.hasher, 1761 )) 1762 1763 // Make sure the start proof doesn't contain any nodes 1764 // that are in the end proof. 1765 endProofKeys := set.Set[Key]{} 1766 for _, node := range rangeProof.EndProof { 1767 endProofKeys.Add(node.Key) 1768 } 1769 1770 for _, node := range rangeProof.StartProof { 1771 require.NotContains(endProofKeys, node.Key) 1772 } 1773 1774 // Make sure the EndProof invariant is maintained 1775 switch { 1776 case end.IsNothing(): 1777 if len(rangeProof.KeyValues) == 0 { 1778 if len(rangeProof.StartProof) == 0 { 1779 require.Len(rangeProof.EndProof, 1) // Just the root 1780 require.Empty(rangeProof.EndProof[0].Key.Bytes()) 1781 } else { 1782 require.Empty(rangeProof.EndProof) 1783 } 1784 } 1785 case len(rangeProof.KeyValues) == 0: 1786 require.NotEmpty(rangeProof.EndProof) 1787 1788 // EndProof should be a proof for upper range bound. 1789 value := maybe.Nothing[[]byte]() 1790 upperRangeBoundVal, err := db.Get(endBytes) 1791 if err != nil { 1792 require.ErrorIs(err, database.ErrNotFound) 1793 } else { 1794 value = maybe.Some(upperRangeBoundVal) 1795 } 1796 1797 proof := Proof{ 1798 Path: rangeProof.EndProof, 1799 Key: ToKey(endBytes), 1800 Value: value, 1801 } 1802 1803 rootID, err := db.GetMerkleRoot(context.Background()) 1804 require.NoError(err) 1805 1806 require.NoError(proof.Verify(context.Background(), rootID, db.tokenSize, db.hasher)) 1807 default: 1808 require.NotEmpty(rangeProof.EndProof) 1809 1810 greatestKV := rangeProof.KeyValues[len(rangeProof.KeyValues)-1] 1811 // EndProof should be a proof for largest key-value. 1812 proof := Proof{ 1813 Path: rangeProof.EndProof, 1814 Key: ToKey(greatestKV.Key), 1815 Value: maybe.Some(greatestKV.Value), 1816 } 1817 1818 rootID, err := db.GetMerkleRoot(context.Background()) 1819 require.NoError(err) 1820 1821 require.NoError(proof.Verify(context.Background(), rootID, db.tokenSize, db.hasher)) 1822 } 1823 }) 1824 } 1825 1826 func FuzzProofVerification(f *testing.F) { 1827 deletePortion := 0.25 1828 f.Fuzz(func( 1829 t *testing.T, 1830 key []byte, 1831 randSeed int64, 1832 numKeyValues uint, 1833 ) { 1834 rand := rand.New(rand.NewSource(randSeed)) // #nosec G404 1835 require := require.New(t) 1836 db, err := getBasicDB() 1837 require.NoError(err) 1838 1839 // Insert a bunch of random key values. 1840 insertRandomKeyValues( 1841 require, 1842 rand, 1843 []database.Database{db}, 1844 numKeyValues, 1845 deletePortion, 1846 ) 1847 1848 if db.getMerkleRoot() == ids.Empty { 1849 return 1850 } 1851 1852 proof, err := db.GetProof( 1853 context.Background(), 1854 key, 1855 ) 1856 1857 require.NoError(err) 1858 1859 rootID, err := db.GetMerkleRoot(context.Background()) 1860 require.NoError(err) 1861 1862 require.NoError(proof.Verify(context.Background(), rootID, db.tokenSize, db.hasher)) 1863 1864 // Insert a new key-value pair 1865 newKey := make([]byte, 32) 1866 _, _ = rand.Read(newKey) // #nosec G404 1867 newValue := make([]byte, 32) 1868 _, _ = rand.Read(newValue) // #nosec G404 1869 require.NoError(db.Put(newKey, newValue)) 1870 1871 // Delete a key-value pair so database doesn't grow unbounded 1872 iter := db.NewIterator() 1873 deleteKey := iter.Key() 1874 iter.Release() 1875 1876 require.NoError(db.Delete(deleteKey)) 1877 }) 1878 } 1879 1880 // Generate change proofs and verify that they are valid. 1881 func FuzzChangeProofVerification(f *testing.F) { 1882 const ( 1883 numKeyValues = defaultHistoryLength / 2 1884 deletePortion = 0.25 1885 ) 1886 1887 f.Fuzz(func( 1888 t *testing.T, 1889 startBytes []byte, 1890 endBytes []byte, 1891 maxProofLen uint, 1892 randSeed int64, 1893 ) { 1894 require := require.New(t) 1895 rand := rand.New(rand.NewSource(randSeed)) // #nosec G404 1896 1897 db, err := getBasicDB() 1898 require.NoError(err) 1899 1900 startRootID, err := db.GetMerkleRoot(context.Background()) 1901 require.NoError(err) 1902 1903 // Insert a bunch of random key values. 1904 // Don't insert so many that we have insufficient history. 1905 insertRandomKeyValues( 1906 require, 1907 rand, 1908 []database.Database{db}, 1909 numKeyValues, 1910 deletePortion, 1911 ) 1912 1913 endRootID, err := db.GetMerkleRoot(context.Background()) 1914 require.NoError(err) 1915 1916 // Make sure proof bounds are valid 1917 if len(endBytes) != 0 && bytes.Compare(startBytes, endBytes) > 0 { 1918 return 1919 } 1920 // Make sure proof length is valid 1921 if maxProofLen == 0 { 1922 return 1923 } 1924 1925 start := maybe.Nothing[[]byte]() 1926 if len(startBytes) != 0 { 1927 start = maybe.Some(startBytes) 1928 } 1929 1930 end := maybe.Nothing[[]byte]() 1931 if len(endBytes) != 0 { 1932 end = maybe.Some(endBytes) 1933 } 1934 1935 changeProof, err := db.GetChangeProof( 1936 context.Background(), 1937 startRootID, 1938 endRootID, 1939 start, 1940 end, 1941 int(maxProofLen), 1942 ) 1943 require.NoError(err) 1944 1945 require.NoError(db.VerifyChangeProof( 1946 context.Background(), 1947 changeProof, 1948 start, 1949 end, 1950 endRootID, 1951 )) 1952 }) 1953 }