github.com/decred/dcrd/blockchain@v1.2.1/votebits_test.go (about) 1 // Copyright (c) 2017-2019 The Decred developers 2 // Use of this source code is governed by an ISC 3 // license that can be found in the LICENSE file. 4 5 package blockchain 6 7 import ( 8 "testing" 9 "time" 10 11 "github.com/decred/dcrd/blockchain/stake" 12 "github.com/decred/dcrd/chaincfg" 13 ) 14 15 var ( 16 posVersion = uint32(4) 17 powVersion = int32(4) 18 19 pedro = chaincfg.Vote{ 20 Id: "voteforpedro", 21 Description: "You should always vote for Pedro", 22 Mask: 0x6, // 0b0110 23 Choices: []chaincfg.Choice{ 24 { 25 Id: "Abstain", 26 Description: "Abstain voting for Pedro", 27 Bits: 0x0, // 0b0000 28 IsAbstain: true, 29 IsNo: false, 30 }, 31 { 32 Id: "Yes", 33 Description: "Vote for Pedro", 34 Bits: 0x2, // 0b0010 35 IsAbstain: false, 36 IsNo: false, 37 }, 38 { 39 Id: "No", 40 Description: "Dont vote for Pedro", 41 Bits: 0x4, // 0b0100 42 IsAbstain: false, 43 IsNo: true, 44 }, 45 }, 46 } 47 48 multipleChoice = chaincfg.Vote{ 49 Id: "multiplechoice", 50 Description: "Pick one", 51 Mask: 0x70, // 0b0111 0000 52 Choices: []chaincfg.Choice{ 53 { 54 Id: "Abstain", 55 Description: "Abstain multiple choice", 56 Bits: 0x0, // 0b0000 0000 57 IsAbstain: true, 58 IsNo: false, 59 }, 60 { 61 Id: "one", 62 Description: "Choice 1", 63 Bits: 0x10, // 0b0001 0000 64 IsAbstain: false, 65 IsNo: false, 66 }, 67 { 68 Id: "Vote against", 69 Description: "Vote against all multiple ", 70 Bits: 0x20, // 0b0010 0000 71 IsAbstain: false, 72 IsNo: true, 73 }, 74 { 75 Id: "two", 76 Description: "Choice 2", 77 Bits: 0x30, // 0b0011 0000 78 IsAbstain: false, 79 IsNo: false, 80 }, 81 { 82 Id: "three", 83 Description: "Choice 3", 84 Bits: 0x40, // 0b0100 0000 85 IsAbstain: false, 86 IsNo: false, 87 }, 88 { 89 Id: "four", 90 Description: "Choice 4", 91 Bits: 0x50, // 0b0101 0000 92 IsAbstain: false, 93 IsNo: false, 94 }, 95 }, 96 } 97 ) 98 99 // defaultParams returns net parameters modified to have a single known 100 // deployment that is used throughout the various votebit tests. 101 func defaultParams(vote chaincfg.Vote) chaincfg.Params { 102 params := chaincfg.RegNetParams 103 params.Deployments = make(map[uint32][]chaincfg.ConsensusDeployment) 104 params.Deployments[posVersion] = []chaincfg.ConsensusDeployment{{ 105 Vote: vote, 106 StartTime: uint64(time.Now().Add(time.Duration( 107 params.RuleChangeActivationInterval) * 108 time.Second).Unix()), 109 ExpireTime: uint64(time.Now().Add(24 * time.Hour).Unix()), 110 }} 111 112 return params 113 } 114 115 // TestNoQuorum ensures that the quorum behavior works as expected with no 116 // votes. 117 func TestNoQuorum(t *testing.T) { 118 params := defaultParams(pedro) 119 bc := newFakeChain(¶ms) 120 node := bc.bestChain.Tip() 121 node.stakeVersion = posVersion 122 123 // get to svi 124 curTimestamp := time.Now() 125 for i := uint32(0); i < uint32(params.StakeValidationHeight); i++ { 126 node = newFakeNode(node, powVersion, posVersion, 0, curTimestamp) 127 bc.bestChain.SetTip(node) 128 bc.index.AddNode(node) 129 curTimestamp = curTimestamp.Add(time.Second) 130 } 131 ts, err := bc.NextThresholdState(&node.hash, posVersion, pedro.Id) 132 if err != nil { 133 t.Fatalf("NextThresholdState(SVI): %v", err) 134 } 135 tse := ThresholdStateTuple{ 136 State: ThresholdDefined, 137 Choice: invalidChoice, 138 } 139 if ts != tse { 140 t.Fatalf("expected %+v got %+v", ts, tse) 141 } 142 143 // get to started 144 for i := uint32(0); i < params.RuleChangeActivationInterval-1; i++ { 145 // Set stake versions and vote bits. 146 node = newFakeNode(node, powVersion, posVersion, 0, curTimestamp) 147 appendFakeVotes(node, params.TicketsPerBlock, posVersion, 0x01) 148 bc.bestChain.SetTip(node) 149 bc.index.AddNode(node) 150 curTimestamp = curTimestamp.Add(time.Second) 151 } 152 153 ts, err = bc.NextThresholdState(&node.hash, posVersion, pedro.Id) 154 if err != nil { 155 t.Fatalf("NextThresholdState(started): %v", err) 156 } 157 tse = ThresholdStateTuple{ 158 State: ThresholdStarted, 159 Choice: invalidChoice, 160 } 161 if ts != tse { 162 t.Fatalf("expected %+v got %+v", ts, tse) 163 } 164 165 // get to quorum - 1 166 voteCount := uint32(0) 167 for i := uint32(0); i < params.RuleChangeActivationInterval; i++ { 168 // Set stake versions and vote bits. 169 node = newFakeNode(node, powVersion, posVersion, 0, curTimestamp) 170 for x := 0; x < int(params.TicketsPerBlock); x++ { 171 bits := uint16(0x01) // abstain 172 if voteCount < params.RuleChangeActivationQuorum-1 { 173 bits = 0x05 // vote no 174 } 175 appendFakeVotes(node, 1, posVersion, bits) 176 voteCount++ 177 } 178 179 bc.bestChain.SetTip(node) 180 bc.index.AddNode(node) 181 curTimestamp = curTimestamp.Add(time.Second) 182 } 183 184 ts, err = bc.NextThresholdState(&node.hash, posVersion, pedro.Id) 185 if err != nil { 186 t.Fatalf("NextThresholdState(quorum-1): %v", err) 187 } 188 tse = ThresholdStateTuple{ 189 State: ThresholdStarted, 190 Choice: invalidChoice, 191 } 192 if ts != tse { 193 t.Fatalf("expected %+v got %+v", ts, tse) 194 } 195 196 // get to exact quorum but with 75%%-1 yes votes 197 voteCount = uint32(0) 198 for i := uint32(0); i < params.RuleChangeActivationInterval; i++ { 199 // Set stake versions and vote bits. 200 node = newFakeNode(node, powVersion, posVersion, 0, curTimestamp) 201 for x := 0; x < int(params.TicketsPerBlock); x++ { 202 // 119 no, 41 yes -> 120 == 75% and 120 reaches quorum 203 bits := uint16(0x01) // abstain 204 quorum := params.RuleChangeActivationQuorum* 205 params.RuleChangeActivationMultiplier/ 206 params.RuleChangeActivationDivisor - 1 207 if voteCount < quorum { 208 bits = 0x05 // vote no 209 } else if voteCount < params.RuleChangeActivationQuorum { 210 bits = 0x03 // vote yes 211 } 212 appendFakeVotes(node, 1, posVersion, bits) 213 voteCount++ 214 } 215 216 bc.bestChain.SetTip(node) 217 bc.index.AddNode(node) 218 curTimestamp = curTimestamp.Add(time.Second) 219 } 220 221 ts, err = bc.NextThresholdState(&node.hash, posVersion, pedro.Id) 222 if err != nil { 223 t.Fatalf("NextThresholdState(quorum 75%%-1): %v", err) 224 } 225 tse = ThresholdStateTuple{ 226 State: ThresholdStarted, 227 Choice: invalidChoice, 228 } 229 if ts != tse { 230 t.Fatalf("expected %+v got %+v", ts, tse) 231 } 232 233 // get to exact quorum with exactly 75% of votes 234 voteCount = uint32(0) 235 for i := uint32(0); i < params.RuleChangeActivationInterval; i++ { 236 // Set stake versions and vote bits. 237 node = newFakeNode(node, powVersion, posVersion, 0, curTimestamp) 238 for x := 0; x < int(params.TicketsPerBlock); x++ { 239 // 120 no, 40 yes -> 120 == 75% and 120 reaches quorum 240 bits := uint16(0x01) // abstain 241 quorum := params.RuleChangeActivationQuorum * 242 params.RuleChangeActivationMultiplier / 243 params.RuleChangeActivationDivisor 244 if voteCount < quorum { 245 bits = 0x05 // vote no 246 } else if voteCount < params.RuleChangeActivationQuorum { 247 bits = 0x03 // vote yes 248 } 249 appendFakeVotes(node, 1, posVersion, bits) 250 voteCount++ 251 } 252 253 bc.bestChain.SetTip(node) 254 bc.index.AddNode(node) 255 curTimestamp = curTimestamp.Add(time.Second) 256 } 257 258 ts, err = bc.NextThresholdState(&node.hash, posVersion, pedro.Id) 259 if err != nil { 260 t.Fatalf("NextThresholdState(quorum 75%%): %v", err) 261 } 262 tse = ThresholdStateTuple{ 263 State: ThresholdFailed, 264 Choice: 0x02, 265 } 266 if ts != tse { 267 t.Fatalf("expected %+v got %+v", ts, tse) 268 } 269 } 270 271 // TestNoQuorum ensures that the quorum behavior works as expected with yes 272 // votes. 273 func TestYesQuorum(t *testing.T) { 274 params := defaultParams(pedro) 275 bc := newFakeChain(¶ms) 276 node := bc.bestChain.Tip() 277 node.stakeVersion = posVersion 278 279 // get to svi 280 curTimestamp := time.Now() 281 for i := uint32(0); i < uint32(params.StakeValidationHeight); i++ { 282 node = newFakeNode(node, powVersion, posVersion, 0, curTimestamp) 283 284 bc.bestChain.SetTip(node) 285 bc.index.AddNode(node) 286 curTimestamp = curTimestamp.Add(time.Second) 287 } 288 ts, err := bc.NextThresholdState(&node.hash, posVersion, pedro.Id) 289 if err != nil { 290 t.Fatalf("NextThresholdState(SVI): %v", err) 291 } 292 tse := ThresholdStateTuple{ 293 State: ThresholdDefined, 294 Choice: invalidChoice, 295 } 296 if ts != tse { 297 t.Fatalf("expected %+v got %+v", ts, tse) 298 } 299 300 // get to started 301 for i := uint32(0); i < params.RuleChangeActivationInterval-1; i++ { 302 // Set stake versions and vote bits. 303 node = newFakeNode(node, powVersion, posVersion, 0, curTimestamp) 304 appendFakeVotes(node, params.TicketsPerBlock, posVersion, 0x01) 305 bc.bestChain.SetTip(node) 306 bc.index.AddNode(node) 307 curTimestamp = curTimestamp.Add(time.Second) 308 } 309 310 ts, err = bc.NextThresholdState(&node.hash, posVersion, pedro.Id) 311 if err != nil { 312 t.Fatalf("NextThresholdState(started): %v", err) 313 } 314 tse = ThresholdStateTuple{ 315 State: ThresholdStarted, 316 Choice: invalidChoice, 317 } 318 if ts != tse { 319 t.Fatalf("expected %+v got %+v", ts, tse) 320 } 321 322 // get to quorum - 1 323 voteCount := uint32(0) 324 for i := uint32(0); i < params.RuleChangeActivationInterval; i++ { 325 // Set stake versions and vote bits. 326 node = newFakeNode(node, powVersion, posVersion, 0, curTimestamp) 327 for x := 0; x < int(params.TicketsPerBlock); x++ { 328 bits := uint16(0x01) // abstain 329 if voteCount < params.RuleChangeActivationQuorum-1 { 330 bits = 0x03 // vote yes 331 } 332 appendFakeVotes(node, 1, posVersion, bits) 333 voteCount++ 334 } 335 336 bc.bestChain.SetTip(node) 337 bc.index.AddNode(node) 338 curTimestamp = curTimestamp.Add(time.Second) 339 } 340 341 ts, err = bc.NextThresholdState(&node.hash, posVersion, pedro.Id) 342 if err != nil { 343 t.Fatalf("NextThresholdState(quorum-1): %v", err) 344 } 345 tse = ThresholdStateTuple{ 346 State: ThresholdStarted, 347 Choice: invalidChoice, 348 } 349 if ts != tse { 350 t.Fatalf("expected %+v got %+v", ts, tse) 351 } 352 353 // get to exact quorum but with 75%-1 yes votes 354 voteCount = uint32(0) 355 for i := uint32(0); i < params.RuleChangeActivationInterval; i++ { 356 // Set stake versions and vote bits. 357 node = newFakeNode(node, powVersion, posVersion, 0, curTimestamp) 358 for x := 0; x < int(params.TicketsPerBlock); x++ { 359 // 119 yes, 41 no -> 120 == 75% and 120 reaches quorum 360 bits := uint16(0x01) // abstain 361 quorum := params.RuleChangeActivationQuorum* 362 params.RuleChangeActivationMultiplier/ 363 params.RuleChangeActivationDivisor - 1 364 if voteCount < quorum { 365 bits = 0x03 // vote yes 366 } else if voteCount < params.RuleChangeActivationQuorum { 367 bits = 0x05 // vote no 368 } 369 appendFakeVotes(node, 1, posVersion, bits) 370 voteCount++ 371 } 372 373 bc.bestChain.SetTip(node) 374 bc.index.AddNode(node) 375 curTimestamp = curTimestamp.Add(time.Second) 376 } 377 378 ts, err = bc.NextThresholdState(&node.hash, posVersion, pedro.Id) 379 if err != nil { 380 t.Fatalf("NextThresholdState(quorum 75%%-1): %v", err) 381 } 382 tse = ThresholdStateTuple{ 383 State: ThresholdStarted, 384 Choice: invalidChoice, 385 } 386 if ts != tse { 387 t.Fatalf("expected %+v got %+v", ts, tse) 388 } 389 390 // get to exact quorum with exactly 75% of votes 391 voteCount = uint32(0) 392 for i := uint32(0); i < params.RuleChangeActivationInterval; i++ { 393 // Set stake versions and vote bits. 394 node = newFakeNode(node, powVersion, posVersion, 0, curTimestamp) 395 for x := 0; x < int(params.TicketsPerBlock); x++ { 396 // 120 yes, 40 no -> 120 == 75% and 120 reaches quorum 397 bits := uint16(0x01) // abstain 398 quorum := params.RuleChangeActivationQuorum * 399 params.RuleChangeActivationMultiplier / 400 params.RuleChangeActivationDivisor 401 if voteCount < quorum { 402 bits = 0x03 // vote yes 403 } else if voteCount < params.RuleChangeActivationQuorum { 404 bits = 0x05 // vote no 405 } 406 appendFakeVotes(node, 1, posVersion, bits) 407 voteCount++ 408 } 409 410 bc.bestChain.SetTip(node) 411 bc.index.AddNode(node) 412 curTimestamp = curTimestamp.Add(time.Second) 413 } 414 415 ts, err = bc.NextThresholdState(&node.hash, posVersion, pedro.Id) 416 if err != nil { 417 t.Fatalf("NextThresholdState(quorum 75%%): %v", err) 418 } 419 tse = ThresholdStateTuple{ 420 State: ThresholdLockedIn, 421 Choice: 0x01, 422 } 423 if ts != tse { 424 t.Fatalf("expected %+v got %+v", ts, tse) 425 } 426 } 427 428 // TestVoting ensure the overall voting of an agenda works as expected including 429 // a wide variety of conditions. 430 func TestVoting(t *testing.T) { 431 params := defaultParams(chaincfg.Vote{}) 432 rci := params.RuleChangeActivationInterval 433 svh := uint32(params.StakeValidationHeight) 434 svi := uint32(params.StakeVersionInterval) 435 436 type voteCount struct { 437 vote stake.VoteVersionTuple 438 count uint32 439 } 440 441 tests := []struct { 442 name string 443 vote chaincfg.Vote 444 blockVersion int32 445 startStakeVersion uint32 446 end func(time.Time) uint64 447 voteBitsCounts []voteCount 448 expectedState []ThresholdStateTuple 449 }{ 450 { 451 name: "pedro too shallow", 452 vote: pedro, 453 blockVersion: powVersion, 454 startStakeVersion: posVersion, 455 voteBitsCounts: []voteCount{{ 456 vote: stake.VoteVersionTuple{ 457 Version: posVersion, 458 Bits: 0x01, 459 }, 460 count: svh - 1, 461 }}, 462 expectedState: []ThresholdStateTuple{{ 463 State: ThresholdDefined, 464 Choice: invalidChoice, 465 }}, 466 }, 467 { 468 name: "pedro greater PoS version", 469 vote: pedro, 470 blockVersion: powVersion, 471 startStakeVersion: posVersion - 1, 472 voteBitsCounts: []voteCount{{ 473 vote: stake.VoteVersionTuple{ 474 Version: posVersion, 475 Bits: 0x01, 476 }, 477 count: svh, 478 }, { 479 vote: stake.VoteVersionTuple{ 480 Version: posVersion, 481 Bits: 0x01, 482 }, 483 count: svi - 1, 484 }, { 485 vote: stake.VoteVersionTuple{ 486 Version: posVersion, 487 Bits: 0x01, 488 }, 489 count: rci - svi, 490 }, { 491 vote: stake.VoteVersionTuple{ 492 Version: posVersion, 493 Bits: 0x03, 494 }, 495 count: rci, 496 }}, 497 expectedState: []ThresholdStateTuple{{ 498 State: ThresholdDefined, 499 Choice: invalidChoice, 500 }, { 501 State: ThresholdDefined, 502 Choice: invalidChoice, 503 }, { 504 State: ThresholdStarted, 505 Choice: invalidChoice, 506 }, { 507 State: ThresholdLockedIn, 508 Choice: 1, 509 }}, 510 }, 511 { 512 name: "pedro greater PoS version calcStakeVersion", 513 vote: pedro, 514 blockVersion: powVersion, 515 startStakeVersion: posVersion - 1, 516 voteBitsCounts: []voteCount{{ 517 vote: stake.VoteVersionTuple{ 518 Version: posVersion - 1, 519 Bits: 0x01, 520 }, 521 count: svh + 2*svi - 1, 522 }, { 523 vote: stake.VoteVersionTuple{ 524 Version: posVersion, 525 Bits: 0x01, 526 }, 527 count: rci % svi, 528 }, { 529 vote: stake.VoteVersionTuple{ 530 Version: posVersion, 531 Bits: 0x01, 532 }, 533 count: rci, 534 }, { 535 vote: stake.VoteVersionTuple{ 536 Version: posVersion, 537 Bits: 0x03}, 538 count: rci, 539 }}, 540 expectedState: []ThresholdStateTuple{{ 541 State: ThresholdDefined, 542 Choice: invalidChoice, 543 }, { 544 State: ThresholdDefined, 545 Choice: invalidChoice, 546 }, { 547 State: ThresholdStarted, 548 Choice: invalidChoice, 549 }, { 550 State: ThresholdLockedIn, 551 Choice: 1, 552 }}, 553 }, 554 { 555 name: "pedro smaller PoS version", 556 vote: pedro, 557 blockVersion: powVersion, 558 startStakeVersion: posVersion + 1, 559 voteBitsCounts: []voteCount{{ 560 vote: stake.VoteVersionTuple{ 561 Version: posVersion, 562 Bits: 0x01, 563 }, 564 count: svh, 565 }, { 566 vote: stake.VoteVersionTuple{ 567 Version: posVersion, 568 Bits: 0x01, 569 }, 570 count: rci - 1, 571 }, { 572 vote: stake.VoteVersionTuple{ 573 Version: posVersion, 574 Bits: 0x03, 575 }, 576 count: rci, 577 }, { 578 vote: stake.VoteVersionTuple{ 579 Version: posVersion, 580 Bits: 0x03, 581 }, 582 count: rci, 583 }}, 584 expectedState: []ThresholdStateTuple{{ 585 State: ThresholdDefined, 586 Choice: invalidChoice, 587 }, { 588 State: ThresholdStarted, 589 Choice: invalidChoice, 590 }, { 591 State: ThresholdLockedIn, 592 Choice: 0x01, 593 }, { 594 State: ThresholdActive, 595 Choice: 0x01, 596 }}, 597 }, 598 { 599 name: "pedro smaller PoW version", 600 vote: pedro, 601 blockVersion: powVersion - 1, 602 startStakeVersion: posVersion, 603 voteBitsCounts: []voteCount{{ 604 vote: stake.VoteVersionTuple{ 605 Version: posVersion, 606 Bits: 0x01, 607 }, 608 count: svh, 609 }, { 610 vote: stake.VoteVersionTuple{ 611 Version: posVersion, 612 Bits: 0x01, 613 }, 614 count: rci - 1, 615 }, { 616 vote: stake.VoteVersionTuple{ 617 Version: posVersion, 618 Bits: 0x03, 619 }, 620 count: rci, 621 }}, 622 expectedState: []ThresholdStateTuple{{ 623 State: ThresholdDefined, 624 Choice: invalidChoice, 625 }, { 626 State: ThresholdDefined, 627 Choice: invalidChoice, 628 }, { 629 State: ThresholdDefined, 630 Choice: invalidChoice, 631 }}, 632 }, 633 { 634 name: "pedro greater PoW version", 635 vote: pedro, 636 blockVersion: powVersion + 1, 637 startStakeVersion: posVersion, 638 voteBitsCounts: []voteCount{{ 639 vote: stake.VoteVersionTuple{ 640 Version: posVersion, 641 Bits: 0x01, 642 }, 643 count: svh, 644 }, { 645 vote: stake.VoteVersionTuple{ 646 Version: posVersion, 647 Bits: 0x01, 648 }, 649 count: rci - 1, 650 }, { 651 vote: stake.VoteVersionTuple{ 652 Version: posVersion, 653 Bits: 0x03, 654 }, 655 count: rci, 656 }, { 657 vote: stake.VoteVersionTuple{ 658 Version: posVersion, 659 Bits: 0x03, 660 }, 661 count: rci, 662 }}, 663 expectedState: []ThresholdStateTuple{{ 664 State: ThresholdDefined, 665 Choice: invalidChoice, 666 }, { 667 State: ThresholdStarted, 668 Choice: invalidChoice, 669 }, { 670 State: ThresholdLockedIn, 671 Choice: 0x01, 672 }, { 673 State: ThresholdActive, 674 Choice: 0x01, 675 }}, 676 }, 677 { 678 name: "pedro 100% yes, wrong version", 679 vote: pedro, 680 blockVersion: powVersion, 681 startStakeVersion: posVersion, 682 voteBitsCounts: []voteCount{{ 683 vote: stake.VoteVersionTuple{ 684 Version: posVersion + 1, 685 Bits: 0x01, 686 }, 687 count: svh, 688 }, { 689 vote: stake.VoteVersionTuple{ 690 Version: posVersion + 1, 691 Bits: 0x01, 692 }, 693 count: rci - 1, 694 }, { 695 vote: stake.VoteVersionTuple{ 696 Version: posVersion + 1, 697 Bits: 0x03, 698 }, 699 count: rci, 700 }, { 701 vote: stake.VoteVersionTuple{ 702 Version: posVersion + 1, 703 Bits: 0x03, 704 }, 705 count: rci, 706 }, { 707 vote: stake.VoteVersionTuple{ 708 Version: posVersion, 709 Bits: 0x03, 710 }, 711 count: rci, 712 }, { 713 vote: stake.VoteVersionTuple{ 714 Version: posVersion, 715 Bits: 0x03, 716 }, 717 count: rci, 718 }, { 719 vote: stake.VoteVersionTuple{ 720 Version: posVersion + 1, 721 Bits: 0x01, 722 }, 723 count: rci, 724 }}, 725 expectedState: []ThresholdStateTuple{{ 726 State: ThresholdDefined, 727 Choice: invalidChoice, 728 }, { 729 State: ThresholdStarted, 730 Choice: invalidChoice, 731 }, { 732 State: ThresholdStarted, 733 Choice: invalidChoice, 734 }, { 735 State: ThresholdStarted, 736 Choice: invalidChoice, 737 }, { 738 State: ThresholdLockedIn, 739 Choice: 0x01, 740 }, { 741 State: ThresholdActive, 742 Choice: 0x01, 743 }, { 744 State: ThresholdActive, 745 Choice: 0x01, 746 }}, 747 }, 748 { 749 name: "pedro 100% yes", 750 vote: pedro, 751 blockVersion: powVersion, 752 startStakeVersion: posVersion, 753 voteBitsCounts: []voteCount{{ 754 vote: stake.VoteVersionTuple{ 755 Version: posVersion, 756 Bits: 0x01, 757 }, 758 count: svh, 759 }, { 760 vote: stake.VoteVersionTuple{ 761 Version: posVersion, 762 Bits: 0x01, 763 }, 764 count: rci - 1, 765 }, { 766 vote: stake.VoteVersionTuple{ 767 Version: posVersion, 768 Bits: 0x03, 769 }, 770 count: rci, 771 }, { 772 vote: stake.VoteVersionTuple{ 773 Version: posVersion, 774 Bits: 0x03, 775 }, 776 count: rci, 777 }, { 778 vote: stake.VoteVersionTuple{ 779 Version: posVersion, 780 Bits: 0x01, 781 }, 782 count: rci, 783 }}, 784 expectedState: []ThresholdStateTuple{{ 785 State: ThresholdDefined, 786 Choice: invalidChoice, 787 }, { 788 State: ThresholdStarted, 789 Choice: invalidChoice, 790 }, { 791 State: ThresholdLockedIn, 792 Choice: 0x01, 793 }, { 794 State: ThresholdActive, 795 Choice: 0x01, 796 }, { 797 State: ThresholdActive, 798 Choice: 0x01, 799 }}, 800 }, 801 { 802 name: "pedro 100% no", 803 vote: pedro, 804 blockVersion: powVersion, 805 startStakeVersion: posVersion, 806 voteBitsCounts: []voteCount{{ 807 vote: stake.VoteVersionTuple{ 808 Version: posVersion, 809 Bits: 0x01, 810 }, 811 count: svh, 812 }, { 813 vote: stake.VoteVersionTuple{ 814 Version: posVersion, 815 Bits: 0x01, 816 }, 817 count: rci - 1, 818 }, { 819 vote: stake.VoteVersionTuple{ 820 Version: posVersion, 821 Bits: 0x05, 822 }, 823 count: rci, 824 }, { 825 vote: stake.VoteVersionTuple{ 826 Version: posVersion, 827 Bits: 0x05, 828 }, 829 count: rci, 830 }, { 831 vote: stake.VoteVersionTuple{ 832 Version: posVersion, 833 Bits: 0x01, 834 }, 835 count: rci, 836 }}, 837 expectedState: []ThresholdStateTuple{{ 838 State: ThresholdDefined, 839 Choice: invalidChoice, 840 }, { 841 State: ThresholdStarted, 842 Choice: invalidChoice, 843 }, { 844 State: ThresholdFailed, 845 Choice: 0x02, 846 }, { 847 State: ThresholdFailed, 848 Choice: 0x02, 849 }, { 850 State: ThresholdFailed, 851 Choice: 0x02, 852 }}, 853 }, 854 { 855 name: "pedro 100% invalid", 856 vote: pedro, 857 blockVersion: powVersion, 858 startStakeVersion: posVersion, 859 voteBitsCounts: []voteCount{{ 860 vote: stake.VoteVersionTuple{ 861 Version: posVersion, 862 Bits: 0x01, 863 }, 864 count: svh, 865 }, { 866 vote: stake.VoteVersionTuple{ 867 Version: posVersion, 868 Bits: 0x01, 869 }, 870 count: rci - 1, 871 }, { 872 vote: stake.VoteVersionTuple{ 873 Version: posVersion, 874 Bits: 0x06, 875 }, 876 count: rci, 877 }, { 878 vote: stake.VoteVersionTuple{ 879 Version: posVersion, 880 Bits: 0x06, 881 }, 882 count: rci, 883 }, { 884 vote: stake.VoteVersionTuple{ 885 Version: posVersion, 886 Bits: 0x03, 887 }, 888 count: rci, 889 }, { 890 vote: stake.VoteVersionTuple{ 891 Version: posVersion, 892 Bits: 0x01, 893 }, 894 count: rci, 895 }}, 896 expectedState: []ThresholdStateTuple{{ 897 State: ThresholdDefined, 898 Choice: invalidChoice, 899 }, { 900 State: ThresholdStarted, 901 Choice: invalidChoice, 902 }, { 903 State: ThresholdStarted, 904 Choice: invalidChoice, 905 }, { 906 State: ThresholdStarted, 907 Choice: invalidChoice, 908 }, { 909 State: ThresholdLockedIn, 910 Choice: 0x01, 911 }, { 912 State: ThresholdActive, 913 Choice: 0x01, 914 }}, 915 }, 916 { 917 name: "pedro 100% abstain", 918 vote: pedro, 919 blockVersion: powVersion, 920 startStakeVersion: posVersion, 921 voteBitsCounts: []voteCount{{ 922 vote: stake.VoteVersionTuple{ 923 Version: posVersion, 924 Bits: 0x01, 925 }, 926 count: svh, 927 }, { 928 vote: stake.VoteVersionTuple{ 929 Version: posVersion, 930 Bits: 0x01, 931 }, 932 count: rci - 1, 933 }, { 934 vote: stake.VoteVersionTuple{ 935 Version: posVersion, 936 Bits: 0x01, 937 }, 938 count: rci, 939 }, { 940 vote: stake.VoteVersionTuple{ 941 Version: posVersion, 942 Bits: 0x01, 943 }, 944 count: rci, 945 }, { 946 vote: stake.VoteVersionTuple{ 947 Version: posVersion, 948 Bits: 0x01, 949 }, 950 count: rci, 951 }}, 952 expectedState: []ThresholdStateTuple{{ 953 State: ThresholdDefined, 954 Choice: invalidChoice, 955 }, { 956 State: ThresholdStarted, 957 Choice: invalidChoice, 958 }, { 959 State: ThresholdStarted, 960 Choice: invalidChoice, 961 }, { 962 State: ThresholdStarted, 963 Choice: invalidChoice, 964 }, { 965 State: ThresholdStarted, 966 Choice: invalidChoice, 967 }}, 968 }, 969 { 970 name: "pedro expire before started", 971 vote: pedro, 972 blockVersion: powVersion, 973 startStakeVersion: posVersion - 1, 974 end: func(t time.Time) uint64 { 975 return uint64(t.Add(time.Second * 976 time.Duration(int64(svh)+int64(rci+rci/2))).Unix()) 977 }, 978 voteBitsCounts: []voteCount{{ 979 vote: stake.VoteVersionTuple{ 980 Version: posVersion - 1, 981 Bits: 0x01, 982 }, 983 count: svh, 984 }, { 985 vote: stake.VoteVersionTuple{ 986 Version: posVersion - 1, 987 Bits: 0x05, 988 }, 989 count: rci - 1, 990 }, { 991 vote: stake.VoteVersionTuple{ 992 Version: posVersion - 1, 993 Bits: 0x05, 994 }, 995 count: rci, 996 }}, 997 expectedState: []ThresholdStateTuple{{ 998 State: ThresholdDefined, 999 Choice: invalidChoice, 1000 }, { 1001 State: ThresholdDefined, 1002 Choice: invalidChoice, 1003 }, { 1004 State: ThresholdFailed, 1005 Choice: invalidChoice, 1006 }}, 1007 }, 1008 { 1009 name: "pedro expire after started", 1010 vote: pedro, 1011 blockVersion: powVersion, 1012 startStakeVersion: posVersion, 1013 end: func(t time.Time) uint64 { 1014 return uint64(t.Add(time.Second * 1015 time.Duration(int64(svh)+int64(rci+rci/2))).Unix()) 1016 }, 1017 voteBitsCounts: []voteCount{{ 1018 vote: stake.VoteVersionTuple{ 1019 Version: posVersion, 1020 Bits: 0x01, 1021 }, 1022 count: svh, 1023 }, { 1024 vote: stake.VoteVersionTuple{ 1025 Version: posVersion, 1026 Bits: 0x05, 1027 }, 1028 count: rci - 1, 1029 }, { 1030 vote: stake.VoteVersionTuple{ 1031 Version: posVersion, 1032 Bits: 0x05, 1033 }, 1034 count: rci, 1035 }}, 1036 expectedState: []ThresholdStateTuple{{ 1037 State: ThresholdDefined, 1038 Choice: invalidChoice, 1039 }, { 1040 State: ThresholdStarted, 1041 Choice: invalidChoice, 1042 }, { 1043 State: ThresholdFailed, 1044 Choice: invalidChoice, 1045 }}, 1046 }, 1047 { 1048 name: "pedro overlap", 1049 vote: pedro, 1050 blockVersion: powVersion, 1051 startStakeVersion: posVersion - 1, 1052 voteBitsCounts: []voteCount{{ 1053 vote: stake.VoteVersionTuple{ 1054 Version: posVersion - 1, 1055 Bits: 0x01, 1056 }, 1057 count: svh + 19*svi - 1, 1058 }, { 1059 vote: stake.VoteVersionTuple{ 1060 Version: posVersion, 1061 Bits: 0x01, 1062 }, 1063 count: svi - 1, 1064 }, { 1065 vote: stake.VoteVersionTuple{ 1066 Version: posVersion, 1067 Bits: 0x01, 1068 }, 1069 count: 1, 1070 }, { 1071 vote: stake.VoteVersionTuple{ 1072 Version: posVersion, 1073 Bits: 0x03, 1074 }, 1075 count: rci - 1, 1076 }, { 1077 vote: stake.VoteVersionTuple{ 1078 Version: posVersion, 1079 Bits: 0x03, 1080 }, 1081 count: 1, 1082 }, { 1083 vote: stake.VoteVersionTuple{ 1084 Version: posVersion, 1085 Bits: 0x01, 1086 }, 1087 count: rci, 1088 }}, 1089 expectedState: []ThresholdStateTuple{{ 1090 State: ThresholdDefined, 1091 Choice: invalidChoice, 1092 }, { 1093 State: ThresholdDefined, 1094 Choice: invalidChoice, 1095 }, { 1096 State: ThresholdStarted, 1097 Choice: invalidChoice, 1098 }, { 1099 State: ThresholdStarted, 1100 Choice: invalidChoice, 1101 }, { 1102 State: ThresholdLockedIn, 1103 Choice: 1, 1104 }, { 1105 State: ThresholdActive, 1106 Choice: 1, 1107 }}, 1108 }, 1109 { 1110 name: "multiple choice 100% abstain", 1111 vote: multipleChoice, 1112 blockVersion: powVersion, 1113 startStakeVersion: posVersion, 1114 voteBitsCounts: []voteCount{{ 1115 vote: stake.VoteVersionTuple{ 1116 Version: posVersion, 1117 Bits: 0x01, 1118 }, 1119 count: svh, 1120 }, { 1121 vote: stake.VoteVersionTuple{ 1122 Version: posVersion, 1123 Bits: 0x01, 1124 }, 1125 count: rci - 1, 1126 }, { 1127 vote: stake.VoteVersionTuple{ 1128 Version: posVersion, 1129 Bits: 0x01, 1130 }, 1131 count: rci, 1132 }}, 1133 expectedState: []ThresholdStateTuple{{ 1134 State: ThresholdDefined, 1135 Choice: invalidChoice, 1136 }, { 1137 State: ThresholdStarted, 1138 Choice: invalidChoice, 1139 }, { 1140 State: ThresholdStarted, 1141 Choice: invalidChoice, 1142 }}, 1143 }, 1144 { 1145 name: "multiple choice 100% no", 1146 vote: multipleChoice, 1147 blockVersion: powVersion, 1148 startStakeVersion: posVersion, 1149 voteBitsCounts: []voteCount{{ 1150 vote: stake.VoteVersionTuple{ 1151 Version: posVersion, 1152 Bits: 0x01, 1153 }, 1154 count: svh, 1155 }, { 1156 vote: stake.VoteVersionTuple{ 1157 Version: posVersion, 1158 Bits: 0x01, 1159 }, 1160 count: rci - 1, 1161 }, { 1162 vote: stake.VoteVersionTuple{ 1163 Version: posVersion, 1164 Bits: 0x21, 1165 }, 1166 count: rci, 1167 }}, 1168 expectedState: []ThresholdStateTuple{{ 1169 State: ThresholdDefined, 1170 Choice: invalidChoice, 1171 }, { 1172 State: ThresholdStarted, 1173 Choice: invalidChoice, 1174 }, { 1175 State: ThresholdFailed, 1176 Choice: 2, 1177 }}, 1178 }, 1179 { 1180 name: "multiple choice 100% choice 1", 1181 vote: multipleChoice, 1182 blockVersion: powVersion, 1183 startStakeVersion: posVersion, 1184 voteBitsCounts: []voteCount{{ 1185 vote: stake.VoteVersionTuple{ 1186 Version: posVersion, 1187 Bits: 0x01, 1188 }, 1189 count: svh, 1190 }, { 1191 vote: stake.VoteVersionTuple{ 1192 Version: posVersion, 1193 Bits: 0x01, 1194 }, 1195 count: rci - 1, 1196 }, { 1197 vote: stake.VoteVersionTuple{ 1198 Version: posVersion, 1199 Bits: 0x11, 1200 }, 1201 count: rci, 1202 }, { 1203 vote: stake.VoteVersionTuple{ 1204 Version: posVersion, 1205 Bits: 0x11, 1206 }, 1207 count: rci, 1208 }, { 1209 vote: stake.VoteVersionTuple{ 1210 Version: posVersion, 1211 Bits: 0x01, 1212 }, 1213 count: rci, 1214 }}, 1215 expectedState: []ThresholdStateTuple{{ 1216 State: ThresholdDefined, 1217 Choice: invalidChoice, 1218 }, { 1219 State: ThresholdStarted, 1220 Choice: invalidChoice, 1221 }, { 1222 State: ThresholdLockedIn, 1223 Choice: 1, 1224 }, { 1225 State: ThresholdActive, 1226 Choice: 1, 1227 }, { 1228 State: ThresholdActive, 1229 Choice: 1, 1230 }}, 1231 }, 1232 { 1233 name: "multiple choice 100% choice 2", 1234 vote: multipleChoice, 1235 blockVersion: powVersion, 1236 startStakeVersion: posVersion, 1237 voteBitsCounts: []voteCount{{ 1238 vote: stake.VoteVersionTuple{ 1239 Version: posVersion, 1240 Bits: 0x01, 1241 }, 1242 count: svh, 1243 }, { 1244 vote: stake.VoteVersionTuple{ 1245 Version: posVersion, 1246 Bits: 0x01, 1247 }, 1248 count: rci - 1, 1249 }, { 1250 vote: stake.VoteVersionTuple{ 1251 Version: posVersion, 1252 Bits: 0x31, 1253 }, 1254 count: rci, 1255 }, { 1256 vote: stake.VoteVersionTuple{ 1257 Version: posVersion, 1258 Bits: 0x31, 1259 }, 1260 count: rci, 1261 }, { 1262 vote: stake.VoteVersionTuple{ 1263 Version: posVersion, 1264 Bits: 0x01, 1265 }, 1266 count: rci, 1267 }}, 1268 expectedState: []ThresholdStateTuple{{ 1269 State: ThresholdDefined, 1270 Choice: invalidChoice, 1271 }, { 1272 State: ThresholdStarted, 1273 Choice: invalidChoice, 1274 }, { 1275 State: ThresholdLockedIn, 1276 Choice: 3, 1277 }, { 1278 State: ThresholdActive, 1279 Choice: 3, 1280 }, { 1281 State: ThresholdActive, 1282 Choice: 3, 1283 }}, 1284 }, 1285 { 1286 name: "multiple choice 100% choice 3", 1287 vote: multipleChoice, 1288 blockVersion: powVersion, 1289 startStakeVersion: posVersion, 1290 voteBitsCounts: []voteCount{{ 1291 vote: stake.VoteVersionTuple{ 1292 Version: posVersion, 1293 Bits: 0x01, 1294 }, 1295 count: svh, 1296 }, { 1297 vote: stake.VoteVersionTuple{ 1298 Version: posVersion, 1299 Bits: 0x01, 1300 }, 1301 count: rci - 1, 1302 }, { 1303 vote: stake.VoteVersionTuple{ 1304 Version: posVersion, 1305 Bits: 0x41, 1306 }, 1307 count: rci, 1308 }, { 1309 vote: stake.VoteVersionTuple{ 1310 Version: posVersion, 1311 Bits: 0x41, 1312 }, 1313 count: rci, 1314 }, { 1315 vote: stake.VoteVersionTuple{ 1316 Version: posVersion, 1317 Bits: 0x01, 1318 }, 1319 count: rci, 1320 }}, 1321 expectedState: []ThresholdStateTuple{{ 1322 State: ThresholdDefined, 1323 Choice: invalidChoice, 1324 }, { 1325 State: ThresholdStarted, 1326 Choice: invalidChoice, 1327 }, { 1328 State: ThresholdLockedIn, 1329 Choice: 4, 1330 }, { 1331 State: ThresholdActive, 1332 Choice: 4, 1333 }, { 1334 State: ThresholdActive, 1335 Choice: 4, 1336 }}, 1337 }, 1338 { 1339 name: "multiple choice 100% choice 4", 1340 vote: multipleChoice, 1341 blockVersion: powVersion, 1342 startStakeVersion: posVersion, 1343 voteBitsCounts: []voteCount{{ 1344 vote: stake.VoteVersionTuple{ 1345 Version: posVersion, 1346 Bits: 0x01, 1347 }, 1348 count: svh, 1349 }, { 1350 vote: stake.VoteVersionTuple{ 1351 Version: posVersion, 1352 Bits: 0x01, 1353 }, 1354 count: rci - 1, 1355 }, { 1356 vote: stake.VoteVersionTuple{ 1357 Version: posVersion, 1358 Bits: 0x51, 1359 }, 1360 count: rci, 1361 }, { 1362 vote: stake.VoteVersionTuple{ 1363 Version: posVersion, 1364 Bits: 0x51, 1365 }, 1366 count: rci, 1367 }, { 1368 vote: stake.VoteVersionTuple{ 1369 Version: posVersion, 1370 Bits: 0x01, 1371 }, 1372 count: rci, 1373 }}, 1374 expectedState: []ThresholdStateTuple{{ 1375 State: ThresholdDefined, 1376 Choice: invalidChoice, 1377 }, { 1378 State: ThresholdStarted, 1379 Choice: invalidChoice, 1380 }, { 1381 State: ThresholdLockedIn, 1382 Choice: 5, 1383 }, { 1384 State: ThresholdActive, 1385 Choice: 5, 1386 }, { 1387 State: ThresholdActive, 1388 Choice: 5, 1389 }}, 1390 }, 1391 { 1392 name: "multiple choice 100% choice 5 (invalid)", 1393 vote: multipleChoice, 1394 blockVersion: powVersion, 1395 startStakeVersion: posVersion, 1396 voteBitsCounts: []voteCount{{ 1397 vote: stake.VoteVersionTuple{ 1398 Version: posVersion, 1399 Bits: 0x01, 1400 }, 1401 count: svh, 1402 }, { 1403 vote: stake.VoteVersionTuple{ 1404 Version: posVersion, 1405 Bits: 0x01, 1406 }, 1407 count: rci - 1, 1408 }, { 1409 vote: stake.VoteVersionTuple{ 1410 Version: posVersion, 1411 Bits: 0x61, 1412 }, 1413 count: rci, 1414 }, { 1415 vote: stake.VoteVersionTuple{ 1416 Version: posVersion, 1417 Bits: 0x61, 1418 }, 1419 count: rci, 1420 }, { 1421 vote: stake.VoteVersionTuple{ 1422 Version: posVersion, 1423 Bits: 0x01, 1424 }, 1425 count: rci, 1426 }}, 1427 expectedState: []ThresholdStateTuple{{ 1428 State: ThresholdDefined, 1429 Choice: invalidChoice, 1430 }, { 1431 State: ThresholdStarted, 1432 Choice: invalidChoice, 1433 }, { 1434 State: ThresholdStarted, 1435 Choice: invalidChoice, 1436 }, { 1437 State: ThresholdStarted, 1438 Choice: invalidChoice, 1439 }, { 1440 State: ThresholdStarted, 1441 Choice: invalidChoice, 1442 }}, 1443 }, 1444 } 1445 1446 for _, test := range tests { 1447 // Reset params. 1448 params = defaultParams(test.vote) 1449 // We have to reset the cache for every test. 1450 bc := newFakeChain(¶ms) 1451 node := bc.bestChain.Tip() 1452 node.stakeVersion = test.startStakeVersion 1453 1454 t.Logf("running: %v", test.name) 1455 1456 // Override start time. 1457 curTimestamp := time.Now() 1458 1459 // Override expiration time. 1460 if test.end != nil { 1461 params.Deployments[posVersion][0].ExpireTime = 1462 test.end(curTimestamp) 1463 } 1464 1465 t.Logf("curTimestamp %v start %v expiration %v", 1466 uint64(curTimestamp.Unix()), 1467 params.Deployments[posVersion][0].StartTime, 1468 params.Deployments[posVersion][0].ExpireTime) 1469 1470 for k := range test.expectedState { 1471 for i := uint32(0); i < test.voteBitsCounts[k].count; i++ { 1472 // Set stake versions and vote bits. 1473 node = newFakeNode(node, test.blockVersion, 1474 test.startStakeVersion, 0, curTimestamp) 1475 vote := &test.voteBitsCounts[k].vote 1476 appendFakeVotes(node, params.TicketsPerBlock, 1477 vote.Version, vote.Bits) 1478 1479 bc.bestChain.SetTip(node) 1480 bc.index.AddNode(node) 1481 curTimestamp = curTimestamp.Add(time.Second) 1482 } 1483 t.Logf("Height %v, Start time %v, curTime %v, delta %v", 1484 node.height, params.Deployments[4][0].StartTime, 1485 node.timestamp, node.timestamp- 1486 int64(params.Deployments[4][0].StartTime)) 1487 ts, err := bc.NextThresholdState(&node.hash, posVersion, 1488 test.vote.Id) 1489 if err != nil { 1490 t.Fatalf("NextThresholdState(%v): %v", k, err) 1491 } 1492 if ts != test.expectedState[k] { 1493 t.Fatalf("%v.%v (%v) got state %+v wanted "+ 1494 "state %+v", test.name, test.vote.Id, k, 1495 ts, test.expectedState[k]) 1496 } 1497 } 1498 } 1499 } 1500 1501 // defaultParallelParams returns net parameters modified to have two known 1502 // deployments that are used throughout the parallel votebit tests. 1503 func defaultParallelParams() chaincfg.Params { 1504 params := chaincfg.RegNetParams 1505 params.Deployments = make(map[uint32][]chaincfg.ConsensusDeployment) 1506 params.Deployments[posVersion] = []chaincfg.ConsensusDeployment{ 1507 { 1508 Vote: testDummy1, 1509 StartTime: uint64(time.Now().Add(time.Duration(params.RuleChangeActivationInterval) * 1510 time.Second).Unix()), 1511 ExpireTime: uint64(time.Now().Add(24 * time.Hour).Unix()), 1512 }, 1513 { 1514 Vote: testDummy2, 1515 StartTime: uint64(time.Now().Add(time.Duration(params.RuleChangeActivationInterval) * 1516 time.Second).Unix()), 1517 ExpireTime: uint64(time.Now().Add(24 * time.Hour).Unix()), 1518 }, 1519 } 1520 1521 return params 1522 } 1523 1524 // TestParallelVoting ensures that two agendas running at the same time progress 1525 // through the expected states. 1526 func TestParallelVoting(t *testing.T) { 1527 params := defaultParallelParams() 1528 1529 type voteCount struct { 1530 vote stake.VoteVersionTuple 1531 count uint32 1532 } 1533 1534 tests := []struct { 1535 name string 1536 vote []chaincfg.Vote 1537 blockVersion int32 1538 startStakeVersion uint32 1539 voteBitsCounts []voteCount 1540 expectedState [][]ThresholdStateTuple 1541 }{ 1542 { 1543 name: "parallel", 1544 vote: []chaincfg.Vote{testDummy1, testDummy2}, 1545 blockVersion: powVersion, 1546 startStakeVersion: posVersion, 1547 voteBitsCounts: []voteCount{{ 1548 vote: stake.VoteVersionTuple{ 1549 Version: posVersion, 1550 Bits: 0x01, 1551 }, 1552 count: uint32(params.StakeValidationHeight), 1553 }, { 1554 vote: stake.VoteVersionTuple{ 1555 Version: posVersion, 1556 Bits: 0x01, 1557 }, 1558 count: params.RuleChangeActivationInterval - 1, 1559 }, { 1560 vote: stake.VoteVersionTuple{ 1561 Version: posVersion - 1, 1562 Bits: vbTestDummy1Yes | vbTestDummy2No, 1563 }, 1564 count: params.RuleChangeActivationInterval, 1565 }, { 1566 vote: stake.VoteVersionTuple{ 1567 Version: posVersion, 1568 Bits: vbTestDummy1Yes | vbTestDummy2No, 1569 }, 1570 count: params.RuleChangeActivationInterval, 1571 }, { 1572 vote: stake.VoteVersionTuple{ 1573 Version: posVersion, 1574 Bits: 0x01, 1575 }, 1576 count: params.RuleChangeActivationInterval, 1577 }, { 1578 vote: stake.VoteVersionTuple{ 1579 Version: posVersion, 1580 Bits: 0x01, 1581 }, 1582 count: params.RuleChangeActivationInterval, 1583 }}, 1584 expectedState: [][]ThresholdStateTuple{ 1585 // 0 1586 {{ 1587 State: ThresholdDefined, 1588 Choice: invalidChoice, 1589 }, { 1590 State: ThresholdStarted, 1591 Choice: invalidChoice, 1592 }, { 1593 State: ThresholdStarted, 1594 Choice: invalidChoice, 1595 }, { 1596 State: ThresholdLockedIn, 1597 Choice: 0x02, 1598 }, { 1599 State: ThresholdActive, 1600 Choice: 0x02, 1601 }, { 1602 State: ThresholdActive, 1603 Choice: 0x02, 1604 }}, 1605 // 1 1606 {{ 1607 State: ThresholdDefined, 1608 Choice: invalidChoice, 1609 }, { 1610 State: ThresholdStarted, 1611 Choice: invalidChoice, 1612 }, { 1613 State: ThresholdStarted, 1614 Choice: invalidChoice, 1615 }, { 1616 State: ThresholdFailed, 1617 Choice: 0x01, 1618 }, { 1619 State: ThresholdFailed, 1620 Choice: 0x01, 1621 }, { 1622 State: ThresholdFailed, 1623 Choice: 0x01, 1624 }}, 1625 }, 1626 }, 1627 } 1628 1629 for _, test := range tests { 1630 // Reset params. 1631 params = defaultParallelParams() 1632 // We have to reset the cache for every test. 1633 bc := newFakeChain(¶ms) 1634 node := bc.bestChain.Tip() 1635 node.stakeVersion = test.startStakeVersion 1636 1637 curTimestamp := time.Now() 1638 for k := range test.expectedState[0] { 1639 for i := uint32(0); i < test.voteBitsCounts[k].count; i++ { 1640 // Set stake versions and vote bits. 1641 node = newFakeNode(node, test.blockVersion, 1642 test.startStakeVersion, 0, curTimestamp) 1643 vote := &test.voteBitsCounts[k].vote 1644 appendFakeVotes(node, params.TicketsPerBlock, 1645 vote.Version, vote.Bits) 1646 1647 bc.bestChain.SetTip(node) 1648 bc.index.AddNode(node) 1649 curTimestamp = curTimestamp.Add(time.Second) 1650 } 1651 for i := range test.vote { 1652 ts, err := bc.NextThresholdState(&node.hash, 1653 posVersion, test.vote[i].Id) 1654 if err != nil { 1655 t.Fatalf("NextThresholdState(%v): %v", k, err) 1656 } 1657 1658 if ts != test.expectedState[i][k] { 1659 t.Fatalf("%v.%v (%v) got state %+v "+ 1660 "wanted state %+v", 1661 test.name, test.vote[i].Id, k, 1662 ts, test.expectedState[i][k]) 1663 } 1664 } 1665 } 1666 } 1667 }