github.com/filecoin-project/specs-actors/v4@v4.0.2/actors/builtin/reward/reward_logic_test.go (about)

     1  package reward
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	gbig "math/big"
     7  	"testing"
     8  
     9  	"github.com/filecoin-project/go-state-types/abi"
    10  	"github.com/filecoin-project/go-state-types/big"
    11  	"github.com/stretchr/testify/assert"
    12  	"github.com/xorcare/golden"
    13  
    14  	"github.com/filecoin-project/specs-actors/v4/actors/builtin"
    15  	"github.com/filecoin-project/specs-actors/v4/actors/util/math"
    16  )
    17  
    18  func q128ToF(x big.Int) float64 {
    19  	q128 := new(gbig.Int).SetInt64(1)
    20  	q128 = q128.Lsh(q128, math.Precision128)
    21  	res, _ := new(gbig.Rat).SetFrac(x.Int, q128).Float64()
    22  	return res
    23  }
    24  
    25  func TestComputeRTeta(t *testing.T) {
    26  	baselinePowerAt := func(epoch abi.ChainEpoch) abi.StoragePower {
    27  		return big.Mul(big.NewInt(int64(epoch+1)), big.NewInt(2048))
    28  	}
    29  
    30  	assert.Equal(t, 0.5, q128ToF(ComputeRTheta(1, baselinePowerAt(1), big.NewInt(2048+2*2048*0.5), big.NewInt(2048+2*2048))))
    31  	assert.Equal(t, 0.25, q128ToF(ComputeRTheta(1, baselinePowerAt(1), big.NewInt(2048+2*2048*0.25), big.NewInt(2048+2*2048))))
    32  
    33  	cumsum15 := big.NewInt(0)
    34  	for i := abi.ChainEpoch(0); i < 16; i++ {
    35  		cumsum15 = big.Add(cumsum15, baselinePowerAt(i))
    36  	}
    37  	assert.Equal(t, 15.25, q128ToF(ComputeRTheta(16,
    38  		baselinePowerAt(16),
    39  		big.Add(cumsum15, big.Div(baselinePowerAt(16), big.NewInt(4))),
    40  		big.Add(cumsum15, baselinePowerAt(16)))))
    41  }
    42  
    43  func TestBaselineReward(t *testing.T) {
    44  	step := gbig.NewInt(5000)
    45  	step = step.Lsh(step, math.Precision128)
    46  	step = step.Sub(step, gbig.NewInt(77777777777)) // offset from full integers
    47  
    48  	delta := gbig.NewInt(1)
    49  	delta = delta.Lsh(delta, math.Precision128)
    50  	delta = delta.Sub(delta, gbig.NewInt(33333333333)) // offset from full integers
    51  
    52  	prevTheta := new(gbig.Int)
    53  	theta := new(gbig.Int).Set(delta)
    54  
    55  	b := &bytes.Buffer{}
    56  	b.WriteString("t0, t1, y\n")
    57  	simple := computeReward(0, big.Zero(), big.Zero(), DefaultSimpleTotal, DefaultBaselineTotal)
    58  
    59  	for i := 0; i < 512; i++ {
    60  		reward := computeReward(0, big.NewFromGo(prevTheta), big.NewFromGo(theta), DefaultSimpleTotal, DefaultBaselineTotal)
    61  		reward = big.Sub(reward, simple)
    62  		fmt.Fprintf(b, "%s,%s,%s\n", prevTheta, theta, reward.Int)
    63  		prevTheta = prevTheta.Add(prevTheta, step)
    64  		theta = theta.Add(theta, step)
    65  	}
    66  
    67  	golden.Assert(t, b.Bytes())
    68  }
    69  
    70  func TestSimpleReward(t *testing.T) {
    71  	b := &bytes.Buffer{}
    72  	b.WriteString("x, y\n")
    73  	for i := int64(0); i < 512; i++ {
    74  		x := i * 5000
    75  		reward := computeReward(abi.ChainEpoch(x), big.Zero(), big.Zero(), DefaultSimpleTotal, DefaultBaselineTotal)
    76  		fmt.Fprintf(b, "%d,%s\n", x, reward.Int)
    77  	}
    78  
    79  	golden.Assert(t, b.Bytes())
    80  }
    81  
    82  func TestBaselineRewardGrowth(t *testing.T) {
    83  
    84  	baselineInYears := func(start abi.StoragePower, x abi.ChainEpoch) abi.StoragePower {
    85  		baseline := start
    86  		for i := abi.ChainEpoch(0); i < x*builtin.EpochsInYear; i++ {
    87  			baseline = BaselinePowerFromPrev(baseline)
    88  		}
    89  		return baseline
    90  	}
    91  
    92  	// Baseline reward should have 100% growth rate
    93  	// This implies that for every year x, the baseline function should be:
    94  	// StartVal * 2^x.
    95  	//
    96  	// Error values for 1 years of growth were determined empirically with latest
    97  	// baseline power construction to set bounds in this test in order to
    98  	// 1. throw a test error if function changes and percent error goes up
    99  	// 2. serve as documentation of current error bounds
   100  	type growthTestCase struct {
   101  		StartVal abi.StoragePower
   102  		ErrBound float64
   103  	}
   104  	cases := []growthTestCase{
   105  		// 1 byte
   106  		{
   107  			abi.NewStoragePower(1),
   108  			1,
   109  		},
   110  		// GiB
   111  		{
   112  			abi.NewStoragePower(1 << 30),
   113  			1e-3,
   114  		},
   115  		// TiB
   116  		{
   117  			abi.NewStoragePower(1 << 40),
   118  			1e-6,
   119  		},
   120  		// PiB
   121  		{
   122  			abi.NewStoragePower(1 << 50),
   123  			1e-8,
   124  		},
   125  		// EiB
   126  		{
   127  			BaselineInitialValue,
   128  			1e-8,
   129  		},
   130  		// ZiB
   131  		{
   132  			big.Lsh(big.NewInt(1), 70),
   133  			1e-8,
   134  		},
   135  		// non power of 2 ~ 1 EiB
   136  		{
   137  			abi.NewStoragePower(513633559722596517),
   138  			1e-8,
   139  		},
   140  	}
   141  	for _, testCase := range cases {
   142  		years := int64(1)
   143  		end := baselineInYears(testCase.StartVal, abi.ChainEpoch(1))
   144  
   145  		multiplier := big.Exp(big.NewInt(2), big.NewInt(years)) // keeping this generalized in case we want to test more years
   146  		expected := big.Mul(testCase.StartVal, multiplier)
   147  		diff := big.Sub(expected, end)
   148  
   149  		perrFrac := gbig.NewRat(1, 1).SetFrac(diff.Int, expected.Int)
   150  		perr, _ := perrFrac.Float64()
   151  
   152  		assert.Less(t, perr, testCase.ErrBound)
   153  	}
   154  }