dcrd/blockchain/difficulty_test.go
Dave Collins cb40146dc7
blockchain: Accept parent in blockNode constructor.
This modifies the newBlockNode function to accept the parent as an
argument to automatically connect the newly created node.  When it is
not nil, the work sum will automatically be summed and the parent of the
new node will be set accordingly.

This simplifies the block node construction a bit and allows some
redundant code to be removed.  It also paves the way for easier simpler
full block index construction in the future.
2018-02-18 20:45:22 -06:00

770 lines
23 KiB
Go

// Copyright (c) 2014 The btcsuite developers
// Copyright (c) 2015-2018 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package blockchain
import (
"math/big"
"runtime"
"testing"
"github.com/decred/dcrd/chaincfg"
"github.com/decred/dcrd/wire"
)
func TestBigToCompact(t *testing.T) {
tests := []struct {
in int64
out uint32
}{
{0, 0},
{-1, 25231360},
}
for x, test := range tests {
n := big.NewInt(test.in)
r := BigToCompact(n)
if r != test.out {
t.Errorf("TestBigToCompact test #%d failed: got %d want %d\n",
x, r, test.out)
return
}
}
}
func TestCompactToBig(t *testing.T) {
tests := []struct {
in uint32
out int64
}{
{10000000, 0},
}
for x, test := range tests {
n := CompactToBig(test.in)
want := big.NewInt(test.out)
if n.Cmp(want) != 0 {
t.Errorf("TestCompactToBig test #%d failed: got %d want %d\n",
x, n.Int64(), want.Int64())
return
}
}
}
func TestCalcWork(t *testing.T) {
tests := []struct {
in uint32
out int64
}{
{10000000, 0},
}
for x, test := range tests {
bits := uint32(test.in)
r := CalcWork(bits)
if r.Int64() != test.out {
t.Errorf("TestCalcWork test #%d failed: got %v want %d\n",
x, r.Int64(), test.out)
return
}
}
}
// TestEstimateSupply ensures the supply estimation function used in the stake
// difficulty algorithm defined by DCP0001 works as expected.
func TestEstimateSupply(t *testing.T) {
t.Parallel()
// The parameters used for the supply estimation.
params := &chaincfg.MainNetParams
baseSubsidy := params.BaseSubsidy
reduxInterval := params.SubsidyReductionInterval
blockOneSubsidy := params.BlockOneSubsidy()
// intervalSubsidy is a helper function to return the full block subsidy
// for the given reduction interval.
intervalSubsidy := func(interval int) int64 {
subsidy := baseSubsidy
for i := 0; i < interval; i++ {
subsidy *= params.MulSubsidy
subsidy /= params.DivSubsidy
}
return subsidy
}
// Useful calculations for the tests below.
intervalOneSubsidy := intervalSubsidy(1)
intervalTwoSubsidy := intervalSubsidy(2)
reduxIntervalMinusOneSupply := blockOneSubsidy + (baseSubsidy * (reduxInterval - 2))
reduxIntervalTwoMinusOneSupply := reduxIntervalMinusOneSupply + (intervalOneSubsidy * reduxInterval)
tests := []struct {
height int64
expected int64
}{
{height: -1, expected: 0},
{height: 0, expected: 0},
{height: 1, expected: blockOneSubsidy},
{height: 2, expected: blockOneSubsidy + baseSubsidy},
{height: 3, expected: blockOneSubsidy + baseSubsidy*2},
{height: reduxInterval - 1, expected: reduxIntervalMinusOneSupply},
{height: reduxInterval, expected: reduxIntervalMinusOneSupply + intervalOneSubsidy},
{height: reduxInterval + 1, expected: reduxIntervalMinusOneSupply + intervalOneSubsidy*2},
{height: reduxInterval*2 - 1, expected: reduxIntervalTwoMinusOneSupply},
{height: reduxInterval * 2, expected: reduxIntervalTwoMinusOneSupply + intervalTwoSubsidy},
{height: reduxInterval*2 + 1, expected: reduxIntervalTwoMinusOneSupply + intervalTwoSubsidy*2},
}
for _, test := range tests {
// Ensure the function to calculate the estimated supply is
// working properly.
gotSupply := estimateSupply(params, test.height)
if gotSupply != test.expected {
t.Errorf("estimateSupply (height %d): did not get "+
"expected supply - got %d, want %d", test.height,
gotSupply, test.expected)
continue
}
}
}
// assertStakeDiffParams ensure the passed params have the values used in the
// tests related to stake difficulty calculation.
func assertStakeDiffParams(t *testing.T, params *chaincfg.Params) {
if params.MinimumStakeDiff != 200000000 {
_, file, line, _ := runtime.Caller(1)
t.Fatalf("%s:%d -- expect params with minimum stake diff of "+
"%d, got %d", file, line, 200000000,
params.MinimumStakeDiff)
}
if params.TicketMaturity != 256 {
_, file, line, _ := runtime.Caller(1)
t.Fatalf("%s:%d -- expect params with ticket maturity of "+
"%d, got %d", file, line, 256, params.TicketMaturity)
}
if params.StakeValidationHeight != 4096 {
_, file, line, _ := runtime.Caller(1)
t.Fatalf("%s:%d -- expect params with stake val height of %d, "+
"got %d", file, line, 4096, params.StakeValidationHeight)
}
if params.StakeDiffWindowSize != 144 {
_, file, line, _ := runtime.Caller(1)
t.Fatalf("%s:%d -- expect params with stake diff interval of "+
"%d, got %d", file, line, 144, params.StakeDiffWindowSize)
}
if params.TicketsPerBlock != 5 {
_, file, line, _ := runtime.Caller(1)
t.Fatalf("%s:%d -- expect params with tickets per block of "+
"%d, got %d", file, line, 5, params.TicketsPerBlock)
}
}
// TestCalcNextRequiredStakeDiffV2 ensure the stake diff calculation function
// for the algorithm defined by DCP0001 works as expected.
func TestCalcNextRequiredStakeDiffV2(t *testing.T) {
t.Parallel()
// ticketInfo is used to control the tests by specifying the details
// about how many fake blocks to create with the specified number of
// ticket and stake difficulty.
type ticketInfo struct {
numNodes uint32
newTickets uint8
stakeDiff int64
}
// Specify the params used in the tests and assert the values directly
// used by the tests are the expected ones. All of the test values will
// need to be updated if these parameters change since they are manually
// calculated based on them.
params := &chaincfg.MainNetParams
assertStakeDiffParams(t, params)
minStakeDiff := params.MinimumStakeDiff
ticketMaturity := uint32(params.TicketMaturity)
stakeValidationHeight := params.StakeValidationHeight
tests := []struct {
name string
ticketInfo []ticketInfo
expectedDiff int64
}{
{
// Next retarget is at 144. Prior to coinbase maturity,
// so will always be the minimum.
name: "genesis block",
ticketInfo: []ticketInfo{{0, 0, minStakeDiff}},
expectedDiff: minStakeDiff,
},
{
// Next retarget is at 144. Prior to coinbase maturity,
// so will always be the minimum.
name: "1st retarget, before coinbase",
ticketInfo: []ticketInfo{{143, 0, minStakeDiff}},
expectedDiff: minStakeDiff,
},
{
// Next retarget is at 288.
//
// Tickets could not possibly have been bought yet, but
// ensure the algorithm handles it properly.
name: "coinbase maturity with impossible num tickets",
ticketInfo: []ticketInfo{{255, 20, minStakeDiff}},
expectedDiff: minStakeDiff,
},
{
// Next retarget is at 288.
//
// Block 0 has no spendable outputs, so tickets could
// not have possibly been bought yet.
name: "coinbase maturity + 1",
ticketInfo: []ticketInfo{
{256, 0, minStakeDiff},
},
expectedDiff: minStakeDiff,
},
{
// Next retarget is at 288.
name: "2nd retarget interval - 1, 100% demand",
ticketInfo: []ticketInfo{
{256, 0, minStakeDiff}, // 256
{30, 20, minStakeDiff}, // 286
},
expectedDiff: minStakeDiff,
},
{
// Next retarget is at 288.
name: "2nd retarget interval, 100% demand",
ticketInfo: []ticketInfo{
{256, 0, minStakeDiff}, // 256
{31, 20, minStakeDiff}, // 287
},
expectedDiff: minStakeDiff,
},
{
// Next retarget is at 432.
name: "3rd retarget interval, 100% demand",
ticketInfo: []ticketInfo{
{256, 0, minStakeDiff}, // 256
{175, 20, minStakeDiff}, // 431
},
expectedDiff: minStakeDiff,
},
{
// Next retarget is at 2304.
name: "16th retarget interval - 1, 100% demand",
ticketInfo: []ticketInfo{
{256, 0, minStakeDiff}, // 256
{2046, 20, minStakeDiff}, // 2302
},
expectedDiff: minStakeDiff,
},
{
// Next retarget is at 2304.
name: "16th retarget interval, 100% demand",
ticketInfo: []ticketInfo{
{256, 0, minStakeDiff}, // 256
{2047, 20, minStakeDiff}, // 2303
},
expectedDiff: 208418769,
},
{
// Next retarget is at 2448.
name: "17th retarget interval - 1, 100% demand",
ticketInfo: []ticketInfo{
{256, 0, minStakeDiff}, // 256
{2047, 20, minStakeDiff}, // 2303
{143, 20, 208418769}, // 2446
},
expectedDiff: 208418769,
},
{
// Next retarget is at 2448.
name: "17th retarget interval, 100% demand",
ticketInfo: []ticketInfo{
{256, 0, minStakeDiff}, // 256
{2047, 20, minStakeDiff}, // 2303
{144, 20, 208418769}, // 2447
},
expectedDiff: 231326567,
},
{
// Next retarget is at 2592.
name: "17th retarget interval+1, 100% demand",
ticketInfo: []ticketInfo{
{256, 0, minStakeDiff}, // 256
{2047, 20, minStakeDiff}, // 2303
{144, 20, 208418769}, // 2447
{1, 20, 231326567}, // 2448
},
expectedDiff: 231326567,
},
{
// Next retarget is at 3456.
name: "24th retarget interval, varying demand",
ticketInfo: []ticketInfo{
{256, 0, minStakeDiff}, // 256
{31, 20, minStakeDiff}, // 287
{144, 10, minStakeDiff}, // 431
{144, 20, minStakeDiff}, // 575
{144, 10, minStakeDiff}, // 719
{144, 20, minStakeDiff}, // 863
{144, 10, minStakeDiff}, // 1007
{144, 20, minStakeDiff}, // 1151
{144, 10, minStakeDiff}, // 1295
{144, 20, minStakeDiff}, // 1439
{144, 10, minStakeDiff}, // 1583
{144, 20, minStakeDiff}, // 1727
{144, 10, minStakeDiff}, // 1871
{144, 20, minStakeDiff}, // 2015
{144, 10, minStakeDiff}, // 2159
{144, 20, minStakeDiff}, // 2303
{144, 10, minStakeDiff}, // 2447
{144, 20, minStakeDiff}, // 2591
{144, 10, minStakeDiff}, // 2735
{144, 20, minStakeDiff}, // 2879
{144, 9, 201743368}, // 3023
{144, 20, 201093236}, // 3167
{144, 8, 222625877}, // 3311
{144, 20, 242331291}, // 3455
},
expectedDiff: 291317641,
},
{
// Next retarget is at 4176. Post stake validation
// height.
name: "29th retarget interval, 100% demand",
ticketInfo: []ticketInfo{
{256, 0, minStakeDiff}, // 256
{2047, 20, minStakeDiff}, // 2303
{144, 20, 208418769}, // 2447
{144, 20, 231326567}, // 2591
{144, 20, 272451490}, // 2735
{144, 20, 339388424}, // 2879
{144, 20, 445827839}, // 3023
{144, 20, 615949254}, // 3167
{144, 20, 892862990}, // 3311
{144, 20, 1354989669}, // 3455
{144, 20, 2148473276}, // 3599
{144, 20, 3552797658}, // 3743
{144, 20, 6116808441}, // 3887
{144, 20, 10947547379}, // 4031
{144, 20, 20338554623}, // 4175
},
expectedDiff: 22097687698,
},
{
// Next retarget is at 4176. Post stake validation
// height.
name: "29th retarget interval, 50% demand",
ticketInfo: []ticketInfo{
{256, 0, minStakeDiff}, // 256
{3919, 10, minStakeDiff}, // 4175
},
expectedDiff: minStakeDiff,
},
{
// Next retarget is at 4464. Post stake validation
// height.
name: "31st retarget interval, waning demand",
ticketInfo: []ticketInfo{
{256, 0, minStakeDiff}, // 256
{2047, 20, minStakeDiff}, // 2303
{144, 20, 208418769}, // 2447
{144, 20, 231326567}, // 2591
{144, 20, 272451490}, // 2735
{144, 20, 339388424}, // 2879
{144, 20, 445827839}, // 3023
{144, 20, 615949254}, // 3167
{144, 20, 892862990}, // 3311
{144, 20, 1354989669}, // 3455
{144, 20, 2148473276}, // 3599
{144, 20, 3552797658}, // 3743
{144, 13, 6116808441}, // 3887
{144, 0, 10645659768}, // 4031
{144, 0, 18046712136}, // 4175
{144, 0, 22097687698}, // 4319
{144, 0, 22152524112}, // 4463
},
expectedDiff: 22207360526,
},
}
nextTest:
for _, test := range tests {
bc := newFakeChain(params)
// immatureTickets tracks which height the purchased tickets
// will mature and thus be eligible for admission to the live
// ticket pool.
immatureTickets := make(map[uint32]uint8)
var poolSize uint32
for _, ticketInfo := range test.ticketInfo {
// Ensure the test data isn't faking ticket purchases at
// an incorrect difficulty.
gotDiff, err := bc.calcNextRequiredStakeDifficultyV2(bc.bestNode)
if err != nil {
t.Errorf("calcNextRequiredStakeDifficultyV2 (%s): "+
"unexpected error: %v", test.name, err)
continue nextTest
}
if gotDiff != ticketInfo.stakeDiff {
t.Errorf("calcNextRequiredStakeDifficultyV2 (%s): "+
"did not get expected stake difficulty -- got "+
"%d, want %d", test.name, gotDiff,
ticketInfo.stakeDiff)
continue nextTest
}
for i := uint32(0); i < ticketInfo.numNodes; i++ {
// Make up a header.
nextHeight := uint32(bc.bestNode.height) + 1
header := &wire.BlockHeader{
Version: 4,
SBits: ticketInfo.stakeDiff,
Height: nextHeight,
FreshStake: ticketInfo.newTickets,
PoolSize: poolSize,
}
node := newBlockNode(header, bc.bestNode)
// Update the pool size for the next header.
// Notice how tickets that mature for this block
// do not show up in the pool size until the
// next block. This is correct behavior.
poolSize += uint32(immatureTickets[nextHeight])
delete(immatureTickets, nextHeight)
if int64(nextHeight) >= stakeValidationHeight {
poolSize -= uint32(params.TicketsPerBlock)
}
// Track maturity height for new ticket
// purchases.
maturityHeight := nextHeight + ticketMaturity
immatureTickets[maturityHeight] = ticketInfo.newTickets
// Update the chain to use the new fake node as
// the new best node.
bc.bestNode = node
}
}
// Ensure the calculated difficulty matches the expected value.
gotDiff, err := bc.calcNextRequiredStakeDifficultyV2(bc.bestNode)
if err != nil {
t.Errorf("calcNextRequiredStakeDifficultyV2 (%s): "+
"unexpected error: %v", test.name, err)
continue
}
if gotDiff != test.expectedDiff {
t.Errorf("calcNextRequiredStakeDifficultyV2 (%s): "+
"did not get expected stake difficulty -- got "+
"%d, want %d", test.name, gotDiff,
test.expectedDiff)
continue
}
}
}
// TestEstimateNextStakeDiffV2 ensures the function that estimates the stake
// diff calculation for the algorithm defined by DCP0001 works as expected.
func TestEstimateNextStakeDiffV2(t *testing.T) {
t.Parallel()
// ticketInfo is used to control the tests by specifying the details
// about how many fake blocks to create with the specified number of
// ticket and stake difficulty.
type ticketInfo struct {
numNodes uint32
newTickets uint8
stakeDiff int64
}
// Specify the params used in the tests and assert the values directly
// used by the tests are the expected ones. All of the test values will
// need to be updated if these parameters change since they are manually
// calculated based on them.
params := &chaincfg.MainNetParams
assertStakeDiffParams(t, params)
minStakeDiff := params.MinimumStakeDiff
ticketMaturity := uint32(params.TicketMaturity)
stakeValidationHeight := params.StakeValidationHeight
tests := []struct {
name string
ticketInfo []ticketInfo
newTickets int64
useMaxTickets bool
expectedDiff int64
}{
{
// Regardless of claiming tickets will be purchased, the
// resulting stake difficulty should be the minimum
// because the first retarget is before the start
// height.
name: "genesis block",
ticketInfo: []ticketInfo{{0, 0, minStakeDiff}},
newTickets: 2860,
useMaxTickets: false,
expectedDiff: minStakeDiff,
},
{
// Next retarget is 144. Resulting stake difficulty
// should be the minimum regardless of claimed ticket
// purchases because the previous pool size is still 0.
name: "during retarget, but before coinbase",
ticketInfo: []ticketInfo{{140, 0, minStakeDiff}},
newTickets: 20 * 3, // blocks 141, 142, and 143.
useMaxTickets: true,
expectedDiff: minStakeDiff,
},
{
// Next retarget is at 288. Regardless of claiming
// tickets will be purchased, the resulting stake
// difficulty should be the min because the previous
// pool size is still 0.
name: "at coinbase maturity",
ticketInfo: []ticketInfo{{256, 0, minStakeDiff}},
useMaxTickets: true,
expectedDiff: minStakeDiff,
},
{
// Next retarget is at 288. Regardless of actually
// purchasing tickets and claiming more tickets will be
// purchased, the resulting stake difficulty should be
// the min because the previous pool size is still 0.
name: "2nd retarget interval - 2, 100% demand",
ticketInfo: []ticketInfo{
{256, 0, minStakeDiff}, // 256
{30, 20, minStakeDiff}, // 286
},
useMaxTickets: true,
expectedDiff: minStakeDiff,
},
{
// Next retarget is at 288. Still expect minimum stake
// difficulty since the raw result would be lower.
name: "2nd retarget interval - 1, 100% demand",
ticketInfo: []ticketInfo{
{256, 0, minStakeDiff}, // 256
{31, 20, minStakeDiff}, // 287
},
useMaxTickets: true,
expectedDiff: minStakeDiff,
},
{
// Next retarget is at 432.
name: "3rd retarget interval, 100% demand, 1st block",
ticketInfo: []ticketInfo{
{256, 0, minStakeDiff}, // 256
{32, 20, minStakeDiff}, // 288
},
useMaxTickets: true,
expectedDiff: minStakeDiff,
},
{
// Next retarget is at 2304.
name: "16th retarget interval, 100% demand, 1st block",
ticketInfo: []ticketInfo{
{256, 0, minStakeDiff}, // 256
{1904, 20, minStakeDiff}, // 2160
},
useMaxTickets: true,
expectedDiff: 208418769,
},
{
// Next retarget is at 2304.
name: "16th retarget interval, 100% demand, 2nd block",
ticketInfo: []ticketInfo{
{256, 0, minStakeDiff}, // 256
{1905, 20, minStakeDiff}, // 2161
},
useMaxTickets: true,
expectedDiff: 208418769,
},
{
// Next retarget is at 2304.
name: "16th retarget interval, 100% demand, final block",
ticketInfo: []ticketInfo{
{256, 0, minStakeDiff}, // 256
{2047, 20, minStakeDiff}, // 2303
},
useMaxTickets: true,
expectedDiff: 208418769,
},
{
// Next retarget is at 3456.
name: "24th retarget interval, varying demand, 5th block",
ticketInfo: []ticketInfo{
{256, 0, minStakeDiff}, // 256
{31, 20, minStakeDiff}, // 287
{144, 10, minStakeDiff}, // 431
{144, 20, minStakeDiff}, // 575
{144, 10, minStakeDiff}, // 719
{144, 20, minStakeDiff}, // 863
{144, 10, minStakeDiff}, // 1007
{144, 20, minStakeDiff}, // 1151
{144, 10, minStakeDiff}, // 1295
{144, 20, minStakeDiff}, // 1439
{144, 10, minStakeDiff}, // 1583
{144, 20, minStakeDiff}, // 1727
{144, 10, minStakeDiff}, // 1871
{144, 20, minStakeDiff}, // 2015
{144, 10, minStakeDiff}, // 2159
{144, 20, minStakeDiff}, // 2303
{144, 10, minStakeDiff}, // 2447
{144, 20, minStakeDiff}, // 2591
{144, 10, minStakeDiff}, // 2735
{144, 20, minStakeDiff}, // 2879
{144, 9, 201743368}, // 3023
{144, 20, 201093236}, // 3167
{144, 8, 222625877}, // 3311
{5, 20, 242331291}, // 3316
},
useMaxTickets: true,
expectedDiff: 291317641,
},
{
// Next retarget is at 4176. Post stake validation
// height.
name: "29th retarget interval, 100% demand, 10th block",
ticketInfo: []ticketInfo{
{256, 0, minStakeDiff}, // 256
{2047, 20, minStakeDiff}, // 2303
{144, 20, 208418769}, // 2447
{144, 20, 231326567}, // 2591
{144, 20, 272451490}, // 2735
{144, 20, 339388424}, // 2879
{144, 20, 445827839}, // 3023
{144, 20, 615949254}, // 3167
{144, 20, 892862990}, // 3311
{144, 20, 1354989669}, // 3455
{144, 20, 2148473276}, // 3599
{144, 20, 3552797658}, // 3743
{144, 20, 6116808441}, // 3887
{144, 20, 10947547379}, // 4031
{10, 20, 20338554623}, // 4041
},
useMaxTickets: true,
expectedDiff: 22097687698,
},
{
// Next retarget is at 4176. Post stake validation
// height.
name: "29th retarget interval, 50% demand, 23rd block",
ticketInfo: []ticketInfo{
{256, 0, minStakeDiff}, // 256
{3775, 10, minStakeDiff}, // 4031
{23, 10, minStakeDiff}, // 4054
},
newTickets: 1210, // 121 * 10
useMaxTickets: false,
expectedDiff: minStakeDiff,
},
{
// Next retarget is at 4464. Post stake validation
// height.
name: "31st retarget interval, waning demand, 117th block",
ticketInfo: []ticketInfo{
{256, 0, minStakeDiff}, // 256
{2047, 20, minStakeDiff}, // 2303
{144, 20, 208418769}, // 2447
{144, 20, 231326567}, // 2591
{144, 20, 272451490}, // 2735
{144, 20, 339388424}, // 2879
{144, 20, 445827839}, // 3023
{144, 20, 615949254}, // 3167
{144, 20, 892862990}, // 3311
{144, 20, 1354989669}, // 3455
{144, 20, 2148473276}, // 3599
{144, 20, 3552797658}, // 3743
{144, 13, 6116808441}, // 3887
{144, 0, 10645659768}, // 4031
{144, 0, 18046712136}, // 4175
{144, 0, 22097687698}, // 4319
{117, 0, 22152524112}, // 4436
},
useMaxTickets: false,
newTickets: 0,
expectedDiff: 22207360526,
},
}
nextTest:
for _, test := range tests {
bc := newFakeChain(params)
// immatureTickets track which height the purchased tickets will
// mature and thus be eligible for admission to the live ticket
// pool.
immatureTickets := make(map[uint32]uint8)
var poolSize uint32
for _, ticketInfo := range test.ticketInfo {
// Ensure the test data isn't faking ticket purchases at
// an incorrect difficulty.
reqDiff, err := bc.calcNextRequiredStakeDifficultyV2(bc.bestNode)
if err != nil {
t.Errorf("calcNextRequiredStakeDifficultyV2 (%s): "+
"unexpected error: %v", test.name, err)
continue nextTest
}
if ticketInfo.stakeDiff != reqDiff {
t.Errorf("calcNextRequiredStakeDifficultyV2 (%s): "+
"test data has incorrect stake difficulty: "+
"has %d, requires %d", test.name,
ticketInfo.stakeDiff, reqDiff)
continue nextTest
}
for i := uint32(0); i < ticketInfo.numNodes; i++ {
// Make up a header.
nextHeight := uint32(bc.bestNode.height) + 1
header := &wire.BlockHeader{
Version: 4,
SBits: ticketInfo.stakeDiff,
Height: nextHeight,
FreshStake: ticketInfo.newTickets,
PoolSize: poolSize,
}
node := newBlockNode(header, bc.bestNode)
// Update the pool size for the next header.
// Notice how tickets that mature for this block
// do not show up in the pool size until the
// next block. This is correct behavior.
poolSize += uint32(immatureTickets[nextHeight])
delete(immatureTickets, nextHeight)
if int64(nextHeight) >= stakeValidationHeight {
poolSize -= uint32(params.TicketsPerBlock)
}
// Track maturity height for new ticket
// purchases.
maturityHeight := nextHeight + ticketMaturity
immatureTickets[maturityHeight] = ticketInfo.newTickets
// Update the chain to use the new fake node as
// the new best node.
bc.bestNode = node
}
}
// Ensure the calculated difficulty matches the expected value.
gotDiff, err := bc.estimateNextStakeDifficultyV2(bc.bestNode,
test.newTickets, test.useMaxTickets)
if err != nil {
t.Errorf("estimateNextStakeDifficultyV2 (%s): "+
"unexpected error: %v", test.name, err)
continue
}
if gotDiff != test.expectedDiff {
t.Errorf("estimateNextStakeDifficultyV2 (%s): did not "+
"get expected stake difficulty -- got %d, "+
"want %d", test.name, gotDiff, test.expectedDiff)
continue
}
}
}