github.com/MetalBlockchain/metalgo@v1.11.9/snow/consensus/snowman/consensus_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 snowman 5 6 import ( 7 "context" 8 "errors" 9 "path" 10 "reflect" 11 "runtime" 12 "strings" 13 "testing" 14 15 "github.com/prometheus/client_golang/prometheus" 16 "github.com/stretchr/testify/require" 17 "gonum.org/v1/gonum/mathext/prng" 18 19 "github.com/MetalBlockchain/metalgo/ids" 20 "github.com/MetalBlockchain/metalgo/snow/choices" 21 "github.com/MetalBlockchain/metalgo/snow/consensus/snowball" 22 "github.com/MetalBlockchain/metalgo/snow/consensus/snowman/snowmantest" 23 "github.com/MetalBlockchain/metalgo/snow/snowtest" 24 "github.com/MetalBlockchain/metalgo/utils/bag" 25 ) 26 27 type testFunc func(*testing.T, Factory) 28 29 var ( 30 testFuncs = []testFunc{ 31 InitializeTest, 32 NumProcessingTest, 33 AddToTailTest, 34 AddToNonTailTest, 35 AddOnUnknownParentTest, 36 StatusOrProcessingPreviouslyAcceptedTest, 37 StatusOrProcessingPreviouslyRejectedTest, 38 StatusOrProcessingUnissuedTest, 39 StatusOrProcessingIssuedTest, 40 RecordPollAcceptSingleBlockTest, 41 RecordPollAcceptAndRejectTest, 42 RecordPollSplitVoteNoChangeTest, 43 RecordPollWhenFinalizedTest, 44 RecordPollRejectTransitivelyTest, 45 RecordPollTransitivelyResetConfidenceTest, 46 RecordPollInvalidVoteTest, 47 RecordPollTransitiveVotingTest, 48 RecordPollDivergedVotingWithNoConflictingBitTest, 49 RecordPollChangePreferredChainTest, 50 LastAcceptedTest, 51 MetricsProcessingErrorTest, 52 MetricsAcceptedErrorTest, 53 MetricsRejectedErrorTest, 54 ErrorOnAcceptTest, 55 ErrorOnRejectSiblingTest, 56 ErrorOnTransitiveRejectionTest, 57 RandomizedConsistencyTest, 58 ErrorOnAddDecidedBlockTest, 59 RecordPollWithDefaultParameters, 60 RecordPollRegressionCalculateInDegreeIndegreeCalculation, 61 } 62 63 errTest = errors.New("non-nil error") 64 ) 65 66 // Execute all tests against a consensus implementation 67 func runConsensusTests(t *testing.T, factory Factory) { 68 for _, test := range testFuncs { 69 t.Run(getTestName(test), func(tt *testing.T) { 70 test(tt, factory) 71 }) 72 } 73 } 74 75 func getTestName(i interface{}) string { 76 return strings.Split(path.Base(runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name()), ".")[1] 77 } 78 79 // Make sure that initialize sets the state correctly 80 func InitializeTest(t *testing.T, factory Factory) { 81 require := require.New(t) 82 83 sm := factory.New() 84 85 snowCtx := snowtest.Context(t, snowtest.CChainID) 86 ctx := snowtest.ConsensusContext(snowCtx) 87 params := snowball.Parameters{ 88 K: 1, 89 AlphaPreference: 1, 90 AlphaConfidence: 1, 91 Beta: 3, 92 ConcurrentRepolls: 1, 93 OptimalProcessing: 1, 94 MaxOutstandingItems: 1, 95 MaxItemProcessingTime: 1, 96 } 97 98 require.NoError(sm.Initialize( 99 ctx, 100 params, 101 snowmantest.GenesisID, 102 snowmantest.GenesisHeight, 103 snowmantest.GenesisTimestamp, 104 )) 105 106 require.Equal(snowmantest.GenesisID, sm.Preference()) 107 require.Zero(sm.NumProcessing()) 108 } 109 110 // Make sure that the number of processing blocks is tracked correctly 111 func NumProcessingTest(t *testing.T, factory Factory) { 112 require := require.New(t) 113 114 sm := factory.New() 115 116 snowCtx := snowtest.Context(t, snowtest.CChainID) 117 ctx := snowtest.ConsensusContext(snowCtx) 118 params := snowball.Parameters{ 119 K: 1, 120 AlphaPreference: 1, 121 AlphaConfidence: 1, 122 Beta: 1, 123 ConcurrentRepolls: 1, 124 OptimalProcessing: 1, 125 MaxOutstandingItems: 1, 126 MaxItemProcessingTime: 1, 127 } 128 require.NoError(sm.Initialize( 129 ctx, 130 params, 131 snowmantest.GenesisID, 132 snowmantest.GenesisHeight, 133 snowmantest.GenesisTimestamp, 134 )) 135 136 block := snowmantest.BuildChild(snowmantest.Genesis) 137 138 require.Zero(sm.NumProcessing()) 139 140 // Adding to the previous preference will update the preference 141 require.NoError(sm.Add(block)) 142 require.Equal(1, sm.NumProcessing()) 143 144 votes := bag.Of(block.ID()) 145 require.NoError(sm.RecordPoll(context.Background(), votes)) 146 require.Zero(sm.NumProcessing()) 147 } 148 149 // Make sure that adding a block to the tail updates the preference 150 func AddToTailTest(t *testing.T, factory Factory) { 151 require := require.New(t) 152 153 sm := factory.New() 154 155 snowCtx := snowtest.Context(t, snowtest.CChainID) 156 ctx := snowtest.ConsensusContext(snowCtx) 157 params := snowball.Parameters{ 158 K: 1, 159 AlphaPreference: 1, 160 AlphaConfidence: 1, 161 Beta: 3, 162 ConcurrentRepolls: 1, 163 OptimalProcessing: 1, 164 MaxOutstandingItems: 1, 165 MaxItemProcessingTime: 1, 166 } 167 require.NoError(sm.Initialize( 168 ctx, 169 params, 170 snowmantest.GenesisID, 171 snowmantest.GenesisHeight, 172 snowmantest.GenesisTimestamp, 173 )) 174 175 block := snowmantest.BuildChild(snowmantest.Genesis) 176 177 // Adding to the previous preference will update the preference 178 require.NoError(sm.Add(block)) 179 require.Equal(block.ID(), sm.Preference()) 180 require.True(sm.IsPreferred(block.ID())) 181 182 pref, ok := sm.PreferenceAtHeight(block.Height()) 183 require.True(ok) 184 require.Equal(block.ID(), pref) 185 } 186 187 // Make sure that adding a block not to the tail doesn't change the preference 188 func AddToNonTailTest(t *testing.T, factory Factory) { 189 require := require.New(t) 190 191 sm := factory.New() 192 193 snowCtx := snowtest.Context(t, snowtest.CChainID) 194 ctx := snowtest.ConsensusContext(snowCtx) 195 params := snowball.Parameters{ 196 K: 1, 197 AlphaPreference: 1, 198 AlphaConfidence: 1, 199 Beta: 3, 200 ConcurrentRepolls: 1, 201 OptimalProcessing: 1, 202 MaxOutstandingItems: 1, 203 MaxItemProcessingTime: 1, 204 } 205 require.NoError(sm.Initialize( 206 ctx, 207 params, 208 snowmantest.GenesisID, 209 snowmantest.GenesisHeight, 210 snowmantest.GenesisTimestamp, 211 )) 212 213 firstBlock := snowmantest.BuildChild(snowmantest.Genesis) 214 secondBlock := snowmantest.BuildChild(snowmantest.Genesis) 215 216 // Adding to the previous preference will update the preference 217 require.NoError(sm.Add(firstBlock)) 218 require.Equal(firstBlock.IDV, sm.Preference()) 219 220 // Adding to something other than the previous preference won't update the 221 // preference 222 require.NoError(sm.Add(secondBlock)) 223 require.Equal(firstBlock.IDV, sm.Preference()) 224 } 225 226 // Make sure that adding a block that is detached from the rest of the tree 227 // returns an error 228 func AddOnUnknownParentTest(t *testing.T, factory Factory) { 229 require := require.New(t) 230 231 sm := factory.New() 232 233 snowCtx := snowtest.Context(t, snowtest.CChainID) 234 ctx := snowtest.ConsensusContext(snowCtx) 235 params := snowball.Parameters{ 236 K: 1, 237 AlphaPreference: 1, 238 AlphaConfidence: 1, 239 Beta: 3, 240 ConcurrentRepolls: 1, 241 OptimalProcessing: 1, 242 MaxOutstandingItems: 1, 243 MaxItemProcessingTime: 1, 244 } 245 require.NoError(sm.Initialize( 246 ctx, 247 params, 248 snowmantest.GenesisID, 249 snowmantest.GenesisHeight, 250 snowmantest.GenesisTimestamp, 251 )) 252 253 block := &snowmantest.Block{ 254 TestDecidable: choices.TestDecidable{ 255 IDV: ids.GenerateTestID(), 256 StatusV: choices.Processing, 257 }, 258 ParentV: ids.GenerateTestID(), 259 HeightV: snowmantest.GenesisHeight + 2, 260 } 261 262 // Adding a block with an unknown parent should error. 263 err := sm.Add(block) 264 require.ErrorIs(err, errUnknownParentBlock) 265 } 266 267 func StatusOrProcessingPreviouslyAcceptedTest(t *testing.T, factory Factory) { 268 require := require.New(t) 269 270 sm := factory.New() 271 272 snowCtx := snowtest.Context(t, snowtest.CChainID) 273 ctx := snowtest.ConsensusContext(snowCtx) 274 params := snowball.Parameters{ 275 K: 1, 276 AlphaPreference: 1, 277 AlphaConfidence: 1, 278 Beta: 3, 279 ConcurrentRepolls: 1, 280 OptimalProcessing: 1, 281 MaxOutstandingItems: 1, 282 MaxItemProcessingTime: 1, 283 } 284 require.NoError(sm.Initialize( 285 ctx, 286 params, 287 snowmantest.GenesisID, 288 snowmantest.GenesisHeight, 289 snowmantest.GenesisTimestamp, 290 )) 291 292 require.Equal(choices.Accepted, snowmantest.Genesis.Status()) 293 require.False(sm.Processing(snowmantest.Genesis.ID())) 294 require.True(sm.IsPreferred(snowmantest.Genesis.ID())) 295 296 pref, ok := sm.PreferenceAtHeight(snowmantest.Genesis.Height()) 297 require.True(ok) 298 require.Equal(snowmantest.Genesis.ID(), pref) 299 } 300 301 func StatusOrProcessingPreviouslyRejectedTest(t *testing.T, factory Factory) { 302 require := require.New(t) 303 304 sm := factory.New() 305 306 snowCtx := snowtest.Context(t, snowtest.CChainID) 307 ctx := snowtest.ConsensusContext(snowCtx) 308 params := snowball.Parameters{ 309 K: 1, 310 AlphaPreference: 1, 311 AlphaConfidence: 1, 312 Beta: 3, 313 ConcurrentRepolls: 1, 314 OptimalProcessing: 1, 315 MaxOutstandingItems: 1, 316 MaxItemProcessingTime: 1, 317 } 318 require.NoError(sm.Initialize( 319 ctx, 320 params, 321 snowmantest.GenesisID, 322 snowmantest.GenesisHeight, 323 snowmantest.GenesisTimestamp, 324 )) 325 326 block := snowmantest.BuildChild(snowmantest.Genesis) 327 require.NoError(block.Reject(context.Background())) 328 329 require.Equal(choices.Rejected, block.Status()) 330 require.False(sm.Processing(block.ID())) 331 require.False(sm.IsPreferred(block.ID())) 332 333 _, ok := sm.PreferenceAtHeight(block.Height()) 334 require.False(ok) 335 } 336 337 func StatusOrProcessingUnissuedTest(t *testing.T, factory Factory) { 338 require := require.New(t) 339 340 sm := factory.New() 341 342 snowCtx := snowtest.Context(t, snowtest.CChainID) 343 ctx := snowtest.ConsensusContext(snowCtx) 344 params := snowball.Parameters{ 345 K: 1, 346 AlphaPreference: 1, 347 AlphaConfidence: 1, 348 Beta: 3, 349 ConcurrentRepolls: 1, 350 OptimalProcessing: 1, 351 MaxOutstandingItems: 1, 352 MaxItemProcessingTime: 1, 353 } 354 require.NoError(sm.Initialize( 355 ctx, 356 params, 357 snowmantest.GenesisID, 358 snowmantest.GenesisHeight, 359 snowmantest.GenesisTimestamp, 360 )) 361 362 block := snowmantest.BuildChild(snowmantest.Genesis) 363 364 require.Equal(choices.Processing, block.Status()) 365 require.False(sm.Processing(block.ID())) 366 require.False(sm.IsPreferred(block.ID())) 367 368 _, ok := sm.PreferenceAtHeight(block.Height()) 369 require.False(ok) 370 } 371 372 func StatusOrProcessingIssuedTest(t *testing.T, factory Factory) { 373 require := require.New(t) 374 375 sm := factory.New() 376 377 snowCtx := snowtest.Context(t, snowtest.CChainID) 378 ctx := snowtest.ConsensusContext(snowCtx) 379 params := snowball.Parameters{ 380 K: 1, 381 AlphaPreference: 1, 382 AlphaConfidence: 1, 383 Beta: 3, 384 ConcurrentRepolls: 1, 385 OptimalProcessing: 1, 386 MaxOutstandingItems: 1, 387 MaxItemProcessingTime: 1, 388 } 389 require.NoError(sm.Initialize( 390 ctx, 391 params, 392 snowmantest.GenesisID, 393 snowmantest.GenesisHeight, 394 snowmantest.GenesisTimestamp, 395 )) 396 397 block := snowmantest.BuildChild(snowmantest.Genesis) 398 399 require.NoError(sm.Add(block)) 400 require.Equal(choices.Processing, block.Status()) 401 require.True(sm.Processing(block.ID())) 402 require.True(sm.IsPreferred(block.ID())) 403 404 pref, ok := sm.PreferenceAtHeight(block.Height()) 405 require.True(ok) 406 require.Equal(block.ID(), pref) 407 } 408 409 func RecordPollAcceptSingleBlockTest(t *testing.T, factory Factory) { 410 require := require.New(t) 411 412 sm := factory.New() 413 414 snowCtx := snowtest.Context(t, snowtest.CChainID) 415 ctx := snowtest.ConsensusContext(snowCtx) 416 params := snowball.Parameters{ 417 K: 1, 418 AlphaPreference: 1, 419 AlphaConfidence: 1, 420 Beta: 2, 421 ConcurrentRepolls: 1, 422 OptimalProcessing: 1, 423 MaxOutstandingItems: 1, 424 MaxItemProcessingTime: 1, 425 } 426 require.NoError(sm.Initialize( 427 ctx, 428 params, 429 snowmantest.GenesisID, 430 snowmantest.GenesisHeight, 431 snowmantest.GenesisTimestamp, 432 )) 433 434 block := snowmantest.BuildChild(snowmantest.Genesis) 435 436 require.NoError(sm.Add(block)) 437 438 votes := bag.Of(block.ID()) 439 require.NoError(sm.RecordPoll(context.Background(), votes)) 440 require.Equal(block.ID(), sm.Preference()) 441 require.Equal(1, sm.NumProcessing()) 442 require.Equal(choices.Processing, block.Status()) 443 444 require.NoError(sm.RecordPoll(context.Background(), votes)) 445 require.Equal(block.ID(), sm.Preference()) 446 require.Zero(sm.NumProcessing()) 447 require.Equal(choices.Accepted, block.Status()) 448 } 449 450 func RecordPollAcceptAndRejectTest(t *testing.T, factory Factory) { 451 require := require.New(t) 452 453 sm := factory.New() 454 455 snowCtx := snowtest.Context(t, snowtest.CChainID) 456 ctx := snowtest.ConsensusContext(snowCtx) 457 params := snowball.Parameters{ 458 K: 1, 459 AlphaPreference: 1, 460 AlphaConfidence: 1, 461 Beta: 2, 462 ConcurrentRepolls: 1, 463 OptimalProcessing: 1, 464 MaxOutstandingItems: 1, 465 MaxItemProcessingTime: 1, 466 } 467 require.NoError(sm.Initialize( 468 ctx, 469 params, 470 snowmantest.GenesisID, 471 snowmantest.GenesisHeight, 472 snowmantest.GenesisTimestamp, 473 )) 474 475 firstBlock := snowmantest.BuildChild(snowmantest.Genesis) 476 secondBlock := snowmantest.BuildChild(snowmantest.Genesis) 477 478 require.NoError(sm.Add(firstBlock)) 479 require.NoError(sm.Add(secondBlock)) 480 481 votes := bag.Of(firstBlock.ID()) 482 483 require.NoError(sm.RecordPoll(context.Background(), votes)) 484 require.Equal(firstBlock.ID(), sm.Preference()) 485 require.Equal(2, sm.NumProcessing()) 486 require.Equal(choices.Processing, firstBlock.Status()) 487 require.Equal(choices.Processing, secondBlock.Status()) 488 489 require.NoError(sm.RecordPoll(context.Background(), votes)) 490 require.Equal(firstBlock.ID(), sm.Preference()) 491 require.Zero(sm.NumProcessing()) 492 require.Equal(choices.Accepted, firstBlock.Status()) 493 require.Equal(choices.Rejected, secondBlock.Status()) 494 } 495 496 func RecordPollSplitVoteNoChangeTest(t *testing.T, factory Factory) { 497 require := require.New(t) 498 sm := factory.New() 499 500 snowCtx := snowtest.Context(t, snowtest.CChainID) 501 ctx := snowtest.ConsensusContext(snowCtx) 502 registerer := prometheus.NewRegistry() 503 ctx.Registerer = registerer 504 505 params := snowball.Parameters{ 506 K: 2, 507 AlphaPreference: 2, 508 AlphaConfidence: 2, 509 Beta: 1, 510 ConcurrentRepolls: 1, 511 OptimalProcessing: 1, 512 MaxOutstandingItems: 1, 513 MaxItemProcessingTime: 1, 514 } 515 require.NoError(sm.Initialize( 516 ctx, 517 params, 518 snowmantest.GenesisID, 519 snowmantest.GenesisHeight, 520 snowmantest.GenesisTimestamp, 521 )) 522 523 firstBlock := snowmantest.BuildChild(snowmantest.Genesis) 524 secondBlock := snowmantest.BuildChild(snowmantest.Genesis) 525 526 require.NoError(sm.Add(firstBlock)) 527 require.NoError(sm.Add(secondBlock)) 528 529 votes := bag.Of(firstBlock.ID(), secondBlock.ID()) 530 531 // The first poll will accept shared bits 532 require.NoError(sm.RecordPoll(context.Background(), votes)) 533 require.Equal(firstBlock.ID(), sm.Preference()) 534 require.Equal(2, sm.NumProcessing()) 535 536 metrics := gatherCounterGauge(t, registerer) 537 require.Zero(metrics["polls_failed"]) 538 require.Equal(float64(1), metrics["polls_successful"]) 539 540 // The second poll will do nothing 541 require.NoError(sm.RecordPoll(context.Background(), votes)) 542 require.Equal(firstBlock.ID(), sm.Preference()) 543 require.Equal(2, sm.NumProcessing()) 544 545 metrics = gatherCounterGauge(t, registerer) 546 require.Equal(float64(1), metrics["polls_failed"]) 547 require.Equal(float64(1), metrics["polls_successful"]) 548 } 549 550 func RecordPollWhenFinalizedTest(t *testing.T, factory Factory) { 551 require := require.New(t) 552 553 sm := factory.New() 554 555 snowCtx := snowtest.Context(t, snowtest.CChainID) 556 ctx := snowtest.ConsensusContext(snowCtx) 557 params := snowball.Parameters{ 558 K: 1, 559 AlphaPreference: 1, 560 AlphaConfidence: 1, 561 Beta: 1, 562 ConcurrentRepolls: 1, 563 OptimalProcessing: 1, 564 MaxOutstandingItems: 1, 565 MaxItemProcessingTime: 1, 566 } 567 require.NoError(sm.Initialize( 568 ctx, 569 params, 570 snowmantest.GenesisID, 571 snowmantest.GenesisHeight, 572 snowmantest.GenesisTimestamp, 573 )) 574 575 votes := bag.Of(snowmantest.GenesisID) 576 require.NoError(sm.RecordPoll(context.Background(), votes)) 577 require.Zero(sm.NumProcessing()) 578 require.Equal(snowmantest.GenesisID, sm.Preference()) 579 } 580 581 func RecordPollRejectTransitivelyTest(t *testing.T, factory Factory) { 582 require := require.New(t) 583 584 sm := factory.New() 585 586 snowCtx := snowtest.Context(t, snowtest.CChainID) 587 ctx := snowtest.ConsensusContext(snowCtx) 588 params := snowball.Parameters{ 589 K: 1, 590 AlphaPreference: 1, 591 AlphaConfidence: 1, 592 Beta: 1, 593 ConcurrentRepolls: 1, 594 OptimalProcessing: 1, 595 MaxOutstandingItems: 1, 596 MaxItemProcessingTime: 1, 597 } 598 require.NoError(sm.Initialize( 599 ctx, 600 params, 601 snowmantest.GenesisID, 602 snowmantest.GenesisHeight, 603 snowmantest.GenesisTimestamp, 604 )) 605 606 block0 := snowmantest.BuildChild(snowmantest.Genesis) 607 block1 := snowmantest.BuildChild(snowmantest.Genesis) 608 block2 := snowmantest.BuildChild(block1) 609 610 require.NoError(sm.Add(block0)) 611 require.NoError(sm.Add(block1)) 612 require.NoError(sm.Add(block2)) 613 614 // Current graph structure: 615 // G 616 // / \ 617 // 0 1 618 // | 619 // 2 620 // Tail = 0 621 622 votes := bag.Of(block0.ID()) 623 require.NoError(sm.RecordPoll(context.Background(), votes)) 624 625 // Current graph structure: 626 // 0 627 // Tail = 0 628 629 require.Zero(sm.NumProcessing()) 630 require.Equal(block0.ID(), sm.Preference()) 631 require.Equal(choices.Accepted, block0.Status()) 632 require.Equal(choices.Rejected, block1.Status()) 633 require.Equal(choices.Rejected, block2.Status()) 634 } 635 636 func RecordPollTransitivelyResetConfidenceTest(t *testing.T, factory Factory) { 637 require := require.New(t) 638 639 sm := factory.New() 640 641 snowCtx := snowtest.Context(t, snowtest.CChainID) 642 ctx := snowtest.ConsensusContext(snowCtx) 643 params := snowball.Parameters{ 644 K: 1, 645 AlphaPreference: 1, 646 AlphaConfidence: 1, 647 Beta: 2, 648 ConcurrentRepolls: 1, 649 OptimalProcessing: 1, 650 MaxOutstandingItems: 1, 651 MaxItemProcessingTime: 1, 652 } 653 require.NoError(sm.Initialize( 654 ctx, 655 params, 656 snowmantest.GenesisID, 657 snowmantest.GenesisHeight, 658 snowmantest.GenesisTimestamp, 659 )) 660 661 block0 := snowmantest.BuildChild(snowmantest.Genesis) 662 block1 := snowmantest.BuildChild(snowmantest.Genesis) 663 block2 := snowmantest.BuildChild(block1) 664 block3 := snowmantest.BuildChild(block1) 665 666 require.NoError(sm.Add(block0)) 667 require.NoError(sm.Add(block1)) 668 require.NoError(sm.Add(block2)) 669 require.NoError(sm.Add(block3)) 670 671 // Current graph structure: 672 // G 673 // / \ 674 // 0 1 675 // / \ 676 // 2 3 677 678 votesFor2 := bag.Of(block2.ID()) 679 require.NoError(sm.RecordPoll(context.Background(), votesFor2)) 680 require.Equal(4, sm.NumProcessing()) 681 require.Equal(block2.ID(), sm.Preference()) 682 683 emptyVotes := bag.Bag[ids.ID]{} 684 require.NoError(sm.RecordPoll(context.Background(), emptyVotes)) 685 require.Equal(4, sm.NumProcessing()) 686 require.Equal(block2.ID(), sm.Preference()) 687 688 require.NoError(sm.RecordPoll(context.Background(), votesFor2)) 689 require.Equal(4, sm.NumProcessing()) 690 require.Equal(block2.ID(), sm.Preference()) 691 692 votesFor3 := bag.Of(block3.ID()) 693 require.NoError(sm.RecordPoll(context.Background(), votesFor3)) 694 require.Equal(2, sm.NumProcessing()) 695 require.Equal(block2.ID(), sm.Preference()) 696 697 require.NoError(sm.RecordPoll(context.Background(), votesFor3)) 698 require.Zero(sm.NumProcessing()) 699 require.Equal(block3.ID(), sm.Preference()) 700 require.Equal(choices.Rejected, block0.Status()) 701 require.Equal(choices.Accepted, block1.Status()) 702 require.Equal(choices.Rejected, block2.Status()) 703 require.Equal(choices.Accepted, block3.Status()) 704 } 705 706 func RecordPollInvalidVoteTest(t *testing.T, factory Factory) { 707 require := require.New(t) 708 709 sm := factory.New() 710 711 snowCtx := snowtest.Context(t, snowtest.CChainID) 712 ctx := snowtest.ConsensusContext(snowCtx) 713 params := snowball.Parameters{ 714 K: 1, 715 AlphaPreference: 1, 716 AlphaConfidence: 1, 717 Beta: 2, 718 ConcurrentRepolls: 1, 719 OptimalProcessing: 1, 720 MaxOutstandingItems: 1, 721 MaxItemProcessingTime: 1, 722 } 723 require.NoError(sm.Initialize( 724 ctx, 725 params, 726 snowmantest.GenesisID, 727 snowmantest.GenesisHeight, 728 snowmantest.GenesisTimestamp, 729 )) 730 731 block := snowmantest.BuildChild(snowmantest.Genesis) 732 unknownBlockID := ids.GenerateTestID() 733 734 require.NoError(sm.Add(block)) 735 736 validVotes := bag.Of(block.ID()) 737 require.NoError(sm.RecordPoll(context.Background(), validVotes)) 738 739 invalidVotes := bag.Of(unknownBlockID) 740 require.NoError(sm.RecordPoll(context.Background(), invalidVotes)) 741 require.NoError(sm.RecordPoll(context.Background(), validVotes)) 742 require.Equal(1, sm.NumProcessing()) 743 require.Equal(block.ID(), sm.Preference()) 744 } 745 746 func RecordPollTransitiveVotingTest(t *testing.T, factory Factory) { 747 require := require.New(t) 748 749 sm := factory.New() 750 751 snowCtx := snowtest.Context(t, snowtest.CChainID) 752 ctx := snowtest.ConsensusContext(snowCtx) 753 params := snowball.Parameters{ 754 K: 3, 755 AlphaPreference: 3, 756 AlphaConfidence: 3, 757 Beta: 1, 758 ConcurrentRepolls: 1, 759 OptimalProcessing: 1, 760 MaxOutstandingItems: 1, 761 MaxItemProcessingTime: 1, 762 } 763 require.NoError(sm.Initialize( 764 ctx, 765 params, 766 snowmantest.GenesisID, 767 snowmantest.GenesisHeight, 768 snowmantest.GenesisTimestamp, 769 )) 770 771 block0 := snowmantest.BuildChild(snowmantest.Genesis) 772 block1 := snowmantest.BuildChild(block0) 773 block2 := snowmantest.BuildChild(block1) 774 block3 := snowmantest.BuildChild(block0) 775 block4 := snowmantest.BuildChild(block3) 776 777 require.NoError(sm.Add(block0)) 778 require.NoError(sm.Add(block1)) 779 require.NoError(sm.Add(block2)) 780 require.NoError(sm.Add(block3)) 781 require.NoError(sm.Add(block4)) 782 783 // Current graph structure: 784 // G 785 // | 786 // 0 787 // / \ 788 // 1 3 789 // | | 790 // 2 4 791 // Tail = 2 792 793 votes0_2_4 := bag.Of(block0.ID(), block2.ID(), block4.ID()) 794 require.NoError(sm.RecordPoll(context.Background(), votes0_2_4)) 795 796 // Current graph structure: 797 // 0 798 // / \ 799 // 1 3 800 // | | 801 // 2 4 802 // Tail = 2 803 804 require.Equal(4, sm.NumProcessing()) 805 require.Equal(block2.ID(), sm.Preference()) 806 require.Equal(choices.Accepted, block0.Status()) 807 require.Equal(choices.Processing, block1.Status()) 808 require.Equal(choices.Processing, block2.Status()) 809 require.Equal(choices.Processing, block3.Status()) 810 require.Equal(choices.Processing, block4.Status()) 811 812 dep2_2_2 := bag.Of(block2.ID(), block2.ID(), block2.ID()) 813 require.NoError(sm.RecordPoll(context.Background(), dep2_2_2)) 814 815 // Current graph structure: 816 // 2 817 // Tail = 2 818 819 require.Zero(sm.NumProcessing()) 820 require.Equal(block2.ID(), sm.Preference()) 821 require.Equal(choices.Accepted, block0.Status()) 822 require.Equal(choices.Accepted, block1.Status()) 823 require.Equal(choices.Accepted, block2.Status()) 824 require.Equal(choices.Rejected, block3.Status()) 825 require.Equal(choices.Rejected, block4.Status()) 826 } 827 828 func RecordPollDivergedVotingWithNoConflictingBitTest(t *testing.T, factory Factory) { 829 sm := factory.New() 830 require := require.New(t) 831 832 snowCtx := snowtest.Context(t, snowtest.CChainID) 833 ctx := snowtest.ConsensusContext(snowCtx) 834 params := snowball.Parameters{ 835 K: 1, 836 AlphaPreference: 1, 837 AlphaConfidence: 1, 838 Beta: 2, 839 ConcurrentRepolls: 1, 840 OptimalProcessing: 1, 841 MaxOutstandingItems: 1, 842 MaxItemProcessingTime: 1, 843 } 844 require.NoError(sm.Initialize( 845 ctx, 846 params, 847 snowmantest.GenesisID, 848 snowmantest.GenesisHeight, 849 snowmantest.GenesisTimestamp, 850 )) 851 852 block0 := &snowmantest.Block{ 853 TestDecidable: choices.TestDecidable{ 854 IDV: ids.ID{0x06}, // 0110 855 StatusV: choices.Processing, 856 }, 857 ParentV: snowmantest.GenesisID, 858 HeightV: snowmantest.GenesisHeight + 1, 859 } 860 block1 := &snowmantest.Block{ 861 TestDecidable: choices.TestDecidable{ 862 IDV: ids.ID{0x08}, // 0001 863 StatusV: choices.Processing, 864 }, 865 ParentV: snowmantest.GenesisID, 866 HeightV: snowmantest.GenesisHeight + 1, 867 } 868 block2 := &snowmantest.Block{ 869 TestDecidable: choices.TestDecidable{ 870 IDV: ids.ID{0x01}, // 1000 871 StatusV: choices.Processing, 872 }, 873 ParentV: snowmantest.GenesisID, 874 HeightV: snowmantest.GenesisHeight + 1, 875 } 876 block3 := snowmantest.BuildChild(block2) 877 878 require.NoError(sm.Add(block0)) 879 require.NoError(sm.Add(block1)) 880 881 // When voting for [block0], we end up finalizing the first bit as 0. The 882 // second bit is contested as either 0 or 1. For when the second bit is 1, 883 // the following bits have been decided to follow the 254 remaining bits of 884 // [block0]. 885 votes0 := bag.Of(block0.ID()) 886 require.NoError(sm.RecordPoll(context.Background(), votes0)) 887 888 // Although we are adding in [block2] here - the underlying snowball 889 // instance has already decided it is rejected. Snowman doesn't actually 890 // know that though, because that is an implementation detail of the 891 // Snowball trie that is used. 892 require.NoError(sm.Add(block2)) 893 894 // Because [block2] is effectively rejected, [block3] is also effectively 895 // rejected. 896 require.NoError(sm.Add(block3)) 897 898 require.Equal(block0.ID(), sm.Preference()) 899 require.Equal(choices.Processing, block0.Status(), "should not be decided yet") 900 require.Equal(choices.Processing, block1.Status(), "should not be decided yet") 901 require.Equal(choices.Processing, block2.Status(), "should not be decided yet") 902 require.Equal(choices.Processing, block3.Status(), "should not be decided yet") 903 904 // Current graph structure: 905 // G 906 // / \ 907 // * | 908 // / \ | 909 // 0 1 2 910 // | 911 // 3 912 // Tail = 0 913 914 // Transitively votes for [block2] by voting for its child [block3]. Because 915 // [block2] doesn't share any processing bits with [block0] or [block1], the 916 // votes are over only rejected bits. Therefore, the votes for [block2] are 917 // dropped. Although the votes for [block3] are still applied, [block3] will 918 // only be marked as accepted after [block2] is marked as accepted; which 919 // will never happen. 920 votes3 := bag.Of(block3.ID()) 921 require.NoError(sm.RecordPoll(context.Background(), votes3)) 922 923 require.Equal(4, sm.NumProcessing()) 924 require.Equal(choices.Processing, block0.Status()) 925 require.Equal(choices.Processing, block1.Status()) 926 require.Equal(choices.Processing, block2.Status()) 927 require.Equal(choices.Processing, block3.Status()) 928 } 929 930 func RecordPollChangePreferredChainTest(t *testing.T, factory Factory) { 931 require := require.New(t) 932 933 sm := factory.New() 934 935 snowCtx := snowtest.Context(t, snowtest.CChainID) 936 ctx := snowtest.ConsensusContext(snowCtx) 937 params := snowball.Parameters{ 938 K: 1, 939 AlphaPreference: 1, 940 AlphaConfidence: 1, 941 Beta: 10, 942 ConcurrentRepolls: 1, 943 OptimalProcessing: 1, 944 MaxOutstandingItems: 1, 945 MaxItemProcessingTime: 1, 946 } 947 require.NoError(sm.Initialize( 948 ctx, 949 params, 950 snowmantest.GenesisID, 951 snowmantest.GenesisHeight, 952 snowmantest.GenesisTimestamp, 953 )) 954 955 a1Block := snowmantest.BuildChild(snowmantest.Genesis) 956 b1Block := snowmantest.BuildChild(snowmantest.Genesis) 957 a2Block := snowmantest.BuildChild(a1Block) 958 b2Block := snowmantest.BuildChild(b1Block) 959 960 require.NoError(sm.Add(a1Block)) 961 require.NoError(sm.Add(a2Block)) 962 require.NoError(sm.Add(b1Block)) 963 require.NoError(sm.Add(b2Block)) 964 965 require.Equal(a2Block.ID(), sm.Preference()) 966 967 require.True(sm.IsPreferred(a1Block.ID())) 968 require.True(sm.IsPreferred(a2Block.ID())) 969 require.False(sm.IsPreferred(b1Block.ID())) 970 require.False(sm.IsPreferred(b2Block.ID())) 971 972 pref, ok := sm.PreferenceAtHeight(a1Block.Height()) 973 require.True(ok) 974 require.Equal(a1Block.ID(), pref) 975 976 pref, ok = sm.PreferenceAtHeight(a2Block.Height()) 977 require.True(ok) 978 require.Equal(a2Block.ID(), pref) 979 980 b2Votes := bag.Of(b2Block.ID()) 981 require.NoError(sm.RecordPoll(context.Background(), b2Votes)) 982 983 require.Equal(b2Block.ID(), sm.Preference()) 984 require.False(sm.IsPreferred(a1Block.ID())) 985 require.False(sm.IsPreferred(a2Block.ID())) 986 require.True(sm.IsPreferred(b1Block.ID())) 987 require.True(sm.IsPreferred(b2Block.ID())) 988 989 pref, ok = sm.PreferenceAtHeight(b1Block.Height()) 990 require.True(ok) 991 require.Equal(b1Block.ID(), pref) 992 993 pref, ok = sm.PreferenceAtHeight(b2Block.Height()) 994 require.True(ok) 995 require.Equal(b2Block.ID(), pref) 996 997 a1Votes := bag.Of(a1Block.ID()) 998 require.NoError(sm.RecordPoll(context.Background(), a1Votes)) 999 require.NoError(sm.RecordPoll(context.Background(), a1Votes)) 1000 1001 require.Equal(a2Block.ID(), sm.Preference()) 1002 require.True(sm.IsPreferred(a1Block.ID())) 1003 require.True(sm.IsPreferred(a2Block.ID())) 1004 require.False(sm.IsPreferred(b1Block.ID())) 1005 require.False(sm.IsPreferred(b2Block.ID())) 1006 1007 pref, ok = sm.PreferenceAtHeight(a1Block.Height()) 1008 require.True(ok) 1009 require.Equal(a1Block.ID(), pref) 1010 1011 pref, ok = sm.PreferenceAtHeight(a2Block.Height()) 1012 require.True(ok) 1013 require.Equal(a2Block.ID(), pref) 1014 } 1015 1016 func LastAcceptedTest(t *testing.T, factory Factory) { 1017 sm := factory.New() 1018 require := require.New(t) 1019 1020 snowCtx := snowtest.Context(t, snowtest.CChainID) 1021 ctx := snowtest.ConsensusContext(snowCtx) 1022 params := snowball.Parameters{ 1023 K: 1, 1024 AlphaPreference: 1, 1025 AlphaConfidence: 1, 1026 Beta: 2, 1027 ConcurrentRepolls: 1, 1028 OptimalProcessing: 1, 1029 MaxOutstandingItems: 1, 1030 MaxItemProcessingTime: 1, 1031 } 1032 require.NoError(sm.Initialize( 1033 ctx, 1034 params, 1035 snowmantest.GenesisID, 1036 snowmantest.GenesisHeight, 1037 snowmantest.GenesisTimestamp, 1038 )) 1039 1040 block0 := snowmantest.BuildChild(snowmantest.Genesis) 1041 block1 := snowmantest.BuildChild(block0) 1042 block2 := snowmantest.BuildChild(block1) 1043 block1Conflict := snowmantest.BuildChild(block0) 1044 1045 lastAcceptedID, lastAcceptedHeight := sm.LastAccepted() 1046 require.Equal(snowmantest.GenesisID, lastAcceptedID) 1047 require.Equal(snowmantest.GenesisHeight, lastAcceptedHeight) 1048 1049 require.NoError(sm.Add(block0)) 1050 require.NoError(sm.Add(block1)) 1051 require.NoError(sm.Add(block1Conflict)) 1052 require.NoError(sm.Add(block2)) 1053 1054 lastAcceptedID, lastAcceptedHeight = sm.LastAccepted() 1055 require.Equal(snowmantest.GenesisID, lastAcceptedID) 1056 require.Equal(snowmantest.GenesisHeight, lastAcceptedHeight) 1057 1058 require.NoError(sm.RecordPoll(context.Background(), bag.Of(block0.IDV))) 1059 1060 lastAcceptedID, lastAcceptedHeight = sm.LastAccepted() 1061 require.Equal(snowmantest.GenesisID, lastAcceptedID) 1062 require.Equal(snowmantest.GenesisHeight, lastAcceptedHeight) 1063 1064 require.NoError(sm.RecordPoll(context.Background(), bag.Of(block1.IDV))) 1065 1066 lastAcceptedID, lastAcceptedHeight = sm.LastAccepted() 1067 require.Equal(block0.IDV, lastAcceptedID) 1068 require.Equal(block0.HeightV, lastAcceptedHeight) 1069 1070 require.NoError(sm.RecordPoll(context.Background(), bag.Of(block1.IDV))) 1071 1072 lastAcceptedID, lastAcceptedHeight = sm.LastAccepted() 1073 require.Equal(block1.IDV, lastAcceptedID) 1074 require.Equal(block1.HeightV, lastAcceptedHeight) 1075 1076 require.NoError(sm.RecordPoll(context.Background(), bag.Of(block2.IDV))) 1077 1078 lastAcceptedID, lastAcceptedHeight = sm.LastAccepted() 1079 require.Equal(block1.IDV, lastAcceptedID) 1080 require.Equal(block1.HeightV, lastAcceptedHeight) 1081 1082 require.NoError(sm.RecordPoll(context.Background(), bag.Of(block2.IDV))) 1083 1084 lastAcceptedID, lastAcceptedHeight = sm.LastAccepted() 1085 require.Equal(block2.IDV, lastAcceptedID) 1086 require.Equal(block2.HeightV, lastAcceptedHeight) 1087 } 1088 1089 func MetricsProcessingErrorTest(t *testing.T, factory Factory) { 1090 require := require.New(t) 1091 1092 sm := factory.New() 1093 1094 snowCtx := snowtest.Context(t, snowtest.CChainID) 1095 ctx := snowtest.ConsensusContext(snowCtx) 1096 params := snowball.Parameters{ 1097 K: 1, 1098 AlphaPreference: 1, 1099 AlphaConfidence: 1, 1100 Beta: 1, 1101 ConcurrentRepolls: 1, 1102 OptimalProcessing: 1, 1103 MaxOutstandingItems: 1, 1104 MaxItemProcessingTime: 1, 1105 } 1106 1107 numProcessing := prometheus.NewGauge(prometheus.GaugeOpts{ 1108 Name: "blks_processing", 1109 }) 1110 1111 require.NoError(ctx.Registerer.Register(numProcessing)) 1112 1113 err := sm.Initialize( 1114 ctx, 1115 params, 1116 snowmantest.GenesisID, 1117 snowmantest.GenesisHeight, 1118 snowmantest.GenesisTimestamp, 1119 ) 1120 require.Error(err) //nolint:forbidigo // error is not exported https://github.com/prometheus/client_golang/blob/main/prometheus/registry.go#L315 1121 } 1122 1123 func MetricsAcceptedErrorTest(t *testing.T, factory Factory) { 1124 require := require.New(t) 1125 1126 sm := factory.New() 1127 1128 snowCtx := snowtest.Context(t, snowtest.CChainID) 1129 ctx := snowtest.ConsensusContext(snowCtx) 1130 params := snowball.Parameters{ 1131 K: 1, 1132 AlphaPreference: 1, 1133 AlphaConfidence: 1, 1134 Beta: 1, 1135 ConcurrentRepolls: 1, 1136 OptimalProcessing: 1, 1137 MaxOutstandingItems: 1, 1138 MaxItemProcessingTime: 1, 1139 } 1140 1141 numAccepted := prometheus.NewGauge(prometheus.GaugeOpts{ 1142 Name: "blks_accepted_count", 1143 }) 1144 1145 require.NoError(ctx.Registerer.Register(numAccepted)) 1146 1147 err := sm.Initialize( 1148 ctx, 1149 params, 1150 snowmantest.GenesisID, 1151 snowmantest.GenesisHeight, 1152 snowmantest.GenesisTimestamp, 1153 ) 1154 require.Error(err) //nolint:forbidigo // error is not exported https://github.com/prometheus/client_golang/blob/main/prometheus/registry.go#L315 1155 } 1156 1157 func MetricsRejectedErrorTest(t *testing.T, factory Factory) { 1158 require := require.New(t) 1159 1160 sm := factory.New() 1161 1162 snowCtx := snowtest.Context(t, snowtest.CChainID) 1163 ctx := snowtest.ConsensusContext(snowCtx) 1164 params := snowball.Parameters{ 1165 K: 1, 1166 AlphaPreference: 1, 1167 AlphaConfidence: 1, 1168 Beta: 1, 1169 ConcurrentRepolls: 1, 1170 OptimalProcessing: 1, 1171 MaxOutstandingItems: 1, 1172 MaxItemProcessingTime: 1, 1173 } 1174 1175 numRejected := prometheus.NewGauge(prometheus.GaugeOpts{ 1176 Name: "blks_rejected_count", 1177 }) 1178 1179 require.NoError(ctx.Registerer.Register(numRejected)) 1180 1181 err := sm.Initialize( 1182 ctx, 1183 params, 1184 snowmantest.GenesisID, 1185 snowmantest.GenesisHeight, 1186 snowmantest.GenesisTimestamp, 1187 ) 1188 require.Error(err) //nolint:forbidigo // error is not exported https://github.com/prometheus/client_golang/blob/main/prometheus/registry.go#L315 1189 } 1190 1191 func ErrorOnAcceptTest(t *testing.T, factory Factory) { 1192 require := require.New(t) 1193 1194 sm := factory.New() 1195 1196 snowCtx := snowtest.Context(t, snowtest.CChainID) 1197 ctx := snowtest.ConsensusContext(snowCtx) 1198 params := snowball.Parameters{ 1199 K: 1, 1200 AlphaPreference: 1, 1201 AlphaConfidence: 1, 1202 Beta: 1, 1203 ConcurrentRepolls: 1, 1204 OptimalProcessing: 1, 1205 MaxOutstandingItems: 1, 1206 MaxItemProcessingTime: 1, 1207 } 1208 1209 require.NoError(sm.Initialize( 1210 ctx, 1211 params, 1212 snowmantest.GenesisID, 1213 snowmantest.GenesisHeight, 1214 snowmantest.GenesisTimestamp, 1215 )) 1216 1217 block := snowmantest.BuildChild(snowmantest.Genesis) 1218 block.AcceptV = errTest 1219 1220 require.NoError(sm.Add(block)) 1221 1222 votes := bag.Of(block.ID()) 1223 err := sm.RecordPoll(context.Background(), votes) 1224 require.ErrorIs(err, errTest) 1225 } 1226 1227 func ErrorOnRejectSiblingTest(t *testing.T, factory Factory) { 1228 require := require.New(t) 1229 1230 sm := factory.New() 1231 1232 snowCtx := snowtest.Context(t, snowtest.CChainID) 1233 ctx := snowtest.ConsensusContext(snowCtx) 1234 params := snowball.Parameters{ 1235 K: 1, 1236 AlphaPreference: 1, 1237 AlphaConfidence: 1, 1238 Beta: 1, 1239 ConcurrentRepolls: 1, 1240 OptimalProcessing: 1, 1241 MaxOutstandingItems: 1, 1242 MaxItemProcessingTime: 1, 1243 } 1244 1245 require.NoError(sm.Initialize( 1246 ctx, 1247 params, 1248 snowmantest.GenesisID, 1249 snowmantest.GenesisHeight, 1250 snowmantest.GenesisTimestamp, 1251 )) 1252 1253 block0 := snowmantest.BuildChild(snowmantest.Genesis) 1254 block1 := snowmantest.BuildChild(snowmantest.Genesis) 1255 block1.RejectV = errTest 1256 1257 require.NoError(sm.Add(block0)) 1258 require.NoError(sm.Add(block1)) 1259 1260 votes := bag.Of(block0.ID()) 1261 err := sm.RecordPoll(context.Background(), votes) 1262 require.ErrorIs(err, errTest) 1263 } 1264 1265 func ErrorOnTransitiveRejectionTest(t *testing.T, factory Factory) { 1266 require := require.New(t) 1267 1268 sm := factory.New() 1269 1270 snowCtx := snowtest.Context(t, snowtest.CChainID) 1271 ctx := snowtest.ConsensusContext(snowCtx) 1272 params := snowball.Parameters{ 1273 K: 1, 1274 AlphaPreference: 1, 1275 AlphaConfidence: 1, 1276 Beta: 1, 1277 ConcurrentRepolls: 1, 1278 OptimalProcessing: 1, 1279 MaxOutstandingItems: 1, 1280 MaxItemProcessingTime: 1, 1281 } 1282 1283 require.NoError(sm.Initialize( 1284 ctx, 1285 params, 1286 snowmantest.GenesisID, 1287 snowmantest.GenesisHeight, 1288 snowmantest.GenesisTimestamp, 1289 )) 1290 1291 block0 := snowmantest.BuildChild(snowmantest.Genesis) 1292 block1 := snowmantest.BuildChild(snowmantest.Genesis) 1293 block2 := snowmantest.BuildChild(block1) 1294 block2.RejectV = errTest 1295 1296 require.NoError(sm.Add(block0)) 1297 require.NoError(sm.Add(block1)) 1298 require.NoError(sm.Add(block2)) 1299 1300 votes := bag.Of(block0.ID()) 1301 err := sm.RecordPoll(context.Background(), votes) 1302 require.ErrorIs(err, errTest) 1303 } 1304 1305 func RandomizedConsistencyTest(t *testing.T, factory Factory) { 1306 require := require.New(t) 1307 1308 var ( 1309 numColors = 50 1310 numNodes = 100 1311 params = snowball.Parameters{ 1312 K: 20, 1313 AlphaPreference: 15, 1314 AlphaConfidence: 15, 1315 Beta: 20, 1316 ConcurrentRepolls: 1, 1317 OptimalProcessing: 1, 1318 MaxOutstandingItems: 1, 1319 MaxItemProcessingTime: 1, 1320 } 1321 seed uint64 = 0 1322 source = prng.NewMT19937() 1323 ) 1324 1325 source.Seed(seed) 1326 1327 n := NewNetwork(params, numColors, source) 1328 1329 for i := 0; i < numNodes; i++ { 1330 require.NoError(n.AddNode(t, factory.New())) 1331 } 1332 1333 for !n.Finalized() { 1334 require.NoError(n.Round()) 1335 } 1336 1337 require.True(n.Agreement()) 1338 } 1339 1340 func ErrorOnAddDecidedBlockTest(t *testing.T, factory Factory) { 1341 sm := factory.New() 1342 require := require.New(t) 1343 1344 snowCtx := snowtest.Context(t, snowtest.CChainID) 1345 ctx := snowtest.ConsensusContext(snowCtx) 1346 params := snowball.Parameters{ 1347 K: 1, 1348 AlphaPreference: 1, 1349 AlphaConfidence: 1, 1350 Beta: 1, 1351 ConcurrentRepolls: 1, 1352 OptimalProcessing: 1, 1353 MaxOutstandingItems: 1, 1354 MaxItemProcessingTime: 1, 1355 } 1356 require.NoError(sm.Initialize( 1357 ctx, 1358 params, 1359 snowmantest.GenesisID, 1360 snowmantest.GenesisHeight, 1361 snowmantest.GenesisTimestamp, 1362 )) 1363 1364 err := sm.Add(snowmantest.Genesis) 1365 require.ErrorIs(err, errUnknownParentBlock) 1366 } 1367 1368 func gatherCounterGauge(t *testing.T, reg prometheus.Gatherer) map[string]float64 { 1369 ms, err := reg.Gather() 1370 require.NoError(t, err) 1371 mss := make(map[string]float64) 1372 for _, mf := range ms { 1373 name := mf.GetName() 1374 for _, m := range mf.GetMetric() { 1375 cnt := m.GetCounter() 1376 if cnt != nil { 1377 mss[name] = cnt.GetValue() 1378 break 1379 } 1380 gg := m.GetGauge() 1381 if gg != nil { 1382 mss[name] = gg.GetValue() 1383 break 1384 } 1385 } 1386 } 1387 return mss 1388 } 1389 1390 // You can run this test with "go test -v -run TestTopological/RecordPollWithDefaultParameters" 1391 func RecordPollWithDefaultParameters(t *testing.T, factory Factory) { 1392 require := require.New(t) 1393 1394 sm := factory.New() 1395 1396 snowCtx := snowtest.Context(t, snowtest.CChainID) 1397 ctx := snowtest.ConsensusContext(snowCtx) 1398 params := snowball.DefaultParameters 1399 require.NoError(sm.Initialize( 1400 ctx, 1401 params, 1402 snowmantest.GenesisID, 1403 snowmantest.GenesisHeight, 1404 snowmantest.GenesisTimestamp, 1405 )) 1406 1407 // "blk1" and "blk2" are in conflict 1408 blk1 := snowmantest.BuildChild(snowmantest.Genesis) 1409 blk2 := snowmantest.BuildChild(snowmantest.Genesis) 1410 1411 require.NoError(sm.Add(blk1)) 1412 require.NoError(sm.Add(blk2)) 1413 1414 votes := bag.Bag[ids.ID]{} 1415 votes.AddCount(blk1.ID(), params.AlphaConfidence) 1416 // Require beta rounds to finalize 1417 for i := 0; i < params.Beta; i++ { 1418 // should not finalize with less than beta rounds 1419 require.Equal(2, sm.NumProcessing()) 1420 require.NoError(sm.RecordPoll(context.Background(), votes)) 1421 } 1422 require.Zero(sm.NumProcessing()) 1423 } 1424 1425 // If a block that was voted for received additional votes from another block, 1426 // the indegree of the topological sort should not traverse into the parent 1427 // node. 1428 func RecordPollRegressionCalculateInDegreeIndegreeCalculation(t *testing.T, factory Factory) { 1429 require := require.New(t) 1430 1431 sm := factory.New() 1432 1433 snowCtx := snowtest.Context(t, snowtest.CChainID) 1434 ctx := snowtest.ConsensusContext(snowCtx) 1435 params := snowball.Parameters{ 1436 K: 3, 1437 AlphaPreference: 2, 1438 AlphaConfidence: 2, 1439 Beta: 1, 1440 ConcurrentRepolls: 1, 1441 OptimalProcessing: 1, 1442 MaxOutstandingItems: 1, 1443 MaxItemProcessingTime: 1, 1444 } 1445 require.NoError(sm.Initialize( 1446 ctx, 1447 params, 1448 snowmantest.GenesisID, 1449 snowmantest.GenesisHeight, 1450 snowmantest.GenesisTimestamp, 1451 )) 1452 1453 blk1 := snowmantest.BuildChild(snowmantest.Genesis) 1454 blk2 := snowmantest.BuildChild(blk1) 1455 blk3 := snowmantest.BuildChild(blk2) 1456 1457 require.NoError(sm.Add(blk1)) 1458 require.NoError(sm.Add(blk2)) 1459 require.NoError(sm.Add(blk3)) 1460 1461 votes := bag.Bag[ids.ID]{} 1462 votes.AddCount(blk2.ID(), 1) 1463 votes.AddCount(blk3.ID(), 2) 1464 require.NoError(sm.RecordPoll(context.Background(), votes)) 1465 require.Equal(choices.Accepted, blk1.Status()) 1466 require.Equal(choices.Accepted, blk2.Status()) 1467 require.Equal(choices.Accepted, blk3.Status()) 1468 }