github.com/klaytn/klaytn@v1.12.1/governance/api_test.go (about) 1 package governance 2 3 import ( 4 "encoding/json" 5 "math/big" 6 "testing" 7 "time" 8 9 "github.com/golang/mock/gomock" 10 "github.com/klaytn/klaytn/blockchain/state" 11 "github.com/klaytn/klaytn/blockchain/types" 12 "github.com/klaytn/klaytn/common" 13 "github.com/klaytn/klaytn/consensus" 14 "github.com/klaytn/klaytn/networks/rpc" 15 "github.com/klaytn/klaytn/params" 16 "github.com/klaytn/klaytn/reward" 17 "github.com/klaytn/klaytn/storage/database" 18 "github.com/klaytn/klaytn/work/mocks" 19 "github.com/stretchr/testify/assert" 20 ) 21 22 type testBlockChain struct { 23 num uint64 24 config *params.ChainConfig 25 } 26 27 func newTestBlockchain(config *params.ChainConfig) *testBlockChain { 28 return &testBlockChain{ 29 config: config, 30 } 31 } 32 33 func newTestGovernanceApi() *GovernanceAPI { 34 config := params.CypressChainConfig 35 config.Governance.KIP71 = params.GetDefaultKIP71Config() 36 govApi := NewGovernanceAPI(NewMixedEngine(config, database.NewMemoryDBManager())) 37 govApi.governance.SetNodeAddress(common.HexToAddress("0x52d41ca72af615a1ac3301b0a93efa222ecc7541")) 38 bc := newTestBlockchain(config) 39 govApi.governance.SetBlockchain(bc) 40 return govApi 41 } 42 43 func TestUpperBoundBaseFeeSet(t *testing.T) { 44 govApi := newTestGovernanceApi() 45 46 curLowerBoundBaseFee := govApi.governance.CurrentParams().LowerBoundBaseFee() 47 // unexpected case : upperboundbasefee < lowerboundbasefee 48 invalidUpperBoundBaseFee := curLowerBoundBaseFee - 100 49 _, err := govApi.Vote("kip71.upperboundbasefee", invalidUpperBoundBaseFee) 50 assert.Equal(t, err, errInvalidUpperBound) 51 } 52 53 func TestLowerBoundFeeSet(t *testing.T) { 54 govApi := newTestGovernanceApi() 55 56 curUpperBoundBaseFee := govApi.governance.CurrentParams().UpperBoundBaseFee() 57 // unexpected case : upperboundbasefee < lowerboundbasefee 58 invalidLowerBoundBaseFee := curUpperBoundBaseFee + 100 59 _, err := govApi.Vote("kip71.lowerboundbasefee", invalidLowerBoundBaseFee) 60 assert.Equal(t, err, errInvalidLowerBound) 61 } 62 63 func TestGetRewards(t *testing.T) { 64 type expected = map[int]uint64 65 type strMap = map[string]interface{} 66 type override struct { 67 num int 68 strMap strMap 69 } 70 type testcase struct { 71 length int // total number of blocks to simulate 72 override []override 73 expected expected 74 } 75 76 var ( 77 mintAmount = uint64(1) 78 koreBlock = uint64(9) 79 epoch = 3 80 latestNum = rpc.BlockNumber(-1) 81 proposer = common.HexToAddress("0x0000000000000000000000000000000000000000") 82 config = getTestConfig() 83 ) 84 85 testcases := []testcase{ 86 { 87 12, 88 []override{ 89 { 90 3, 91 strMap{ 92 "reward.mintingamount": "2", 93 }, 94 }, 95 { 96 6, 97 strMap{ 98 "reward.mintingamount": "3", 99 }, 100 }, 101 }, 102 map[int]uint64{ 103 1: 1, 104 2: 1, 105 3: 1, 106 4: 1, 107 5: 1, 108 6: 1, 109 7: 2, // 2 is minted from now 110 8: 2, 111 9: 3, // 3 is minted from now 112 10: 3, 113 11: 3, 114 12: 3, 115 13: 3, 116 }, 117 }, 118 } 119 120 for _, tc := range testcases { 121 config.Governance.Reward.MintingAmount = new(big.Int).SetUint64(mintAmount) 122 config.Istanbul.Epoch = uint64(epoch) 123 config.KoreCompatibleBlock = new(big.Int).SetUint64(koreBlock) 124 125 bc := newTestBlockchain(config) 126 127 dbm := database.NewDBManager(&database.DBConfig{DBType: database.MemoryDB}) 128 129 e := NewMixedEngine(config, dbm) 130 e.SetBlockchain(bc) 131 e.UpdateParams(bc.CurrentBlock().NumberU64()) 132 133 // write initial gov items and overrides to database 134 pset, _ := params.NewGovParamSetChainConfig(config) 135 gset := NewGovernanceSet() 136 gset.Import(pset.StrMap()) 137 e.headerGov.WriteGovernance(0, NewGovernanceSet(), gset) 138 for _, o := range tc.override { 139 override := NewGovernanceSet() 140 override.Import(o.strMap) 141 e.headerGov.WriteGovernance(uint64(o.num), gset, override) 142 } 143 144 govKlayApi := NewGovernanceKlayAPI(e, bc) 145 146 for num := 1; num <= tc.length; num++ { 147 bc.SetBlockNum(uint64(num)) 148 149 rewardSpec, err := govKlayApi.GetRewards(&latestNum) 150 assert.Nil(t, err) 151 152 minted := new(big.Int).SetUint64(tc.expected[num]) 153 expectedRewardSpec := &reward.RewardSpec{ 154 Minted: minted, 155 TotalFee: common.Big0, 156 BurntFee: common.Big0, 157 Proposer: minted, 158 Stakers: common.Big0, 159 KFF: common.Big0, 160 KCF: common.Big0, 161 Rewards: map[common.Address]*big.Int{ 162 proposer: minted, 163 }, 164 } 165 assert.Equal(t, expectedRewardSpec, rewardSpec, "wrong at block %d", num) 166 } 167 } 168 } 169 170 func TestGetRewardsAccumulated(t *testing.T) { 171 mockCtrl := gomock.NewController(t) 172 defer mockCtrl.Finish() 173 174 mockBlockchain := mocks.NewMockBlockChain(mockCtrl) 175 mockGovEngine := NewMockEngine(mockCtrl) 176 db := database.NewMemoryDBManager() 177 178 // prepare configurations and data for the test environment 179 chainConfig := params.CypressChainConfig.Copy() 180 chainConfig.KoreCompatibleBlock = big.NewInt(0) 181 chainConfig.Governance.Reward.Ratio = "50/20/30" 182 chainConfig.Governance.Reward.Kip82Ratio = params.DefaultKip82Ratio 183 184 govParamSet, err := params.NewGovParamSetChainConfig(chainConfig) 185 if err != nil { 186 t.Fatal(err) 187 } 188 189 oldSm := reward.GetStakingManager() 190 defer reward.SetTestStakingManager(oldSm) 191 reward.SetTestStakingManagerWithChain(mockBlockchain, mockGovEngine, db) 192 193 testAddrList := []common.Address{ 194 common.HexToAddress("0x1111111111111111111111111111111111111111"), 195 common.HexToAddress("0x2222222222222222222222222222222222222222"), 196 common.HexToAddress("0x3333333333333333333333333333333333333333"), 197 common.HexToAddress("0x4444444444444444444444444444444444444444"), 198 } 199 200 testStakingAmountList := []uint64{ 201 uint64(5000000), 202 uint64(10000000), 203 uint64(15000000), 204 uint64(20000000), 205 } 206 207 stInfo := reward.StakingInfo{ 208 BlockNum: 0, 209 CouncilNodeAddrs: testAddrList, 210 CouncilStakingAddrs: testAddrList, 211 CouncilRewardAddrs: testAddrList, 212 KCFAddr: common.HexToAddress("0xCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC"), 213 KFFAddr: common.HexToAddress("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"), 214 CouncilStakingAmounts: testStakingAmountList, 215 } 216 217 siBytes, _ := json.Marshal(stInfo) 218 if err := db.WriteStakingInfo(stInfo.BlockNum, siBytes); err != nil { 219 t.Fatal(err) 220 } 221 222 startBlockNum := 0 223 endBlockNum := 10 224 blocks := make([]*types.Block, endBlockNum-startBlockNum+1) 225 226 // set testing data for mock instances 227 for i := startBlockNum; i <= endBlockNum; i++ { 228 blocks[i] = types.NewBlockWithHeader(&types.Header{ 229 Number: big.NewInt(int64(i)), 230 Rewardbase: stInfo.CouncilRewardAddrs[i%4], // round-robin way 231 GasUsed: uint64(1000), 232 BaseFee: big.NewInt(25 * params.Ston), 233 Time: big.NewInt(int64(1000 + i)), 234 }) 235 236 mockBlockchain.EXPECT().GetHeaderByNumber(uint64(i)).Return(blocks[i].Header()).AnyTimes() 237 } 238 239 mockBlockchain.EXPECT().Config().Return(chainConfig).AnyTimes() 240 mockBlockchain.EXPECT().CurrentBlock().Return(blocks[endBlockNum]).AnyTimes() 241 mockGovEngine.EXPECT().EffectiveParams(gomock.Any()).Return(govParamSet, nil).AnyTimes() 242 mockGovEngine.EXPECT().BlockChain().Return(mockBlockchain).AnyTimes() 243 244 // execute a target function 245 govAPI := NewGovernanceAPI(mockGovEngine) 246 ret, err := govAPI.GetRewardsAccumulated(rpc.BlockNumber(startBlockNum), rpc.BlockNumber(endBlockNum)) 247 if err != nil { 248 t.Fatal(err) 249 } 250 assert.NotNil(t, ret) 251 252 // pre-calculated estimated rewards per a block 253 blockMinted, _ := new(big.Int).SetString("9600000000000000000", 10) // 9.6 KLAY 254 blockProposer, _ := new(big.Int).SetString("960000000000000000", 10) // 0.96 KLAY = 9.6 KLAY * 0.5 * 0.2 255 blockStaking, _ := new(big.Int).SetString("3840000000000000000", 10) // 3.84 KLAY = 9.6 KLAY * 0.5 * 0.8 256 blockTxFee, _ := new(big.Int).SetString("25000000000000", 10) // 25000 Ston = 1000 * 25 Ston 257 blockTxBurnt := blockTxFee 258 blockKFF, _ := new(big.Int).SetString("1920000000000000000", 10) // 1.92 KLAY = 9.6 KLAY * 0.2 259 blockKCF, _ := new(big.Int).SetString("2880000000000000000", 10) // 2.88 KLAY = 9.6 KLAY * 0.3 260 261 // check the execution result 262 assert.Equal(t, time.Unix(blocks[startBlockNum].Time().Int64(), 0).String(), ret.FirstBlockTime) 263 assert.Equal(t, time.Unix(blocks[endBlockNum].Time().Int64(), 0).String(), ret.LastBlockTime) 264 assert.Equal(t, uint64(startBlockNum), ret.FirstBlock.Uint64()) 265 assert.Equal(t, uint64(endBlockNum), ret.LastBlock.Uint64()) 266 267 blockCount := big.NewInt(int64(endBlockNum - startBlockNum + 1)) 268 assert.Equal(t, new(big.Int).Mul(blockMinted, blockCount), ret.TotalMinted) 269 assert.Equal(t, new(big.Int).Mul(blockTxFee, blockCount), ret.TotalTxFee) 270 assert.Equal(t, new(big.Int).Mul(blockTxBurnt, blockCount), ret.TotalBurntTxFee) 271 assert.Equal(t, new(big.Int).Mul(blockProposer, blockCount), ret.TotalProposerRewards) 272 assert.Equal(t, new(big.Int).Mul(blockStaking, blockCount), ret.TotalStakingRewards) 273 assert.Equal(t, new(big.Int).Mul(blockKFF, blockCount), ret.TotalKFFRewards) 274 assert.Equal(t, new(big.Int).Mul(blockKCF, blockCount), ret.TotalKCFRewards) 275 276 gcReward := big.NewInt(0) 277 for acc, bal := range ret.Rewards { 278 if acc != stInfo.KFFAddr && acc != stInfo.KCFAddr { 279 gcReward.Add(gcReward, bal) 280 } 281 } 282 assert.Equal(t, gcReward, new(big.Int).Add(ret.TotalStakingRewards, ret.TotalProposerRewards)) 283 } 284 285 func (bc *testBlockChain) Engine() consensus.Engine { return nil } 286 func (bc *testBlockChain) GetHeader(common.Hash, uint64) *types.Header { return nil } 287 func (bc *testBlockChain) GetHeaderByNumber(val uint64) *types.Header { 288 return &types.Header{ 289 Number: new(big.Int).SetUint64(val), 290 } 291 } 292 func (bc *testBlockChain) GetBlockByNumber(num uint64) *types.Block { return nil } 293 func (bc *testBlockChain) StateAt(root common.Hash) (*state.StateDB, error) { return nil, nil } 294 func (bc *testBlockChain) State() (*state.StateDB, error) { return nil, nil } 295 func (bc *testBlockChain) Config() *params.ChainConfig { 296 return bc.config 297 } 298 299 func (bc *testBlockChain) CurrentBlock() *types.Block { 300 return types.NewBlockWithHeader(bc.CurrentHeader()) 301 } 302 303 func (bc *testBlockChain) CurrentHeader() *types.Header { 304 return &types.Header{ 305 Number: new(big.Int).SetUint64(bc.num), 306 } 307 } 308 309 func (bc *testBlockChain) SetBlockNum(num uint64) { 310 bc.num = num 311 } 312 313 func (bc *testBlockChain) GetBlock(hash common.Hash, num uint64) *types.Block { 314 return bc.GetBlockByNumber(num) 315 }