blockchain: Support testnet stake diff estimation.

Currently, the stake difficulty estimation function for algorithm
defined in DCP0001 only works with mainnet due to a limitation of only
working when the interval size is less than or equal to the ticket
maturity.

This generalizes the function to work with all values of interval size
and ticket maturity and adds a full suite of tests using the testnet
parameters to ensure proper functionality.

Of particular note is the case when the current height is before the
ticket maturity floor since that means some of the tickets being
estimated will mature during the interval and that there can be no
non-estimated immature tickets.

This also implies that, unlike when the ticket maturity is greater than
or equal to the interval size, the estimate may not exactly match the
real final value when given the exact same number of tickets to estimate
as real purchased tickets in the remainder of the interval depending on
whether or not the current height is before the ticket maturity floor.
This is the case because the number of real tickets that end up being
purchased before the maturity floor may not match the estimated
assumption of max tickets per block.
This commit is contained in:
Dave Collins 2018-03-03 14:54:54 -06:00
parent 9f7d6a1aac
commit 03f77993bd
No known key found for this signature in database
GPG Key ID: B8904D9D9C93D1F2
2 changed files with 437 additions and 132 deletions

View File

@ -1327,22 +1327,11 @@ func (b *BlockChain) estimateNextStakeDifficultyV2(curNode *blockNode, newTicket
if curNode != nil {
curHeight = curNode.height
}
ticketMaturity := int64(b.chainParams.TicketMaturity)
intervalSize := b.chainParams.StakeDiffWindowSize
blocksUntilRetarget := intervalSize - curHeight%intervalSize
nextRetargetHeight := curHeight + blocksUntilRetarget
// This code really should be updated to work with retarget interval
// size greater than the ticket maturity, such as is the case on
// testnet, but since it does not currently work under that scenario,
// return an error rather than incorrect results.
ticketMaturity := int64(b.chainParams.TicketMaturity)
if intervalSize > ticketMaturity {
return 0, fmt.Errorf("stake difficulty estimation does not "+
"currently work when the retarget interval is larger "+
"than the ticket maturity (interval %d, ticket "+
"maturity %d)", intervalSize, ticketMaturity)
}
// Calculate the maximum possible number of tickets that could be sold
// in the remainder of the interval and potentially override the number
// of new tickets to include in the estimate per the user-specified
@ -1400,33 +1389,69 @@ func (b *BlockChain) estimateNextStakeDifficultyV2(curNode *blockNode, newTicket
}
// Calculate the number of tickets that will still be immature at the
// next retarget based on the known data.
// next retarget based on the known (non-estimated) data.
//
// Note that when the interval size is larger than the ticket maturity,
// the current height might be before the maturity floor (the point
// after which the remaining tickets will remain immature). There are
// therefore no possible remaining immature tickets from the blocks that
// are not being estimated in that case.
var remainingImmatureTickets int64
nextMaturityFloor := nextRetargetHeight - ticketMaturity - 1
remainingImmatureTickets, err := b.sumPurchasedTickets(curNode,
curHeight-nextMaturityFloor)
if err != nil {
return 0, err
if curHeight > nextMaturityFloor {
remainingImmatureTickets, err = b.sumPurchasedTickets(curNode,
curHeight-nextMaturityFloor)
if err != nil {
return 0, err
}
}
// Add the number of tickets that will still be immature at the next
// retarget based on the estimated data.
maxImmatureTickets := ticketMaturity * maxTicketsPerBlock
if newTickets > maxImmatureTickets {
remainingImmatureTickets += maxImmatureTickets
} else {
remainingImmatureTickets += newTickets
}
// Calculate the number of tickets that will mature in the remainder of
// the interval.
// the interval based on the known (non-estimated) data.
//
// NOTE: The pool size in the block headers does not include the tickets
// maturing at the height in which they mature since they are not
// eligible for selection until the next block, so exclude them by
// starting one block before the next maturity floor.
nextMaturityFloorNode, err := b.index.AncestorNode(curNode,
nextMaturityFloor-1)
finalMaturingHeight := nextMaturityFloor - 1
if finalMaturingHeight > curHeight {
finalMaturingHeight = curHeight
}
finalMaturingNode, err := b.index.AncestorNode(curNode, finalMaturingHeight)
if err != nil {
return 0, err
}
curMaturityFloor := curHeight - ticketMaturity
maturingTickets, err := b.sumPurchasedTickets(nextMaturityFloorNode,
nextMaturityFloor-curMaturityFloor)
firstMaturingHeight := curHeight - ticketMaturity
maturingTickets, err := b.sumPurchasedTickets(finalMaturingNode,
finalMaturingHeight-firstMaturingHeight+1)
if err != nil {
return 0, err
}
// Add the number of tickets that will mature based on the estimated data.
//
// Note that when the ticket maturity is greater than or equal to the
// interval size, the current height will always be after the maturity
// floor. There are therefore no possible maturing estimated tickets
// in that case.
if curHeight < nextMaturityFloor {
maturingEstimateNodes := nextMaturityFloor - curHeight - 1
maturingEstimatedTickets := maxTicketsPerBlock * maturingEstimateNodes
if maturingEstimatedTickets > newTickets {
maturingEstimatedTickets = newTickets
}
maturingTickets += maturingEstimatedTickets
}
// Calculate the number of votes that will occur during the remainder of
// the interval.
stakeValidationHeight := b.chainParams.StakeValidationHeight
@ -1443,8 +1468,7 @@ func (b *BlockChain) estimateNextStakeDifficultyV2(curNode *blockNode, newTicket
// Calculate what the pool size would be as of the next interval.
curPoolSize := int64(curNode.poolSize)
estimatedPoolSize := curPoolSize + maturingTickets - pendingVotes
estimatedImmatureTickets := remainingImmatureTickets + newTickets
estimatedPoolSizeAll := estimatedPoolSize + estimatedImmatureTickets
estimatedPoolSizeAll := estimatedPoolSize + remainingImmatureTickets
// Calculate and return the final estimated difficulty.
return calcNextStakeDiffV2(b.chainParams, nextRetargetHeight, curDiff,

View File

@ -131,9 +131,9 @@ func TestEstimateSupply(t *testing.T) {
}
}
// 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) {
// assertStakeDiffParamsMainNet ensure the passed params have the values used in
// the tests related to mainnet stake difficulty calculation.
func assertStakeDiffParamsMainNet(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 "+
@ -162,6 +162,37 @@ func assertStakeDiffParams(t *testing.T, params *chaincfg.Params) {
}
}
// assertStakeDiffParamsTestNet ensure the passed params have the values used in
// the tests related to testnet stake difficulty calculation.
func assertStakeDiffParamsTestNet(t *testing.T, params *chaincfg.Params) {
if params.MinimumStakeDiff != 20000000 {
_, file, line, _ := runtime.Caller(1)
t.Fatalf("%s:%d -- expect params with minimum stake diff of "+
"%d, got %d", file, line, 20000000,
params.MinimumStakeDiff)
}
if params.TicketMaturity != 16 {
_, file, line, _ := runtime.Caller(1)
t.Fatalf("%s:%d -- expect params with ticket maturity of "+
"%d, got %d", file, line, 16, params.TicketMaturity)
}
if params.StakeValidationHeight != 768 {
_, file, line, _ := runtime.Caller(1)
t.Fatalf("%s:%d -- expect params with stake val height of %d, "+
"got %d", file, line, 768, 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) {
@ -181,7 +212,7 @@ func TestCalcNextRequiredStakeDiffV2(t *testing.T) {
// need to be updated if these parameters change since they are manually
// calculated based on them.
params := &chaincfg.MainNetParams
assertStakeDiffParams(t, params)
assertStakeDiffParamsMainNet(t, params)
minStakeDiff := params.MinimumStakeDiff
ticketMaturity := uint32(params.TicketMaturity)
stakeValidationHeight := params.StakeValidationHeight
@ -475,25 +506,26 @@ func TestEstimateNextStakeDiffV2(t *testing.T) {
// 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.
// tickets 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
// Assert the param 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.
mainNetParams := &chaincfg.MainNetParams
testNetParams := &chaincfg.TestNet2Params
assertStakeDiffParamsMainNet(t, mainNetParams)
assertStakeDiffParamsTestNet(t, testNetParams)
minStakeDiffMainNet := mainNetParams.MinimumStakeDiff
minStakeDiffTestNet := testNetParams.MinimumStakeDiff
tests := []struct {
name string
params *chaincfg.Params
ticketInfo []ticketInfo
newTickets int64
useMaxTickets bool
@ -505,20 +537,22 @@ func TestEstimateNextStakeDiffV2(t *testing.T) {
// because the first retarget is before the start
// height.
name: "genesis block",
ticketInfo: []ticketInfo{{0, 0, minStakeDiff}},
params: mainNetParams,
ticketInfo: []ticketInfo{{0, 0, minStakeDiffMainNet}},
newTickets: 2860,
useMaxTickets: false,
expectedDiff: minStakeDiff,
expectedDiff: minStakeDiffMainNet,
},
{
// 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}},
params: mainNetParams,
ticketInfo: []ticketInfo{{140, 0, minStakeDiffMainNet}},
newTickets: 20 * 3, // blocks 141, 142, and 143.
useMaxTickets: true,
expectedDiff: minStakeDiff,
expectedDiff: minStakeDiffMainNet,
},
{
// Next retarget is at 288. Regardless of claiming
@ -526,102 +560,110 @@ func TestEstimateNextStakeDiffV2(t *testing.T) {
// difficulty should be the min because the previous
// pool size is still 0.
name: "at coinbase maturity",
ticketInfo: []ticketInfo{{256, 0, minStakeDiff}},
params: mainNetParams,
ticketInfo: []ticketInfo{{256, 0, minStakeDiffMainNet}},
useMaxTickets: true,
expectedDiff: minStakeDiff,
expectedDiff: minStakeDiffMainNet,
},
{
// 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",
name: "2nd retarget interval - 2, 100% demand",
params: mainNetParams,
ticketInfo: []ticketInfo{
{256, 0, minStakeDiff}, // 256
{30, 20, minStakeDiff}, // 286
{256, 0, minStakeDiffMainNet}, // 256
{30, 20, minStakeDiffMainNet}, // 286
},
useMaxTickets: true,
expectedDiff: minStakeDiff,
expectedDiff: minStakeDiffMainNet,
},
{
// Next retarget is at 288. Still expect minimum stake
// difficulty since the raw result would be lower.
name: "2nd retarget interval - 1, 100% demand",
name: "2nd retarget interval - 1, 100% demand",
params: mainNetParams,
ticketInfo: []ticketInfo{
{256, 0, minStakeDiff}, // 256
{31, 20, minStakeDiff}, // 287
{256, 0, minStakeDiffMainNet}, // 256
{31, 20, minStakeDiffMainNet}, // 287
},
useMaxTickets: true,
expectedDiff: minStakeDiff,
expectedDiff: minStakeDiffMainNet,
},
{
// Next retarget is at 432.
name: "3rd retarget interval, 100% demand, 1st block",
name: "3rd retarget interval, 100% demand, 1st block",
params: mainNetParams,
ticketInfo: []ticketInfo{
{256, 0, minStakeDiff}, // 256
{32, 20, minStakeDiff}, // 288
{256, 0, minStakeDiffMainNet}, // 256
{32, 20, minStakeDiffMainNet}, // 288
},
useMaxTickets: true,
expectedDiff: minStakeDiff,
expectedDiff: minStakeDiffMainNet,
},
{
// Next retarget is at 2304.
name: "16th retarget interval, 100% demand, 1st block",
name: "16th retarget interval, 100% demand, 1st block",
params: mainNetParams,
ticketInfo: []ticketInfo{
{256, 0, minStakeDiff}, // 256
{1904, 20, minStakeDiff}, // 2160
{256, 0, minStakeDiffMainNet}, // 256
{1904, 20, minStakeDiffMainNet}, // 2160
},
useMaxTickets: true,
expectedDiff: 208418769,
},
{
// Next retarget is at 2304.
name: "16th retarget interval, 100% demand, 2nd block",
name: "16th retarget interval, 100% demand, 2nd block",
params: mainNetParams,
ticketInfo: []ticketInfo{
{256, 0, minStakeDiff}, // 256
{1905, 20, minStakeDiff}, // 2161
{256, 0, minStakeDiffMainNet}, // 256
{1905, 20, minStakeDiffMainNet}, // 2161
},
useMaxTickets: true,
expectedDiff: 208418769,
},
{
// Next retarget is at 2304.
name: "16th retarget interval, 100% demand, final block",
name: "16th retarget interval, 100% demand, final block",
params: mainNetParams,
ticketInfo: []ticketInfo{
{256, 0, minStakeDiff}, // 256
{2047, 20, minStakeDiff}, // 2303
{256, 0, minStakeDiffMainNet}, // 256
{2047, 20, minStakeDiffMainNet}, // 2303
},
useMaxTickets: true,
expectedDiff: 208418769,
},
{
// Next retarget is at 3456.
name: "24th retarget interval, varying demand, 5th block",
name: "24th retarget interval, varying demand, 5th block",
params: mainNetParams,
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
{256, 0, minStakeDiffMainNet}, // 256
{31, 20, minStakeDiffMainNet}, // 287
{144, 10, minStakeDiffMainNet}, // 431
{144, 20, minStakeDiffMainNet}, // 575
{144, 10, minStakeDiffMainNet}, // 719
{144, 20, minStakeDiffMainNet}, // 863
{144, 10, minStakeDiffMainNet}, // 1007
{144, 20, minStakeDiffMainNet}, // 1151
{144, 10, minStakeDiffMainNet}, // 1295
{144, 20, minStakeDiffMainNet}, // 1439
{144, 10, minStakeDiffMainNet}, // 1583
{144, 20, minStakeDiffMainNet}, // 1727
{144, 10, minStakeDiffMainNet}, // 1871
{144, 20, minStakeDiffMainNet}, // 2015
{144, 10, minStakeDiffMainNet}, // 2159
{144, 20, minStakeDiffMainNet}, // 2303
{144, 10, minStakeDiffMainNet}, // 2447
{144, 20, minStakeDiffMainNet}, // 2591
{144, 10, minStakeDiffMainNet}, // 2735
{144, 20, minStakeDiffMainNet}, // 2879
{144, 9, 201743368}, // 3023
{144, 20, 201093236}, // 3167
{144, 8, 222625877}, // 3311
{5, 20, 242331291}, // 3316
},
useMaxTickets: true,
expectedDiff: 291317641,
@ -629,23 +671,24 @@ func TestEstimateNextStakeDiffV2(t *testing.T) {
{
// Next retarget is at 4176. Post stake validation
// height.
name: "29th retarget interval, 100% demand, 10th block",
name: "29th retarget interval, 100% demand, 10th block",
params: mainNetParams,
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
{256, 0, minStakeDiffMainNet}, // 256
{2047, 20, minStakeDiffMainNet}, // 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,
@ -653,48 +696,286 @@ func TestEstimateNextStakeDiffV2(t *testing.T) {
{
// Next retarget is at 4176. Post stake validation
// height.
name: "29th retarget interval, 50% demand, 23rd block",
name: "29th retarget interval, 50% demand, 23rd block",
params: mainNetParams,
ticketInfo: []ticketInfo{
{256, 0, minStakeDiff}, // 256
{3775, 10, minStakeDiff}, // 4031
{23, 10, minStakeDiff}, // 4054
{256, 0, minStakeDiffMainNet}, // 256
{3775, 10, minStakeDiffMainNet}, // 4031
{23, 10, minStakeDiffMainNet}, // 4054
},
newTickets: 1210, // 121 * 10
useMaxTickets: false,
expectedDiff: minStakeDiff,
expectedDiff: minStakeDiffMainNet,
},
{
// Next retarget is at 4464. Post stake validation
// height.
name: "31st retarget interval, waning demand, 117th block",
name: "31st retarget interval, waning demand, 117th block",
params: mainNetParams,
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
{256, 0, minStakeDiffMainNet}, // 256
{2047, 20, minStakeDiffMainNet}, // 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,
},
// --------------------------
// TestNet params start here.
// --------------------------
{
// 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",
params: testNetParams,
ticketInfo: []ticketInfo{{0, 0, minStakeDiffTestNet}},
newTickets: 2860,
useMaxTickets: false,
expectedDiff: minStakeDiffTestNet,
},
{
// Next retarget is at 144. 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",
params: testNetParams,
ticketInfo: []ticketInfo{{16, 0, minStakeDiffTestNet}},
useMaxTickets: true,
expectedDiff: minStakeDiffTestNet,
},
{
// Next retarget is at 144. 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: "1st retarget interval - 2, 100% demand",
params: testNetParams,
ticketInfo: []ticketInfo{
{16, 0, minStakeDiffTestNet}, // 16
{126, 20, minStakeDiffTestNet}, // 142
},
useMaxTickets: true,
expectedDiff: minStakeDiffTestNet,
},
{
// Next retarget is at 288. Still expect minimum stake
// difficulty since the raw result would be lower.
name: "2nd retarget interval - 1, 30% demand",
params: testNetParams,
ticketInfo: []ticketInfo{
{16, 0, minStakeDiffTestNet}, // 16
{271, 6, minStakeDiffTestNet}, // 287
},
useMaxTickets: true,
expectedDiff: minStakeDiffTestNet,
},
{
// Next retarget is at 288. Still expect minimum stake
// difficulty since the raw result would be lower.
//
// Since the ticket maturity is smaller than the
// retarget interval, this case ensures some of the
// nodes being estimated will mature during the
// interval.
name: "2nd retarget interval - 23, 30% demand",
params: testNetParams,
ticketInfo: []ticketInfo{
{16, 0, minStakeDiffTestNet}, // 16
{249, 6, minStakeDiffTestNet}, // 265
},
newTickets: 132, // 22 * 6
useMaxTickets: false,
expectedDiff: minStakeDiffTestNet,
},
{
// Next retarget is at 288. Still expect minimum stake
// difficulty since the raw result would be lower.
//
// None of the nodes being estimated will mature during the
// interval.
name: "2nd retarget interval - 11, 30% demand",
params: testNetParams,
ticketInfo: []ticketInfo{
{16, 0, minStakeDiffTestNet}, // 16
{261, 6, minStakeDiffTestNet}, // 277
},
newTickets: 60, // 10 * 6
useMaxTickets: false,
expectedDiff: minStakeDiffTestNet,
},
{
// Next retarget is at 432.
name: "3rd retarget interval, 100% demand, 1st block",
params: testNetParams,
ticketInfo: []ticketInfo{
{16, 0, minStakeDiffTestNet}, // 16
{256, 20, minStakeDiffTestNet}, // 288
},
useMaxTickets: true,
expectedDiff: 44505494,
},
{
// Next retarget is at 432.
//
// None of the nodes being estimated will mature during the
// interval.
name: "3rd retarget interval - 11, 100% demand",
params: testNetParams,
ticketInfo: []ticketInfo{
{16, 0, minStakeDiffTestNet}, // 16
{271, 20, minStakeDiffTestNet}, // 287
{134, 20, 44505494}, // 421
},
useMaxTickets: true,
expectedDiff: 108661875,
},
{
// Next retarget is at 576.
name: "4th retarget interval, 100% demand, 1st block",
params: testNetParams,
ticketInfo: []ticketInfo{
{16, 0, minStakeDiffTestNet}, // 16
{271, 20, minStakeDiffTestNet}, // 287
{144, 20, 44505494}, // 431
{1, 20, 108661875}, // 432
},
useMaxTickets: true,
expectedDiff: 314319918,
},
{
// Next retarget is at 576.
name: "4th retarget interval, 100% demand, 2nd block",
params: testNetParams,
ticketInfo: []ticketInfo{
{16, 0, minStakeDiffTestNet}, // 16
{271, 20, minStakeDiffTestNet}, // 287
{144, 20, 44505494}, // 431
{2, 20, 108661875}, // 433
},
useMaxTickets: true,
expectedDiff: 314319918,
},
{
// Next retarget is at 576.
name: "4th retarget interval, 100% demand, final block",
params: testNetParams,
ticketInfo: []ticketInfo{
{16, 0, minStakeDiffTestNet}, // 16
{271, 20, minStakeDiffTestNet}, // 287
{144, 20, 44505494}, // 431
{144, 20, 108661875}, // 575
},
useMaxTickets: true,
expectedDiff: 314319918,
},
{
// Next retarget is at 1152.
name: "9th retarget interval, varying demand, 137th block",
params: testNetParams,
ticketInfo: []ticketInfo{
{16, 0, minStakeDiffTestNet}, // 16
{127, 20, minStakeDiffTestNet}, // 143
{144, 10, minStakeDiffTestNet}, // 287
{144, 20, 24055097}, // 431
{144, 10, 54516186}, // 575
{144, 20, 105335577}, // 719
{144, 10, 304330579}, // 863
{144, 20, 772249463}, // 1007
{76, 10, 2497324513}, // 1083
{9, 0, 2497324513}, // 1092
{1, 10, 2497324513}, // 1093
{8, 0, 2497324513}, // 1101
{1, 10, 2497324513}, // 1102
{12, 0, 2497324513}, // 1114
{1, 10, 2497324513}, // 1115
{9, 0, 2497324513}, // 1124
{1, 10, 2497324513}, // 1125
{8, 0, 2497324513}, // 1133
{1, 10, 2497324513}, // 1134
{10, 0, 2497324513}, // 1144
},
useMaxTickets: false,
newTickets: 10,
expectedDiff: 6976183842,
},
{
// Next retarget is at 1440. The estimated number of
// tickets are such that they span the ticket maturity
// floor so that the estimation result is slightly
// different as compared to what it would be if each
// remaining node only had 10 ticket purchases. This is
// because it results in a different number of maturing
// tickets depending on how they are allocated on each
// side of the maturity floor.
name: "11th retarget interval, 50% demand, 127th block",
params: testNetParams,
ticketInfo: []ticketInfo{
{16, 0, minStakeDiffTestNet}, // 16
{271, 10, minStakeDiffTestNet}, // 287
{144, 10, 22252747}, // 431
{144, 10, 27165468}, // 575
{144, 10, 39289988}, // 719
{144, 10, 66729608}, // 863
{144, 10, 116554208}, // 1007
{144, 10, 212709675}, // 1151
{144, 10, 417424410}, // 1295
{127, 10, 876591473}, // 1422
},
useMaxTickets: false,
newTickets: 170, // 17 * 10
expectedDiff: 1965171141,
},
{
// Next retarget is at 1440. This is similar to the
// last test except all of the estimated tickets are
// after the ticket maturity floor, so the estimate is
// the same as if each remaining node only had 10 ticket
// purchases.
name: "11th retarget interval, 50% demand, 128th block",
params: testNetParams,
ticketInfo: []ticketInfo{
{16, 0, minStakeDiffTestNet}, // 16
{271, 10, minStakeDiffTestNet}, // 287
{144, 10, 22252747}, // 431
{144, 10, 27165468}, // 575
{144, 10, 39289988}, // 719
{144, 10, 66729608}, // 863
{144, 10, 116554208}, // 1007
{144, 10, 212709675}, // 1151
{144, 10, 417424410}, // 1295
{128, 10, 876591473}, // 1423
},
useMaxTickets: false,
newTickets: 160, // 16 * 10
expectedDiff: 1961558695,
},
}
nextTest:
for _, test := range tests {
bc := newFakeChain(params)
stakeValidationHeight := test.params.StakeValidationHeight
ticketMaturity := uint32(test.params.TicketMaturity)
ticketsPerBlock := uint32(test.params.TicketsPerBlock)
bc := newFakeChain(test.params)
// immatureTickets track which height the purchased tickets will
// mature and thus be eligible for admission to the live ticket
@ -737,7 +1018,7 @@ nextTest:
poolSize += uint32(immatureTickets[nextHeight])
delete(immatureTickets, nextHeight)
if int64(nextHeight) >= stakeValidationHeight {
poolSize -= uint32(params.TicketsPerBlock)
poolSize -= ticketsPerBlock
}
// Track maturity height for new ticket