github.com/klaytn/klaytn@v1.12.1/reward/reward_distributor_test.go (about)

     1  // Copyright 2019 The klaytn Authors
     2  // This file is part of the klaytn library.
     3  //
     4  // The klaytn library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The klaytn library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the klaytn library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package reward
    18  
    19  import (
    20  	"encoding/json"
    21  	"fmt"
    22  	"math/big"
    23  	"testing"
    24  
    25  	"github.com/klaytn/klaytn/blockchain/types"
    26  	"github.com/klaytn/klaytn/common"
    27  	"github.com/klaytn/klaytn/consensus/istanbul"
    28  	"github.com/klaytn/klaytn/params"
    29  	"github.com/stretchr/testify/assert"
    30  	"github.com/stretchr/testify/require"
    31  )
    32  
    33  func (governance *testGovernance) CurrentParams() *params.GovParamSet {
    34  	return governance.p
    35  }
    36  
    37  func (governance *testGovernance) EffectiveParams(num uint64) (*params.GovParamSet, error) {
    38  	return governance.p, nil
    39  }
    40  
    41  func (governance *testGovernance) setTestGovernance(intMap map[int]interface{}) {
    42  	p, _ := params.NewGovParamSetIntMap(intMap)
    43  	governance.p = p
    44  }
    45  
    46  func assertEqualRewardSpecs(t *testing.T, expected, actual *RewardSpec, msgAndArgs ...interface{}) {
    47  	expectedJson, err := json.MarshalIndent(expected, "", "  ")
    48  	require.Nil(t, err)
    49  
    50  	actualJson, err := json.MarshalIndent(actual, "", "  ")
    51  	require.Nil(t, err)
    52  
    53  	assert.Equal(t, string(expectedJson), string(actualJson), msgAndArgs...)
    54  
    55  	lhs := new(big.Int).Add(actual.Minted, actual.TotalFee)
    56  	lhs = lhs.Sub(lhs, actual.BurntFee)
    57  	rhs := new(big.Int).Add(actual.Proposer, actual.Stakers)
    58  	rhs = rhs.Add(rhs, actual.KFF)
    59  	rhs = rhs.Add(rhs, actual.KCF)
    60  	assert.True(t, lhs.Cmp(rhs) == 0, msgAndArgs...)
    61  }
    62  
    63  var (
    64  	cnBaseAddr     = 500 // Dummy addresses goes like 0x000..5nn
    65  	stakeBaseAddr  = 600
    66  	rewardBaseAddr = 700
    67  	minStaking     = uint64(2000000) // changing this value will not change the governance's min staking
    68  	minted, _      = big.NewInt(0).SetString("9600000000000000000", 10)
    69  	proposerAddr   = common.StringToAddress("0x1552F52D459B713E0C4558e66C8c773a75615FA8")
    70  	kcfAddr        = intToAddress(1000)
    71  	kffAddr        = intToAddress(2000)
    72  )
    73  
    74  // 500 -> 0x00000...0500
    75  func intToAddress(x int) common.Address {
    76  	return common.HexToAddress(fmt.Sprintf("0x%040d", x))
    77  }
    78  
    79  // rewardOverride[i] = j means rewards[i] = rewards[j]
    80  // amountOverride[i] = amt means amount[i] = amt
    81  func genStakingInfo(cnNum int, rewardOverride map[int]int, amountOverride map[int]uint64) *StakingInfo {
    82  	cns := make([]common.Address, 0)
    83  	stakes := make([]common.Address, 0)
    84  	rewards := make([]common.Address, 0)
    85  	amounts := make([]uint64, 0)
    86  
    87  	for i := 0; i < cnNum; i++ {
    88  		cns = append(cns, intToAddress(cnBaseAddr+i))
    89  		stakes = append(stakes, intToAddress(stakeBaseAddr+i))
    90  		rewards = append(rewards, intToAddress(rewardBaseAddr+i))
    91  		amounts = append(amounts, minStaking)
    92  	}
    93  
    94  	for i := range rewardOverride {
    95  		rewards[i] = rewards[rewardOverride[i]]
    96  	}
    97  
    98  	for i := range amountOverride {
    99  		amounts[i] = amountOverride[i]
   100  	}
   101  
   102  	return &StakingInfo{
   103  		BlockNum:              0,
   104  		CouncilNodeAddrs:      cns,
   105  		CouncilStakingAddrs:   stakes,
   106  		CouncilRewardAddrs:    rewards,
   107  		KCFAddr:               kcfAddr,
   108  		KFFAddr:               kffAddr,
   109  		UseGini:               false,
   110  		CouncilStakingAmounts: amounts,
   111  	}
   112  }
   113  
   114  type testBalanceAdder struct {
   115  	accounts map[common.Address]*big.Int
   116  }
   117  
   118  func newTestBalanceAdder() *testBalanceAdder {
   119  	balanceAdder := &testBalanceAdder{}
   120  	balanceAdder.accounts = make(map[common.Address]*big.Int)
   121  	return balanceAdder
   122  }
   123  
   124  func getTestConfig() *params.ChainConfig {
   125  	config := &params.ChainConfig{}
   126  	config.SetDefaults() // To use GovParamSet without having parse errors
   127  
   128  	config.MagmaCompatibleBlock = big.NewInt(0)
   129  	config.KoreCompatibleBlock = big.NewInt(0)
   130  	config.UnitPrice = 1
   131  	config.Governance.Reward.MintingAmount = minted
   132  	config.Governance.Reward.Ratio = "34/54/12"
   133  	config.Governance.Reward.Kip82Ratio = "20/80"
   134  	config.Governance.Reward.DeferredTxFee = true
   135  	config.Governance.Reward.MinimumStake = big.NewInt(0).SetUint64(minStaking)
   136  	config.Istanbul.ProposerPolicy = 2
   137  	return config
   138  }
   139  
   140  func (balanceAdder *testBalanceAdder) AddBalance(addr common.Address, v *big.Int) {
   141  	balance, ok := balanceAdder.accounts[addr]
   142  	if ok {
   143  		balanceAdder.accounts[addr] = big.NewInt(0).Add(balance, v)
   144  	} else {
   145  		balanceAdder.accounts[addr] = v
   146  	}
   147  }
   148  
   149  func noMagma(p *params.ChainConfig) *params.ChainConfig {
   150  	p.MagmaCompatibleBlock = big.NewInt(100000000)
   151  	p.KoreCompatibleBlock = big.NewInt(100000000)
   152  	return p
   153  }
   154  
   155  func noKore(p *params.ChainConfig) *params.ChainConfig {
   156  	p.KoreCompatibleBlock = big.NewInt(100000000)
   157  	return p
   158  }
   159  
   160  func noDeferred(p *params.ChainConfig) *params.ChainConfig {
   161  	p.Governance.Reward.DeferredTxFee = false
   162  	return p
   163  }
   164  
   165  func roundrobin(p *params.ChainConfig) *params.ChainConfig {
   166  	p.Istanbul.ProposerPolicy = 0
   167  	return p
   168  }
   169  
   170  func (balanceAdder *testBalanceAdder) GetBalance(addr common.Address) *big.Int {
   171  	balance, ok := balanceAdder.accounts[addr]
   172  	if ok {
   173  		return balance
   174  	} else {
   175  		return nil
   176  	}
   177  }
   178  
   179  func Test_isEmptyAddress(t *testing.T) {
   180  	testCases := []struct {
   181  		address common.Address
   182  		result  bool
   183  	}{
   184  		{
   185  			common.Address{},
   186  			true,
   187  		},
   188  		{
   189  			common.HexToAddress("0x0000000000000000000000000000000000000000"),
   190  			true,
   191  		},
   192  		{
   193  			common.StringToAddress("0xA75Ed91f789BF9dc121DACB822849955ca3AB6aD"),
   194  			false,
   195  		},
   196  		{
   197  			common.StringToAddress("0x4bCDd8E3F9776d16056815E189EcB5A8bF8E4CBb"),
   198  			false,
   199  		},
   200  	}
   201  	for _, testCase := range testCases {
   202  		assert.Equal(t, testCase.result, common.EmptyAddress(testCase.address))
   203  	}
   204  }
   205  
   206  func TestRewardDistributor_GetTotalTxFee(t *testing.T) {
   207  	testCases := []struct {
   208  		gasUsed            uint64
   209  		unitPrice          uint64
   210  		baseFee            *big.Int
   211  		expectedTotalTxFee *big.Int
   212  	}{
   213  		// before magma hardfork
   214  		// baseFee = nil, expectedTotalTxFee = gasUsed * unitPrice
   215  		{0, 25000000000, nil, big.NewInt(0)},
   216  		{200000, 25000000000, nil, big.NewInt(5000000000000000)},
   217  		{200000, 25000000000, nil, big.NewInt(5000000000000000)},
   218  		{129346, 10000000000, nil, big.NewInt(1293460000000000)},
   219  		{129346, 10000000000, nil, big.NewInt(1293460000000000)},
   220  		{9236192, 50000, nil, big.NewInt(461809600000)},
   221  		{9236192, 50000, nil, big.NewInt(461809600000)},
   222  		{12936418927364923, 0, nil, big.NewInt(0)},
   223  		// after magma hardfork, unitprice ignored
   224  		// baseFee != nil, expectedTotalTxFee = gasUsed * baseFee
   225  		{0, 25000000000, big.NewInt(25000000000), big.NewInt(0)},
   226  		{200000, 25000000000, big.NewInt(25000000000), big.NewInt(5000000000000000)},
   227  		{200000, 25000000000, big.NewInt(25000000000), big.NewInt(5000000000000000)},
   228  		{129346, 25000000000, big.NewInt(10000000000), big.NewInt(1293460000000000)},
   229  		{129346, 250, big.NewInt(10000000000), big.NewInt(1293460000000000)},
   230  		{9236192, 9876, big.NewInt(50000), big.NewInt(461809600000)},
   231  		{9236192, 25000000000, big.NewInt(50000), big.NewInt(461809600000)},
   232  		{12936418927364923, 25000000000, big.NewInt(0), big.NewInt(0)},
   233  	}
   234  
   235  	for _, testCase := range testCases {
   236  		header := &types.Header{
   237  			Number:  big.NewInt(0),
   238  			GasUsed: testCase.gasUsed,
   239  			BaseFee: testCase.baseFee,
   240  		}
   241  		config := &params.ChainConfig{
   242  			UnitPrice: testCase.unitPrice,
   243  		}
   244  		if testCase.baseFee != nil {
   245  			// enable Magma
   246  			config.MagmaCompatibleBlock = big.NewInt(0)
   247  		}
   248  
   249  		rules := config.Rules(header.Number)
   250  		pset, err := params.NewGovParamSetChainConfig(config)
   251  		require.Nil(t, err)
   252  
   253  		result := GetTotalTxFee(header, rules, pset)
   254  		assert.Equal(t, testCase.expectedTotalTxFee.Uint64(), result.Uint64())
   255  	}
   256  }
   257  
   258  func TestRewardDistributor_getBurnAmountMagma(t *testing.T) {
   259  	testCases := []struct {
   260  		gasUsed            uint64
   261  		baseFee            *big.Int
   262  		expectedTotalTxFee *big.Int
   263  	}{
   264  		{0, big.NewInt(25000000000), big.NewInt(0)},
   265  		{200000, big.NewInt(25000000000), big.NewInt(5000000000000000 / 2)},
   266  		{200000, big.NewInt(25000000000), big.NewInt(5000000000000000 / 2)},
   267  		{129346, big.NewInt(10000000000), big.NewInt(1293460000000000 / 2)},
   268  		{129346, big.NewInt(10000000000), big.NewInt(1293460000000000 / 2)},
   269  		{9236192, big.NewInt(50000), big.NewInt(461809600000 / 2)},
   270  		{9236192, big.NewInt(50000), big.NewInt(461809600000 / 2)},
   271  		{12936418927364923, big.NewInt(0), big.NewInt(0)},
   272  	}
   273  
   274  	var (
   275  		header = &types.Header{
   276  			Number: big.NewInt(1),
   277  		}
   278  		rules = params.Rules{
   279  			IsMagma: true,
   280  		}
   281  		pset, _ = params.NewGovParamSetIntMap(map[int]interface{}{
   282  			params.UnitPrice: 0, // unused value because Magma
   283  		})
   284  	)
   285  
   286  	for _, testCase := range testCases {
   287  		header.GasUsed = testCase.gasUsed
   288  		header.BaseFee = testCase.baseFee
   289  		txFee := GetTotalTxFee(header, rules, pset)
   290  		burnedTxFee := getBurnAmountMagma(txFee)
   291  		// expectedTotalTxFee = GetTotalTxFee / 2 = BurnedTxFee
   292  		assert.Equal(t, testCase.expectedTotalTxFee.Uint64(), burnedTxFee.Uint64())
   293  	}
   294  }
   295  
   296  func TestRewardDistributor_GetBlockReward(t *testing.T) {
   297  	oldStakingManager := GetStakingManager()
   298  	defer SetTestStakingManager(oldStakingManager)
   299  
   300  	var (
   301  		header = &types.Header{
   302  			Number:     big.NewInt(1),
   303  			GasUsed:    1000,
   304  			BaseFee:    big.NewInt(1),
   305  			Rewardbase: proposerAddr,
   306  		}
   307  		stakingInfo = genStakingInfo(5, nil, map[int]uint64{
   308  			0: minStaking + 4,
   309  			1: minStaking + 3,
   310  		})
   311  		rules = params.Rules{
   312  			IsMagma: true,
   313  			IsKore:  true,
   314  		}
   315  	)
   316  
   317  	testcases := []struct {
   318  		policy        istanbul.ProposerPolicy
   319  		deferredTxFee bool
   320  		expected      *RewardSpec
   321  	}{
   322  		{
   323  			policy:        istanbul.RoundRobin,
   324  			deferredTxFee: true,
   325  			expected: &RewardSpec{
   326  				Minted:   minted,
   327  				TotalFee: new(big.Int).SetUint64(1000),
   328  				BurntFee: new(big.Int).SetUint64(500),
   329  				Proposer: new(big.Int).SetUint64(9.6e18 + 500),
   330  				Stakers:  new(big.Int).SetUint64(0),
   331  				KFF:      new(big.Int).SetUint64(0),
   332  				KCF:      new(big.Int).SetUint64(0),
   333  				Rewards: map[common.Address]*big.Int{
   334  					proposerAddr: new(big.Int).SetUint64(9.6e18 + 500),
   335  				},
   336  			},
   337  		},
   338  		{
   339  			policy:        istanbul.RoundRobin,
   340  			deferredTxFee: false,
   341  			expected: &RewardSpec{
   342  				Minted:   minted,
   343  				TotalFee: new(big.Int).SetUint64(1000),
   344  				BurntFee: new(big.Int).SetUint64(500),
   345  				Proposer: new(big.Int).SetUint64(9.6e18 + 500),
   346  				Stakers:  new(big.Int).SetUint64(0),
   347  				KFF:      new(big.Int).SetUint64(0),
   348  				KCF:      new(big.Int).SetUint64(0),
   349  				Rewards: map[common.Address]*big.Int{
   350  					proposerAddr: new(big.Int).SetUint64(9.6e18 + 500),
   351  				},
   352  			},
   353  		},
   354  		{
   355  			policy:        istanbul.WeightedRandom,
   356  			deferredTxFee: true,
   357  			expected: &RewardSpec{
   358  				Minted:   minted,
   359  				TotalFee: new(big.Int).SetUint64(1000),
   360  				BurntFee: new(big.Int).SetUint64(1000),
   361  				Proposer: new(big.Int).SetUint64(0.6528e18 + 1),
   362  				Stakers:  new(big.Int).SetUint64(2.6112e18 - 1),
   363  				KFF:      new(big.Int).SetUint64(5.184e18),
   364  				KCF:      new(big.Int).SetUint64(1.152e18),
   365  				Rewards: map[common.Address]*big.Int{
   366  					proposerAddr:                     new(big.Int).SetUint64(0.6528e18 + 1),
   367  					kffAddr:                          new(big.Int).SetUint64(5.184e18),
   368  					kcfAddr:                          new(big.Int).SetUint64(1.152e18),
   369  					intToAddress(rewardBaseAddr):     new(big.Int).SetUint64(1492114285714285714),
   370  					intToAddress(rewardBaseAddr + 1): new(big.Int).SetUint64(1119085714285714285),
   371  				},
   372  			},
   373  		},
   374  		{
   375  			policy:        istanbul.WeightedRandom,
   376  			deferredTxFee: false,
   377  			expected: &RewardSpec{
   378  				Minted:   minted,
   379  				TotalFee: new(big.Int).SetUint64(1000),
   380  				BurntFee: new(big.Int).SetUint64(500),
   381  				Proposer: new(big.Int).SetUint64(0.6528e18 + 500 + 1),
   382  				Stakers:  new(big.Int).SetUint64(2.6112e18 - 1),
   383  				KFF:      new(big.Int).SetUint64(5.184e18),
   384  				KCF:      new(big.Int).SetUint64(1.152e18),
   385  				Rewards: map[common.Address]*big.Int{
   386  					proposerAddr:                     new(big.Int).SetUint64(0.6528e18 + 500 + 1),
   387  					kffAddr:                          new(big.Int).SetUint64(5.184e18),
   388  					kcfAddr:                          new(big.Int).SetUint64(1.152e18),
   389  					intToAddress(rewardBaseAddr):     new(big.Int).SetUint64(1492114285714285714),
   390  					intToAddress(rewardBaseAddr + 1): new(big.Int).SetUint64(1119085714285714285),
   391  				},
   392  			},
   393  		},
   394  	}
   395  
   396  	SetTestStakingManagerWithStakingInfoCache(stakingInfo)
   397  
   398  	for i, tc := range testcases {
   399  		config := getTestConfig()
   400  		if !tc.deferredTxFee {
   401  			config = noDeferred(config)
   402  		}
   403  		config.Istanbul.ProposerPolicy = uint64(tc.policy)
   404  
   405  		pset, err := params.NewGovParamSetChainConfig(config)
   406  		require.Nil(t, err)
   407  
   408  		spec, err := GetBlockReward(header, rules, pset)
   409  		require.Nil(t, err, "testcases[%d] failed", i)
   410  		assertEqualRewardSpecs(t, tc.expected, spec, "testcases[%d] failed", i)
   411  	}
   412  }
   413  
   414  func TestRewardDistributor_CalcDeferredRewardSimple(t *testing.T) {
   415  	header := &types.Header{
   416  		Number:     big.NewInt(1),
   417  		GasUsed:    1000,
   418  		BaseFee:    big.NewInt(1),
   419  		Rewardbase: proposerAddr,
   420  	}
   421  
   422  	testcases := []struct {
   423  		isMagma  bool
   424  		expected *RewardSpec
   425  	}{
   426  		{
   427  			isMagma: false,
   428  			expected: &RewardSpec{
   429  				Minted:   minted,
   430  				TotalFee: new(big.Int).SetUint64(1000),
   431  				BurntFee: new(big.Int).SetUint64(0),
   432  				Proposer: new(big.Int).SetUint64(9.6e18 + 1000),
   433  				Stakers:  new(big.Int).SetUint64(0),
   434  				KFF:      new(big.Int).SetUint64(0),
   435  				KCF:      new(big.Int).SetUint64(0),
   436  				Rewards: map[common.Address]*big.Int{
   437  					proposerAddr: new(big.Int).SetUint64(9.6e18 + 1000),
   438  				},
   439  			},
   440  		},
   441  		{
   442  			isMagma: true,
   443  			expected: &RewardSpec{
   444  				Minted:   minted,
   445  				TotalFee: new(big.Int).SetUint64(1000),
   446  				BurntFee: new(big.Int).SetUint64(500), // 50% of tx fee burnt
   447  				Proposer: new(big.Int).SetUint64(9.6e18 + 500),
   448  				Stakers:  new(big.Int).SetUint64(0),
   449  				KFF:      new(big.Int).SetUint64(0),
   450  				KCF:      new(big.Int).SetUint64(0),
   451  				Rewards: map[common.Address]*big.Int{
   452  					proposerAddr: new(big.Int).SetUint64(9.6e18 + 500),
   453  				},
   454  			},
   455  		},
   456  	}
   457  
   458  	for i, tc := range testcases {
   459  		config := roundrobin(getTestConfig())
   460  		if !tc.isMagma {
   461  			config = noMagma(config)
   462  		}
   463  
   464  		rules := config.Rules(header.Number)
   465  		pset, err := params.NewGovParamSetChainConfig(config)
   466  		require.Nil(t, err)
   467  
   468  		spec, err := CalcDeferredRewardSimple(header, rules, pset)
   469  		require.Nil(t, err, "testcases[%d] failed", i)
   470  		assertEqualRewardSpecs(t, tc.expected, spec, "testcases[%d] failed", i)
   471  	}
   472  }
   473  
   474  // Before Kore, there was a bug that distributed txFee at the end of
   475  // block processing regardless of `deferredTxFee` flag.
   476  // See https://github.com/klaytn/klaytn/issues/1692.
   477  // To maintain backward compatibility, we only fix the buggy logic after Magma
   478  // and leave the buggy logic before Kore.
   479  func TestRewardDistributor_CalcDeferredRewardSimple_nodeferred(t *testing.T) {
   480  	header := &types.Header{
   481  		Number:     big.NewInt(1),
   482  		GasUsed:    1000,
   483  		BaseFee:    big.NewInt(1),
   484  		Rewardbase: proposerAddr,
   485  	}
   486  
   487  	testcases := []struct {
   488  		isMagma  bool
   489  		isKore   bool
   490  		expected *RewardSpec
   491  	}{
   492  		{ // totalFee should have been 0, but returned due to bug
   493  			isMagma: false,
   494  			isKore:  false,
   495  			expected: &RewardSpec{
   496  				Minted:   minted,
   497  				TotalFee: new(big.Int).SetUint64(1000),
   498  				BurntFee: new(big.Int).SetUint64(0),
   499  				Proposer: new(big.Int).SetUint64(9.6e18 + 1000),
   500  				Stakers:  new(big.Int).SetUint64(0),
   501  				KFF:      new(big.Int).SetUint64(0),
   502  				KCF:      new(big.Int).SetUint64(0),
   503  				Rewards: map[common.Address]*big.Int{
   504  					proposerAddr: new(big.Int).SetUint64(9.6e18 + 1000),
   505  				},
   506  			},
   507  		},
   508  		{ // totalFee is now 0 because bug is fixed after Magma
   509  			isMagma: true,
   510  			isKore:  false,
   511  			expected: &RewardSpec{
   512  				Minted:   minted,
   513  				TotalFee: new(big.Int).SetUint64(0),
   514  				BurntFee: new(big.Int).SetUint64(0),
   515  				Proposer: new(big.Int).SetUint64(9.6e18),
   516  				Stakers:  new(big.Int).SetUint64(0),
   517  				KFF:      new(big.Int).SetUint64(0),
   518  				KCF:      new(big.Int).SetUint64(0),
   519  				Rewards: map[common.Address]*big.Int{
   520  					proposerAddr: new(big.Int).SetUint64(9.6e18),
   521  				},
   522  			},
   523  		},
   524  		{ // totalFee is now 0 because bug is fixed after Kore
   525  			isMagma: true,
   526  			isKore:  true,
   527  			expected: &RewardSpec{
   528  				Minted:   minted,
   529  				TotalFee: new(big.Int).SetUint64(0),
   530  				BurntFee: new(big.Int).SetUint64(0),
   531  				Proposer: new(big.Int).SetUint64(9.6e18),
   532  				Stakers:  new(big.Int).SetUint64(0),
   533  				KFF:      new(big.Int).SetUint64(0),
   534  				KCF:      new(big.Int).SetUint64(0),
   535  				Rewards: map[common.Address]*big.Int{
   536  					proposerAddr: new(big.Int).SetUint64(9.6e18),
   537  				},
   538  			},
   539  		},
   540  	}
   541  
   542  	for i, tc := range testcases {
   543  		config := noDeferred((getTestConfig()))
   544  		if !tc.isMagma {
   545  			config = noMagma(config)
   546  		}
   547  		if !tc.isKore {
   548  			config = noKore(config)
   549  		}
   550  
   551  		rules := config.Rules(header.Number)
   552  		pset, err := params.NewGovParamSetChainConfig(config)
   553  		require.Nil(t, err)
   554  		spec, err := CalcDeferredRewardSimple(header, rules, pset)
   555  		require.Nil(t, err, "testcases[%d] failed", i)
   556  		assertEqualRewardSpecs(t, tc.expected, spec, "testcases[%d] failed", i)
   557  	}
   558  }
   559  
   560  func TestRewardDistributor_CalcDeferredReward(t *testing.T) {
   561  	oldStakingManager := GetStakingManager()
   562  	defer SetTestStakingManager(oldStakingManager)
   563  
   564  	stakingInfo := genStakingInfo(5, nil, map[int]uint64{
   565  		0: minStaking + 4,
   566  		1: minStaking + 3,
   567  	})
   568  
   569  	testcases := []struct {
   570  		desc     string
   571  		isKore   bool
   572  		isMagma  bool
   573  		fee      uint64
   574  		expected *RewardSpec
   575  	}{
   576  		{
   577  			desc:    "isKore=false, isMagma=false, fee=1000 [000]",
   578  			isKore:  false,
   579  			isMagma: false,
   580  			fee:     1000,
   581  			expected: &RewardSpec{
   582  				Minted:   minted,
   583  				TotalFee: big.NewInt(1000),
   584  				BurntFee: big.NewInt(0),
   585  				Proposer: big.NewInt(0).SetUint64(3.264e18 + 340),
   586  				Stakers:  big.NewInt(0),
   587  				KFF:      big.NewInt(5.184e18 + 540),
   588  				KCF:      big.NewInt(1.152e18 + 120),
   589  				Rewards: map[common.Address]*big.Int{
   590  					proposerAddr: big.NewInt(3.264e18 + 340),
   591  					kffAddr:      big.NewInt(5.184e18 + 540),
   592  					kcfAddr:      big.NewInt(1.152e18 + 120),
   593  				},
   594  			},
   595  		},
   596  		{
   597  			desc:    "isKore=false, isMagma=false, fee=10e18 [001]",
   598  			isKore:  false,
   599  			isMagma: false,
   600  			fee:     10e18,
   601  			expected: &RewardSpec{
   602  				Minted:   minted,
   603  				TotalFee: new(big.Int).SetUint64(10e18),
   604  				BurntFee: new(big.Int).SetUint64(0),
   605  				Proposer: new(big.Int).SetUint64(6.664e18),
   606  				Stakers:  new(big.Int).SetUint64(0),
   607  				KFF:      new(big.Int).SetUint64(10.584e18),
   608  				KCF:      new(big.Int).SetUint64(2.352e18),
   609  				Rewards: map[common.Address]*big.Int{
   610  					proposerAddr: new(big.Int).SetUint64(6.664e18),
   611  					kffAddr:      new(big.Int).SetUint64(10.584e18),
   612  					kcfAddr:      new(big.Int).SetUint64(2.352e18),
   613  				},
   614  			},
   615  		},
   616  		{
   617  			desc:    "isKore=false, isMagma=true, fee=1000 [010]",
   618  			isKore:  false,
   619  			isMagma: true,
   620  			fee:     1000,
   621  			expected: &RewardSpec{
   622  				Minted:   minted,
   623  				TotalFee: new(big.Int).SetUint64(1000),
   624  				BurntFee: new(big.Int).SetUint64(500),
   625  				Proposer: new(big.Int).SetUint64(3.264e18 + 170),
   626  				Stakers:  new(big.Int).SetUint64(0),
   627  				KFF:      new(big.Int).SetUint64(5.184e18 + 270),
   628  				KCF:      new(big.Int).SetUint64(1.152e18 + 60),
   629  				Rewards: map[common.Address]*big.Int{
   630  					proposerAddr: new(big.Int).SetUint64(3.264e18 + 170),
   631  					kcfAddr:      new(big.Int).SetUint64(1.152e18 + 60),
   632  					kffAddr:      new(big.Int).SetUint64(5.184e18 + 270),
   633  				},
   634  			},
   635  		},
   636  		{
   637  			desc:    "isKore=false, isMagma=true, fee=10e18 [011]",
   638  			isKore:  false,
   639  			isMagma: true,
   640  			fee:     10e18,
   641  			expected: &RewardSpec{
   642  				Minted:   minted,
   643  				TotalFee: new(big.Int).SetUint64(10e18),
   644  				BurntFee: new(big.Int).SetUint64(5e18),
   645  				Proposer: new(big.Int).SetUint64(4.964e18),
   646  				Stakers:  new(big.Int).SetUint64(0),
   647  				KFF:      new(big.Int).SetUint64(7.884e18),
   648  				KCF:      new(big.Int).SetUint64(1.752e18),
   649  				Rewards: map[common.Address]*big.Int{
   650  					proposerAddr: new(big.Int).SetUint64(4.964e18),
   651  					kffAddr:      new(big.Int).SetUint64(7.884e18),
   652  					kcfAddr:      new(big.Int).SetUint64(1.752e18),
   653  				},
   654  			},
   655  		},
   656  		{
   657  			desc:    "isKore=true, isMagma=true, fee=1000 [110]",
   658  			isKore:  true,
   659  			isMagma: true,
   660  			fee:     1000,
   661  			expected: &RewardSpec{
   662  				Minted:   minted,
   663  				TotalFee: new(big.Int).SetUint64(1000),
   664  				BurntFee: new(big.Int).SetUint64(1000),
   665  				Proposer: new(big.Int).SetUint64(0.6528e18 + 1),
   666  				Stakers:  new(big.Int).SetUint64(2.6112e18 - 1),
   667  				KFF:      new(big.Int).SetUint64(5.184e18),
   668  				KCF:      new(big.Int).SetUint64(1.152e18),
   669  				Rewards: map[common.Address]*big.Int{
   670  					proposerAddr:                     new(big.Int).SetUint64(0.6528e18 + 1),
   671  					kffAddr:                          new(big.Int).SetUint64(5.184e18),
   672  					kcfAddr:                          new(big.Int).SetUint64(1.152e18),
   673  					intToAddress(rewardBaseAddr):     new(big.Int).SetUint64(1492114285714285714),
   674  					intToAddress(rewardBaseAddr + 1): new(big.Int).SetUint64(1119085714285714285),
   675  				},
   676  			},
   677  		},
   678  		{ // after kore, more-than-default staking, large fee, proposer = rewardbase
   679  			desc:    "isKore=true, isMagma=true, fee=10e18 [111]",
   680  			isKore:  true,
   681  			isMagma: true,
   682  			fee:     10e18,
   683  			expected: &RewardSpec{
   684  				Minted:   minted,
   685  				TotalFee: new(big.Int).SetUint64(10e18),
   686  				BurntFee: new(big.Int).SetUint64(5e18 + 0.6528e18),
   687  				Proposer: new(big.Int).SetUint64(5e18 + 1),
   688  				Stakers:  new(big.Int).SetUint64(2.6112e18 - 1),
   689  				KFF:      new(big.Int).SetUint64(5.184e18),
   690  				KCF:      new(big.Int).SetUint64(1.152e18),
   691  				Rewards: map[common.Address]*big.Int{
   692  					proposerAddr:                     new(big.Int).SetUint64(5e18 + 1),
   693  					kffAddr:                          new(big.Int).SetUint64(5.184e18),
   694  					kcfAddr:                          new(big.Int).SetUint64(1.152e18),
   695  					intToAddress(rewardBaseAddr):     new(big.Int).SetUint64(1492114285714285714),
   696  					intToAddress(rewardBaseAddr + 1): new(big.Int).SetUint64(1119085714285714285),
   697  				},
   698  			},
   699  		},
   700  	}
   701  
   702  	SetTestStakingManagerWithStakingInfoCache(stakingInfo)
   703  
   704  	for _, tc := range testcases {
   705  		header := &types.Header{
   706  			Number:     big.NewInt(1),
   707  			GasUsed:    tc.fee,
   708  			BaseFee:    big.NewInt(1),
   709  			Rewardbase: proposerAddr,
   710  		}
   711  
   712  		config := getTestConfig()
   713  		if !tc.isKore {
   714  			config = noKore(config)
   715  		}
   716  		if !tc.isMagma {
   717  			config = noMagma(config)
   718  		}
   719  
   720  		rules := config.Rules(header.Number)
   721  		pset, err := params.NewGovParamSetChainConfig(config)
   722  		require.Nil(t, err)
   723  
   724  		spec, err := CalcDeferredReward(header, rules, pset)
   725  		require.Nil(t, err, "failed tc: %s", tc.desc)
   726  		assertEqualRewardSpecs(t, tc.expected, spec, "failed tc: %s", tc.desc)
   727  	}
   728  }
   729  
   730  func TestRewardDistributor_CalcDeferredReward_StakingInfos(t *testing.T) {
   731  	oldStakingManager := GetStakingManager()
   732  	defer SetTestStakingManager(oldStakingManager)
   733  
   734  	var (
   735  		header = &types.Header{
   736  			Number:     big.NewInt(1),
   737  			GasUsed:    1000,
   738  			BaseFee:    big.NewInt(1),
   739  			Rewardbase: proposerAddr,
   740  		}
   741  		config  = getTestConfig()
   742  		rules   = config.Rules(header.Number)
   743  		pset, _ = params.NewGovParamSetChainConfig(config)
   744  	)
   745  
   746  	testcases := []struct {
   747  		desc        string
   748  		stakingInfo *StakingInfo
   749  		expected    *RewardSpec
   750  	}{
   751  		{
   752  			desc:        "stakingInfo is nil, its portion goes to proposer",
   753  			stakingInfo: nil,
   754  			expected: &RewardSpec{
   755  				Minted:   minted,
   756  				TotalFee: big.NewInt(1000),
   757  				BurntFee: big.NewInt(1000),
   758  				Proposer: minted,
   759  				Stakers:  big.NewInt(0),
   760  				KFF:      big.NewInt(0),
   761  				KCF:      big.NewInt(0),
   762  				Rewards: map[common.Address]*big.Int{
   763  					proposerAddr: minted,
   764  				},
   765  			},
   766  		},
   767  		{
   768  			desc: "stakingInfo has no kff, its portion goes to proposer",
   769  			stakingInfo: &StakingInfo{
   770  				KCFAddr: kcfAddr,
   771  				KFFAddr: common.Address{},
   772  			},
   773  			expected: &RewardSpec{
   774  				Minted:   minted,
   775  				TotalFee: big.NewInt(1000),
   776  				BurntFee: big.NewInt(1000),
   777  				Proposer: big.NewInt(8.448e18),
   778  				Stakers:  big.NewInt(0),
   779  				KFF:      big.NewInt(0),
   780  				KCF:      big.NewInt(1.152e18), // minted * 0.12
   781  				Rewards: map[common.Address]*big.Int{
   782  					proposerAddr: big.NewInt(8.448e18),
   783  					kcfAddr:      big.NewInt(1.152e18),
   784  				},
   785  			},
   786  		},
   787  		{
   788  			desc: "stakingInfo has no kcf, its portion goes to proposer",
   789  			stakingInfo: &StakingInfo{
   790  				KCFAddr: common.Address{},
   791  				KFFAddr: kffAddr,
   792  			},
   793  			expected: &RewardSpec{
   794  				Minted:   minted,
   795  				TotalFee: big.NewInt(1000),
   796  				BurntFee: big.NewInt(1000),
   797  				Proposer: big.NewInt(4.416e18),
   798  				Stakers:  big.NewInt(0),
   799  				KFF:      big.NewInt(5.184e18), // minted * 0.54
   800  				KCF:      big.NewInt(0),
   801  				Rewards: map[common.Address]*big.Int{
   802  					proposerAddr: big.NewInt(4.416e18),
   803  					kffAddr:      big.NewInt(5.184e18),
   804  				},
   805  			},
   806  		},
   807  		{
   808  			desc: "stakingInfo has the same kff and kcf",
   809  			stakingInfo: &StakingInfo{
   810  				KCFAddr: kffAddr,
   811  				KFFAddr: kffAddr,
   812  			},
   813  			expected: &RewardSpec{
   814  				Minted:   minted,
   815  				TotalFee: big.NewInt(1000),
   816  				BurntFee: big.NewInt(1000),
   817  				Proposer: big.NewInt(3.264e18),
   818  				Stakers:  big.NewInt(0),
   819  				KFF:      big.NewInt(5.184e18),
   820  				KCF:      big.NewInt(1.152e18),
   821  				Rewards: map[common.Address]*big.Int{
   822  					proposerAddr: big.NewInt(3.264e18),
   823  					kffAddr:      big.NewInt(6.336e18),
   824  				},
   825  			},
   826  		},
   827  	}
   828  
   829  	for i, tc := range testcases {
   830  		if tc.stakingInfo == nil {
   831  			SetTestStakingManager(nil)
   832  		} else {
   833  			SetTestStakingManagerWithStakingInfoCache(tc.stakingInfo)
   834  		}
   835  		spec, err := CalcDeferredReward(header, rules, pset)
   836  		require.Nil(t, err, "testcases[%d] failed", i)
   837  		assertEqualRewardSpecs(t, tc.expected, spec, "testcases[%d] failed: %s", i, tc.desc)
   838  	}
   839  }
   840  
   841  func TestRewardDistributor_CalcDeferredReward_Remainings(t *testing.T) {
   842  	oldStakingManager := GetStakingManager()
   843  	defer SetTestStakingManager(oldStakingManager)
   844  
   845  	var (
   846  		header = &types.Header{
   847  			Number:     big.NewInt(1),
   848  			GasUsed:    1000,
   849  			BaseFee:    big.NewInt(1),
   850  			Rewardbase: proposerAddr,
   851  		}
   852  
   853  		stakingInfo = genStakingInfo(5, nil, map[int]uint64{
   854  			0: minStaking + 4,
   855  			1: minStaking + 3,
   856  		})
   857  		splitRemainingConfig = getTestConfig()
   858  	)
   859  	splitRemainingConfig.Governance.Reward.MintingAmount = big.NewInt(333)
   860  
   861  	testcases := []struct {
   862  		desc     string
   863  		config   *params.ChainConfig
   864  		expected *RewardSpec
   865  	}{
   866  		{
   867  			desc:   "split remaining goes to kff",
   868  			config: splitRemainingConfig,
   869  			expected: &RewardSpec{
   870  				Minted:   big.NewInt(333),
   871  				TotalFee: big.NewInt(1000),
   872  				BurntFee: big.NewInt(522),
   873  				Proposer: big.NewInt(501), // proposer=22, rewardFee=478, shareRem=1
   874  				Stakers:  big.NewInt(89),
   875  				KFF:      big.NewInt(182), // splitRem=3
   876  				KCF:      big.NewInt(39),
   877  				Rewards: map[common.Address]*big.Int{
   878  					proposerAddr:                     big.NewInt(501),
   879  					kffAddr:                          big.NewInt(182),
   880  					kcfAddr:                          big.NewInt(39),
   881  					intToAddress(rewardBaseAddr):     big.NewInt(51), // stakers * 4/7
   882  					intToAddress(rewardBaseAddr + 1): big.NewInt(38), // stakers * 3/7
   883  				},
   884  			},
   885  		},
   886  		{
   887  			desc:   "share remaining goes to proposer",
   888  			config: getTestConfig(),
   889  			expected: &RewardSpec{
   890  				Minted:   minted,
   891  				TotalFee: big.NewInt(1000),
   892  				BurntFee: big.NewInt(1000),
   893  				Proposer: big.NewInt(0.6528e18 + 1),
   894  				Stakers:  big.NewInt(2.6112e18 - 1),
   895  				KFF:      big.NewInt(5.184e18),
   896  				KCF:      big.NewInt(1.152e18),
   897  				Rewards: map[common.Address]*big.Int{
   898  					proposerAddr:                     big.NewInt(0.6528e18 + 1),
   899  					kffAddr:                          big.NewInt(5.184e18),
   900  					kcfAddr:                          big.NewInt(1.152e18),
   901  					intToAddress(rewardBaseAddr):     big.NewInt(1492114285714285714), // stakers * 4/7
   902  					intToAddress(rewardBaseAddr + 1): big.NewInt(1119085714285714285), // stakers * 3/7
   903  				},
   904  			},
   905  		},
   906  	}
   907  
   908  	SetTestStakingManagerWithStakingInfoCache(stakingInfo)
   909  
   910  	for _, tc := range testcases {
   911  		rules := tc.config.Rules(header.Number)
   912  		pset, err := params.NewGovParamSetChainConfig(tc.config)
   913  		require.Nil(t, err)
   914  
   915  		spec, err := CalcDeferredReward(header, rules, pset)
   916  		require.Nil(t, err, "failed tc: %s", tc.desc)
   917  		assertEqualRewardSpecs(t, tc.expected, spec, "failed tc: %s", tc.desc)
   918  	}
   919  }
   920  
   921  func TestRewardDistributor_calcDeferredFee(t *testing.T) {
   922  	type Result struct{ total, reward, burnt uint64 }
   923  
   924  	testcases := []struct {
   925  		desc     string
   926  		isKore   bool
   927  		isMagma  bool
   928  		fee      uint64
   929  		expected *Result
   930  	}{
   931  		{
   932  			desc:    "isKore=false, isMagma=false, fee=1000 [000]",
   933  			isKore:  false,
   934  			isMagma: false,
   935  			fee:     1000,
   936  			expected: &Result{
   937  				total:  1000,
   938  				reward: 1000,
   939  				burnt:  0,
   940  			},
   941  		},
   942  		{
   943  			desc:    "isKore=false, isMagma=false, fee=10e18 [001]",
   944  			isKore:  false,
   945  			isMagma: false,
   946  			fee:     10e18,
   947  			expected: &Result{
   948  				total:  10e18,
   949  				reward: 10e18,
   950  				burnt:  0,
   951  			},
   952  		},
   953  		{
   954  			desc:    "isKore=false, isMagma=true, fee=1000 [010]",
   955  			isKore:  false,
   956  			isMagma: true,
   957  			fee:     1000,
   958  			expected: &Result{
   959  				total:  1000,
   960  				reward: 500,
   961  				burnt:  500,
   962  			},
   963  		},
   964  		{
   965  			desc:    "isKore=false, isMagma=true, fee=10e18 [011]",
   966  			isKore:  false,
   967  			isMagma: true,
   968  			fee:     10e18,
   969  			expected: &Result{
   970  				total:  10e18,
   971  				reward: 5e18,
   972  				burnt:  5e18,
   973  			},
   974  		},
   975  		{
   976  			desc:    "isKore=true, isMagma=true, fee=1000 [110]",
   977  			isKore:  true,
   978  			isMagma: true,
   979  			fee:     1000,
   980  			expected: &Result{
   981  				total:  1000,
   982  				reward: 0,
   983  				burnt:  1000,
   984  			},
   985  		},
   986  		{
   987  			desc:    "isKore=true, isMagma=true, fee=10e18 [111]",
   988  			isKore:  true,
   989  			isMagma: true,
   990  			fee:     10e18,
   991  			expected: &Result{
   992  				total:  10e18,
   993  				reward: 4.3472e18, // 5 - minted*0.34*0.2
   994  				burnt:  5.6528e18, // 5 + minted*0.34*0.8
   995  			},
   996  		},
   997  	}
   998  
   999  	for _, tc := range testcases {
  1000  		header := &types.Header{
  1001  			Number:     big.NewInt(1),
  1002  			GasUsed:    tc.fee,
  1003  			BaseFee:    big.NewInt(1),
  1004  			Rewardbase: proposerAddr,
  1005  		}
  1006  
  1007  		config := getTestConfig()
  1008  		if !tc.isKore {
  1009  			config = noKore(config)
  1010  		}
  1011  		if !tc.isMagma {
  1012  			config = noMagma(config)
  1013  		}
  1014  
  1015  		rules := config.Rules(header.Number)
  1016  		pset, err := params.NewGovParamSetChainConfig(config)
  1017  		require.Nil(t, err)
  1018  
  1019  		rc, err := NewRewardConfig(header, rules, pset)
  1020  		require.Nil(t, err)
  1021  
  1022  		total, reward, burnt := calcDeferredFee(rc)
  1023  		actual := &Result{
  1024  			total:  total.Uint64(),
  1025  			reward: reward.Uint64(),
  1026  			burnt:  burnt.Uint64(),
  1027  		}
  1028  		assert.Equal(t, tc.expected, actual, "failed tc: %s", tc.desc)
  1029  	}
  1030  }
  1031  
  1032  func TestRewardDistributor_calcDeferredFee_nodeferred(t *testing.T) {
  1033  	var (
  1034  		header = &types.Header{
  1035  			Number:     big.NewInt(1),
  1036  			GasUsed:    1000,
  1037  			BaseFee:    big.NewInt(1),
  1038  			Rewardbase: proposerAddr,
  1039  		}
  1040  		rules = params.Rules{
  1041  			IsMagma: true,
  1042  		}
  1043  	)
  1044  
  1045  	pset, err := params.NewGovParamSetChainConfig(noDeferred(getTestConfig()))
  1046  	require.Nil(t, err)
  1047  
  1048  	rc, err := NewRewardConfig(header, rules, pset)
  1049  	require.Nil(t, err)
  1050  
  1051  	total, reward, burnt := calcDeferredFee(rc)
  1052  	assert.Equal(t, uint64(0), total.Uint64())
  1053  	assert.Equal(t, uint64(0), reward.Uint64())
  1054  	assert.Equal(t, uint64(0), burnt.Uint64())
  1055  }
  1056  
  1057  func TestRewardDistributor_calcSplit(t *testing.T) {
  1058  	type Result struct{ proposer, stakers, kff, kcf, remaining uint64 }
  1059  
  1060  	header := &types.Header{
  1061  		Number:  big.NewInt(1),
  1062  		BaseFee: big.NewInt(0), // placeholder
  1063  	}
  1064  
  1065  	testcases := []struct {
  1066  		desc     string
  1067  		isKore   bool
  1068  		fee      uint64
  1069  		expected *Result
  1070  	}{
  1071  		{
  1072  			desc:   "kore=false, fee=0",
  1073  			isKore: false,
  1074  			fee:    0,
  1075  			expected: &Result{
  1076  				proposer:  3.264e18, // minted * 0.34
  1077  				stakers:   0,
  1078  				kff:       5.184e18, // minted * 0.54
  1079  				kcf:       1.152e18, // minted * 0.12
  1080  				remaining: 0,
  1081  			},
  1082  		},
  1083  		{
  1084  			desc:   "kore=false, fee=55555",
  1085  			isKore: false,
  1086  			fee:    55555,
  1087  			expected: &Result{
  1088  				proposer:  3.264e18 + 18888, // (minted + fee) * 0.34
  1089  				stakers:   0,
  1090  				kff:       5.184e18 + 29999, // (minted + fee) * 0.54
  1091  				kcf:       1.152e18 + 6666,  // (minted + fee) * 0.12
  1092  				remaining: 2,
  1093  			},
  1094  		},
  1095  		{
  1096  			desc:   "kore=true, fee=0",
  1097  			isKore: true,
  1098  			fee:    0,
  1099  			expected: &Result{
  1100  				proposer:  0.6528e18, // minted * 0.34 * 0.2
  1101  				stakers:   2.6112e18, // minted * 0.34 * 0.8
  1102  				kff:       5.184e18,  // minted * 0.54
  1103  				kcf:       1.152e18,  // minted * 0.12
  1104  				remaining: 0,
  1105  			},
  1106  		},
  1107  		{
  1108  			desc:   "kore=true, fee=55555",
  1109  			isKore: true,
  1110  			fee:    55555,
  1111  			expected: &Result{
  1112  				proposer:  0.6528e18 + 55555, // minted * 0.34 * 0.2 + fee
  1113  				stakers:   2.6112e18,         // minted * 0.34 * 0.8
  1114  				kff:       5.184e18,          // minted * 0.54
  1115  				kcf:       1.152e18,          // minted * 0.12
  1116  				remaining: 0,
  1117  			},
  1118  		},
  1119  	}
  1120  
  1121  	for _, tc := range testcases {
  1122  		config := getTestConfig()
  1123  		if !tc.isKore {
  1124  			config = noKore(config)
  1125  		}
  1126  
  1127  		rules := config.Rules(header.Number)
  1128  		pset, err := params.NewGovParamSetChainConfig(config)
  1129  		require.Nil(t, err)
  1130  
  1131  		rc, err := NewRewardConfig(header, rules, pset)
  1132  		require.Nil(t, err)
  1133  
  1134  		fee := new(big.Int).SetUint64(tc.fee)
  1135  		proposer, stakers, kff, kcf, remaining := calcSplit(rc, minted, fee)
  1136  		actual := &Result{
  1137  			proposer:  proposer.Uint64(),
  1138  			stakers:   stakers.Uint64(),
  1139  			kff:       kff.Uint64(),
  1140  			kcf:       kcf.Uint64(),
  1141  			remaining: remaining.Uint64(),
  1142  		}
  1143  		assert.Equal(t, tc.expected, actual, "failed tc: %s", tc.desc)
  1144  
  1145  		expectedTotalAmount := big.NewInt(0)
  1146  		expectedTotalAmount = expectedTotalAmount.Add(minted, fee)
  1147  
  1148  		actualTotalAmount := big.NewInt(0)
  1149  		actualTotalAmount = actualTotalAmount.Add(actualTotalAmount, proposer)
  1150  		actualTotalAmount = actualTotalAmount.Add(actualTotalAmount, stakers)
  1151  		actualTotalAmount = actualTotalAmount.Add(actualTotalAmount, kff)
  1152  		actualTotalAmount = actualTotalAmount.Add(actualTotalAmount, kcf)
  1153  		actualTotalAmount = actualTotalAmount.Add(actualTotalAmount, remaining)
  1154  		assert.Equal(t, expectedTotalAmount, actualTotalAmount, "failed tc: %s", tc.desc)
  1155  	}
  1156  }
  1157  
  1158  func TestRewardDistributor_calcShares(t *testing.T) {
  1159  	type Result struct {
  1160  		shares    map[common.Address]*big.Int
  1161  		remaining uint64
  1162  	}
  1163  
  1164  	testcases := []struct {
  1165  		desc        string
  1166  		stakingInfo *StakingInfo
  1167  		stakeReward *big.Int
  1168  		expected    *Result
  1169  	}{
  1170  		{
  1171  			desc:        "all nodes 0%",
  1172  			stakingInfo: genStakingInfo(5, nil, nil),
  1173  			stakeReward: big.NewInt(500),
  1174  			expected: &Result{
  1175  				shares:    map[common.Address]*big.Int{},
  1176  				remaining: 500,
  1177  			},
  1178  		},
  1179  		{
  1180  			desc:        "no staking info",
  1181  			stakingInfo: nil,
  1182  			stakeReward: big.NewInt(500),
  1183  			expected: &Result{
  1184  				shares:    map[common.Address]*big.Int{},
  1185  				remaining: 500,
  1186  			},
  1187  		},
  1188  		{
  1189  			desc:        "CN0: 100%",
  1190  			stakingInfo: genStakingInfo(5, nil, map[int]uint64{0: minStaking + 1}),
  1191  			stakeReward: big.NewInt(500),
  1192  			expected: &Result{
  1193  				shares: map[common.Address]*big.Int{
  1194  					intToAddress(rewardBaseAddr): big.NewInt(500),
  1195  				},
  1196  				remaining: 0,
  1197  			},
  1198  		},
  1199  		{
  1200  			desc: "CN0, CN1: 50%",
  1201  			stakingInfo: genStakingInfo(5, nil, map[int]uint64{
  1202  				0: minStaking + 1,
  1203  				1: minStaking + 1,
  1204  			}),
  1205  			stakeReward: big.NewInt(500),
  1206  			expected: &Result{
  1207  				shares: map[common.Address]*big.Int{
  1208  					intToAddress(rewardBaseAddr):     big.NewInt(250),
  1209  					intToAddress(rewardBaseAddr + 1): big.NewInt(250),
  1210  				},
  1211  				remaining: 0,
  1212  			},
  1213  		},
  1214  		{
  1215  			desc: "CN0: 66%, CN1: 33%",
  1216  			stakingInfo: genStakingInfo(5, nil, map[int]uint64{
  1217  				0: minStaking + 2,
  1218  				1: minStaking + 1,
  1219  			}),
  1220  			stakeReward: big.NewInt(500),
  1221  			expected: &Result{
  1222  				shares: map[common.Address]*big.Int{
  1223  					intToAddress(rewardBaseAddr):     big.NewInt(333),
  1224  					intToAddress(rewardBaseAddr + 1): big.NewInt(166),
  1225  				},
  1226  				remaining: 1,
  1227  			},
  1228  		},
  1229  		{
  1230  			desc: "CN0: 66/97, CN1: 17/97, CN2: 11/97, CN3: 2/97, CN4: 1/97",
  1231  			stakingInfo: genStakingInfo(7, nil, map[int]uint64{
  1232  				0: minStaking + 66,
  1233  				1: minStaking + 17,
  1234  				2: minStaking + 11,
  1235  				3: minStaking + 2,
  1236  				4: minStaking + 1, // total: 97
  1237  			}),
  1238  			stakeReward: big.NewInt(555),
  1239  			expected: &Result{
  1240  				shares: map[common.Address]*big.Int{
  1241  					intToAddress(rewardBaseAddr):     big.NewInt(377),
  1242  					intToAddress(rewardBaseAddr + 1): big.NewInt(97),
  1243  					intToAddress(rewardBaseAddr + 2): big.NewInt(62),
  1244  					intToAddress(rewardBaseAddr + 3): big.NewInt(11),
  1245  					intToAddress(rewardBaseAddr + 4): big.NewInt(5),
  1246  				},
  1247  				remaining: 3,
  1248  			},
  1249  		},
  1250  	}
  1251  
  1252  	for _, tc := range testcases {
  1253  		shares, remaining := calcShares(tc.stakingInfo, tc.stakeReward, minStaking)
  1254  		actual := &Result{
  1255  			shares:    shares,
  1256  			remaining: remaining.Uint64(),
  1257  		}
  1258  		assert.Equal(t, tc.expected, actual, "failed tc: %s", tc.desc)
  1259  	}
  1260  }
  1261  
  1262  func benchSetup() (*types.Header, params.Rules, *params.GovParamSet) {
  1263  	// in the worst case, distribute stake shares among N
  1264  	amounts := make(map[int]uint64)
  1265  	N := 50
  1266  	for i := 0; i < N; i++ {
  1267  		amounts[i] = minStaking + 1
  1268  	}
  1269  
  1270  	stakingInfo := genStakingInfo(N, nil, amounts)
  1271  	SetTestStakingManagerWithStakingInfoCache(stakingInfo)
  1272  
  1273  	config := getTestConfig()
  1274  
  1275  	header := &types.Header{}
  1276  	header.BaseFee = big.NewInt(30000000000)
  1277  	header.Number = big.NewInt(0)
  1278  	header.Rewardbase = intToAddress(rewardBaseAddr)
  1279  
  1280  	rules := config.Rules(header.Number)
  1281  	pset, _ := params.NewGovParamSetChainConfig(config)
  1282  
  1283  	return header, rules, pset
  1284  }
  1285  
  1286  func Benchmark_CalcDeferredReward(b *testing.B) {
  1287  	oldStakingManager := GetStakingManager()
  1288  	defer SetTestStakingManager(oldStakingManager)
  1289  
  1290  	header, rules, pset := benchSetup()
  1291  
  1292  	b.ResetTimer()
  1293  	for i := 0; i < b.N; i++ {
  1294  		CalcDeferredReward(header, rules, pset)
  1295  	}
  1296  }
  1297  
  1298  func TestRewardConfigCache_parseRewardRatio(t *testing.T) {
  1299  	testCases := []struct {
  1300  		s   string
  1301  		cn  int64
  1302  		kff int64
  1303  		kcf int64
  1304  		err error
  1305  	}{
  1306  		{"34/54/12", 34, 54, 12, nil},
  1307  		{"3/3/3", 3, 3, 3, nil},
  1308  		{"10/20/30", 10, 20, 30, nil},
  1309  		{"34,54,12", 0, 0, 0, errInvalidFormat},
  1310  		{"/", 0, 0, 0, errInvalidFormat},
  1311  		{"///", 0, 0, 0, errInvalidFormat},
  1312  		{"1//", 0, 0, 0, errParsingRatio},
  1313  		{"/1/", 0, 0, 0, errParsingRatio},
  1314  		{"//1", 0, 0, 0, errParsingRatio},
  1315  		{"1/2/3/4/", 0, 0, 0, errInvalidFormat},
  1316  		{"3.3/3.3/3.3", 0, 0, 0, errParsingRatio},
  1317  		{"a/b/c", 0, 0, 0, errParsingRatio},
  1318  	}
  1319  
  1320  	for i := 0; i < len(testCases); i++ {
  1321  		cn, kff, kcf, total, err := parseRewardRatio(testCases[i].s)
  1322  
  1323  		assert.Equal(t, testCases[i].cn, cn)
  1324  		assert.Equal(t, testCases[i].kff, kff)
  1325  		assert.Equal(t, testCases[i].kcf, kcf)
  1326  		assert.Equal(t, testCases[i].err, err)
  1327  
  1328  		expectedTotal := testCases[i].cn + testCases[i].kff + testCases[i].kcf
  1329  		assert.Equal(t, expectedTotal, total)
  1330  	}
  1331  }
  1332  
  1333  func TestRewardConfigCache_parseRewardKip82Ratio(t *testing.T) {
  1334  	testCases := []struct {
  1335  		s        string
  1336  		proposer int64
  1337  		staking  int64
  1338  		err      error
  1339  	}{
  1340  		{"34/54", 34, 54, nil},
  1341  		{"20/80", 20, 80, nil},
  1342  		{"0/100", 0, 100, nil},
  1343  		{"34,54", 0, 0, errInvalidFormat},
  1344  		{"", 0, 0, errInvalidFormat},
  1345  		{"//", 0, 0, errInvalidFormat},
  1346  		{"1/", 0, 0, errParsingRatio},
  1347  		{"/1", 0, 0, errParsingRatio},
  1348  		{"1/2/", 0, 0, errInvalidFormat},
  1349  		{"3.3/3.3", 0, 0, errParsingRatio},
  1350  		{"a/b", 0, 0, errParsingRatio},
  1351  	}
  1352  
  1353  	for i := 0; i < len(testCases); i++ {
  1354  		proposer, staking, total, err := parseRewardKip82Ratio(testCases[i].s)
  1355  
  1356  		assert.Equal(t, testCases[i].proposer, proposer)
  1357  		assert.Equal(t, testCases[i].staking, staking)
  1358  		assert.Equal(t, testCases[i].err, err, "tc[%d] failed", i)
  1359  
  1360  		expectedTotal := testCases[i].proposer + testCases[i].staking
  1361  		assert.Equal(t, expectedTotal, total)
  1362  	}
  1363  }