github.com/deso-protocol/core@v1.2.9/lib/supply_test.go (about)

     1  package lib
     2  
     3  import (
     4  	"fmt"
     5  	"math"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/stretchr/testify/assert"
    10  	"github.com/stretchr/testify/require"
    11  )
    12  
    13  const (
    14  	satoshisPerBitcoin = 100000000
    15  )
    16  
    17  func TestTotalMiningSupply(t *testing.T) {
    18  	require := require.New(t)
    19  
    20  	// Sum all of the mining intervals to make sure there is no overflow.
    21  	totalMiningSupply := uint64(0)
    22  	for intervalIndex, currentInterval := range MiningSupplyIntervals {
    23  		if intervalIndex == 0 {
    24  			// Skip the first index
    25  			continue
    26  		}
    27  		prevInterval := MiningSupplyIntervals[intervalIndex-1]
    28  		blockRewardNanos := prevInterval.BlockRewardNanos
    29  		numBlocksInInterval := currentInterval.StartBlockHeight - prevInterval.StartBlockHeight
    30  
    31  		numNanosMinedInInterval := blockRewardNanos * uint64(numBlocksInInterval)
    32  		totalMiningSupply += numNanosMinedInInterval
    33  	}
    34  	require.Equal(int64(276238800000000), int64(totalMiningSupply))
    35  }
    36  
    37  func TestCalcBlockReward(t *testing.T) {
    38  	require := require.New(t)
    39  
    40  	blocksPerYear := (time.Hour * 24 * 365 / DeSoMainnetParams.TimeBetweenBlocks)
    41  	require.Equal(int64(blocksPerYear), int64(BlocksPerYear))
    42  
    43  	require.Equal(1*NanosPerUnit, CalcBlockRewardNanos(0))
    44  	require.Equal(1*NanosPerUnit, CalcBlockRewardNanos(1))
    45  
    46  	// .75
    47  	require.Equal(1*NanosPerUnit, CalcBlockRewardNanos(DeflationBombBlockRewardAdjustmentBlockHeight-1))
    48  	require.Equal(int64(float64(NanosPerUnit) * .75), int64(CalcBlockRewardNanos(DeflationBombBlockRewardAdjustmentBlockHeight)))
    49  	// .5
    50  	require.Equal(int64(float64(NanosPerUnit) * .75), int64(CalcBlockRewardNanos(DeflationBombBlockRewardAdjustmentBlockHeight + 288 - 1)))
    51  	require.Equal(int64(float64(NanosPerUnit) * .5), int64(CalcBlockRewardNanos(DeflationBombBlockRewardAdjustmentBlockHeight + 288)))
    52  	// .25
    53  	require.Equal(int64(float64(NanosPerUnit) * .5), int64(CalcBlockRewardNanos(DeflationBombBlockRewardAdjustmentBlockHeight + 2*288 - 1)))
    54  	require.Equal(int64(float64(NanosPerUnit) * .25), int64(CalcBlockRewardNanos(DeflationBombBlockRewardAdjustmentBlockHeight + 2*288)))
    55  	// .125
    56  	require.Equal(int64(float64(NanosPerUnit) * .25), int64(CalcBlockRewardNanos(DeflationBombBlockRewardAdjustmentBlockHeight + 3*288 - 1)))
    57  	require.Equal(int64(float64(NanosPerUnit) * .125), int64(CalcBlockRewardNanos(DeflationBombBlockRewardAdjustmentBlockHeight + 3*288)))
    58  	// .1
    59  	require.Equal(int64(float64(NanosPerUnit) * .125), int64(CalcBlockRewardNanos(DeflationBombBlockRewardAdjustmentBlockHeight + 4*288 - 1)))
    60  	require.Equal(int64(float64(NanosPerUnit) * .1), int64(CalcBlockRewardNanos(DeflationBombBlockRewardAdjustmentBlockHeight + 4*288)))
    61  
    62  	// .05
    63  	require.Equal(int64(1*NanosPerUnit/10), int64(CalcBlockRewardNanos(15*BlocksPerYear-1)))
    64  	require.Equal(NanosPerUnit/20, CalcBlockRewardNanos(15*BlocksPerYear))
    65  	require.Equal(NanosPerUnit/20, CalcBlockRewardNanos(15*BlocksPerYear+1))
    66  	// 0
    67  	require.Equal(NanosPerUnit/20, CalcBlockRewardNanos(32*BlocksPerYear-1))
    68  	require.Equal(uint64(0), CalcBlockRewardNanos(32*BlocksPerYear))
    69  	require.Equal(uint64(0), CalcBlockRewardNanos(32*BlocksPerYear+1))
    70  	require.Equal(uint64(0), CalcBlockRewardNanos(35*BlocksPerYear+1))
    71  	require.Equal(uint64(0), CalcBlockRewardNanos(math.MaxUint32))
    72  }
    73  
    74  func TestGetPrice(t *testing.T) {
    75  	oldInitialUSDCentsPerBitcoinExchangeRate := InitialUSDCentsPerBitcoinExchangeRate
    76  	InitialUSDCentsPerBitcoinExchangeRate = 1350000
    77  	defer func() {
    78  		InitialUSDCentsPerBitcoinExchangeRate = oldInitialUSDCentsPerBitcoinExchangeRate
    79  	}()
    80  	assert := assert.New(t)
    81  	{
    82  		startPriceSatoshis := GetStartPriceSatoshisPerDeSo(InitialUSDCentsPerBitcoinExchangeRate)
    83  		assert.Equal(int64(startPriceSatoshis), int64(GetSatoshisPerUnitExchangeRate(0, InitialUSDCentsPerBitcoinExchangeRate)))
    84  		assert.Equal(int64(startPriceSatoshis), int64(GetSatoshisPerUnitExchangeRate(1, InitialUSDCentsPerBitcoinExchangeRate)))
    85  		assert.Equal(int64(startPriceSatoshis), int64(GetSatoshisPerUnitExchangeRate(10, InitialUSDCentsPerBitcoinExchangeRate)))
    86  		assert.Equal(int64(startPriceSatoshis), int64(GetSatoshisPerUnitExchangeRate(1000, InitialUSDCentsPerBitcoinExchangeRate)))
    87  		assert.Equal(int64(startPriceSatoshis), int64(GetSatoshisPerUnitExchangeRate(1000000000, InitialUSDCentsPerBitcoinExchangeRate)))
    88  		assert.Equal(int64(startPriceSatoshis), int64(GetSatoshisPerUnitExchangeRate(10000000000, InitialUSDCentsPerBitcoinExchangeRate)))
    89  		assert.Equal(int64(startPriceSatoshis), int64(GetSatoshisPerUnitExchangeRate(100000000000, InitialUSDCentsPerBitcoinExchangeRate)))
    90  		assert.Equal(int64(startPriceSatoshis+2), int64(GetSatoshisPerUnitExchangeRate(1000*NanosPerUnit, InitialUSDCentsPerBitcoinExchangeRate)))
    91  		assert.Equal(int64(2*startPriceSatoshis), int64(GetSatoshisPerUnitExchangeRate(1000000*NanosPerUnit, InitialUSDCentsPerBitcoinExchangeRate)))
    92  		assert.Equal(int64(16135), int64(GetSatoshisPerUnitExchangeRate(2123456*NanosPerUnit, InitialUSDCentsPerBitcoinExchangeRate)))
    93  		assert.Equal(int64(8*startPriceSatoshis-1), int64(GetSatoshisPerUnitExchangeRate(3000000*NanosPerUnit, InitialUSDCentsPerBitcoinExchangeRate)))
    94  		assert.Equal(int64(8*startPriceSatoshis), int64(GetSatoshisPerUnitExchangeRate(3000001*NanosPerUnit, InitialUSDCentsPerBitcoinExchangeRate)))
    95  		assert.Equal(int64(262144*startPriceSatoshis-1), int64(GetSatoshisPerUnitExchangeRate(18000000*NanosPerUnit, InitialUSDCentsPerBitcoinExchangeRate)))
    96  		assert.Equal(int64(33554432*startPriceSatoshis-1), int64(GetSatoshisPerUnitExchangeRate(25000000*NanosPerUnit, InitialUSDCentsPerBitcoinExchangeRate)))
    97  	}
    98  	// Doubling the exchange rate should double the price outputted.
    99  	{
   100  		startPriceSatoshis := GetStartPriceSatoshisPerDeSo(2 * InitialUSDCentsPerBitcoinExchangeRate)
   101  		assert.Equal(int64(startPriceSatoshis), int64(GetSatoshisPerUnitExchangeRate(0, 2*InitialUSDCentsPerBitcoinExchangeRate)))
   102  		assert.Equal(int64(startPriceSatoshis), int64(GetSatoshisPerUnitExchangeRate(1, 2*InitialUSDCentsPerBitcoinExchangeRate)))
   103  		assert.Equal(int64(startPriceSatoshis), int64(GetSatoshisPerUnitExchangeRate(10, 2*InitialUSDCentsPerBitcoinExchangeRate)))
   104  		assert.Equal(int64(startPriceSatoshis), int64(GetSatoshisPerUnitExchangeRate(1000, 2*InitialUSDCentsPerBitcoinExchangeRate)))
   105  		assert.Equal(int64(startPriceSatoshis), int64(GetSatoshisPerUnitExchangeRate(1000000000, 2*InitialUSDCentsPerBitcoinExchangeRate)))
   106  		assert.Equal(int64(startPriceSatoshis), int64(GetSatoshisPerUnitExchangeRate(10000000000, 2*InitialUSDCentsPerBitcoinExchangeRate)))
   107  		assert.Equal(int64(startPriceSatoshis), int64(GetSatoshisPerUnitExchangeRate(100000000000, 2*InitialUSDCentsPerBitcoinExchangeRate)))
   108  		assert.Equal(int64(startPriceSatoshis+1), int64(GetSatoshisPerUnitExchangeRate(1000*NanosPerUnit, 2*InitialUSDCentsPerBitcoinExchangeRate)))
   109  		assert.Equal(int64(2*startPriceSatoshis), int64(GetSatoshisPerUnitExchangeRate(1000000*NanosPerUnit, 2*InitialUSDCentsPerBitcoinExchangeRate)))
   110  		assert.Equal(int64(16135/2-2), int64(GetSatoshisPerUnitExchangeRate(2123456*NanosPerUnit, 2*InitialUSDCentsPerBitcoinExchangeRate)))
   111  		assert.Equal(int64(8*startPriceSatoshis-1), int64(GetSatoshisPerUnitExchangeRate(3000000*NanosPerUnit, 2*InitialUSDCentsPerBitcoinExchangeRate)))
   112  		assert.Equal(int64(262144*startPriceSatoshis-1), int64(GetSatoshisPerUnitExchangeRate(18000000*NanosPerUnit, 2*InitialUSDCentsPerBitcoinExchangeRate)))
   113  		assert.Equal(int64(33554432*startPriceSatoshis-1), int64(GetSatoshisPerUnitExchangeRate(25000000*NanosPerUnit, 2*InitialUSDCentsPerBitcoinExchangeRate)))
   114  	}
   115  }
   116  
   117  func TestCalcNanosToCreate(t *testing.T) {
   118  	assert := assert.New(t)
   119  	require := require.New(t)
   120  
   121  	oldInitialUSDCentsPerBitcoinExchangeRate := InitialUSDCentsPerBitcoinExchangeRate
   122  	InitialUSDCentsPerBitcoinExchangeRate = 1350000
   123  	defer func() {
   124  		InitialUSDCentsPerBitcoinExchangeRate = oldInitialUSDCentsPerBitcoinExchangeRate
   125  	}()
   126  
   127  	// Comment this in to test specific fields.
   128  	//
   129  	startNanos := uint64(8157483223947843)
   130  	//satoshisToBurn := uint64(500000000)
   131  	usdCentsPerBitcoin := uint64(5400000)
   132  	xxx := float64(GetSatoshisPerUnitExchangeRate(startNanos, usdCentsPerBitcoin)) / 1e8 * float64(5700000) / 100.0
   133  	fmt.Println(xxx)
   134  	return
   135  
   136  	//nanosToCreate1 := CalcNanosToCreate(
   137  	//startNanos [>startNanos*/, satoshisToBurn /*satoshisToBurn*/, usdCentsPerBitcoin /*usdCentsPerBitcoin<])
   138  	//fmt.Println(nanosToCreate1)
   139  	//nanosToCreate2 := CalcNanosToCreate(
   140  	//startNanos+nanosToCreate1 [>startNanos*/, satoshisToBurn /*satoshisToBurn*/, usdCentsPerBitcoin /*usdCentsPerBitcoin<])
   141  	//diff := nanosToCreate1 - nanosToCreate2
   142  	//fmt.Println(diff)
   143  	//fmt.Println(float64(diff) / float64(nanosToCreate2))
   144  
   145  	//startPriceSatoshisPerDeSo := GetStartPriceSatoshisPerDeSo(usdCentsPerBitcoin)
   146  	//assert.Equal(int64(1805), int64(startPriceSatoshisPerDeSo))
   147  
   148  	//nanosComponent := Div(NewFloat().SetUint64(NanosPerUnit), NewFloat().SetUint64(TrancheSizeNanos))
   149  	//{
   150  	//x, _ := nanosComponent.Float64()
   151  	//assert.Equal(float64(1e-06), x)
   152  	//}
   153  
   154  	//bitcoinComponent := Div(NewFloat().SetUint64(satoshisToBurn), NewFloat().SetUint64(startPriceSatoshisPerDeSo))
   155  	//{
   156  	//x, _ := bitcoinComponent.Float64()
   157  	//assert.Equal(float64(5.511003236565097e+06), x)
   158  	//}
   159  
   160  	//bigFloatFinalDeSoNanos := Mul(NewFloat().SetUint64(TrancheSizeNanos), BigFloatLog2(
   161  	//Add(Mul(nanosComponent, Mul(bitcoinComponent, NaturalLogOfTwo)),
   162  	//BigFloatPow(BigTwo, Div(NewFloat().SetUint64(startNanos), NewFloat().SetUint64(TrancheSizeNanos))))))
   163  
   164  	//{
   165  	//x, _ := Div(NewFloat().SetUint64(startNanos), NewFloat().SetUint64(TrancheSizeNanos)).Float64()
   166  	//assert.Equal(float64(29.525895384803288), x)
   167  	//}
   168  	//{
   169  	//fmt.Println("RIGHT BEFORE FAILING TEST")
   170  	//x, _ := BigFloatPow(BigTwo, Div(NewFloat().SetUint64(startNanos), NewFloat().SetUint64(TrancheSizeNanos))).Float64()
   171  	//fmt.Println("RIGHT AFTER FAILING TEST")
   172  	//assert.Equal(float64(7.730011849578111e+08), x)
   173  	//}
   174  	//{
   175  	//x, _ := Mul(nanosComponent, Mul(bitcoinComponent, NaturalLogOfTwo)).Float64()
   176  	//assert.Equal(float64(3.8199363554818304), x)
   177  	//}
   178  	//{
   179  	//x, _ := Add(Mul(nanosComponent, Mul(bitcoinComponent, NaturalLogOfTwo)),
   180  	//BigFloatPow(BigTwo, Div(NewFloat().SetUint64(startNanos), NewFloat().SetUint64(TrancheSizeNanos)))).Float64()
   181  	//assert.Equal(float64(7.730011887777475e+08), x)
   182  	//}
   183  	//{
   184  	//x, _ := BigFloatLog2(
   185  	//Add(Mul(nanosComponent, Mul(bitcoinComponent, NaturalLogOfTwo)),
   186  	//BigFloatPow(BigTwo, Div(NewFloat().SetUint64(startNanos), NewFloat().SetUint64(TrancheSizeNanos))))).Float64()
   187  	//assert.Equal(float64(29.52589539193265), x)
   188  	//}
   189  	//{
   190  	//x, _ := Mul(NewFloat().SetUint64(TrancheSizeNanos), BigFloatLog2(
   191  	//Add(Mul(nanosComponent, Mul(bitcoinComponent, NaturalLogOfTwo)),
   192  	//BigFloatPow(BigTwo, Div(NewFloat().SetUint64(startNanos), NewFloat().SetUint64(TrancheSizeNanos)))))).Float64()
   193  	//assert.Equal(float64(2.9525895391932652e+16), x)
   194  	//}
   195  
   196  	//{
   197  	//x, _ := bigFloatFinalDeSoNanos.Float64()
   198  	//assert.Equal(float64(2.9525895391932652e+16), x)
   199  	//}
   200  	//require.Equal(int64(7129365), int64(nanosToCreate))
   201  	//}
   202  
   203  	{
   204  		for ii := 0; ii < len(randomStartNanos); ii++ {
   205  			nanosToCreate := CalcNanosToCreate(
   206  				randomStartNanos[ii] /*startNanos*/, randomSatoshisToBurn[ii] /*satoshisToBurn*/, randomUsdCentsPerBitcoinExchangeRate[ii] /*usdCentsPerBitcoin*/)
   207  
   208  			//if nanosToCreate == 7129365 {
   209  			//fmt.Println("DELETEME: xxx")
   210  			//fmt.Println(randomStartNanos[ii] [>startNanos*/, randomSatoshisToBurn[ii] /*satoshisToBurn*/, randomUsdCentsPerBitcoinExchangeRate[ii] /*usdCentsPerBitcoin<])
   211  			//}
   212  
   213  			calcDiff := int64(expectedRandomNanosToCreate[ii]) - int64(nanosToCreate)
   214  			assert.Equalf(int64(expectedRandomNanosToCreate[ii]), int64(nanosToCreate), "Off by: %v", calcDiff)
   215  			require.Less(math.Abs(float64(calcDiff)), float64(16), "Error too large")
   216  		}
   217  
   218  		// Run this to regenerate the supplydata_test.go data. Make sure you delete the
   219  		// data in that file first, though.
   220  		//
   221  		//for startNanosIter := uint64(0); startNanosIter < 30000000*1e9; startNanosIter += 500000 * 1e9 {
   222  		//for satoshisToBurnIter := uint64(10); satoshisToBurnIter < 100*1e8; satoshisToBurnIter += 1e8 {
   223  		//for usdCentsPerBitcoinExchangeRateIter := uint64(100); usdCentsPerBitcoinExchangeRateIter < 100000*100; usdCentsPerBitcoinExchangeRateIter += 2500 * 100 {
   224  		//startNanos := startNanosIter + uint64(float64(500000*1e9*rand.Float64()))
   225  		//satoshisToBurn := satoshisToBurnIter + uint64(float64(1e8*rand.Float64()))
   226  		//usdCentsPerBitcoinExchangeRate := usdCentsPerBitcoinExchangeRateIter + uint64(float64(1000*100*rand.Float64()))
   227  
   228  		//// Zero satoshi means zero nanos
   229  		//nanosToCreate := CalcNanosToCreate(
   230  		//startNanos [>startNanos*/, satoshisToBurn /*satoshisToBurn*/, usdCentsPerBitcoinExchangeRate /*usdCentsPerBitcoin<])
   231  
   232  		//randomStartNanos = append(randomStartNanos, startNanos)
   233  		//randomSatoshisToBurn = append(randomSatoshisToBurn, satoshisToBurn)
   234  		//randomUsdCentsPerBitcoinExchangeRate = append(randomUsdCentsPerBitcoinExchangeRate, usdCentsPerBitcoinExchangeRate)
   235  		//expectedRandomNanosToCreate = append(expectedRandomNanosToCreate, nanosToCreate)
   236  		//}
   237  		//}
   238  		//}
   239  	}
   240  
   241  	// Run this to regenerate the supplydata_test.go data. Make sure you delete the
   242  	// data in that file first, though.
   243  	//
   244  	//fmt.Println("StartNanos")
   245  	//for ii := 0; ii < len(randomStartNanos); ii++ {
   246  	//fmt.Printf("%v, ", randomStartNanos[ii])
   247  	//}
   248  	//fmt.Println("\nSatoshisToBurn")
   249  	//for ii := 0; ii < len(randomStartNanos); ii++ {
   250  	//fmt.Printf("%v, ", randomSatoshisToBurn[ii])
   251  	//}
   252  	//fmt.Println("\nusdCentsPerBitcoinExchangeRate")
   253  	//for ii := 0; ii < len(randomStartNanos); ii++ {
   254  	//fmt.Printf("%v, ", randomUsdCentsPerBitcoinExchangeRate[ii])
   255  	//}
   256  	//fmt.Println("\nnanosToCreate")
   257  	//for ii := 0; ii < len(randomStartNanos); ii++ {
   258  	//fmt.Printf("%v, ", expectedRandomNanosToCreate[ii])
   259  	//}
   260  
   261  	{
   262  		// Zero satoshi means zero nanos
   263  		nanosToCreate := CalcNanosToCreate(
   264  			945603607309490 /*startNanos*/, 650000000 /*satoshisToBurn*/, 1550000 /*usdCentsPerBitcoin*/)
   265  		assert.Equal(int64(101026173281102), int64(nanosToCreate))
   266  	}
   267  	{
   268  		// Zero satoshi means zero nanos
   269  		nanosToCreate := CalcNanosToCreate(
   270  			1046606985637137 /*startNanos*/, 1287001287 /*satoshisToBurn*/, 1554000 /*usdCentsPerBitcoin*/)
   271  		assert.Equal(int64(181730399315476), int64(nanosToCreate))
   272  	}
   273  	{
   274  		// Zero satoshi means zero nanos
   275  		nanosToCreate := CalcNanosToCreate(0, 0, InitialUSDCentsPerBitcoinExchangeRate)
   276  		assert.Equal(uint64(0), nanosToCreate)
   277  	}
   278  	{
   279  		// This amount of satoshis should print zero nanos at this price.
   280  		nanosToCreate := CalcNanosToCreate(10, 0, InitialUSDCentsPerBitcoinExchangeRate)
   281  		assert.Equal(uint64(0), nanosToCreate)
   282  	}
   283  	{
   284  		// Zero satoshi means zero nanos: second tranche
   285  		nanosToCreate := CalcNanosToCreate(1000001*NanosPerUnit, 0, InitialUSDCentsPerBitcoinExchangeRate)
   286  		assert.Equal(uint64(0), nanosToCreate)
   287  	}
   288  	{
   289  		// Zero satoshis should print zero nanos, even when the supply is very large.
   290  		nanosToCreate := CalcNanosToCreate(18000001*NanosPerUnit, 0, InitialUSDCentsPerBitcoinExchangeRate)
   291  		assert.Equal(uint64(0), nanosToCreate)
   292  	}
   293  	{
   294  		// Zero satoshis should print zero nanos, even when the supply is very large.
   295  		nanosToCreate := CalcNanosToCreate(25000001*NanosPerUnit, 0, InitialUSDCentsPerBitcoinExchangeRate)
   296  		assert.Equal(uint64(0), nanosToCreate)
   297  	}
   298  	{
   299  		// One satoshi should print zero nanos when the supply is large.
   300  		nanosToCreate := CalcNanosToCreate(18000001*NanosPerUnit, 1, InitialUSDCentsPerBitcoinExchangeRate)
   301  		assert.Equal(uint64(0), nanosToCreate)
   302  	}
   303  	{
   304  		nanosToCreate := CalcNanosToCreate(10000001*NanosPerUnit, 1, InitialUSDCentsPerBitcoinExchangeRate)
   305  		assert.Equal(int64(262), int64(nanosToCreate))
   306  	}
   307  	{
   308  		// <131 satoshis should not hurdle the threshold.
   309  		nanosToCreate := CalcNanosToCreate(20000001*NanosPerUnit, 125, InitialUSDCentsPerBitcoinExchangeRate)
   310  		assert.Equal(int64(0), int64(nanosToCreate))
   311  	}
   312  	{
   313  		// >131 satoshis should hurdle the threshold and print some.
   314  		nanosToCreate := CalcNanosToCreate(18000001*NanosPerUnit, 135, InitialUSDCentsPerBitcoinExchangeRate)
   315  		assert.Equal(int64(140), int64(nanosToCreate))
   316  	}
   317  	{
   318  		// One satoshi should print zero nanos when the supply is large.
   319  		nanosToCreate := CalcNanosToCreate(25000001*NanosPerUnit, 1, InitialUSDCentsPerBitcoinExchangeRate)
   320  		assert.Equal(uint64(0), nanosToCreate)
   321  	}
   322  	{
   323  		// One satoshi should print X minus the discount initially.
   324  		nanosToCreate := CalcNanosToCreate(0*NanosPerUnit, 1, InitialUSDCentsPerBitcoinExchangeRate)
   325  		assert.Equal(int64(270051), int64(nanosToCreate))
   326  	}
   327  	{
   328  		// One satoshi should print X minus the discount initially.
   329  		nanosToCreate := CalcNanosToCreate(10*NanosPerUnit, 10, InitialUSDCentsPerBitcoinExchangeRate)
   330  		assert.Equal(int64(2700494), int64(nanosToCreate))
   331  	}
   332  	{
   333  		// Print 1 BTC at the beginning. Should be about 10k DeSo, but less
   334  		// than that because the price is increasing slightly as they buy it.
   335  		nanosToCreate := CalcNanosToCreate(0*NanosPerUnit, satoshisPerBitcoin+1, InitialUSDCentsPerBitcoinExchangeRate)
   336  		assert.Equal(int64(26755493480681), int64(nanosToCreate))
   337  	}
   338  	{
   339  		// The first purchase should work even if it's large.
   340  		nanosToCreate := CalcNanosToCreate(0*NanosPerUnit, 200*satoshisPerBitcoin+1, InitialUSDCentsPerBitcoinExchangeRate)
   341  		assert.Equal(int64(2246014623084247), int64(nanosToCreate))
   342  	}
   343  	{
   344  		// Making a purchase part-way through the first tranche should work. Should
   345  		// cost <10k but not too much less than that.
   346  		nanosToCreate := CalcNanosToCreate(200001*NanosPerUnit, satoshisPerBitcoin+1, InitialUSDCentsPerBitcoinExchangeRate)
   347  		assert.Equal(int64(23319824667603), int64(nanosToCreate))
   348  	}
   349  	{
   350  		// Make a large purchase partway through the first tranche.
   351  		nanosToCreate := CalcNanosToCreate(200001*NanosPerUnit, 200*satoshisPerBitcoin+1, InitialUSDCentsPerBitcoinExchangeRate)
   352  		assert.Equal(int64(2090542905078737), int64(nanosToCreate))
   353  	}
   354  	{
   355  		// A purchase part-way through a middle tranche should work.
   356  		nanosToCreate := CalcNanosToCreate(6123456123456789, 5712345678, InitialUSDCentsPerBitcoinExchangeRate)
   357  		assert.Equal(int64(21958743502996), int64(nanosToCreate))
   358  	}
   359  
   360  	{
   361  		startVal := uint64(6123456123456789)
   362  		nanosToCreate := CalcNanosToCreate(startVal, 560988080987, InitialUSDCentsPerBitcoinExchangeRate)
   363  		// Be careful: Your calculator will lose precision when you try to calculate this
   364  		// to check it if you let it do floating point at any step.
   365  		assert.Equal(int64(7448955216307525), int64(nanosToCreate)+int64(startVal))
   366  	}
   367  
   368  	{
   369  		// Try a weird situation where there is less than one satoshi left worth of nanos
   370  		// at the end of a tranche and the purchaser tries to buy zero satoshis. This should
   371  		// result in zero nanos being created.
   372  		startVal := uint64(7000000000000000 - 99)
   373  		nanosToCreate := CalcNanosToCreate(startVal, 0, InitialUSDCentsPerBitcoinExchangeRate)
   374  		assert.Equal(int64(0), int64(nanosToCreate))
   375  	}
   376  	{
   377  		// Try a weird situation where there is less than one satoshi left worth of nanos
   378  		// at the end of a tranche and the purchaser tries to buy one satoshi worth of nanos.
   379  		startVal := uint64(7000000000000000 - 99)
   380  		nanosToCreate := CalcNanosToCreate(startVal, 1, InitialUSDCentsPerBitcoinExchangeRate)
   381  		assert.Equal(int64(2111), int64(nanosToCreate))
   382  	}
   383  	{
   384  		startVal := uint64(16000000123456789)
   385  		satoshisToCleanOutTranche := uint64(655359919091358)
   386  		nanosToCreate := CalcNanosToCreate(startVal, satoshisToCleanOutTranche, InitialUSDCentsPerBitcoinExchangeRate)
   387  		assert.Equal(int64(17521981851378602), int64(startVal+nanosToCreate))
   388  	}
   389  	{
   390  		// Try a situation where a user starts in the last tranche right at the end
   391  		// and zero satoshis are burned.
   392  		startVal := uint64(16999999999999998)
   393  		// satoshisPerUnit := uint64(655360000)
   394  		// (17000000*NanosPerUnit - startVal) * satoshisPerUnit / NanosPerUnit
   395  		nanosToCreate := CalcNanosToCreate(startVal, 0, InitialUSDCentsPerBitcoinExchangeRate)
   396  		assert.Equal(int64(0), int64(nanosToCreate))
   397  	}
   398  	{
   399  		// Try a situation where a user starts in the last tranche right at the end
   400  		// and 1 satoshi is burned. This should result in zero since it doesn't hurdle
   401  		// the floating point threshold.
   402  		startVal := uint64(16999999999999998)
   403  		nanosToCreate := CalcNanosToCreate(startVal, 1, InitialUSDCentsPerBitcoinExchangeRate)
   404  		assert.Equal(int64(0), int64(nanosToCreate))
   405  	}
   406  	{
   407  		// Try a situation where a user starts in the last tranche right at the end
   408  		// and 2 satoshi is burned. Should still be zero.
   409  		startVal := uint64(16999999999999998)
   410  		// satoshisPerUnit := uint64(655360000)
   411  		// (17000000*NanosPerUnit - startVal) * satoshisPerUnit / NanosPerUnit
   412  		nanosToCreate := CalcNanosToCreate(startVal, 2, InitialUSDCentsPerBitcoinExchangeRate)
   413  		assert.Equal(int64(0), int64(nanosToCreate))
   414  	}
   415  	{
   416  		// Try a situation where a user starts in the last tranche right at the end
   417  		// and 3 satoshi is burned. In this case we should not cross the threshold.
   418  		startVal := uint64(16999999999999998)
   419  		nanosToCreate := CalcNanosToCreate(startVal, 3, InitialUSDCentsPerBitcoinExchangeRate)
   420  		assert.Equal(int64(0), int64(nanosToCreate))
   421  	}
   422  	{
   423  		// Try a situation where a user starts in the last tranche and buys just *beyond*
   424  		// the end (i.e. fully completes the last tranche).
   425  		startVal := uint64(16000000123456789)
   426  		// satoshisPerUnit := uint64(655360000)
   427  		// (17000000*NanosPerUnit - startVal) * satoshisPerUnit / NanosPerUnit
   428  		satoshisToCleanOutTranche := uint64(655359919091359)
   429  		nanosToCreate := CalcNanosToCreate(startVal, satoshisToCleanOutTranche, InitialUSDCentsPerBitcoinExchangeRate)
   430  		assert.Equal(int64(17521981851378602), int64(startVal+nanosToCreate))
   431  	}
   432  	{
   433  		// Try a situation where a user starts in the last tranche and buys way *beyond*
   434  		// the end (i.e. fully completes the last tranche).
   435  		startVal := uint64(16000000123456789)
   436  		// satoshisPerUnit := uint64(655360000)
   437  		// (17000000*NanosPerUnit - startVal) * satoshisPerUnit / NanosPerUnit
   438  		satoshisToCleanOutTranche := uint64(665359919091359)
   439  		nanosToCreate := CalcNanosToCreate(startVal, satoshisToCleanOutTranche, InitialUSDCentsPerBitcoinExchangeRate)
   440  		assert.Equal(int64(17536259392211874), int64(startVal+nanosToCreate))
   441  	}
   442  	{
   443  		// Try a situation where a user starts at the end and buys zero. Should result
   444  		// in no nanos being created.
   445  		startVal := uint64(17000000000000000)
   446  		nanosToCreate := CalcNanosToCreate(startVal, 0, InitialUSDCentsPerBitcoinExchangeRate)
   447  		assert.Equal(int64(0), int64(nanosToCreate))
   448  	}
   449  	{
   450  		// Try a situation where a user starts at the end and burns one satoshi. Should result
   451  		// in no nanos being created.
   452  		startVal := uint64(17000000000000000)
   453  		nanosToCreate := CalcNanosToCreate(startVal, 1, InitialUSDCentsPerBitcoinExchangeRate)
   454  		assert.Equal(int64(0), int64(nanosToCreate))
   455  	}
   456  	{
   457  		// Try a situation where a user starts beyond the end and burns one satoshi.
   458  		// Should never happen but should result in no nanos being created nevertheless.
   459  		startVal := uint64(17000000000000001)
   460  		nanosToCreate := CalcNanosToCreate(startVal, 1, InitialUSDCentsPerBitcoinExchangeRate)
   461  		assert.Equal(int64(0), int64(nanosToCreate))
   462  	}
   463  	{
   464  		// Spending a million Bitcoin at the max should be near-zero
   465  		startVal := uint64(MaxNanos)
   466  		nanosToCreate := CalcNanosToCreate(startVal, 1000000*100000000, InitialUSDCentsPerBitcoinExchangeRate)
   467  		assert.Greater(int64(100*NanosPerUnit), int64(nanosToCreate))
   468  	}
   469  }
   470  
   471  func TestBigFloat(t *testing.T) {
   472  	//assert := assert.New(t)
   473  	require := require.New(t)
   474  
   475  	require.Equal(NewFloat().SetFloat64(0.33403410169116804), BigFloatPow(NewFloat().SetFloat64(0.6938468198960861), NewFloat().SetUint64(uint64(3))))
   476  }
   477  
   478  func TestSumBalances(t *testing.T) {
   479  	assert := assert.New(t)
   480  	require := require.New(t)
   481  	_, _ = assert, require
   482  
   483  	// Balances should sum to the amount purchased.
   484  	params := &DeSoMainnetParams
   485  	amounts := uint64(0)
   486  	balancesByPublicKey := make(map[string]int64)
   487  	for _, seedBal := range params.SeedBalances {
   488  		amounts += seedBal.AmountNanos
   489  		pkStr := PkToStringMainnet(seedBal.PublicKey)
   490  		if amountFound, exists := balancesByPublicKey[pkStr]; exists {
   491  			require.Fail(fmt.Sprintf("Public key %v found twice in map: %v %v",
   492  				pkStr, int64(seedBal.AmountNanos), int64(amountFound)))
   493  		}
   494  		balancesByPublicKey[pkStr] = int64(seedBal.AmountNanos)
   495  	}
   496  	require.Equal(int64(params.DeSoNanosPurchasedAtGenesis)+int64(2e6*NanosPerUnit), int64(amounts))
   497  
   498  	// Spot-check a few balances
   499  	_checkBalance := func(pkStr string, expectedVal int64) {
   500  		val, exists := balancesByPublicKey[pkStr]
   501  		assert.Truef(exists, "Public key %v must exist in genesis block", pkStr)
   502  		assert.Equal(expectedVal, int64(val))
   503  	}
   504  
   505  	_checkBalance("BC1YLjAkTwNw5AKy1TCHT8qjZjmdEojvtNpB7wgFdguZ78scMu3KeBo", 285857902913000)
   506  	_checkBalance("BC1YLhX3HZsZKYyJiv8aaoAdR5mgtf87RUiC2PyFDUFaRT7cMhtNiep", 8333340003200)
   507  	_checkBalance("BC1YLfqL4neTSBPiiURxTyajt1y1jhkqG4qUHqEuYDtZwDD2mPo3ff6", 2888778956800)
   508  	_checkBalance("BC1YLjTYqQV5CfH3ckQZAdwdbkEu1uSWJg1FNBu6CmL3DQZJwLceHXH", 267648349450008)
   509  	_checkBalance("BC1YLiYxGdXeuPc3QMzgBv26EwfxrpwemdGxGZAZbh5qXgf7DennfhL", 379387259042300)
   510  	_checkBalance("BC1YLgnKq3aJ9SL7zmiMexjRRqvenLeHQoVNRKnbCiNM4QxPgn9QU1q", 91625252862600)
   511  	_checkBalance("BC1YLitnSuYscJ2GyHt9g3SfQKWz5ht1Ee5LUxBNk22Jo8Cde7Wupy7", 91625252862600)
   512  	_checkBalance("BC1YLhgrsxAejRUyhYmZRexhXq3nNbBgWH45TC56rxErHCjrKEhseYq", 166000000000000)
   513  	_checkBalance("BC1YLgGUvSCBToN9gbThF3cETR4B2dhcaFBTyUy64NCmY4Y483WfHUX", 30000000000000)
   514  	_checkBalance("BC1YLg26dcBA1HjTkDwXPH4oog7bVGbsQKj4G6rmHkZ6o7ApUzW4S8j", 62500000000000)
   515  }