github.com/decred/dcrd/blockchain@v1.2.1/difficulty_test.go (about)

     1  // Copyright (c) 2014 The btcsuite developers
     2  // Copyright (c) 2015-2019 The Decred developers
     3  // Use of this source code is governed by an ISC
     4  // license that can be found in the LICENSE file.
     5  
     6  package blockchain
     7  
     8  import (
     9  	"math/big"
    10  	"runtime"
    11  	"testing"
    12  	"time"
    13  
    14  	"github.com/decred/dcrd/chaincfg"
    15  	"github.com/decred/dcrd/wire"
    16  )
    17  
    18  func TestBigToCompact(t *testing.T) {
    19  	tests := []struct {
    20  		in  int64
    21  		out uint32
    22  	}{
    23  		{0, 0},
    24  		{-1, 25231360},
    25  	}
    26  
    27  	for x, test := range tests {
    28  		n := big.NewInt(test.in)
    29  		r := BigToCompact(n)
    30  		if r != test.out {
    31  			t.Errorf("TestBigToCompact test #%d failed: got %d want %d\n",
    32  				x, r, test.out)
    33  			return
    34  		}
    35  	}
    36  }
    37  
    38  func TestCompactToBig(t *testing.T) {
    39  	tests := []struct {
    40  		in  uint32
    41  		out int64
    42  	}{
    43  		{10000000, 0},
    44  	}
    45  
    46  	for x, test := range tests {
    47  		n := CompactToBig(test.in)
    48  		want := big.NewInt(test.out)
    49  		if n.Cmp(want) != 0 {
    50  			t.Errorf("TestCompactToBig test #%d failed: got %d want %d\n",
    51  				x, n.Int64(), want.Int64())
    52  			return
    53  		}
    54  	}
    55  }
    56  
    57  func TestCalcWork(t *testing.T) {
    58  	tests := []struct {
    59  		in  uint32
    60  		out int64
    61  	}{
    62  		{10000000, 0},
    63  	}
    64  
    65  	for x, test := range tests {
    66  		r := CalcWork(test.in)
    67  		if r.Int64() != test.out {
    68  			t.Errorf("TestCalcWork test #%d failed: got %v want %d\n",
    69  				x, r.Int64(), test.out)
    70  			return
    71  		}
    72  	}
    73  }
    74  
    75  // TestEstimateSupply ensures the supply estimation function used in the stake
    76  // difficulty algorithm defined by DCP0001 works as expected.
    77  func TestEstimateSupply(t *testing.T) {
    78  	t.Parallel()
    79  
    80  	// The parameters used for the supply estimation.
    81  	params := &chaincfg.MainNetParams
    82  	baseSubsidy := params.BaseSubsidy
    83  	reduxInterval := params.SubsidyReductionInterval
    84  	blockOneSubsidy := params.BlockOneSubsidy()
    85  
    86  	// intervalSubsidy is a helper function to return the full block subsidy
    87  	// for the given reduction interval.
    88  	intervalSubsidy := func(interval int) int64 {
    89  		subsidy := baseSubsidy
    90  		for i := 0; i < interval; i++ {
    91  			subsidy *= params.MulSubsidy
    92  			subsidy /= params.DivSubsidy
    93  		}
    94  		return subsidy
    95  	}
    96  
    97  	// Useful calculations for the tests below.
    98  	intervalOneSubsidy := intervalSubsidy(1)
    99  	intervalTwoSubsidy := intervalSubsidy(2)
   100  	reduxIntervalMinusOneSupply := blockOneSubsidy + (baseSubsidy * (reduxInterval - 2))
   101  	reduxIntervalTwoMinusOneSupply := reduxIntervalMinusOneSupply + (intervalOneSubsidy * reduxInterval)
   102  
   103  	tests := []struct {
   104  		height   int64
   105  		expected int64
   106  	}{
   107  		{height: -1, expected: 0},
   108  		{height: 0, expected: 0},
   109  		{height: 1, expected: blockOneSubsidy},
   110  		{height: 2, expected: blockOneSubsidy + baseSubsidy},
   111  		{height: 3, expected: blockOneSubsidy + baseSubsidy*2},
   112  		{height: reduxInterval - 1, expected: reduxIntervalMinusOneSupply},
   113  		{height: reduxInterval, expected: reduxIntervalMinusOneSupply + intervalOneSubsidy},
   114  		{height: reduxInterval + 1, expected: reduxIntervalMinusOneSupply + intervalOneSubsidy*2},
   115  		{height: reduxInterval*2 - 1, expected: reduxIntervalTwoMinusOneSupply},
   116  		{height: reduxInterval * 2, expected: reduxIntervalTwoMinusOneSupply + intervalTwoSubsidy},
   117  		{height: reduxInterval*2 + 1, expected: reduxIntervalTwoMinusOneSupply + intervalTwoSubsidy*2},
   118  	}
   119  
   120  	for _, test := range tests {
   121  		// Ensure the function to calculate the estimated supply is
   122  		// working properly.
   123  		gotSupply := estimateSupply(params, test.height)
   124  		if gotSupply != test.expected {
   125  			t.Errorf("estimateSupply (height %d): did not get "+
   126  				"expected supply - got %d, want %d", test.height,
   127  				gotSupply, test.expected)
   128  			continue
   129  		}
   130  	}
   131  }
   132  
   133  // assertStakeDiffParamsMainNet ensure the passed params have the values used in
   134  // the tests related to mainnet stake difficulty calculation.
   135  func assertStakeDiffParamsMainNet(t *testing.T, params *chaincfg.Params) {
   136  	if params.MinimumStakeDiff != 200000000 {
   137  		_, file, line, _ := runtime.Caller(1)
   138  		t.Fatalf("%s:%d -- expect params with minimum stake diff of "+
   139  			"%d, got %d", file, line, 200000000,
   140  			params.MinimumStakeDiff)
   141  	}
   142  	if params.TicketMaturity != 256 {
   143  		_, file, line, _ := runtime.Caller(1)
   144  		t.Fatalf("%s:%d -- expect params with ticket maturity of "+
   145  			"%d, got %d", file, line, 256, params.TicketMaturity)
   146  	}
   147  	if params.StakeValidationHeight != 4096 {
   148  		_, file, line, _ := runtime.Caller(1)
   149  		t.Fatalf("%s:%d -- expect params with stake val height of %d, "+
   150  			"got %d", file, line, 4096, params.StakeValidationHeight)
   151  	}
   152  	if params.StakeDiffWindowSize != 144 {
   153  		_, file, line, _ := runtime.Caller(1)
   154  		t.Fatalf("%s:%d -- expect params with stake diff interval of "+
   155  			"%d, got %d", file, line, 144, params.StakeDiffWindowSize)
   156  	}
   157  	if params.TicketsPerBlock != 5 {
   158  		_, file, line, _ := runtime.Caller(1)
   159  		t.Fatalf("%s:%d -- expect params with tickets per block of "+
   160  			"%d, got %d", file, line, 5, params.TicketsPerBlock)
   161  	}
   162  }
   163  
   164  // assertStakeDiffParamsTestNet ensure the passed params have the values used in
   165  // the tests related to testnet stake difficulty calculation.
   166  func assertStakeDiffParamsTestNet(t *testing.T, params *chaincfg.Params) {
   167  	if params.MinimumStakeDiff != 20000000 {
   168  		_, file, line, _ := runtime.Caller(1)
   169  		t.Fatalf("%s:%d -- expect params with minimum stake diff of "+
   170  			"%d, got %d", file, line, 20000000,
   171  			params.MinimumStakeDiff)
   172  	}
   173  	if params.TicketMaturity != 16 {
   174  		_, file, line, _ := runtime.Caller(1)
   175  		t.Fatalf("%s:%d -- expect params with ticket maturity of "+
   176  			"%d, got %d", file, line, 16, params.TicketMaturity)
   177  	}
   178  	if params.StakeValidationHeight != 768 {
   179  		_, file, line, _ := runtime.Caller(1)
   180  		t.Fatalf("%s:%d -- expect params with stake val height of %d, "+
   181  			"got %d", file, line, 768, params.StakeValidationHeight)
   182  	}
   183  	if params.StakeDiffWindowSize != 144 {
   184  		_, file, line, _ := runtime.Caller(1)
   185  		t.Fatalf("%s:%d -- expect params with stake diff interval of "+
   186  			"%d, got %d", file, line, 144, params.StakeDiffWindowSize)
   187  	}
   188  	if params.TicketsPerBlock != 5 {
   189  		_, file, line, _ := runtime.Caller(1)
   190  		t.Fatalf("%s:%d -- expect params with tickets per block of "+
   191  			"%d, got %d", file, line, 5, params.TicketsPerBlock)
   192  	}
   193  }
   194  
   195  // TestCalcNextRequiredStakeDiffV2 ensure the stake diff calculation function
   196  // for the algorithm defined by DCP0001 works as expected.
   197  func TestCalcNextRequiredStakeDiffV2(t *testing.T) {
   198  	t.Parallel()
   199  
   200  	// ticketInfo is used to control the tests by specifying the details
   201  	// about how many fake blocks to create with the specified number of
   202  	// ticket and stake difficulty.
   203  	type ticketInfo struct {
   204  		numNodes   uint32
   205  		newTickets uint8
   206  		stakeDiff  int64
   207  	}
   208  
   209  	// Specify the params used in the tests and assert the values directly
   210  	// used by the tests are the expected ones.  All of the test values will
   211  	// need to be updated if these parameters change since they are manually
   212  	// calculated based on them.
   213  	params := &chaincfg.MainNetParams
   214  	assertStakeDiffParamsMainNet(t, params)
   215  	minStakeDiff := params.MinimumStakeDiff
   216  	ticketMaturity := uint32(params.TicketMaturity)
   217  	stakeValidationHeight := params.StakeValidationHeight
   218  
   219  	tests := []struct {
   220  		name         string
   221  		ticketInfo   []ticketInfo
   222  		expectedDiff int64
   223  	}{
   224  		{
   225  			// Next retarget is at 144.  Prior to coinbase maturity,
   226  			// so will always be the minimum.
   227  			name:         "genesis block",
   228  			ticketInfo:   []ticketInfo{{0, 0, minStakeDiff}},
   229  			expectedDiff: minStakeDiff,
   230  		},
   231  		{
   232  			// Next retarget is at 144.  Prior to coinbase maturity,
   233  			// so will always be the minimum.
   234  			name:         "1st retarget, before coinbase",
   235  			ticketInfo:   []ticketInfo{{143, 0, minStakeDiff}},
   236  			expectedDiff: minStakeDiff,
   237  		},
   238  		{
   239  			// Next retarget is at 288.
   240  			//
   241  			// Tickets could not possibly have been bought yet, but
   242  			// ensure the algorithm handles it properly.
   243  			name:         "coinbase maturity with impossible num tickets",
   244  			ticketInfo:   []ticketInfo{{255, 20, minStakeDiff}},
   245  			expectedDiff: minStakeDiff,
   246  		},
   247  		{
   248  			// Next retarget is at 288.
   249  			//
   250  			// Block 0 has no spendable outputs, so tickets could
   251  			// not have possibly been bought yet.
   252  			name: "coinbase maturity + 1",
   253  			ticketInfo: []ticketInfo{
   254  				{256, 0, minStakeDiff},
   255  			},
   256  			expectedDiff: minStakeDiff,
   257  		},
   258  		{
   259  			// Next retarget is at 288.
   260  			name: "2nd retarget interval - 1, 100% demand",
   261  			ticketInfo: []ticketInfo{
   262  				{256, 0, minStakeDiff}, // 256
   263  				{30, 20, minStakeDiff}, // 286
   264  			},
   265  			expectedDiff: minStakeDiff,
   266  		},
   267  		{
   268  			// Next retarget is at 288.
   269  			name: "2nd retarget interval, 100% demand",
   270  			ticketInfo: []ticketInfo{
   271  				{256, 0, minStakeDiff}, // 256
   272  				{31, 20, minStakeDiff}, // 287
   273  			},
   274  			expectedDiff: minStakeDiff,
   275  		},
   276  		{
   277  			// Next retarget is at 432.
   278  			name: "3rd retarget interval, 100% demand",
   279  			ticketInfo: []ticketInfo{
   280  				{256, 0, minStakeDiff},  // 256
   281  				{175, 20, minStakeDiff}, // 431
   282  			},
   283  			expectedDiff: minStakeDiff,
   284  		},
   285  		{
   286  			// Next retarget is at 2304.
   287  			name: "16th retarget interval - 1, 100% demand",
   288  			ticketInfo: []ticketInfo{
   289  				{256, 0, minStakeDiff},   // 256
   290  				{2046, 20, minStakeDiff}, // 2302
   291  			},
   292  			expectedDiff: minStakeDiff,
   293  		},
   294  		{
   295  			// Next retarget is at 2304.
   296  			name: "16th retarget interval, 100% demand",
   297  			ticketInfo: []ticketInfo{
   298  				{256, 0, minStakeDiff},   // 256
   299  				{2047, 20, minStakeDiff}, // 2303
   300  			},
   301  			expectedDiff: 208418769,
   302  		},
   303  		{
   304  			// Next retarget is at 2448.
   305  			name: "17th retarget interval - 1, 100% demand",
   306  			ticketInfo: []ticketInfo{
   307  				{256, 0, minStakeDiff},   // 256
   308  				{2047, 20, minStakeDiff}, // 2303
   309  				{143, 20, 208418769},     // 2446
   310  			},
   311  			expectedDiff: 208418769,
   312  		},
   313  		{
   314  			// Next retarget is at 2448.
   315  			name: "17th retarget interval, 100% demand",
   316  			ticketInfo: []ticketInfo{
   317  				{256, 0, minStakeDiff},   // 256
   318  				{2047, 20, minStakeDiff}, // 2303
   319  				{144, 20, 208418769},     // 2447
   320  			},
   321  			expectedDiff: 231326567,
   322  		},
   323  		{
   324  			// Next retarget is at 2592.
   325  			name: "17th retarget interval+1, 100% demand",
   326  			ticketInfo: []ticketInfo{
   327  				{256, 0, minStakeDiff},   // 256
   328  				{2047, 20, minStakeDiff}, // 2303
   329  				{144, 20, 208418769},     // 2447
   330  				{1, 20, 231326567},       // 2448
   331  			},
   332  			expectedDiff: 231326567,
   333  		},
   334  		{
   335  			// Next retarget is at 3456.
   336  			name: "24th retarget interval, varying demand",
   337  			ticketInfo: []ticketInfo{
   338  				{256, 0, minStakeDiff},  // 256
   339  				{31, 20, minStakeDiff},  // 287
   340  				{144, 10, minStakeDiff}, // 431
   341  				{144, 20, minStakeDiff}, // 575
   342  				{144, 10, minStakeDiff}, // 719
   343  				{144, 20, minStakeDiff}, // 863
   344  				{144, 10, minStakeDiff}, // 1007
   345  				{144, 20, minStakeDiff}, // 1151
   346  				{144, 10, minStakeDiff}, // 1295
   347  				{144, 20, minStakeDiff}, // 1439
   348  				{144, 10, minStakeDiff}, // 1583
   349  				{144, 20, minStakeDiff}, // 1727
   350  				{144, 10, minStakeDiff}, // 1871
   351  				{144, 20, minStakeDiff}, // 2015
   352  				{144, 10, minStakeDiff}, // 2159
   353  				{144, 20, minStakeDiff}, // 2303
   354  				{144, 10, minStakeDiff}, // 2447
   355  				{144, 20, minStakeDiff}, // 2591
   356  				{144, 10, minStakeDiff}, // 2735
   357  				{144, 20, minStakeDiff}, // 2879
   358  				{144, 9, 201743368},     // 3023
   359  				{144, 20, 201093236},    // 3167
   360  				{144, 8, 222625877},     // 3311
   361  				{144, 20, 242331291},    // 3455
   362  			},
   363  			expectedDiff: 291317641,
   364  		},
   365  		{
   366  			// Next retarget is at 4176.  Post stake validation
   367  			// height.
   368  			name: "29th retarget interval, 100% demand",
   369  			ticketInfo: []ticketInfo{
   370  				{256, 0, minStakeDiff},   // 256
   371  				{2047, 20, minStakeDiff}, // 2303
   372  				{144, 20, 208418769},     // 2447
   373  				{144, 20, 231326567},     // 2591
   374  				{144, 20, 272451490},     // 2735
   375  				{144, 20, 339388424},     // 2879
   376  				{144, 20, 445827839},     // 3023
   377  				{144, 20, 615949254},     // 3167
   378  				{144, 20, 892862990},     // 3311
   379  				{144, 20, 1354989669},    // 3455
   380  				{144, 20, 2148473276},    // 3599
   381  				{144, 20, 3552797658},    // 3743
   382  				{144, 20, 6116808441},    // 3887
   383  				{144, 20, 10947547379},   // 4031
   384  				{144, 20, 20338554623},   // 4175
   385  			},
   386  			expectedDiff: 22097687698,
   387  		},
   388  		{
   389  			// Next retarget is at 4176.  Post stake validation
   390  			// height.
   391  			name: "29th retarget interval, 50% demand",
   392  			ticketInfo: []ticketInfo{
   393  				{256, 0, minStakeDiff},   // 256
   394  				{3919, 10, minStakeDiff}, // 4175
   395  			},
   396  			expectedDiff: minStakeDiff,
   397  		},
   398  		{
   399  			// Next retarget is at 4464.  Post stake validation
   400  			// height.
   401  			name: "31st retarget interval, waning demand",
   402  			ticketInfo: []ticketInfo{
   403  				{256, 0, minStakeDiff},   // 256
   404  				{2047, 20, minStakeDiff}, // 2303
   405  				{144, 20, 208418769},     // 2447
   406  				{144, 20, 231326567},     // 2591
   407  				{144, 20, 272451490},     // 2735
   408  				{144, 20, 339388424},     // 2879
   409  				{144, 20, 445827839},     // 3023
   410  				{144, 20, 615949254},     // 3167
   411  				{144, 20, 892862990},     // 3311
   412  				{144, 20, 1354989669},    // 3455
   413  				{144, 20, 2148473276},    // 3599
   414  				{144, 20, 3552797658},    // 3743
   415  				{144, 13, 6116808441},    // 3887
   416  				{144, 0, 10645659768},    // 4031
   417  				{144, 0, 18046712136},    // 4175
   418  				{144, 0, 22097687698},    // 4319
   419  				{144, 0, 22152524112},    // 4463
   420  			},
   421  			expectedDiff: 22207360526,
   422  		},
   423  	}
   424  
   425  nextTest:
   426  	for _, test := range tests {
   427  		bc := newFakeChain(params)
   428  
   429  		// immatureTickets tracks which height the purchased tickets
   430  		// will mature and thus be eligible for admission to the live
   431  		// ticket pool.
   432  		immatureTickets := make(map[uint32]uint8)
   433  		var poolSize uint32
   434  		for _, ticketInfo := range test.ticketInfo {
   435  			// Ensure the test data isn't faking ticket purchases at
   436  			// an incorrect difficulty.
   437  			tip := bc.bestChain.Tip()
   438  			gotDiff, err := bc.calcNextRequiredStakeDifficultyV2(tip)
   439  			if err != nil {
   440  				t.Errorf("calcNextRequiredStakeDifficultyV2 (%s): "+
   441  					"unexpected error: %v", test.name, err)
   442  				continue nextTest
   443  			}
   444  			if gotDiff != ticketInfo.stakeDiff {
   445  				t.Errorf("calcNextRequiredStakeDifficultyV2 (%s): "+
   446  					"did not get expected stake difficulty -- got "+
   447  					"%d, want %d", test.name, gotDiff,
   448  					ticketInfo.stakeDiff)
   449  				continue nextTest
   450  			}
   451  
   452  			for i := uint32(0); i < ticketInfo.numNodes; i++ {
   453  				// Make up a header.
   454  				nextHeight := uint32(tip.height) + 1
   455  				header := &wire.BlockHeader{
   456  					Version:    4,
   457  					SBits:      ticketInfo.stakeDiff,
   458  					Height:     nextHeight,
   459  					FreshStake: ticketInfo.newTickets,
   460  					PoolSize:   poolSize,
   461  				}
   462  				tip = newBlockNode(header, tip)
   463  
   464  				// Update the pool size for the next header.
   465  				// Notice how tickets that mature for this block
   466  				// do not show up in the pool size until the
   467  				// next block.  This is correct behavior.
   468  				poolSize += uint32(immatureTickets[nextHeight])
   469  				delete(immatureTickets, nextHeight)
   470  				if int64(nextHeight) >= stakeValidationHeight {
   471  					poolSize -= uint32(params.TicketsPerBlock)
   472  				}
   473  
   474  				// Track maturity height for new ticket
   475  				// purchases.
   476  				maturityHeight := nextHeight + ticketMaturity
   477  				immatureTickets[maturityHeight] = ticketInfo.newTickets
   478  
   479  				// Update the chain to use the new fake node as
   480  				// the new best node.
   481  				bc.bestChain.SetTip(tip)
   482  			}
   483  		}
   484  
   485  		// Ensure the calculated difficulty matches the expected value.
   486  		gotDiff, err := bc.calcNextRequiredStakeDifficultyV2(bc.bestChain.Tip())
   487  		if err != nil {
   488  			t.Errorf("calcNextRequiredStakeDifficultyV2 (%s): "+
   489  				"unexpected error: %v", test.name, err)
   490  			continue
   491  		}
   492  		if gotDiff != test.expectedDiff {
   493  			t.Errorf("calcNextRequiredStakeDifficultyV2 (%s): "+
   494  				"did not get expected stake difficulty -- got "+
   495  				"%d, want %d", test.name, gotDiff,
   496  				test.expectedDiff)
   497  			continue
   498  		}
   499  	}
   500  }
   501  
   502  // TestEstimateNextStakeDiffV2 ensures the function that estimates the stake
   503  // diff calculation for the algorithm defined by DCP0001 works as expected.
   504  func TestEstimateNextStakeDiffV2(t *testing.T) {
   505  	t.Parallel()
   506  
   507  	// ticketInfo is used to control the tests by specifying the details
   508  	// about how many fake blocks to create with the specified number of
   509  	// tickets and stake difficulty.
   510  	type ticketInfo struct {
   511  		numNodes   uint32
   512  		newTickets uint8
   513  		stakeDiff  int64
   514  	}
   515  
   516  	// Assert the param values directly used by the tests are the expected
   517  	// ones.  All of the test values will need to be updated if these
   518  	// parameters change since they are manually calculated based on them.
   519  	mainNetParams := &chaincfg.MainNetParams
   520  	testNetParams := &chaincfg.TestNet3Params
   521  	assertStakeDiffParamsMainNet(t, mainNetParams)
   522  	assertStakeDiffParamsTestNet(t, testNetParams)
   523  	minStakeDiffMainNet := mainNetParams.MinimumStakeDiff
   524  	minStakeDiffTestNet := testNetParams.MinimumStakeDiff
   525  
   526  	tests := []struct {
   527  		name          string
   528  		params        *chaincfg.Params
   529  		ticketInfo    []ticketInfo
   530  		newTickets    int64
   531  		useMaxTickets bool
   532  		expectedDiff  int64
   533  	}{
   534  		{
   535  			// Regardless of claiming tickets will be purchased, the
   536  			// resulting stake difficulty should be the minimum
   537  			// because the first retarget is before the start
   538  			// height.
   539  			name:          "genesis block",
   540  			params:        mainNetParams,
   541  			ticketInfo:    []ticketInfo{{0, 0, minStakeDiffMainNet}},
   542  			newTickets:    2860,
   543  			useMaxTickets: false,
   544  			expectedDiff:  minStakeDiffMainNet,
   545  		},
   546  		{
   547  			// Next retarget is 144.  Resulting stake difficulty
   548  			// should be the minimum regardless of claimed ticket
   549  			// purchases because the previous pool size is still 0.
   550  			name:          "during retarget, but before coinbase",
   551  			params:        mainNetParams,
   552  			ticketInfo:    []ticketInfo{{140, 0, minStakeDiffMainNet}},
   553  			newTickets:    20 * 3, // blocks 141, 142, and 143.
   554  			useMaxTickets: true,
   555  			expectedDiff:  minStakeDiffMainNet,
   556  		},
   557  		{
   558  			// Next retarget is at 288.  Regardless of claiming
   559  			// tickets will be purchased, the resulting stake
   560  			// difficulty should be the min because the previous
   561  			// pool size is still 0.
   562  			name:          "at coinbase maturity",
   563  			params:        mainNetParams,
   564  			ticketInfo:    []ticketInfo{{256, 0, minStakeDiffMainNet}},
   565  			useMaxTickets: true,
   566  			expectedDiff:  minStakeDiffMainNet,
   567  		},
   568  		{
   569  			// Next retarget is at 288.  Regardless of actually
   570  			// purchasing tickets and claiming more tickets will be
   571  			// purchased, the resulting stake difficulty should be
   572  			// the min because the previous pool size is still 0.
   573  			name:   "2nd retarget interval - 2, 100% demand",
   574  			params: mainNetParams,
   575  			ticketInfo: []ticketInfo{
   576  				{256, 0, minStakeDiffMainNet}, // 256
   577  				{30, 20, minStakeDiffMainNet}, // 286
   578  			},
   579  			useMaxTickets: true,
   580  			expectedDiff:  minStakeDiffMainNet,
   581  		},
   582  		{
   583  			// Next retarget is at 288.  Still expect minimum stake
   584  			// difficulty since the raw result would be lower.
   585  			name:   "2nd retarget interval - 1, 100% demand",
   586  			params: mainNetParams,
   587  			ticketInfo: []ticketInfo{
   588  				{256, 0, minStakeDiffMainNet}, // 256
   589  				{31, 20, minStakeDiffMainNet}, // 287
   590  			},
   591  			useMaxTickets: true,
   592  			expectedDiff:  minStakeDiffMainNet,
   593  		},
   594  		{
   595  			// Next retarget is at 432.
   596  			name:   "3rd retarget interval, 100% demand, 1st block",
   597  			params: mainNetParams,
   598  			ticketInfo: []ticketInfo{
   599  				{256, 0, minStakeDiffMainNet}, // 256
   600  				{32, 20, minStakeDiffMainNet}, // 288
   601  			},
   602  			useMaxTickets: true,
   603  			expectedDiff:  minStakeDiffMainNet,
   604  		},
   605  		{
   606  			// Next retarget is at 2304.
   607  			name:   "16th retarget interval, 100% demand, 1st block",
   608  			params: mainNetParams,
   609  			ticketInfo: []ticketInfo{
   610  				{256, 0, minStakeDiffMainNet},   // 256
   611  				{1904, 20, minStakeDiffMainNet}, // 2160
   612  			},
   613  			useMaxTickets: true,
   614  			expectedDiff:  208418769,
   615  		},
   616  		{
   617  			// Next retarget is at 2304.
   618  			name:   "16th retarget interval, 100% demand, 2nd block",
   619  			params: mainNetParams,
   620  			ticketInfo: []ticketInfo{
   621  				{256, 0, minStakeDiffMainNet},   // 256
   622  				{1905, 20, minStakeDiffMainNet}, // 2161
   623  			},
   624  			useMaxTickets: true,
   625  			expectedDiff:  208418769,
   626  		},
   627  		{
   628  			// Next retarget is at 2304.
   629  			name:   "16th retarget interval, 100% demand, final block",
   630  			params: mainNetParams,
   631  			ticketInfo: []ticketInfo{
   632  				{256, 0, minStakeDiffMainNet},   // 256
   633  				{2047, 20, minStakeDiffMainNet}, // 2303
   634  			},
   635  			useMaxTickets: true,
   636  			expectedDiff:  208418769,
   637  		},
   638  		{
   639  			// Next retarget is at 3456.
   640  			name:   "24th retarget interval, varying demand, 5th block",
   641  			params: mainNetParams,
   642  			ticketInfo: []ticketInfo{
   643  				{256, 0, minStakeDiffMainNet},  // 256
   644  				{31, 20, minStakeDiffMainNet},  // 287
   645  				{144, 10, minStakeDiffMainNet}, // 431
   646  				{144, 20, minStakeDiffMainNet}, // 575
   647  				{144, 10, minStakeDiffMainNet}, // 719
   648  				{144, 20, minStakeDiffMainNet}, // 863
   649  				{144, 10, minStakeDiffMainNet}, // 1007
   650  				{144, 20, minStakeDiffMainNet}, // 1151
   651  				{144, 10, minStakeDiffMainNet}, // 1295
   652  				{144, 20, minStakeDiffMainNet}, // 1439
   653  				{144, 10, minStakeDiffMainNet}, // 1583
   654  				{144, 20, minStakeDiffMainNet}, // 1727
   655  				{144, 10, minStakeDiffMainNet}, // 1871
   656  				{144, 20, minStakeDiffMainNet}, // 2015
   657  				{144, 10, minStakeDiffMainNet}, // 2159
   658  				{144, 20, minStakeDiffMainNet}, // 2303
   659  				{144, 10, minStakeDiffMainNet}, // 2447
   660  				{144, 20, minStakeDiffMainNet}, // 2591
   661  				{144, 10, minStakeDiffMainNet}, // 2735
   662  				{144, 20, minStakeDiffMainNet}, // 2879
   663  				{144, 9, 201743368},            // 3023
   664  				{144, 20, 201093236},           // 3167
   665  				{144, 8, 222625877},            // 3311
   666  				{5, 20, 242331291},             // 3316
   667  			},
   668  			useMaxTickets: true,
   669  			expectedDiff:  291317641,
   670  		},
   671  		{
   672  			// Next retarget is at 4176.  Post stake validation
   673  			// height.
   674  			name:   "29th retarget interval, 100% demand, 10th block",
   675  			params: mainNetParams,
   676  			ticketInfo: []ticketInfo{
   677  				{256, 0, minStakeDiffMainNet},   // 256
   678  				{2047, 20, minStakeDiffMainNet}, // 2303
   679  				{144, 20, 208418769},            // 2447
   680  				{144, 20, 231326567},            // 2591
   681  				{144, 20, 272451490},            // 2735
   682  				{144, 20, 339388424},            // 2879
   683  				{144, 20, 445827839},            // 3023
   684  				{144, 20, 615949254},            // 3167
   685  				{144, 20, 892862990},            // 3311
   686  				{144, 20, 1354989669},           // 3455
   687  				{144, 20, 2148473276},           // 3599
   688  				{144, 20, 3552797658},           // 3743
   689  				{144, 20, 6116808441},           // 3887
   690  				{144, 20, 10947547379},          // 4031
   691  				{10, 20, 20338554623},           // 4041
   692  			},
   693  			useMaxTickets: true,
   694  			expectedDiff:  22097687698,
   695  		},
   696  		{
   697  			// Next retarget is at 4176.  Post stake validation
   698  			// height.
   699  			name:   "29th retarget interval, 50% demand, 23rd block",
   700  			params: mainNetParams,
   701  			ticketInfo: []ticketInfo{
   702  				{256, 0, minStakeDiffMainNet},   // 256
   703  				{3775, 10, minStakeDiffMainNet}, // 4031
   704  				{23, 10, minStakeDiffMainNet},   // 4054
   705  			},
   706  			newTickets:    1210, // 121 * 10
   707  			useMaxTickets: false,
   708  			expectedDiff:  minStakeDiffMainNet,
   709  		},
   710  		{
   711  			// Next retarget is at 4464.  Post stake validation
   712  			// height.
   713  			name:   "31st retarget interval, waning demand, 117th block",
   714  			params: mainNetParams,
   715  			ticketInfo: []ticketInfo{
   716  				{256, 0, minStakeDiffMainNet},   // 256
   717  				{2047, 20, minStakeDiffMainNet}, // 2303
   718  				{144, 20, 208418769},            // 2447
   719  				{144, 20, 231326567},            // 2591
   720  				{144, 20, 272451490},            // 2735
   721  				{144, 20, 339388424},            // 2879
   722  				{144, 20, 445827839},            // 3023
   723  				{144, 20, 615949254},            // 3167
   724  				{144, 20, 892862990},            // 3311
   725  				{144, 20, 1354989669},           // 3455
   726  				{144, 20, 2148473276},           // 3599
   727  				{144, 20, 3552797658},           // 3743
   728  				{144, 13, 6116808441},           // 3887
   729  				{144, 0, 10645659768},           // 4031
   730  				{144, 0, 18046712136},           // 4175
   731  				{144, 0, 22097687698},           // 4319
   732  				{117, 0, 22152524112},           // 4436
   733  			},
   734  			useMaxTickets: false,
   735  			newTickets:    0,
   736  			expectedDiff:  22207360526,
   737  		},
   738  		// --------------------------
   739  		// TestNet params start here.
   740  		// --------------------------
   741  		{
   742  			// Regardless of claiming tickets will be purchased, the
   743  			// resulting stake difficulty should be the minimum
   744  			// because the first retarget is before the start
   745  			// height.
   746  			name:          "genesis block",
   747  			params:        testNetParams,
   748  			ticketInfo:    []ticketInfo{{0, 0, minStakeDiffTestNet}},
   749  			newTickets:    2860,
   750  			useMaxTickets: false,
   751  			expectedDiff:  minStakeDiffTestNet,
   752  		},
   753  		{
   754  			// Next retarget is at 144.  Regardless of claiming
   755  			// tickets will be purchased, the resulting stake
   756  			// difficulty should be the min because the previous
   757  			// pool size is still 0.
   758  			name:          "at coinbase maturity",
   759  			params:        testNetParams,
   760  			ticketInfo:    []ticketInfo{{16, 0, minStakeDiffTestNet}},
   761  			useMaxTickets: true,
   762  			expectedDiff:  minStakeDiffTestNet,
   763  		},
   764  		{
   765  			// Next retarget is at 144.  Regardless of actually
   766  			// purchasing tickets and claiming more tickets will be
   767  			// purchased, the resulting stake difficulty should be
   768  			// the min because the previous pool size is still 0.
   769  			name:   "1st retarget interval - 2, 100% demand",
   770  			params: testNetParams,
   771  			ticketInfo: []ticketInfo{
   772  				{16, 0, minStakeDiffTestNet},   // 16
   773  				{126, 20, minStakeDiffTestNet}, // 142
   774  			},
   775  			useMaxTickets: true,
   776  			expectedDiff:  minStakeDiffTestNet,
   777  		},
   778  		{
   779  			// Next retarget is at 288.  Still expect minimum stake
   780  			// difficulty since the raw result would be lower.
   781  			name:   "2nd retarget interval - 1, 30% demand",
   782  			params: testNetParams,
   783  			ticketInfo: []ticketInfo{
   784  				{16, 0, minStakeDiffTestNet},  // 16
   785  				{271, 6, minStakeDiffTestNet}, // 287
   786  			},
   787  			useMaxTickets: true,
   788  			expectedDiff:  minStakeDiffTestNet,
   789  		},
   790  		{
   791  			// Next retarget is at 288.  Still expect minimum stake
   792  			// difficulty since the raw result would be lower.
   793  			//
   794  			// Since the ticket maturity is smaller than the
   795  			// retarget interval, this case ensures some of the
   796  			// nodes being estimated will mature during the
   797  			// interval.
   798  			name:   "2nd retarget interval - 23, 30% demand",
   799  			params: testNetParams,
   800  			ticketInfo: []ticketInfo{
   801  				{16, 0, minStakeDiffTestNet},  // 16
   802  				{249, 6, minStakeDiffTestNet}, // 265
   803  			},
   804  			newTickets:    132, // 22 * 6
   805  			useMaxTickets: false,
   806  			expectedDiff:  minStakeDiffTestNet,
   807  		},
   808  		{
   809  			// Next retarget is at 288.  Still expect minimum stake
   810  			// difficulty since the raw result would be lower.
   811  			//
   812  			// None of the nodes being estimated will mature during the
   813  			// interval.
   814  			name:   "2nd retarget interval - 11, 30% demand",
   815  			params: testNetParams,
   816  			ticketInfo: []ticketInfo{
   817  				{16, 0, minStakeDiffTestNet},  // 16
   818  				{261, 6, minStakeDiffTestNet}, // 277
   819  			},
   820  			newTickets:    60, // 10 * 6
   821  			useMaxTickets: false,
   822  			expectedDiff:  minStakeDiffTestNet,
   823  		},
   824  		{
   825  			// Next retarget is at 432.
   826  			name:   "3rd retarget interval, 100% demand, 1st block",
   827  			params: testNetParams,
   828  			ticketInfo: []ticketInfo{
   829  				{16, 0, minStakeDiffTestNet},   // 16
   830  				{256, 20, minStakeDiffTestNet}, // 288
   831  			},
   832  			useMaxTickets: true,
   833  			expectedDiff:  44505494,
   834  		},
   835  		{
   836  			// Next retarget is at 432.
   837  			//
   838  			// None of the nodes being estimated will mature during the
   839  			// interval.
   840  			name:   "3rd retarget interval - 11, 100% demand",
   841  			params: testNetParams,
   842  			ticketInfo: []ticketInfo{
   843  				{16, 0, minStakeDiffTestNet},   // 16
   844  				{271, 20, minStakeDiffTestNet}, // 287
   845  				{134, 20, 44505494},            // 421
   846  			},
   847  			useMaxTickets: true,
   848  			expectedDiff:  108661875,
   849  		},
   850  		{
   851  			// Next retarget is at 576.
   852  			name:   "4th retarget interval, 100% demand, 1st block",
   853  			params: testNetParams,
   854  			ticketInfo: []ticketInfo{
   855  				{16, 0, minStakeDiffTestNet},   // 16
   856  				{271, 20, minStakeDiffTestNet}, // 287
   857  				{144, 20, 44505494},            // 431
   858  				{1, 20, 108661875},             // 432
   859  			},
   860  			useMaxTickets: true,
   861  			expectedDiff:  314319918,
   862  		},
   863  		{
   864  			// Next retarget is at 576.
   865  			name:   "4th retarget interval, 100% demand, 2nd block",
   866  			params: testNetParams,
   867  			ticketInfo: []ticketInfo{
   868  				{16, 0, minStakeDiffTestNet},   // 16
   869  				{271, 20, minStakeDiffTestNet}, // 287
   870  				{144, 20, 44505494},            // 431
   871  				{2, 20, 108661875},             // 433
   872  			},
   873  			useMaxTickets: true,
   874  			expectedDiff:  314319918,
   875  		},
   876  		{
   877  			// Next retarget is at 576.
   878  			name:   "4th retarget interval, 100% demand, final block",
   879  			params: testNetParams,
   880  			ticketInfo: []ticketInfo{
   881  				{16, 0, minStakeDiffTestNet},   // 16
   882  				{271, 20, minStakeDiffTestNet}, // 287
   883  				{144, 20, 44505494},            // 431
   884  				{144, 20, 108661875},           // 575
   885  			},
   886  			useMaxTickets: true,
   887  			expectedDiff:  314319918,
   888  		},
   889  		{
   890  			// Next retarget is at 1152.
   891  			name:   "9th retarget interval, varying demand, 137th block",
   892  			params: testNetParams,
   893  			ticketInfo: []ticketInfo{
   894  				{16, 0, minStakeDiffTestNet},   // 16
   895  				{127, 20, minStakeDiffTestNet}, // 143
   896  				{144, 10, minStakeDiffTestNet}, // 287
   897  				{144, 20, 24055097},            // 431
   898  				{144, 10, 54516186},            // 575
   899  				{144, 20, 105335577},           // 719
   900  				{144, 10, 304330579},           // 863
   901  				{144, 20, 772249463},           // 1007
   902  				{76, 10, 2497324513},           // 1083
   903  				{9, 0, 2497324513},             // 1092
   904  				{1, 10, 2497324513},            // 1093
   905  				{8, 0, 2497324513},             // 1101
   906  				{1, 10, 2497324513},            // 1102
   907  				{12, 0, 2497324513},            // 1114
   908  				{1, 10, 2497324513},            // 1115
   909  				{9, 0, 2497324513},             // 1124
   910  				{1, 10, 2497324513},            // 1125
   911  				{8, 0, 2497324513},             // 1133
   912  				{1, 10, 2497324513},            // 1134
   913  				{10, 0, 2497324513},            // 1144
   914  			},
   915  			useMaxTickets: false,
   916  			newTickets:    10,
   917  			expectedDiff:  6976183842,
   918  		},
   919  		{
   920  			// Next retarget is at 1440.  The estimated number of
   921  			// tickets are such that they span the ticket maturity
   922  			// floor so that the estimation result is slightly
   923  			// different as compared to what it would be if each
   924  			// remaining node only had 10 ticket purchases.  This is
   925  			// because it results in a different number of maturing
   926  			// tickets depending on how they are allocated on each
   927  			// side of the maturity floor.
   928  			name:   "11th retarget interval, 50% demand, 127th block",
   929  			params: testNetParams,
   930  			ticketInfo: []ticketInfo{
   931  				{16, 0, minStakeDiffTestNet},   // 16
   932  				{271, 10, minStakeDiffTestNet}, // 287
   933  				{144, 10, 22252747},            // 431
   934  				{144, 10, 27165468},            // 575
   935  				{144, 10, 39289988},            // 719
   936  				{144, 10, 66729608},            // 863
   937  				{144, 10, 116554208},           // 1007
   938  				{144, 10, 212709675},           // 1151
   939  				{144, 10, 417424410},           // 1295
   940  				{127, 10, 876591473},           // 1422
   941  			},
   942  			useMaxTickets: false,
   943  			newTickets:    170, // 17 * 10
   944  			expectedDiff:  1965171141,
   945  		},
   946  		{
   947  			// Next retarget is at 1440.  This is similar to the
   948  			// last test except all of the estimated tickets are
   949  			// after the ticket maturity floor, so the estimate is
   950  			// the same as if each remaining node only had 10 ticket
   951  			// purchases.
   952  			name:   "11th retarget interval, 50% demand, 128th block",
   953  			params: testNetParams,
   954  			ticketInfo: []ticketInfo{
   955  				{16, 0, minStakeDiffTestNet},   // 16
   956  				{271, 10, minStakeDiffTestNet}, // 287
   957  				{144, 10, 22252747},            // 431
   958  				{144, 10, 27165468},            // 575
   959  				{144, 10, 39289988},            // 719
   960  				{144, 10, 66729608},            // 863
   961  				{144, 10, 116554208},           // 1007
   962  				{144, 10, 212709675},           // 1151
   963  				{144, 10, 417424410},           // 1295
   964  				{128, 10, 876591473},           // 1423
   965  			},
   966  			useMaxTickets: false,
   967  			newTickets:    160, // 16 * 10
   968  			expectedDiff:  1961558695,
   969  		},
   970  	}
   971  
   972  nextTest:
   973  	for _, test := range tests {
   974  		stakeValidationHeight := test.params.StakeValidationHeight
   975  		ticketMaturity := uint32(test.params.TicketMaturity)
   976  		ticketsPerBlock := uint32(test.params.TicketsPerBlock)
   977  
   978  		bc := newFakeChain(test.params)
   979  
   980  		// immatureTickets track which height the purchased tickets will
   981  		// mature and thus be eligible for admission to the live ticket
   982  		// pool.
   983  		immatureTickets := make(map[uint32]uint8)
   984  		var poolSize uint32
   985  		for _, ticketInfo := range test.ticketInfo {
   986  			// Ensure the test data isn't faking ticket purchases at
   987  			// an incorrect difficulty.
   988  			tip := bc.bestChain.Tip()
   989  			reqDiff, err := bc.calcNextRequiredStakeDifficultyV2(tip)
   990  			if err != nil {
   991  				t.Errorf("calcNextRequiredStakeDifficultyV2 (%s): "+
   992  					"unexpected error: %v", test.name, err)
   993  				continue nextTest
   994  			}
   995  			if ticketInfo.stakeDiff != reqDiff {
   996  				t.Errorf("calcNextRequiredStakeDifficultyV2 (%s): "+
   997  					"test data has incorrect stake difficulty: "+
   998  					"has %d, requires %d", test.name,
   999  					ticketInfo.stakeDiff, reqDiff)
  1000  				continue nextTest
  1001  			}
  1002  
  1003  			for i := uint32(0); i < ticketInfo.numNodes; i++ {
  1004  				// Make up a header.
  1005  				nextHeight := uint32(tip.height) + 1
  1006  				header := &wire.BlockHeader{
  1007  					Version:    4,
  1008  					SBits:      ticketInfo.stakeDiff,
  1009  					Height:     nextHeight,
  1010  					FreshStake: ticketInfo.newTickets,
  1011  					PoolSize:   poolSize,
  1012  				}
  1013  				tip = newBlockNode(header, tip)
  1014  
  1015  				// Update the pool size for the next header.
  1016  				// Notice how tickets that mature for this block
  1017  				// do not show up in the pool size until the
  1018  				// next block.  This is correct behavior.
  1019  				poolSize += uint32(immatureTickets[nextHeight])
  1020  				delete(immatureTickets, nextHeight)
  1021  				if int64(nextHeight) >= stakeValidationHeight {
  1022  					poolSize -= ticketsPerBlock
  1023  				}
  1024  
  1025  				// Track maturity height for new ticket
  1026  				// purchases.
  1027  				maturityHeight := nextHeight + ticketMaturity
  1028  				immatureTickets[maturityHeight] = ticketInfo.newTickets
  1029  
  1030  				// Update the chain to use the new fake node as
  1031  				// the new best node.
  1032  				bc.bestChain.SetTip(tip)
  1033  			}
  1034  		}
  1035  
  1036  		// Ensure the calculated difficulty matches the expected value.
  1037  		gotDiff, err := bc.estimateNextStakeDifficultyV2(bc.bestChain.Tip(),
  1038  			test.newTickets, test.useMaxTickets)
  1039  		if err != nil {
  1040  			t.Errorf("estimateNextStakeDifficultyV2 (%s): "+
  1041  				"unexpected error: %v", test.name, err)
  1042  			continue
  1043  		}
  1044  		if gotDiff != test.expectedDiff {
  1045  			t.Errorf("estimateNextStakeDifficultyV2 (%s): did not "+
  1046  				"get expected stake difficulty -- got %d, "+
  1047  				"want %d", test.name, gotDiff, test.expectedDiff)
  1048  			continue
  1049  		}
  1050  	}
  1051  }
  1052  
  1053  // TestMinDifficultyReduction ensures the code which results in reducing the
  1054  // minimum required difficulty, when the network params allow it, works as
  1055  // expected.
  1056  func TestMinDifficultyReduction(t *testing.T) {
  1057  	// Create chain params based on regnet params, but set the fields related to
  1058  	// proof-of-work difficulty to specific values expected by the tests.
  1059  	params := chaincfg.RegNetParams
  1060  	params.ReduceMinDifficulty = true
  1061  	params.TargetTimePerBlock = time.Minute * 2
  1062  	params.MinDiffReductionTime = time.Minute * 10 // ~99.3% chance to be mined
  1063  	params.WorkDiffAlpha = 1
  1064  	params.WorkDiffWindowSize = 144
  1065  	params.WorkDiffWindows = 20
  1066  	params.TargetTimespan = params.TargetTimePerBlock *
  1067  		time.Duration(params.WorkDiffWindowSize)
  1068  	params.RetargetAdjustmentFactor = 4
  1069  
  1070  	tests := []struct {
  1071  		name           string
  1072  		timeAdjustment func(i int) time.Duration
  1073  		numBlocks      int64
  1074  		expectedDiff   func(i int) uint32
  1075  	}{
  1076  		{
  1077  			name:           "genesis block",
  1078  			timeAdjustment: func(i int) time.Duration { return time.Second },
  1079  			numBlocks:      1,
  1080  			expectedDiff:   func(i int) uint32 { return params.PowLimitBits },
  1081  		},
  1082  		{
  1083  			name:           "create difficulty spike - part 1",
  1084  			timeAdjustment: func(i int) time.Duration { return time.Second },
  1085  			numBlocks:      params.WorkDiffWindowSize - 2,
  1086  			expectedDiff:   func(i int) uint32 { return 545259519 },
  1087  		},
  1088  		{
  1089  			name:           "create difficulty spike - part 2",
  1090  			timeAdjustment: func(i int) time.Duration { return time.Second },
  1091  			numBlocks:      params.WorkDiffWindowSize,
  1092  			expectedDiff:   func(i int) uint32 { return 545259519 },
  1093  		},
  1094  		{
  1095  			name:           "create difficulty spike - part 3",
  1096  			timeAdjustment: func(i int) time.Duration { return time.Second },
  1097  			numBlocks:      params.WorkDiffWindowSize,
  1098  			expectedDiff:   func(i int) uint32 { return 541100164 },
  1099  		},
  1100  		{
  1101  			name:           "create difficulty spike - part 4",
  1102  			timeAdjustment: func(i int) time.Duration { return time.Second },
  1103  			numBlocks:      params.WorkDiffWindowSize,
  1104  			expectedDiff:   func(i int) uint32 { return 537954654 },
  1105  		},
  1106  		{
  1107  			name:           "create difficulty spike - part 5",
  1108  			timeAdjustment: func(i int) time.Duration { return time.Second },
  1109  			numBlocks:      params.WorkDiffWindowSize,
  1110  			expectedDiff:   func(i int) uint32 { return 537141847 },
  1111  		},
  1112  		{
  1113  			name:           "create difficulty spike - part 6",
  1114  			timeAdjustment: func(i int) time.Duration { return time.Second },
  1115  			numBlocks:      params.WorkDiffWindowSize,
  1116  			expectedDiff:   func(i int) uint32 { return 536938645 },
  1117  		},
  1118  		{
  1119  			name:           "create difficulty spike - part 7",
  1120  			timeAdjustment: func(i int) time.Duration { return time.Second },
  1121  			numBlocks:      params.WorkDiffWindowSize,
  1122  			expectedDiff:   func(i int) uint32 { return 524428608 },
  1123  		},
  1124  		{
  1125  			name:           "create difficulty spike - part 8",
  1126  			timeAdjustment: func(i int) time.Duration { return time.Second },
  1127  			numBlocks:      params.WorkDiffWindowSize,
  1128  			expectedDiff:   func(i int) uint32 { return 521177424 },
  1129  		},
  1130  		{
  1131  			name:           "create difficulty spike - part 9",
  1132  			timeAdjustment: func(i int) time.Duration { return time.Second },
  1133  			numBlocks:      params.WorkDiffWindowSize,
  1134  			expectedDiff:   func(i int) uint32 { return 520364628 },
  1135  		},
  1136  		{
  1137  			name:           "create difficulty spike - part 10",
  1138  			timeAdjustment: func(i int) time.Duration { return time.Second },
  1139  			numBlocks:      params.WorkDiffWindowSize,
  1140  			expectedDiff:   func(i int) uint32 { return 520161429 },
  1141  		},
  1142  		{
  1143  			name: "alternate min diff blocks",
  1144  			timeAdjustment: func(i int) time.Duration {
  1145  				if i%2 == 0 {
  1146  					return params.MinDiffReductionTime + time.Second
  1147  				}
  1148  				return params.TargetTimePerBlock
  1149  			},
  1150  			numBlocks: params.WorkDiffWindowSize,
  1151  			expectedDiff: func(i int) uint32 {
  1152  				if i%2 == 0 && i != 0 {
  1153  					return params.PowLimitBits
  1154  				}
  1155  				return 507651392
  1156  			},
  1157  		},
  1158  		{
  1159  			name: "interval of blocks taking twice the target time - part 1",
  1160  			timeAdjustment: func(i int) time.Duration {
  1161  				return params.TargetTimePerBlock * 2
  1162  			},
  1163  			numBlocks:    params.WorkDiffWindowSize,
  1164  			expectedDiff: func(i int) uint32 { return 509850141 },
  1165  		},
  1166  		{
  1167  			name: "interval of blocks taking twice the target time - part 2",
  1168  			timeAdjustment: func(i int) time.Duration {
  1169  				return params.TargetTimePerBlock * 2
  1170  			},
  1171  			numBlocks:    params.WorkDiffWindowSize,
  1172  			expectedDiff: func(i int) uint32 { return 520138451 },
  1173  		},
  1174  		{
  1175  			name: "interval of blocks taking twice the target time - part 3",
  1176  			timeAdjustment: func(i int) time.Duration {
  1177  				return params.TargetTimePerBlock * 2
  1178  			},
  1179  			numBlocks:    params.WorkDiffWindowSize,
  1180  			expectedDiff: func(i int) uint32 { return 520177692 },
  1181  		},
  1182  	}
  1183  
  1184  	bc := newFakeChain(&params)
  1185  	node := bc.bestChain.Tip()
  1186  	blockTime := time.Unix(node.timestamp, 0)
  1187  	for _, test := range tests {
  1188  		for i := 0; i < int(test.numBlocks); i++ {
  1189  			// Update the block time according to the test data and calculate
  1190  			// the difficulty for the next block.
  1191  			blockTime = blockTime.Add(test.timeAdjustment(i))
  1192  			diff, err := bc.calcNextRequiredDifficulty(node, blockTime)
  1193  			if err != nil {
  1194  				t.Fatalf("calcNextRequiredDifficulty: unexpected err: %v", err)
  1195  			}
  1196  
  1197  			// Ensure the calculated difficulty matches the expected value.
  1198  			expectedDiff := test.expectedDiff(i)
  1199  			if diff != expectedDiff {
  1200  				t.Fatalf("calcNextRequiredDifficulty (%s): did not get "+
  1201  					"expected difficulty -- got %d, want %d", test.name, diff,
  1202  					expectedDiff)
  1203  			}
  1204  
  1205  			node = newFakeNode(node, 1, 1, diff, blockTime)
  1206  			bc.index.AddNode(node)
  1207  			bc.bestChain.SetTip(node)
  1208  		}
  1209  	}
  1210  }