github.com/decred/dcrd/blockchain@v1.2.1/stakeversion_test.go (about) 1 // Copyright (c) 2016-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 "testing" 10 "time" 11 12 "github.com/decred/dcrd/chaincfg" 13 "github.com/decred/dcrd/chaincfg/chainhash" 14 ) 15 16 // isVoterMajorityVersion determines if minVer requirement is met based on 17 // prevNode. The function always uses the voter versions of the prior window. 18 // For example, if StakeVersionInterval = 11 and StakeValidationHeight = 13 the 19 // windows start at 13 + 11 -1 = 24 and are as follows: 24-34, 35-45, 46-56 ... 20 // If height comes in at 35 we use the 24-34 window, up to height 45. 21 // If height comes in at 46 we use the 35-45 window, up to height 56 etc. 22 // 23 // This function MUST be called with the chain state lock held (for writes). 24 func (b *BlockChain) isVoterMajorityVersion(minVer uint32, prevNode *blockNode) bool { 25 // Walk blockchain backwards to calculate version. 26 node := b.findStakeVersionPriorNode(prevNode) 27 if node == nil { 28 return 0 >= minVer 29 } 30 31 // Generate map key and look up cached result. 32 key := stakeMajorityCacheVersionKey(minVer, &node.hash) 33 if result, ok := b.isVoterMajorityVersionCache[key]; ok { 34 return result 35 } 36 37 // Tally both the total number of votes in the previous stake version validation 38 // interval and how many of those votes are at least the requested minimum 39 // version. 40 totalVotesFound := int32(0) 41 versionCount := int32(0) 42 iterNode := node 43 for i := int64(0); i < b.chainParams.StakeVersionInterval && iterNode != nil; i++ { 44 totalVotesFound += int32(len(iterNode.votes)) 45 for _, v := range iterNode.votes { 46 if v.Version >= minVer { 47 versionCount++ 48 } 49 } 50 51 iterNode = iterNode.parent 52 } 53 54 // Determine the required amount of votes to reach supermajority. 55 numRequired := totalVotesFound * b.chainParams.StakeMajorityMultiplier / 56 b.chainParams.StakeMajorityDivisor 57 58 // Cache value. 59 result := versionCount >= numRequired 60 b.isVoterMajorityVersionCache[key] = result 61 62 return result 63 } 64 65 func TestCalcWantHeight(t *testing.T) { 66 // For example, if StakeVersionInterval = 11 and StakeValidationHeight = 13 the 67 // windows start at 13 + (11 * 2) 25 and are as follows: 24-34, 35-45, 46-56 ... 68 // If height comes in at 35 we use the 24-34 window, up to height 45. 69 // If height comes in at 46 we use the 35-45 window, up to height 56 etc. 70 tests := []struct { 71 name string 72 skip int64 73 interval int64 74 multiplier int64 75 negative int64 76 }{ 77 { 78 name: "13 11 10000", 79 skip: 13, 80 interval: 11, 81 multiplier: 10000, 82 }, 83 { 84 name: "27 33 10000", 85 skip: 27, 86 interval: 33, 87 multiplier: 10000, 88 }, 89 { 90 name: "mainnet params", 91 skip: chaincfg.MainNetParams.StakeValidationHeight, 92 interval: chaincfg.MainNetParams.StakeVersionInterval, 93 multiplier: 5000, 94 }, 95 { 96 name: "testnet3 params", 97 skip: chaincfg.TestNet3Params.StakeValidationHeight, 98 interval: chaincfg.TestNet3Params.StakeVersionInterval, 99 multiplier: 1000, 100 }, 101 { 102 name: "simnet params", 103 skip: chaincfg.SimNetParams.StakeValidationHeight, 104 interval: chaincfg.SimNetParams.StakeVersionInterval, 105 multiplier: 10000, 106 }, 107 { 108 name: "regnet params", 109 skip: chaincfg.RegNetParams.StakeValidationHeight, 110 interval: chaincfg.RegNetParams.StakeVersionInterval, 111 multiplier: 10000, 112 }, 113 { 114 name: "negative mainnet params", 115 skip: chaincfg.MainNetParams.StakeValidationHeight, 116 interval: chaincfg.MainNetParams.StakeVersionInterval, 117 multiplier: 1000, 118 negative: 1, 119 }, 120 } 121 122 for _, test := range tests { 123 t.Logf("running: %v skip: %v interval: %v", 124 test.name, test.skip, test.interval) 125 126 start := test.skip + test.interval*2 127 expectedHeight := start - 1 // zero based 128 x := int64(0) + test.negative 129 for i := start; i < test.multiplier*test.interval; i++ { 130 if x%test.interval == 0 && i != start { 131 expectedHeight += test.interval 132 } 133 wantHeight := calcWantHeight(test.skip, test.interval, i) 134 135 if wantHeight != expectedHeight { 136 if test.negative == 0 { 137 t.Fatalf("%v: i %v x %v -> wantHeight %v expectedHeight %v\n", 138 test.name, i, x, wantHeight, expectedHeight) 139 } 140 } 141 142 x++ 143 } 144 } 145 } 146 147 // TestCalcStakeVersionCorners ensures that stake version calculation works as 148 // intended under various corner cases such as attempting to go back backwards. 149 func TestCalcStakeVersionCorners(t *testing.T) { 150 params := &chaincfg.SimNetParams 151 svh := params.StakeValidationHeight 152 svi := params.StakeVersionInterval 153 154 // Generate enough nodes to reach stake validation height with stake 155 // versions set to 0. 156 bc := newFakeChain(params) 157 node := bc.bestChain.Tip() 158 for i := int64(1); i <= svh; i++ { 159 node = newFakeNode(node, 0, 0, 0, time.Now()) 160 bc.bestChain.SetTip(node) 161 } 162 if node.height != svh { 163 t.Fatalf("invalid height got %v expected %v", node.height, svh) 164 } 165 166 // Generate 3 intervals with v2 votes and calculated stake version. 167 for i := int64(0); i < svi*3; i++ { 168 sv := bc.calcStakeVersion(node) 169 170 // Set vote and stake versions. 171 node = newFakeNode(node, 3, sv, 0, time.Now()) 172 appendFakeVotes(node, params.TicketsPerBlock, 2, 0) 173 bc.bestChain.SetTip(node) 174 } 175 176 // Versions 0 and 2 should now be considered the majority version, but 177 // v4 should not yet be considered majority. 178 if !bc.isStakeMajorityVersion(0, node) { 179 t.Fatalf("invalid StakeVersion expected 0 -> true") 180 } 181 if !bc.isStakeMajorityVersion(2, node) { 182 t.Fatalf("invalid StakeVersion expected 2 -> true") 183 } 184 if bc.isStakeMajorityVersion(4, node) { 185 t.Fatalf("invalid StakeVersion expected 4 -> false") 186 } 187 188 // Generate 3 intervals with v4 votes and calculated stake version. 189 for i := int64(0); i < svi*3; i++ { 190 sv := bc.calcStakeVersion(node) 191 192 // Set vote and stake versions. 193 node = newFakeNode(node, 3, sv, 0, time.Now()) 194 appendFakeVotes(node, params.TicketsPerBlock, 4, 0) 195 bc.bestChain.SetTip(node) 196 } 197 198 // Versions up to and including v4 should now be considered the majority 199 // version, but v5 should not yet be considered majority. 200 for _, version := range []uint32{0, 2, 4} { 201 if !bc.isStakeMajorityVersion(version, node) { 202 t.Fatalf("invalid StakeVersion expected %d -> true", 203 version) 204 } 205 206 } 207 if bc.isStakeMajorityVersion(5, node) { 208 t.Fatalf("invalid StakeVersion expected 5 -> false") 209 } 210 211 // Generate 3 intervals with v2 votes and calculated stake version. 212 for i := int64(0); i < svi*3; i++ { 213 sv := bc.calcStakeVersion(node) 214 215 // Set vote and stake versions. 216 node = newFakeNode(node, 3, sv, 0, time.Now()) 217 appendFakeVotes(node, params.TicketsPerBlock, 2, 0) 218 bc.bestChain.SetTip(node) 219 } 220 221 // Versions up to and including v4 should still be considered the 222 // majority version since even though there were multiple intervals with 223 // a majority v2 votes, the stake version is not allowed to go 224 // backwards. Version 5 should still not be consider majority. 225 for _, version := range []uint32{0, 2, 4} { 226 if !bc.isStakeMajorityVersion(version, node) { 227 t.Fatalf("invalid StakeVersion expected %d -> true", 228 version) 229 } 230 231 } 232 if bc.isStakeMajorityVersion(5, node) { 233 t.Fatalf("invalid StakeVersion expected 5 -> false") 234 } 235 236 // Generate 2 intervals with v5 votes and calculated stake version. 237 for i := int64(0); i < svi*2; i++ { 238 sv := bc.calcStakeVersion(node) 239 240 // Set vote and stake versions. 241 node = newFakeNode(node, 3, sv, 0, time.Now()) 242 appendFakeVotes(node, params.TicketsPerBlock, 5, 0) 243 bc.bestChain.SetTip(node) 244 } 245 246 // Versions up to and including v5 should now be considered the majority 247 // version, but v6 should not yet be. 248 for _, version := range []uint32{0, 2, 4, 5} { 249 if !bc.isStakeMajorityVersion(version, node) { 250 t.Fatalf("invalid StakeVersion expected %d -> true", 251 version) 252 } 253 254 } 255 if bc.isStakeMajorityVersion(6, node) { 256 t.Fatalf("invalid StakeVersion expected 6 -> false") 257 } 258 259 // Generate 1 interval with v4 votes to test the edge condition. 260 for i := int64(0); i < svi; i++ { 261 sv := bc.calcStakeVersion(node) 262 263 // Set vote and stake versions. 264 node = newFakeNode(node, 3, sv, 0, time.Now()) 265 appendFakeVotes(node, params.TicketsPerBlock, 4, 0) 266 bc.bestChain.SetTip(node) 267 268 } 269 270 // Versions up to and including v5 should still be considered the 271 // majority version since even though there was an interval with a 272 // majority v4 votes, the stake version is not allowed to go backwards. 273 // Version 6 should still not be consider majority. 274 for _, version := range []uint32{0, 2, 4, 5} { 275 if !bc.isStakeMajorityVersion(version, node) { 276 t.Fatalf("invalid StakeVersion expected %d -> true", 277 version) 278 } 279 280 } 281 if bc.isStakeMajorityVersion(6, node) { 282 t.Fatalf("invalid StakeVersion expected 6 -> false") 283 } 284 285 // Generate another interval with v4 votes. 286 for i := int64(0); i < svi; i++ { 287 sv := bc.calcStakeVersion(node) 288 289 // Set stake versions. 290 node = newFakeNode(node, 3, sv, 0, time.Now()) 291 appendFakeVotes(node, params.TicketsPerBlock, 4, 0) 292 bc.bestChain.SetTip(node) 293 294 } 295 296 // Versions up to and including v5 should still be considered the 297 // majority version since even though there was another interval with a 298 // majority v4 votes, the stake version is not allowed to go backwards. 299 // Version 6 should still not be consider majority. 300 for _, version := range []uint32{0, 2, 4, 5} { 301 if !bc.isStakeMajorityVersion(version, node) { 302 t.Fatalf("invalid StakeVersion expected %d -> true", 303 version) 304 } 305 306 } 307 if bc.isStakeMajorityVersion(6, node) { 308 t.Fatalf("invalid StakeVersion expected 6 -> false") 309 } 310 } 311 312 // TestCalcStakeVersion ensures that stake version calculation works as 313 // intended when 314 func TestCalcStakeVersion(t *testing.T) { 315 params := &chaincfg.SimNetParams 316 svh := params.StakeValidationHeight 317 svi := params.StakeVersionInterval 318 tpb := params.TicketsPerBlock 319 320 tests := []struct { 321 name string 322 numNodes int64 323 expectVersion uint32 324 set func(*blockNode) 325 }{ 326 { 327 name: "headerStake 2 votes 3", 328 numNodes: svh + svi*3, 329 expectVersion: 3, 330 set: func(node *blockNode) { 331 if node.height > svh { 332 appendFakeVotes(node, tpb, 3, 0) 333 node.stakeVersion = 2 334 node.blockVersion = 3 335 } 336 }, 337 }, 338 { 339 name: "headerStake 3 votes 2", 340 numNodes: svh + svi*3, 341 expectVersion: 3, 342 set: func(node *blockNode) { 343 if node.height > svh { 344 appendFakeVotes(node, tpb, 2, 0) 345 node.stakeVersion = 3 346 node.blockVersion = 3 347 } 348 }, 349 }, 350 } 351 352 for _, test := range tests { 353 bc := newFakeChain(params) 354 node := bc.bestChain.Tip() 355 356 for i := int64(1); i <= test.numNodes; i++ { 357 node = newFakeNode(node, 1, 0, 0, time.Now()) 358 test.set(node) 359 bc.bestChain.SetTip(node) 360 } 361 362 version := bc.calcStakeVersion(bc.bestChain.Tip()) 363 if version != test.expectVersion { 364 t.Fatalf("version mismatch: got %v expected %v", 365 version, test.expectVersion) 366 } 367 } 368 } 369 370 // TestIsStakeMajorityVersion ensures that determining the current majority 371 // stake version works as intended under a wide variety of scenarios. 372 func TestIsStakeMajorityVersion(t *testing.T) { 373 params := &chaincfg.RegNetParams 374 svh := params.StakeValidationHeight 375 svi := params.StakeVersionInterval 376 tpb := params.TicketsPerBlock 377 378 // Calculate super majority for 5 and 3 ticket maxes. 379 maxTickets5 := int32(svi) * int32(tpb) 380 sm5 := maxTickets5 * params.StakeMajorityMultiplier / params.StakeMajorityDivisor 381 maxTickets3 := int32(svi) * int32(tpb-2) 382 sm3 := maxTickets3 * params.StakeMajorityMultiplier / params.StakeMajorityDivisor 383 384 // Keep track of ticketcount in set. Must be reset every test. 385 ticketCount := int32(0) 386 387 tests := []struct { 388 name string 389 numNodes int64 390 set func(*blockNode) 391 blockVersion int32 392 startStakeVersion uint32 393 expectedStakeVersion uint32 394 expectedCalcVersion uint32 395 result bool 396 }{ 397 { 398 name: "too shallow", 399 numNodes: svh + svi - 1, 400 startStakeVersion: 1, 401 expectedStakeVersion: 1, 402 expectedCalcVersion: 0, 403 result: true, 404 }, 405 { 406 name: "just enough", 407 numNodes: svh + svi, 408 startStakeVersion: 1, 409 expectedStakeVersion: 1, 410 expectedCalcVersion: 0, 411 result: true, 412 }, 413 { 414 name: "odd", 415 numNodes: svh + svi + 1, 416 startStakeVersion: 1, 417 expectedStakeVersion: 1, 418 expectedCalcVersion: 0, 419 result: true, 420 }, 421 { 422 name: "100%", 423 numNodes: svh + svi, 424 set: func(node *blockNode) { 425 if node.height > svh { 426 appendFakeVotes(node, tpb, 2, 0) 427 } 428 }, 429 startStakeVersion: 1, 430 expectedStakeVersion: 2, 431 expectedCalcVersion: 0, 432 result: true, 433 }, 434 { 435 name: "50%", 436 numNodes: svh + (svi * 2), 437 set: func(node *blockNode) { 438 if node.height <= svh { 439 return 440 } 441 442 if node.height < svh+svi { 443 appendFakeVotes(node, tpb, 1, 0) 444 return 445 } 446 447 threshold := maxTickets5 / 2 448 449 v := uint32(1) 450 for i := 0; i < int(tpb); i++ { 451 if ticketCount >= threshold { 452 v = 2 453 } 454 appendFakeVotes(node, 1, v, 0) 455 ticketCount++ 456 } 457 }, 458 startStakeVersion: 1, 459 expectedStakeVersion: 2, 460 expectedCalcVersion: 0, 461 result: false, 462 }, 463 { 464 name: "75%-1", 465 numNodes: svh + (svi * 2), 466 set: func(node *blockNode) { 467 if node.height < svh { 468 return 469 } 470 471 if node.height < svh+svi { 472 appendFakeVotes(node, tpb, 1, 0) 473 return 474 } 475 476 threshold := maxTickets5 - sm5 + 1 477 478 v := uint32(1) 479 for i := 0; i < int(tpb); i++ { 480 if ticketCount >= threshold { 481 v = 2 482 } 483 appendFakeVotes(node, 1, v, 0) 484 ticketCount++ 485 } 486 }, 487 startStakeVersion: 1, 488 expectedStakeVersion: 2, 489 expectedCalcVersion: 0, 490 result: false, 491 }, 492 { 493 name: "75%", 494 numNodes: svh + (svi * 2), 495 set: func(node *blockNode) { 496 if node.height <= svh { 497 return 498 } 499 500 if node.height < svh+svi { 501 appendFakeVotes(node, tpb, 1, 0) 502 return 503 } 504 505 threshold := maxTickets5 - sm5 506 507 v := uint32(1) 508 for i := 0; i < int(tpb); i++ { 509 if ticketCount >= threshold { 510 v = 2 511 } 512 appendFakeVotes(node, 1, v, 0) 513 ticketCount++ 514 } 515 }, 516 startStakeVersion: 1, 517 expectedStakeVersion: 2, 518 expectedCalcVersion: 0, 519 result: true, 520 }, 521 { 522 name: "100% after several non majority intervals", 523 numNodes: svh + (params.StakeVersionInterval * 222), 524 set: func(node *blockNode) { 525 if node.height <= svh { 526 return 527 } 528 529 if node.height < svh+svi { 530 appendFakeVotes(node, tpb, 1, 0) 531 return 532 } 533 534 for i := uint32(0); i < uint32(tpb); i++ { 535 appendFakeVotes(node, 1, i%5, 0) 536 } 537 }, 538 startStakeVersion: 1, 539 expectedStakeVersion: 1, 540 expectedCalcVersion: 0, 541 result: true, 542 }, 543 { 544 name: "no majority ever", 545 numNodes: svh + (svi * 8), 546 set: func(node *blockNode) { 547 if node.height <= svh { 548 return 549 } 550 551 for i := uint32(0); i < uint32(tpb); i++ { 552 appendFakeVotes(node, 1, i%5, 0) 553 } 554 }, 555 startStakeVersion: 1, 556 expectedStakeVersion: 1, 557 expectedCalcVersion: 0, 558 result: true, 559 }, 560 { 561 name: "75%-1 with 3 votes", 562 numNodes: svh + (svi * 2), 563 set: func(node *blockNode) { 564 if node.height < svh { 565 return 566 } 567 568 if node.height < svh+svi { 569 appendFakeVotes(node, tpb-2, 1, 0) 570 return 571 } 572 573 threshold := maxTickets3 - sm3 + 1 574 575 v := uint32(1) 576 for i := 0; i < int(tpb-2); i++ { 577 if ticketCount >= threshold { 578 v = 2 579 } 580 appendFakeVotes(node, 1, v, 0) 581 ticketCount++ 582 } 583 }, 584 startStakeVersion: 1, 585 expectedStakeVersion: 2, 586 expectedCalcVersion: 0, 587 result: false, 588 }, 589 { 590 name: "75% with 3 votes", 591 numNodes: svh + (svi * 2), 592 set: func(node *blockNode) { 593 if node.height <= svh { 594 return 595 } 596 597 if node.height < svh+svi { 598 appendFakeVotes(node, tpb-2, 1, 0) 599 return 600 } 601 602 threshold := maxTickets3 - sm3 603 604 v := uint32(1) 605 for i := 0; i < int(tpb-2); i++ { 606 if ticketCount >= threshold { 607 v = 2 608 } 609 appendFakeVotes(node, 1, v, 0) 610 ticketCount++ 611 } 612 }, 613 startStakeVersion: 1, 614 expectedStakeVersion: 2, 615 expectedCalcVersion: 0, 616 result: true, 617 }, 618 { 619 name: "75% with 3 votes blockversion 3", 620 numNodes: svh + (svi * 2), 621 set: func(node *blockNode) { 622 if node.height <= svh { 623 return 624 } 625 626 if node.height < svh+svi { 627 appendFakeVotes(node, tpb-2, 1, 0) 628 return 629 } 630 631 threshold := maxTickets3 - sm3 632 633 v := uint32(1) 634 for i := 0; i < int(tpb-2); i++ { 635 if ticketCount >= threshold { 636 v = 2 637 } 638 appendFakeVotes(node, 1, v, 0) 639 ticketCount++ 640 } 641 }, 642 blockVersion: 3, 643 startStakeVersion: 1, 644 expectedStakeVersion: 2, 645 expectedCalcVersion: 2, 646 result: true, 647 }, 648 { 649 name: "75%-1 with 3 votes blockversion 3", 650 numNodes: svh + (svi * 2), 651 set: func(node *blockNode) { 652 if node.height < svh { 653 return 654 } 655 656 if node.height < svh+svi { 657 appendFakeVotes(node, tpb-2, 1, 0) 658 return 659 } 660 661 threshold := maxTickets3 - sm3 + 1 662 663 v := uint32(1) 664 for i := 0; i < int(tpb-2); i++ { 665 if ticketCount >= threshold { 666 v = 2 667 } 668 appendFakeVotes(node, 1, v, 0) 669 ticketCount++ 670 } 671 }, 672 blockVersion: 3, 673 startStakeVersion: 1, 674 expectedStakeVersion: 2, 675 expectedCalcVersion: 1, 676 result: false, 677 }, 678 } 679 680 for _, test := range tests { 681 // Create new BlockChain in order to blow away cache. 682 bc := newFakeChain(params) 683 node := bc.bestChain.Tip() 684 node.stakeVersion = test.startStakeVersion 685 686 ticketCount = 0 687 688 for i := int64(1); i <= test.numNodes; i++ { 689 node = newFakeNode(node, test.blockVersion, 690 test.startStakeVersion, 0, time.Now()) 691 692 // Override version. 693 if test.set != nil { 694 test.set(node) 695 } else { 696 appendFakeVotes(node, tpb, 697 test.startStakeVersion, 0) 698 } 699 700 bc.bestChain.SetTip(node) 701 } 702 703 res := bc.isVoterMajorityVersion(test.expectedStakeVersion, node) 704 if res != test.result { 705 t.Fatalf("%v isVoterMajorityVersion", test.name) 706 } 707 708 // validate calcStakeVersion 709 version := bc.calcStakeVersion(node) 710 if version != test.expectedCalcVersion { 711 t.Fatalf("%v calcStakeVersionByNode got %v expected %v", 712 test.name, version, test.expectedCalcVersion) 713 } 714 } 715 } 716 717 func TestLarge(t *testing.T) { 718 params := &chaincfg.MainNetParams 719 720 numRuns := 5 721 numBlocks := params.StakeVersionInterval * 100 722 numBlocksShallow := params.StakeVersionInterval * 10 723 tests := []struct { 724 name string 725 numNodes int64 726 blockVersion int32 727 startStakeVersion uint32 728 expectedStakeVersion uint32 729 expectedCalcVersion uint32 730 result bool 731 }{ 732 { 733 name: "shallow cache", 734 numNodes: numBlocksShallow, 735 startStakeVersion: 1, 736 expectedStakeVersion: 1, 737 expectedCalcVersion: 0, 738 result: true, 739 }, 740 { 741 name: "deep cache", 742 numNodes: numBlocks, 743 startStakeVersion: 1, 744 expectedStakeVersion: 1, 745 expectedCalcVersion: 0, 746 result: true, 747 }, 748 } 749 750 for _, test := range tests { 751 // Create new BlockChain in order to blow away cache. 752 bc := newFakeChain(params) 753 node := bc.bestChain.Tip() 754 node.stakeVersion = test.startStakeVersion 755 756 for i := int64(1); i <= test.numNodes; i++ { 757 node = newFakeNode(node, test.blockVersion, 758 test.startStakeVersion, 0, time.Now()) 759 760 // Override version. 761 appendFakeVotes(node, params.TicketsPerBlock, 762 test.startStakeVersion, 0) 763 bc.bestChain.SetTip(node) 764 } 765 766 for x := 0; x < numRuns; x++ { 767 start := time.Now() 768 res := bc.isVoterMajorityVersion(test.expectedStakeVersion, node) 769 if res != test.result { 770 t.Fatalf("%v isVoterMajorityVersion got %v expected %v", test.name, res, test.result) 771 } 772 773 // validate calcStakeVersion 774 version := bc.calcStakeVersion(node) 775 if version != test.expectedCalcVersion { 776 t.Fatalf("%v calcStakeVersion got %v expected %v", 777 test.name, version, test.expectedCalcVersion) 778 } 779 end := time.Now() 780 781 setup := "setup 0" 782 if x != 0 { 783 setup = fmt.Sprintf("run %v", x) 784 } 785 786 vkey := stakeMajorityCacheKeySize + 8 // bool on x86_64 787 key := chainhash.HashSize + 4 // size of uint32 788 789 cost := len(bc.isVoterMajorityVersionCache) * vkey 790 cost += len(bc.isStakeMajorityVersionCache) * vkey 791 cost += len(bc.calcPriorStakeVersionCache) * key 792 cost += len(bc.calcVoterVersionIntervalCache) * key 793 cost += len(bc.calcStakeVersionCache) * key 794 memoryCost := fmt.Sprintf("memory cost: %v", cost) 795 796 t.Logf("run time (%v) %v %v", setup, end.Sub(start), 797 memoryCost) 798 } 799 } 800 }