github.com/decred/dcrd/blockchain@v1.2.1/thresholdstate_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 "fmt" 9 "math" 10 "testing" 11 "time" 12 13 "github.com/decred/dcrd/blockchain/chaingen" 14 "github.com/decred/dcrd/chaincfg" 15 ) 16 17 const ( 18 // vbPrevBlockValid defines the vote bit necessary to vote yes to the 19 // previous block being valid. 20 vbPrevBlockValid = 0x01 21 22 // testDummy1ID is the human-readable ID for the first test dummy voting 23 // agenda. 24 testDummy1ID = "testdummy1" 25 26 // testDummy1YesIndex is the offset in the choices slice of the first 27 // test dummy agenda for the yes choice. 28 testDummy1YesIndex = 2 29 30 // testDummy2NoIndex is the offset in the choices slice of the second 31 // test dummy agenda for the no choice. 32 testDummy2NoIndex = 1 33 34 // vbTestDummy1No defines the vote bits necessary to vote no on the first 35 // test dummy agenda as well as yes to the previous block being valid. 36 vbTestDummy1No = 0x02 37 38 // vbTestDummy1Yes defines the vote bits necessary to vote yes on the 39 // first test dummy agenda as well as yes to the previous block being 40 // valid. 41 vbTestDummy1Yes = 0x04 42 43 // testDummy2ID is the human-readable ID for the second test dummy 44 // voting agenda. 45 testDummy2ID = "testdummy2" 46 47 // vbTestDummy2No defines the vote bits necessary to vote no on the 48 // second test dummy agenda as well as yes to the previous block being 49 // valid. 50 vbTestDummy2No = 0x08 51 52 // vbTestDummy2Yes defines the vote bits necessary to vote yes on the 53 // second test dummy agenda as well as yes to the previous block being 54 // valid. 55 vbTestDummy2Yes = 0x10 56 ) 57 58 var ( 59 // testDummy1 is a voting agenda used throughout these tests. 60 testDummy1 = chaincfg.Vote{ 61 Id: testDummy1ID, 62 Description: "", 63 Mask: 0x6, // 0b0110 64 Choices: []chaincfg.Choice{{ 65 Id: "abstain", 66 Description: "abstain voting for change", 67 Bits: 0x0000, 68 IsAbstain: true, 69 IsNo: false, 70 }, { 71 Id: "no", 72 Description: "vote no", 73 Bits: 0x0002, // Bit 1 74 IsAbstain: false, 75 IsNo: true, 76 }, { 77 Id: "yes", 78 Description: "vote yes", 79 Bits: 0x0004, // Bit 2 80 IsAbstain: false, 81 IsNo: false, 82 }}, 83 } 84 85 // testDummy2 is a voting agenda used throughout these tests. 86 testDummy2 = chaincfg.Vote{ 87 Id: testDummy2ID, 88 Description: "", 89 Mask: 0x18, // 0b11000 90 Choices: []chaincfg.Choice{{ 91 Id: "abstain", 92 Description: "abstain voting for change", 93 Bits: 0x0000, 94 IsAbstain: true, 95 IsNo: false, 96 }, { 97 Id: "no", 98 Description: "vote no", 99 Bits: 0x0008, // Bit 3 100 IsAbstain: false, 101 IsNo: true, 102 }, { 103 Id: "yes", 104 Description: "vote yes", 105 Bits: 0x0010, // Bit 4 106 IsAbstain: false, 107 IsNo: false, 108 }}, 109 } 110 ) 111 112 // TestThresholdState ensures that the threshold state function progresses 113 // through the states correctly. 114 func TestThresholdState(t *testing.T) { 115 // Create chain params based on regnet params, but add a specific test 116 // dummy deployment and set the proof-of-work difficulty readjustment 117 // size to a really large number so that the test chain can be generated 118 // more quickly. 119 posVersion := uint32(4) 120 params := cloneParams(&chaincfg.RegNetParams) 121 params.WorkDiffWindowSize = 200000 122 params.WorkDiffWindows = 1 123 params.TargetTimespan = params.TargetTimePerBlock * 124 time.Duration(params.WorkDiffWindowSize) 125 if params.Deployments == nil { 126 params.Deployments = make(map[uint32][]chaincfg.ConsensusDeployment) 127 } 128 params.Deployments[posVersion] = append(params.Deployments[posVersion], 129 chaincfg.ConsensusDeployment{ 130 Vote: testDummy1, 131 StartTime: 0, 132 ExpireTime: math.MaxUint64, 133 }) 134 params.Deployments[posVersion] = append(params.Deployments[posVersion], 135 chaincfg.ConsensusDeployment{ 136 Vote: testDummy2, 137 StartTime: 0, 138 ExpireTime: math.MaxUint64, 139 }) 140 141 // Create a test harness initialized with the genesis block as the tip. 142 g, teardownFunc := newChaingenHarness(t, params, "thresholdstatetest") 143 defer teardownFunc() 144 145 // Shorter versions of useful params for convenience. 146 ticketsPerBlock := int64(params.TicketsPerBlock) 147 coinbaseMaturity := params.CoinbaseMaturity 148 stakeEnabledHeight := params.StakeEnabledHeight 149 stakeValidationHeight := params.StakeValidationHeight 150 stakeVerInterval := params.StakeVersionInterval 151 ruleChangeInterval := int64(params.RuleChangeActivationInterval) 152 powNumToCheck := int64(params.BlockUpgradeNumToCheck) 153 ruleChangeQuorum := int64(params.RuleChangeActivationQuorum) 154 ruleChangeMult := int64(params.RuleChangeActivationMultiplier) 155 ruleChangeDiv := int64(params.RuleChangeActivationDivisor) 156 157 // --------------------------------------------------------------------- 158 // Block One. 159 // 160 // NOTE: The advance funcs on the harness are intentionally not used in 161 // these tests since they need to manually test the threshold state at 162 // all key heights. 163 // --------------------------------------------------------------------- 164 165 // Add the required initial block. 166 // 167 // genesis -> bfb 168 g.CreatePremineBlock("bfb", 0) 169 g.AssertTipHeight(1) 170 g.AcceptTipBlock() 171 g.TestThresholdStateChoice(testDummy1ID, ThresholdDefined, invalidChoice) 172 g.TestThresholdStateChoice(testDummy2ID, ThresholdDefined, invalidChoice) 173 174 // --------------------------------------------------------------------- 175 // Generate enough blocks to have mature coinbase outputs to work with. 176 // 177 // genesis -> bfb -> bm0 -> bm1 -> ... -> bm# 178 // --------------------------------------------------------------------- 179 180 for i := uint16(0); i < coinbaseMaturity; i++ { 181 blockName := fmt.Sprintf("bm%d", i) 182 g.NextBlock(blockName, nil, nil) 183 g.SaveTipCoinbaseOuts() 184 g.AcceptTipBlock() 185 } 186 g.AssertTipHeight(uint32(coinbaseMaturity) + 1) 187 g.TestThresholdStateChoice(testDummy1ID, ThresholdDefined, invalidChoice) 188 g.TestThresholdStateChoice(testDummy2ID, ThresholdDefined, invalidChoice) 189 190 // --------------------------------------------------------------------- 191 // Generate enough blocks to reach the stake enabled height while 192 // creating ticket purchases that spend from the coinbases matured 193 // above. This will also populate the pool of immature tickets. 194 // 195 // ... -> bm# ... -> bse0 -> bse1 -> ... -> bse# 196 // --------------------------------------------------------------------- 197 198 var ticketsPurchased int 199 for i := int64(0); int64(g.Tip().Header.Height) < stakeEnabledHeight; i++ { 200 outs := g.OldestCoinbaseOuts() 201 ticketOuts := outs[1:] 202 ticketsPurchased += len(ticketOuts) 203 blockName := fmt.Sprintf("bse%d", i) 204 g.NextBlock(blockName, nil, ticketOuts) 205 g.SaveTipCoinbaseOuts() 206 g.AcceptTipBlock() 207 } 208 g.AssertTipHeight(uint32(stakeEnabledHeight)) 209 g.TestThresholdStateChoice(testDummy1ID, ThresholdDefined, invalidChoice) 210 g.TestThresholdStateChoice(testDummy2ID, ThresholdDefined, invalidChoice) 211 212 // --------------------------------------------------------------------- 213 // Generate enough blocks to reach the stake validation height while 214 // continuing to purchase tickets using the coinbases matured above and 215 // allowing the immature tickets to mature and thus become live. 216 // 217 // The blocks are also generated with version 3 to ensure stake version 218 // enforcement is reached. 219 // --------------------------------------------------------------------- 220 221 targetPoolSize := int64(g.Params().TicketPoolSize) * ticketsPerBlock 222 for i := int64(0); int64(g.Tip().Header.Height) < stakeValidationHeight; i++ { 223 // Only purchase tickets until the target ticket pool size is 224 // reached. 225 outs := g.OldestCoinbaseOuts() 226 ticketOuts := outs[1:] 227 if ticketsPurchased+len(ticketOuts) > int(targetPoolSize) { 228 ticketsNeeded := int(targetPoolSize) - ticketsPurchased 229 if ticketsNeeded > 0 { 230 ticketOuts = ticketOuts[1 : ticketsNeeded+1] 231 } else { 232 ticketOuts = nil 233 } 234 } 235 ticketsPurchased += len(ticketOuts) 236 237 blockName := fmt.Sprintf("bsv%d", i) 238 g.NextBlock(blockName, nil, ticketOuts, 239 chaingen.ReplaceBlockVersion(3)) 240 g.SaveTipCoinbaseOuts() 241 g.AcceptTipBlock() 242 } 243 g.AssertTipHeight(uint32(stakeValidationHeight)) 244 g.TestThresholdStateChoice(testDummy1ID, ThresholdDefined, invalidChoice) 245 g.TestThresholdStateChoice(testDummy2ID, ThresholdDefined, invalidChoice) 246 247 // --------------------------------------------------------------------- 248 // Generate enough blocks to reach one block before the next stake 249 // version interval with block version 3, stake version 0, and vote 250 // version 3. 251 // 252 // This will result in triggering enforcement of the stake version and 253 // that the stake version is 3. The treshold state for the test dummy 254 // deployments must still be defined since a v4 majority proof-of-work 255 // and proof-of-stake upgrade are required before moving to started. 256 // --------------------------------------------------------------------- 257 258 blocksNeeded := stakeValidationHeight + stakeVerInterval - 1 - 259 int64(g.Tip().Header.Height) 260 for i := int64(0); i < blocksNeeded; i++ { 261 outs := g.OldestCoinbaseOuts() 262 blockName := fmt.Sprintf("bsvtA%d", i) 263 g.NextBlock(blockName, nil, outs[1:], 264 chaingen.ReplaceBlockVersion(3), 265 chaingen.ReplaceStakeVersion(0), 266 chaingen.ReplaceVoteVersions(3)) 267 g.SaveTipCoinbaseOuts() 268 g.AcceptTipBlock() 269 } 270 g.AssertTipHeight(uint32(stakeValidationHeight + stakeVerInterval - 1)) 271 g.AssertBlockVersion(3) 272 g.AssertStakeVersion(0) 273 g.TestThresholdStateChoice(testDummy1ID, ThresholdDefined, invalidChoice) 274 g.TestThresholdStateChoice(testDummy2ID, ThresholdDefined, invalidChoice) 275 276 // --------------------------------------------------------------------- 277 // Generate enough blocks to reach one block before the next rule change 278 // interval with block version 3, stake version 3, and vote version 3. 279 // 280 // The threshold state for the dummy deployments must still be defined 281 // since it can only change on a rule change boundary and it requires a 282 // v4 majority proof-of-work and proof-of-stake upgrade before moving to 283 // started. 284 // --------------------------------------------------------------------- 285 286 blocksNeeded = stakeValidationHeight + ruleChangeInterval - 2 - 287 int64(g.Tip().Header.Height) 288 for i := int64(0); i < blocksNeeded; i++ { 289 outs := g.OldestCoinbaseOuts() 290 blockName := fmt.Sprintf("bsvtB%d", i) 291 g.NextBlock(blockName, nil, outs[1:], 292 chaingen.ReplaceBlockVersion(3), 293 chaingen.ReplaceStakeVersion(3), 294 chaingen.ReplaceVoteVersions(3)) 295 g.SaveTipCoinbaseOuts() 296 g.AcceptTipBlock() 297 } 298 g.AssertTipHeight(uint32(stakeValidationHeight + ruleChangeInterval - 2)) 299 g.AssertBlockVersion(3) 300 g.AssertStakeVersion(3) 301 g.TestThresholdStateChoice(testDummy1ID, ThresholdDefined, invalidChoice) 302 g.TestThresholdStateChoice(testDummy2ID, ThresholdDefined, invalidChoice) 303 304 // --------------------------------------------------------------------- 305 // Generate enough blocks to reach one block before the next stake 306 // version interval with block version 3, stake version 3, and vote 307 // version 4. 308 // 309 // This will result in achieving stake version 4 enforcement. 310 // 311 // The treshold state for the dummy deployments must still be defined 312 // since it can only change on a rule change boundary and it still 313 // requires a v4 majority proof-of-work upgrade before moving to 314 // started. 315 // --------------------------------------------------------------------- 316 317 blocksNeeded = stakeValidationHeight + stakeVerInterval*4 - 1 - 318 int64(g.Tip().Header.Height) 319 for i := int64(0); i < blocksNeeded; i++ { 320 outs := g.OldestCoinbaseOuts() 321 blockName := fmt.Sprintf("bsvtC%d", i) 322 g.NextBlock(blockName, nil, outs[1:], 323 chaingen.ReplaceBlockVersion(3), 324 chaingen.ReplaceStakeVersion(3), 325 chaingen.ReplaceVoteVersions(4)) 326 g.SaveTipCoinbaseOuts() 327 g.AcceptTipBlock() 328 } 329 g.AssertTipHeight(uint32(stakeValidationHeight + stakeVerInterval*4 - 1)) 330 g.AssertBlockVersion(3) 331 g.AssertStakeVersion(3) 332 g.TestThresholdStateChoice(testDummy1ID, ThresholdDefined, invalidChoice) 333 g.TestThresholdStateChoice(testDummy2ID, ThresholdDefined, invalidChoice) 334 335 // --------------------------------------------------------------------- 336 // Generate enough blocks to reach the next rule change interval with 337 // block version 3 majority, stake version 4, and vote version 4. Set 338 // the final two blocks to block version 4 so that majority version 4 339 // is not achieved, but the final block in the interval is version 4. 340 // 341 // The treshold state for the dummy deployments must still be defined 342 // since it still requires a v4 majority proof-of-work upgrade before 343 // moving to started. 344 // --------------------------------------------------------------------- 345 346 blocksNeeded = stakeValidationHeight + ruleChangeInterval*2 - 1 - 347 int64(g.Tip().Header.Height) 348 for i := int64(0); i < blocksNeeded; i++ { 349 outs := g.OldestCoinbaseOuts() 350 blockName := fmt.Sprintf("bsvtD%d", i) 351 blockVersion := int32(3) 352 if i >= blocksNeeded-2 { 353 blockVersion = 4 354 } 355 g.NextBlock(blockName, nil, outs[1:], 356 chaingen.ReplaceBlockVersion(blockVersion), 357 chaingen.ReplaceStakeVersion(4), 358 chaingen.ReplaceVoteVersions(4)) 359 g.SaveTipCoinbaseOuts() 360 g.AcceptTipBlock() 361 } 362 g.AssertTipHeight(uint32(stakeValidationHeight + ruleChangeInterval*2 - 1)) 363 g.AssertBlockVersion(4) 364 g.AssertStakeVersion(4) 365 g.TestThresholdStateChoice(testDummy1ID, ThresholdDefined, invalidChoice) 366 g.TestThresholdStateChoice(testDummy2ID, ThresholdDefined, invalidChoice) 367 368 // --------------------------------------------------------------------- 369 // Generate enough blocks to achieve proof-of-work block version lockin 370 // with block version 4, stake version 4, and vote version 4. Also, set 371 // the vote bits to include yes votes for the first test dummy agenda 372 // and no for the second test dummy agenda for an upcoming test. 373 // 374 // Since v4 majority proof-of-stake upgrade has been already been 375 // achieved and this will achieve v4 majority proof-of-work upgrade, 376 // voting can begin at the next rule change interval. 377 // 378 // The treshold state for the dummy deployments must still be defined 379 // since even though all required upgrade conditions are met, the state 380 // change must not happen until the start of the next rule change 381 // interval. 382 // --------------------------------------------------------------------- 383 384 for i := int64(0); i < powNumToCheck; i++ { 385 outs := g.OldestCoinbaseOuts() 386 blockName := fmt.Sprintf("bsvtE%d", i) 387 g.NextBlock(blockName, nil, outs[1:], 388 chaingen.ReplaceBlockVersion(4), 389 chaingen.ReplaceStakeVersion(4), 390 chaingen.ReplaceVotes(vbPrevBlockValid|vbTestDummy1Yes| 391 vbTestDummy2No, 4)) 392 g.SaveTipCoinbaseOuts() 393 g.AcceptTipBlock() 394 } 395 g.AssertTipHeight(uint32(stakeValidationHeight + ruleChangeInterval*2 - 396 1 + powNumToCheck)) 397 g.AssertBlockVersion(4) 398 g.AssertStakeVersion(4) 399 g.TestThresholdStateChoice(testDummy1ID, ThresholdDefined, invalidChoice) 400 g.TestThresholdStateChoice(testDummy2ID, ThresholdDefined, invalidChoice) 401 402 // --------------------------------------------------------------------- 403 // Generate enough blocks to reach the next rule change interval with 404 // block version 4, stake version 4, and vote version 4. Also, set the 405 // vote bits to include yes votes for the first test dummy agenda and 406 // no for the second test dummy agenda to ensure they aren't counted. 407 // 408 // The treshold state for the dummy deployments must move to started. 409 // Even though the majority of the votes have already been voting yes 410 // for the first test dummy agenda, and no for the second one, they must 411 // not count, otherwise it would move straight to lockedin or failed, 412 // respectively. 413 // --------------------------------------------------------------------- 414 415 blocksNeeded = stakeValidationHeight + ruleChangeInterval*3 - 1 - 416 int64(g.Tip().Header.Height) 417 for i := int64(0); i < blocksNeeded; i++ { 418 outs := g.OldestCoinbaseOuts() 419 blockName := fmt.Sprintf("bsvtF%d", i) 420 g.NextBlock(blockName, nil, outs[1:], 421 chaingen.ReplaceBlockVersion(4), 422 chaingen.ReplaceStakeVersion(4), 423 chaingen.ReplaceVotes(vbPrevBlockValid|vbTestDummy1Yes| 424 vbTestDummy2No, 4)) 425 g.SaveTipCoinbaseOuts() 426 g.AcceptTipBlock() 427 } 428 g.AssertTipHeight(uint32(stakeValidationHeight + ruleChangeInterval*3 - 1)) 429 g.AssertBlockVersion(4) 430 g.AssertStakeVersion(4) 431 g.TestThresholdStateChoice(testDummy1ID, ThresholdStarted, invalidChoice) 432 g.TestThresholdStateChoice(testDummy2ID, ThresholdStarted, invalidChoice) 433 434 // --------------------------------------------------------------------- 435 // Generate enough blocks to reach the next rule change interval with 436 // block version 4, stake version 4, and vote version 3. Also, set the 437 // vote bits to include yes votes for the first test dummy agenda and 438 // no for the second test dummy agenda to ensure they aren't counted. 439 // 440 // The treshold state for the dummy deployments must remain in started 441 // because the votes are an old version and thus have a different 442 // definition and don't apply to version 4. 443 // --------------------------------------------------------------------- 444 445 blocksNeeded = stakeValidationHeight + ruleChangeInterval*4 - 1 - 446 int64(g.Tip().Header.Height) 447 for i := int64(0); i < blocksNeeded; i++ { 448 outs := g.OldestCoinbaseOuts() 449 blockName := fmt.Sprintf("bsvtG%d", i) 450 g.NextBlock(blockName, nil, outs[1:], 451 chaingen.ReplaceBlockVersion(4), 452 chaingen.ReplaceStakeVersion(4), 453 chaingen.ReplaceVotes(vbPrevBlockValid|vbTestDummy1Yes| 454 vbTestDummy2No, 3)) 455 g.SaveTipCoinbaseOuts() 456 g.AcceptTipBlock() 457 } 458 g.AssertTipHeight(uint32(stakeValidationHeight + ruleChangeInterval*4 - 1)) 459 g.AssertBlockVersion(4) 460 g.AssertStakeVersion(4) 461 g.TestThresholdStateChoice(testDummy1ID, ThresholdStarted, invalidChoice) 462 g.TestThresholdStateChoice(testDummy2ID, ThresholdStarted, invalidChoice) 463 464 // --------------------------------------------------------------------- 465 // Generate enough blocks to reach the next rule change interval with 466 // block version 4, stake version 4, and vote version 4. Set the vote 467 // bits such that quorum is not reached, but there is a majority yes 468 // votes for the first test dummy agenda and a majority no for the 469 // second test dummy agenda. 470 // 471 // The treshold state for the dummy deployments must remain in started 472 // because quorum was not reached. 473 // --------------------------------------------------------------------- 474 475 var totalVotes int64 476 blocksNeeded = stakeValidationHeight + ruleChangeInterval*5 - 1 - 477 int64(g.Tip().Header.Height) 478 for i := int64(0); i < blocksNeeded; i++ { 479 outs := g.OldestCoinbaseOuts() 480 blockName := fmt.Sprintf("bsvtH%d", i) 481 voteBits := uint16(vbPrevBlockValid) // Abstain both test dummy 482 if totalVotes+ticketsPerBlock < ruleChangeQuorum { 483 voteBits = vbPrevBlockValid | vbTestDummy1Yes | 484 vbTestDummy2No 485 } 486 g.NextBlock(blockName, nil, outs[1:], 487 chaingen.ReplaceBlockVersion(4), 488 chaingen.ReplaceStakeVersion(4), 489 chaingen.ReplaceVotes(voteBits, 4)) 490 totalVotes += ticketsPerBlock 491 g.SaveTipCoinbaseOuts() 492 g.AcceptTipBlock() 493 } 494 g.AssertTipHeight(uint32(stakeValidationHeight + ruleChangeInterval*5 - 1)) 495 g.AssertBlockVersion(4) 496 g.AssertStakeVersion(4) 497 g.TestThresholdStateChoice(testDummy1ID, ThresholdStarted, invalidChoice) 498 g.TestThresholdStateChoice(testDummy2ID, ThresholdStarted, invalidChoice) 499 500 // --------------------------------------------------------------------- 501 // Generate enough blocks to reach the next rule change interval with 502 // block version 4, stake version 4, and vote version 4. Set the vote 503 // bits such that quorum is reached, but there are a few votes shy of a 504 // majority yes for the first test dummy agenda and a few votes shy of a 505 // majority no for the second test dummy agenda. 506 // 507 // The treshold state for the dummy deployments must remain in started 508 // because even though quorum was reached, a required majority was not. 509 // --------------------------------------------------------------------- 510 511 blocksNeeded = stakeValidationHeight + ruleChangeInterval*6 - 1 - 512 int64(g.Tip().Header.Height) 513 totalVotes = 0 514 numActiveNeeded := ruleChangeQuorum * 2 515 numMinorityNeeded := numActiveNeeded*ruleChangeMult/ruleChangeDiv - 1 516 if numActiveNeeded > ticketsPerBlock*blocksNeeded { 517 numActiveNeeded = ticketsPerBlock * blocksNeeded 518 } 519 for i := int64(0); i < blocksNeeded; i++ { 520 outs := g.OldestCoinbaseOuts() 521 blockName := fmt.Sprintf("bsvtI%d", i) 522 voteBits := uint16(vbPrevBlockValid) // Abstain both test dummy 523 if totalVotes+ticketsPerBlock < numMinorityNeeded { 524 voteBits = vbPrevBlockValid | vbTestDummy1Yes | 525 vbTestDummy2No 526 } else if totalVotes+ticketsPerBlock <= numActiveNeeded { 527 voteBits = vbPrevBlockValid | vbTestDummy1No | 528 vbTestDummy2Yes 529 } 530 g.NextBlock(blockName, nil, outs[1:], 531 chaingen.ReplaceBlockVersion(4), 532 chaingen.ReplaceStakeVersion(4), 533 chaingen.ReplaceVotes(voteBits, 4)) 534 totalVotes += ticketsPerBlock 535 g.SaveTipCoinbaseOuts() 536 g.AcceptTipBlock() 537 } 538 g.AssertTipHeight(uint32(stakeValidationHeight + ruleChangeInterval*6 - 1)) 539 g.AssertBlockVersion(4) 540 g.AssertStakeVersion(4) 541 g.TestThresholdStateChoice(testDummy1ID, ThresholdStarted, invalidChoice) 542 g.TestThresholdStateChoice(testDummy2ID, ThresholdStarted, invalidChoice) 543 544 // --------------------------------------------------------------------- 545 // Generate enough blocks to reach the next rule change interval with 546 // block version 4, stake version 4, and vote version 4. Also, set the 547 // vote bits to yes for the first test dummy agenda and no to the second 548 // one. 549 // 550 // The treshold state for the first dummy deployment must move to 551 // lockedin since a majority yes vote was achieved while the second 552 // dummy deployment must move to failed since a majority no vote was 553 // achieved. 554 // --------------------------------------------------------------------- 555 556 blocksNeeded = stakeValidationHeight + ruleChangeInterval*7 - 1 - 557 int64(g.Tip().Header.Height) 558 for i := int64(0); i < blocksNeeded; i++ { 559 outs := g.OldestCoinbaseOuts() 560 blockName := fmt.Sprintf("bsvtJ%d", i) 561 g.NextBlock(blockName, nil, outs[1:], 562 chaingen.ReplaceBlockVersion(4), 563 chaingen.ReplaceStakeVersion(4), 564 chaingen.ReplaceVotes(vbPrevBlockValid|vbTestDummy1Yes| 565 vbTestDummy2No, 4)) 566 g.SaveTipCoinbaseOuts() 567 g.AcceptTipBlock() 568 } 569 g.AssertTipHeight(uint32(stakeValidationHeight + ruleChangeInterval*7 - 1)) 570 g.AssertBlockVersion(4) 571 g.AssertStakeVersion(4) 572 g.TestThresholdStateChoice(testDummy1ID, ThresholdLockedIn, testDummy1YesIndex) 573 g.TestThresholdStateChoice(testDummy2ID, ThresholdFailed, testDummy2NoIndex) 574 575 // --------------------------------------------------------------------- 576 // Generate enough blocks to reach the next rule change interval with 577 // block version 4, stake version 4, and vote version 4. Also, set the 578 // vote bits to include no votes for the first test dummy agenda and 579 // yes votes for the second one. 580 // 581 // The treshold state for the first dummy deployment must move to active 582 // since even though the interval had a majority no votes, lockedin 583 // status has already been achieved and can't be undone without a new 584 // agenda. Similarly, the second one must remain in failed even though 585 // the interval had a majority yes votes since a failed state can't be 586 // undone. 587 // --------------------------------------------------------------------- 588 589 blocksNeeded = stakeValidationHeight + ruleChangeInterval*8 - 1 - 590 int64(g.Tip().Header.Height) 591 for i := int64(0); i < blocksNeeded; i++ { 592 outs := g.OldestCoinbaseOuts() 593 blockName := fmt.Sprintf("bsvtK%d", i) 594 g.NextBlock(blockName, nil, outs[1:], 595 chaingen.ReplaceBlockVersion(4), 596 chaingen.ReplaceStakeVersion(4), 597 chaingen.ReplaceVotes(vbPrevBlockValid|vbTestDummy1No| 598 vbTestDummy2Yes, 4)) 599 g.SaveTipCoinbaseOuts() 600 g.AcceptTipBlock() 601 } 602 g.AssertTipHeight(uint32(stakeValidationHeight + ruleChangeInterval*8 - 1)) 603 g.AssertBlockVersion(4) 604 g.AssertStakeVersion(4) 605 g.TestThresholdStateChoice(testDummy1ID, ThresholdActive, testDummy1YesIndex) 606 g.TestThresholdStateChoice(testDummy2ID, ThresholdFailed, testDummy2NoIndex) 607 }