github.com/klaytn/klaytn@v1.10.2/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 := ¶ms.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 := ¶ms.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(0), 345 Proposer: new(big.Int).SetUint64(9.6e18 + 1000), 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 + 1000), 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(0), 381 Proposer: new(big.Int).SetUint64(0.6528e18 + 1000 + 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 + 1000 + 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 Kore 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 should have been 0, but returned due to bug 509 isMagma: true, 510 isKore: false, 511 expected: &RewardSpec{ 512 Minted: minted, 513 TotalFee: new(big.Int).SetUint64(1000), 514 BurntFee: new(big.Int).SetUint64(500), 515 Proposer: new(big.Int).SetUint64(9.6e18 + 500), 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 + 500), 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 555 spec, err := CalcDeferredRewardSimple(header, rules, pset) 556 require.Nil(t, err, "testcases[%d] failed", i) 557 assertEqualRewardSpecs(t, tc.expected, spec, "testcases[%d] failed", i) 558 } 559 } 560 561 func TestRewardDistributor_CalcDeferredReward(t *testing.T) { 562 oldStakingManager := GetStakingManager() 563 defer SetTestStakingManager(oldStakingManager) 564 565 stakingInfo := genStakingInfo(5, nil, map[int]uint64{ 566 0: minStaking + 4, 567 1: minStaking + 3, 568 }) 569 570 testcases := []struct { 571 desc string 572 isKore bool 573 isMagma bool 574 fee uint64 575 expected *RewardSpec 576 }{ 577 { 578 desc: "isKore=false, isMagma=false, fee=1000 [000]", 579 isKore: false, 580 isMagma: false, 581 fee: 1000, 582 expected: &RewardSpec{ 583 Minted: minted, 584 TotalFee: big.NewInt(1000), 585 BurntFee: big.NewInt(0), 586 Proposer: big.NewInt(0).SetUint64(3.264e18 + 340), 587 Stakers: big.NewInt(0), 588 KFF: big.NewInt(5.184e18 + 540), 589 KCF: big.NewInt(1.152e18 + 120), 590 Rewards: map[common.Address]*big.Int{ 591 proposerAddr: big.NewInt(3.264e18 + 340), 592 kffAddr: big.NewInt(5.184e18 + 540), 593 kcfAddr: big.NewInt(1.152e18 + 120), 594 }, 595 }, 596 }, 597 { 598 desc: "isKore=false, isMagma=false, fee=10e18 [001]", 599 isKore: false, 600 isMagma: false, 601 fee: 10e18, 602 expected: &RewardSpec{ 603 Minted: minted, 604 TotalFee: new(big.Int).SetUint64(10e18), 605 BurntFee: new(big.Int).SetUint64(0), 606 Proposer: new(big.Int).SetUint64(6.664e18), 607 Stakers: new(big.Int).SetUint64(0), 608 KFF: new(big.Int).SetUint64(10.584e18), 609 KCF: new(big.Int).SetUint64(2.352e18), 610 Rewards: map[common.Address]*big.Int{ 611 proposerAddr: new(big.Int).SetUint64(6.664e18), 612 kffAddr: new(big.Int).SetUint64(10.584e18), 613 kcfAddr: new(big.Int).SetUint64(2.352e18), 614 }, 615 }, 616 }, 617 { 618 desc: "isKore=false, isMagma=true, fee=1000 [010]", 619 isKore: false, 620 isMagma: true, 621 fee: 1000, 622 expected: &RewardSpec{ 623 Minted: minted, 624 TotalFee: new(big.Int).SetUint64(1000), 625 BurntFee: new(big.Int).SetUint64(500), 626 Proposer: new(big.Int).SetUint64(3.264e18 + 170), 627 Stakers: new(big.Int).SetUint64(0), 628 KFF: new(big.Int).SetUint64(5.184e18 + 270), 629 KCF: new(big.Int).SetUint64(1.152e18 + 60), 630 Rewards: map[common.Address]*big.Int{ 631 proposerAddr: new(big.Int).SetUint64(3.264e18 + 170), 632 kcfAddr: new(big.Int).SetUint64(1.152e18 + 60), 633 kffAddr: new(big.Int).SetUint64(5.184e18 + 270), 634 }, 635 }, 636 }, 637 { 638 desc: "isKore=false, isMagma=true, fee=10e18 [011]", 639 isKore: false, 640 isMagma: true, 641 fee: 10e18, 642 expected: &RewardSpec{ 643 Minted: minted, 644 TotalFee: new(big.Int).SetUint64(10e18), 645 BurntFee: new(big.Int).SetUint64(5e18), 646 Proposer: new(big.Int).SetUint64(4.964e18), 647 Stakers: new(big.Int).SetUint64(0), 648 KFF: new(big.Int).SetUint64(7.884e18), 649 KCF: new(big.Int).SetUint64(1.752e18), 650 Rewards: map[common.Address]*big.Int{ 651 proposerAddr: new(big.Int).SetUint64(4.964e18), 652 kffAddr: new(big.Int).SetUint64(7.884e18), 653 kcfAddr: new(big.Int).SetUint64(1.752e18), 654 }, 655 }, 656 }, 657 { 658 desc: "isKore=true, isMagma=true, fee=1000 [110]", 659 isKore: true, 660 isMagma: true, 661 fee: 1000, 662 expected: &RewardSpec{ 663 Minted: minted, 664 TotalFee: new(big.Int).SetUint64(1000), 665 BurntFee: new(big.Int).SetUint64(1000), 666 Proposer: new(big.Int).SetUint64(0.6528e18 + 1), 667 Stakers: new(big.Int).SetUint64(2.6112e18 - 1), 668 KFF: new(big.Int).SetUint64(5.184e18), 669 KCF: new(big.Int).SetUint64(1.152e18), 670 Rewards: map[common.Address]*big.Int{ 671 proposerAddr: new(big.Int).SetUint64(0.6528e18 + 1), 672 kffAddr: new(big.Int).SetUint64(5.184e18), 673 kcfAddr: new(big.Int).SetUint64(1.152e18), 674 intToAddress(rewardBaseAddr): new(big.Int).SetUint64(1492114285714285714), 675 intToAddress(rewardBaseAddr + 1): new(big.Int).SetUint64(1119085714285714285), 676 }, 677 }, 678 }, 679 { // after kore, more-than-default staking, large fee, proposer = rewardbase 680 desc: "isKore=true, isMagma=true, fee=10e18 [111]", 681 isKore: true, 682 isMagma: true, 683 fee: 10e18, 684 expected: &RewardSpec{ 685 Minted: minted, 686 TotalFee: new(big.Int).SetUint64(10e18), 687 BurntFee: new(big.Int).SetUint64(5e18 + 0.6528e18), 688 Proposer: new(big.Int).SetUint64(5e18 + 1), 689 Stakers: new(big.Int).SetUint64(2.6112e18 - 1), 690 KFF: new(big.Int).SetUint64(5.184e18), 691 KCF: new(big.Int).SetUint64(1.152e18), 692 Rewards: map[common.Address]*big.Int{ 693 proposerAddr: new(big.Int).SetUint64(5e18 + 1), 694 kffAddr: new(big.Int).SetUint64(5.184e18), 695 kcfAddr: new(big.Int).SetUint64(1.152e18), 696 intToAddress(rewardBaseAddr): new(big.Int).SetUint64(1492114285714285714), 697 intToAddress(rewardBaseAddr + 1): new(big.Int).SetUint64(1119085714285714285), 698 }, 699 }, 700 }, 701 } 702 703 SetTestStakingManagerWithStakingInfoCache(stakingInfo) 704 705 for _, tc := range testcases { 706 header := &types.Header{ 707 Number: big.NewInt(1), 708 GasUsed: tc.fee, 709 BaseFee: big.NewInt(1), 710 Rewardbase: proposerAddr, 711 } 712 713 config := getTestConfig() 714 if !tc.isKore { 715 config = noKore(config) 716 } 717 if !tc.isMagma { 718 config = noMagma(config) 719 } 720 721 rules := config.Rules(header.Number) 722 pset, err := params.NewGovParamSetChainConfig(config) 723 require.Nil(t, err) 724 725 spec, err := CalcDeferredReward(header, rules, pset) 726 require.Nil(t, err, "failed tc: %s", tc.desc) 727 assertEqualRewardSpecs(t, tc.expected, spec, "failed tc: %s", tc.desc) 728 } 729 } 730 731 func TestRewardDistributor_CalcDeferredReward_StakingInfos(t *testing.T) { 732 oldStakingManager := GetStakingManager() 733 defer SetTestStakingManager(oldStakingManager) 734 735 var ( 736 header = &types.Header{ 737 Number: big.NewInt(1), 738 GasUsed: 1000, 739 BaseFee: big.NewInt(1), 740 Rewardbase: proposerAddr, 741 } 742 config = getTestConfig() 743 rules = config.Rules(header.Number) 744 pset, _ = params.NewGovParamSetChainConfig(config) 745 ) 746 747 testcases := []struct { 748 desc string 749 stakingInfo *StakingInfo 750 expected *RewardSpec 751 }{ 752 { 753 desc: "stakingInfo is nil, its portion goes to proposer", 754 stakingInfo: nil, 755 expected: &RewardSpec{ 756 Minted: minted, 757 TotalFee: big.NewInt(1000), 758 BurntFee: big.NewInt(1000), 759 Proposer: minted, 760 Stakers: big.NewInt(0), 761 KFF: big.NewInt(0), 762 KCF: big.NewInt(0), 763 Rewards: map[common.Address]*big.Int{ 764 proposerAddr: minted, 765 }, 766 }, 767 }, 768 { 769 desc: "stakingInfo has no kff, its portion goes to proposer", 770 stakingInfo: &StakingInfo{ 771 KCFAddr: kcfAddr, 772 KFFAddr: common.Address{}, 773 }, 774 expected: &RewardSpec{ 775 Minted: minted, 776 TotalFee: big.NewInt(1000), 777 BurntFee: big.NewInt(1000), 778 Proposer: big.NewInt(8.448e18), 779 Stakers: big.NewInt(0), 780 KFF: big.NewInt(0), 781 KCF: big.NewInt(1.152e18), // minted * 0.12 782 Rewards: map[common.Address]*big.Int{ 783 proposerAddr: big.NewInt(8.448e18), 784 kcfAddr: big.NewInt(1.152e18), 785 }, 786 }, 787 }, 788 { 789 desc: "stakingInfo has no kcf, its portion goes to proposer", 790 stakingInfo: &StakingInfo{ 791 KCFAddr: common.Address{}, 792 KFFAddr: kffAddr, 793 }, 794 expected: &RewardSpec{ 795 Minted: minted, 796 TotalFee: big.NewInt(1000), 797 BurntFee: big.NewInt(1000), 798 Proposer: big.NewInt(4.416e18), 799 Stakers: big.NewInt(0), 800 KFF: big.NewInt(5.184e18), // minted * 0.54 801 KCF: big.NewInt(0), 802 Rewards: map[common.Address]*big.Int{ 803 proposerAddr: big.NewInt(4.416e18), 804 kffAddr: big.NewInt(5.184e18), 805 }, 806 }, 807 }, 808 { 809 desc: "stakingInfo has the same kff and kcf", 810 stakingInfo: &StakingInfo{ 811 KCFAddr: kffAddr, 812 KFFAddr: kffAddr, 813 }, 814 expected: &RewardSpec{ 815 Minted: minted, 816 TotalFee: big.NewInt(1000), 817 BurntFee: big.NewInt(1000), 818 Proposer: big.NewInt(3.264e18), 819 Stakers: big.NewInt(0), 820 KFF: big.NewInt(5.184e18), 821 KCF: big.NewInt(1.152e18), 822 Rewards: map[common.Address]*big.Int{ 823 proposerAddr: big.NewInt(3.264e18), 824 kffAddr: big.NewInt(6.336e18), 825 }, 826 }, 827 }, 828 } 829 830 for i, tc := range testcases { 831 if tc.stakingInfo == nil { 832 SetTestStakingManager(nil) 833 } else { 834 SetTestStakingManagerWithStakingInfoCache(tc.stakingInfo) 835 } 836 spec, err := CalcDeferredReward(header, rules, pset) 837 require.Nil(t, err, "testcases[%d] failed", i) 838 assertEqualRewardSpecs(t, tc.expected, spec, "testcases[%d] failed: %s", i, tc.desc) 839 } 840 } 841 842 func TestRewardDistributor_CalcDeferredReward_Remainings(t *testing.T) { 843 oldStakingManager := GetStakingManager() 844 defer SetTestStakingManager(oldStakingManager) 845 846 var ( 847 header = &types.Header{ 848 Number: big.NewInt(1), 849 GasUsed: 1000, 850 BaseFee: big.NewInt(1), 851 Rewardbase: proposerAddr, 852 } 853 854 stakingInfo = genStakingInfo(5, nil, map[int]uint64{ 855 0: minStaking + 4, 856 1: minStaking + 3, 857 }) 858 splitRemainingConfig = getTestConfig() 859 ) 860 splitRemainingConfig.Governance.Reward.MintingAmount = big.NewInt(333) 861 862 testcases := []struct { 863 desc string 864 config *params.ChainConfig 865 expected *RewardSpec 866 }{ 867 { 868 desc: "split remaining goes to kff", 869 config: splitRemainingConfig, 870 expected: &RewardSpec{ 871 Minted: big.NewInt(333), 872 TotalFee: big.NewInt(1000), 873 BurntFee: big.NewInt(522), 874 Proposer: big.NewInt(501), // proposer=22, rewardFee=478, shareRem=1 875 Stakers: big.NewInt(89), 876 KFF: big.NewInt(182), // splitRem=3 877 KCF: big.NewInt(39), 878 Rewards: map[common.Address]*big.Int{ 879 proposerAddr: big.NewInt(501), 880 kffAddr: big.NewInt(182), 881 kcfAddr: big.NewInt(39), 882 intToAddress(rewardBaseAddr): big.NewInt(51), // stakers * 4/7 883 intToAddress(rewardBaseAddr + 1): big.NewInt(38), // stakers * 3/7 884 }, 885 }, 886 }, 887 { 888 desc: "share remaining goes to proposer", 889 config: getTestConfig(), 890 expected: &RewardSpec{ 891 Minted: minted, 892 TotalFee: big.NewInt(1000), 893 BurntFee: big.NewInt(1000), 894 Proposer: big.NewInt(0.6528e18 + 1), 895 Stakers: big.NewInt(2.6112e18 - 1), 896 KFF: big.NewInt(5.184e18), 897 KCF: big.NewInt(1.152e18), 898 Rewards: map[common.Address]*big.Int{ 899 proposerAddr: big.NewInt(0.6528e18 + 1), 900 kffAddr: big.NewInt(5.184e18), 901 kcfAddr: big.NewInt(1.152e18), 902 intToAddress(rewardBaseAddr): big.NewInt(1492114285714285714), // stakers * 4/7 903 intToAddress(rewardBaseAddr + 1): big.NewInt(1119085714285714285), // stakers * 3/7 904 }, 905 }, 906 }, 907 } 908 909 SetTestStakingManagerWithStakingInfoCache(stakingInfo) 910 911 for _, tc := range testcases { 912 rules := tc.config.Rules(header.Number) 913 pset, err := params.NewGovParamSetChainConfig(tc.config) 914 require.Nil(t, err) 915 916 spec, err := CalcDeferredReward(header, rules, pset) 917 require.Nil(t, err, "failed tc: %s", tc.desc) 918 assertEqualRewardSpecs(t, tc.expected, spec, "failed tc: %s", tc.desc) 919 } 920 } 921 922 func TestRewardDistributor_calcDeferredFee(t *testing.T) { 923 type Result struct{ total, reward, burnt uint64 } 924 925 testcases := []struct { 926 desc string 927 isKore bool 928 isMagma bool 929 fee uint64 930 expected *Result 931 }{ 932 { 933 desc: "isKore=false, isMagma=false, fee=1000 [000]", 934 isKore: false, 935 isMagma: false, 936 fee: 1000, 937 expected: &Result{ 938 total: 1000, 939 reward: 1000, 940 burnt: 0, 941 }, 942 }, 943 { 944 desc: "isKore=false, isMagma=false, fee=10e18 [001]", 945 isKore: false, 946 isMagma: false, 947 fee: 10e18, 948 expected: &Result{ 949 total: 10e18, 950 reward: 10e18, 951 burnt: 0, 952 }, 953 }, 954 { 955 desc: "isKore=false, isMagma=true, fee=1000 [010]", 956 isKore: false, 957 isMagma: true, 958 fee: 1000, 959 expected: &Result{ 960 total: 1000, 961 reward: 500, 962 burnt: 500, 963 }, 964 }, 965 { 966 desc: "isKore=false, isMagma=true, fee=10e18 [011]", 967 isKore: false, 968 isMagma: true, 969 fee: 10e18, 970 expected: &Result{ 971 total: 10e18, 972 reward: 5e18, 973 burnt: 5e18, 974 }, 975 }, 976 { 977 desc: "isKore=true, isMagma=true, fee=1000 [110]", 978 isKore: true, 979 isMagma: true, 980 fee: 1000, 981 expected: &Result{ 982 total: 1000, 983 reward: 0, 984 burnt: 1000, 985 }, 986 }, 987 { 988 desc: "isKore=true, isMagma=true, fee=10e18 [111]", 989 isKore: true, 990 isMagma: true, 991 fee: 10e18, 992 expected: &Result{ 993 total: 10e18, 994 reward: 4.3472e18, // 5 - minted*0.34*0.2 995 burnt: 5.6528e18, // 5 + minted*0.34*0.8 996 }, 997 }, 998 } 999 1000 for _, tc := range testcases { 1001 header := &types.Header{ 1002 Number: big.NewInt(1), 1003 GasUsed: tc.fee, 1004 BaseFee: big.NewInt(1), 1005 Rewardbase: proposerAddr, 1006 } 1007 1008 config := getTestConfig() 1009 if !tc.isKore { 1010 config = noKore(config) 1011 } 1012 if !tc.isMagma { 1013 config = noMagma(config) 1014 } 1015 1016 rules := config.Rules(header.Number) 1017 pset, err := params.NewGovParamSetChainConfig(config) 1018 require.Nil(t, err) 1019 1020 rc, err := NewRewardConfig(header, rules, pset) 1021 require.Nil(t, err) 1022 1023 total, reward, burnt := calcDeferredFee(rc) 1024 actual := &Result{ 1025 total: total.Uint64(), 1026 reward: reward.Uint64(), 1027 burnt: burnt.Uint64(), 1028 } 1029 assert.Equal(t, tc.expected, actual, "failed tc: %s", tc.desc) 1030 } 1031 } 1032 1033 func TestRewardDistributor_calcDeferredFee_nodeferred(t *testing.T) { 1034 var ( 1035 header = &types.Header{ 1036 Number: big.NewInt(1), 1037 GasUsed: 1000, 1038 BaseFee: big.NewInt(1), 1039 Rewardbase: proposerAddr, 1040 } 1041 rules = params.Rules{ 1042 IsMagma: true, 1043 } 1044 ) 1045 1046 pset, err := params.NewGovParamSetChainConfig(noDeferred(getTestConfig())) 1047 require.Nil(t, err) 1048 1049 rc, err := NewRewardConfig(header, rules, pset) 1050 require.Nil(t, err) 1051 1052 total, reward, burnt := calcDeferredFee(rc) 1053 assert.Equal(t, uint64(0), total.Uint64()) 1054 assert.Equal(t, uint64(0), reward.Uint64()) 1055 assert.Equal(t, uint64(0), burnt.Uint64()) 1056 } 1057 1058 func TestRewardDistributor_calcSplit(t *testing.T) { 1059 type Result struct{ proposer, stakers, kff, kcf, remaining uint64 } 1060 1061 header := &types.Header{ 1062 Number: big.NewInt(1), 1063 BaseFee: big.NewInt(0), // placeholder 1064 } 1065 1066 testcases := []struct { 1067 desc string 1068 isKore bool 1069 fee uint64 1070 expected *Result 1071 }{ 1072 { 1073 desc: "kore=false, fee=0", 1074 isKore: false, 1075 fee: 0, 1076 expected: &Result{ 1077 proposer: 3.264e18, // minted * 0.34 1078 stakers: 0, 1079 kff: 5.184e18, // minted * 0.54 1080 kcf: 1.152e18, // minted * 0.12 1081 remaining: 0, 1082 }, 1083 }, 1084 { 1085 desc: "kore=false, fee=55555", 1086 isKore: false, 1087 fee: 55555, 1088 expected: &Result{ 1089 proposer: 3.264e18 + 18888, // (minted + fee) * 0.34 1090 stakers: 0, 1091 kff: 5.184e18 + 29999, // (minted + fee) * 0.54 1092 kcf: 1.152e18 + 6666, // (minted + fee) * 0.12 1093 remaining: 2, 1094 }, 1095 }, 1096 { 1097 desc: "kore=true, fee=0", 1098 isKore: true, 1099 fee: 0, 1100 expected: &Result{ 1101 proposer: 0.6528e18, // minted * 0.34 * 0.2 1102 stakers: 2.6112e18, // minted * 0.34 * 0.8 1103 kff: 5.184e18, // minted * 0.54 1104 kcf: 1.152e18, // minted * 0.12 1105 remaining: 0, 1106 }, 1107 }, 1108 { 1109 desc: "kore=true, fee=55555", 1110 isKore: true, 1111 fee: 55555, 1112 expected: &Result{ 1113 proposer: 0.6528e18 + 55555, // minted * 0.34 * 0.2 + fee 1114 stakers: 2.6112e18, // minted * 0.34 * 0.8 1115 kff: 5.184e18, // minted * 0.54 1116 kcf: 1.152e18, // minted * 0.12 1117 remaining: 0, 1118 }, 1119 }, 1120 } 1121 1122 for _, tc := range testcases { 1123 config := getTestConfig() 1124 if !tc.isKore { 1125 config = noKore(config) 1126 } 1127 1128 rules := config.Rules(header.Number) 1129 pset, err := params.NewGovParamSetChainConfig(config) 1130 require.Nil(t, err) 1131 1132 rc, err := NewRewardConfig(header, rules, pset) 1133 require.Nil(t, err) 1134 1135 fee := new(big.Int).SetUint64(tc.fee) 1136 proposer, stakers, kff, kcf, remaining := calcSplit(rc, minted, fee) 1137 actual := &Result{ 1138 proposer: proposer.Uint64(), 1139 stakers: stakers.Uint64(), 1140 kff: kff.Uint64(), 1141 kcf: kcf.Uint64(), 1142 remaining: remaining.Uint64(), 1143 } 1144 assert.Equal(t, tc.expected, actual, "failed tc: %s", tc.desc) 1145 1146 expectedTotalAmount := big.NewInt(0) 1147 expectedTotalAmount = expectedTotalAmount.Add(minted, fee) 1148 1149 actualTotalAmount := big.NewInt(0) 1150 actualTotalAmount = actualTotalAmount.Add(actualTotalAmount, proposer) 1151 actualTotalAmount = actualTotalAmount.Add(actualTotalAmount, stakers) 1152 actualTotalAmount = actualTotalAmount.Add(actualTotalAmount, kff) 1153 actualTotalAmount = actualTotalAmount.Add(actualTotalAmount, kcf) 1154 actualTotalAmount = actualTotalAmount.Add(actualTotalAmount, remaining) 1155 assert.Equal(t, expectedTotalAmount, actualTotalAmount, "failed tc: %s", tc.desc) 1156 } 1157 } 1158 1159 func TestRewardDistributor_calcShares(t *testing.T) { 1160 type Result struct { 1161 shares map[common.Address]*big.Int 1162 remaining uint64 1163 } 1164 1165 testcases := []struct { 1166 desc string 1167 stakingInfo *StakingInfo 1168 stakeReward *big.Int 1169 expected *Result 1170 }{ 1171 { 1172 desc: "all nodes 0%", 1173 stakingInfo: genStakingInfo(5, nil, nil), 1174 stakeReward: big.NewInt(500), 1175 expected: &Result{ 1176 shares: map[common.Address]*big.Int{}, 1177 remaining: 500, 1178 }, 1179 }, 1180 { 1181 desc: "no staking info", 1182 stakingInfo: nil, 1183 stakeReward: big.NewInt(500), 1184 expected: &Result{ 1185 shares: map[common.Address]*big.Int{}, 1186 remaining: 500, 1187 }, 1188 }, 1189 { 1190 desc: "CN0: 100%", 1191 stakingInfo: genStakingInfo(5, nil, map[int]uint64{0: minStaking + 1}), 1192 stakeReward: big.NewInt(500), 1193 expected: &Result{ 1194 shares: map[common.Address]*big.Int{ 1195 intToAddress(rewardBaseAddr): big.NewInt(500), 1196 }, 1197 remaining: 0, 1198 }, 1199 }, 1200 { 1201 desc: "CN0, CN1: 50%", 1202 stakingInfo: genStakingInfo(5, nil, map[int]uint64{ 1203 0: minStaking + 1, 1204 1: minStaking + 1, 1205 }), 1206 stakeReward: big.NewInt(500), 1207 expected: &Result{ 1208 shares: map[common.Address]*big.Int{ 1209 intToAddress(rewardBaseAddr): big.NewInt(250), 1210 intToAddress(rewardBaseAddr + 1): big.NewInt(250), 1211 }, 1212 remaining: 0, 1213 }, 1214 }, 1215 { 1216 desc: "CN0: 66%, CN1: 33%", 1217 stakingInfo: genStakingInfo(5, nil, map[int]uint64{ 1218 0: minStaking + 2, 1219 1: minStaking + 1, 1220 }), 1221 stakeReward: big.NewInt(500), 1222 expected: &Result{ 1223 shares: map[common.Address]*big.Int{ 1224 intToAddress(rewardBaseAddr): big.NewInt(333), 1225 intToAddress(rewardBaseAddr + 1): big.NewInt(166), 1226 }, 1227 remaining: 1, 1228 }, 1229 }, 1230 { 1231 desc: "CN0: 66/97, CN1: 17/97, CN2: 11/97, CN3: 2/97, CN4: 1/97", 1232 stakingInfo: genStakingInfo(7, nil, map[int]uint64{ 1233 0: minStaking + 66, 1234 1: minStaking + 17, 1235 2: minStaking + 11, 1236 3: minStaking + 2, 1237 4: minStaking + 1, // total: 97 1238 }), 1239 stakeReward: big.NewInt(555), 1240 expected: &Result{ 1241 shares: map[common.Address]*big.Int{ 1242 intToAddress(rewardBaseAddr): big.NewInt(377), 1243 intToAddress(rewardBaseAddr + 1): big.NewInt(97), 1244 intToAddress(rewardBaseAddr + 2): big.NewInt(62), 1245 intToAddress(rewardBaseAddr + 3): big.NewInt(11), 1246 intToAddress(rewardBaseAddr + 4): big.NewInt(5), 1247 }, 1248 remaining: 3, 1249 }, 1250 }, 1251 } 1252 1253 for _, tc := range testcases { 1254 shares, remaining := calcShares(tc.stakingInfo, tc.stakeReward, minStaking) 1255 actual := &Result{ 1256 shares: shares, 1257 remaining: remaining.Uint64(), 1258 } 1259 assert.Equal(t, tc.expected, actual, "failed tc: %s", tc.desc) 1260 } 1261 } 1262 1263 func benchSetup() (*types.Header, params.Rules, *params.GovParamSet) { 1264 // in the worst case, distribute stake shares among N 1265 amounts := make(map[int]uint64) 1266 N := 50 1267 for i := 0; i < N; i++ { 1268 amounts[i] = minStaking + 1 1269 } 1270 1271 stakingInfo := genStakingInfo(N, nil, amounts) 1272 SetTestStakingManagerWithStakingInfoCache(stakingInfo) 1273 1274 config := getTestConfig() 1275 1276 header := &types.Header{} 1277 header.BaseFee = big.NewInt(30000000000) 1278 header.Number = big.NewInt(0) 1279 header.Rewardbase = intToAddress(rewardBaseAddr) 1280 1281 rules := config.Rules(header.Number) 1282 pset, _ := params.NewGovParamSetChainConfig(config) 1283 1284 return header, rules, pset 1285 } 1286 1287 func Benchmark_CalcDeferredReward(b *testing.B) { 1288 oldStakingManager := GetStakingManager() 1289 defer SetTestStakingManager(oldStakingManager) 1290 1291 header, rules, pset := benchSetup() 1292 1293 b.ResetTimer() 1294 for i := 0; i < b.N; i++ { 1295 CalcDeferredReward(header, rules, pset) 1296 } 1297 } 1298 1299 func TestRewardConfigCache_parseRewardRatio(t *testing.T) { 1300 testCases := []struct { 1301 s string 1302 cn int64 1303 kff int64 1304 kcf int64 1305 err error 1306 }{ 1307 {"34/54/12", 34, 54, 12, nil}, 1308 {"3/3/3", 3, 3, 3, nil}, 1309 {"10/20/30", 10, 20, 30, nil}, 1310 {"34,54,12", 0, 0, 0, errInvalidFormat}, 1311 {"/", 0, 0, 0, errInvalidFormat}, 1312 {"///", 0, 0, 0, errInvalidFormat}, 1313 {"1//", 0, 0, 0, errParsingRatio}, 1314 {"/1/", 0, 0, 0, errParsingRatio}, 1315 {"//1", 0, 0, 0, errParsingRatio}, 1316 {"1/2/3/4/", 0, 0, 0, errInvalidFormat}, 1317 {"3.3/3.3/3.3", 0, 0, 0, errParsingRatio}, 1318 {"a/b/c", 0, 0, 0, errParsingRatio}, 1319 } 1320 1321 for i := 0; i < len(testCases); i++ { 1322 cn, kff, kcf, total, err := parseRewardRatio(testCases[i].s) 1323 1324 assert.Equal(t, testCases[i].cn, cn) 1325 assert.Equal(t, testCases[i].kff, kff) 1326 assert.Equal(t, testCases[i].kcf, kcf) 1327 assert.Equal(t, testCases[i].err, err) 1328 1329 expectedTotal := testCases[i].cn + testCases[i].kff + testCases[i].kcf 1330 assert.Equal(t, expectedTotal, total) 1331 } 1332 } 1333 1334 func TestRewardConfigCache_parseRewardKip82Ratio(t *testing.T) { 1335 testCases := []struct { 1336 s string 1337 proposer int64 1338 staking int64 1339 err error 1340 }{ 1341 {"34/54", 34, 54, nil}, 1342 {"20/80", 20, 80, nil}, 1343 {"0/100", 0, 100, nil}, 1344 {"34,54", 0, 0, errInvalidFormat}, 1345 {"", 0, 0, errInvalidFormat}, 1346 {"//", 0, 0, errInvalidFormat}, 1347 {"1/", 0, 0, errParsingRatio}, 1348 {"/1", 0, 0, errParsingRatio}, 1349 {"1/2/", 0, 0, errInvalidFormat}, 1350 {"3.3/3.3", 0, 0, errParsingRatio}, 1351 {"a/b", 0, 0, errParsingRatio}, 1352 } 1353 1354 for i := 0; i < len(testCases); i++ { 1355 proposer, staking, total, err := parseRewardKip82Ratio(testCases[i].s) 1356 1357 assert.Equal(t, testCases[i].proposer, proposer) 1358 assert.Equal(t, testCases[i].staking, staking) 1359 assert.Equal(t, testCases[i].err, err, "tc[%d] failed", i) 1360 1361 expectedTotal := testCases[i].proposer + testCases[i].staking 1362 assert.Equal(t, expectedTotal, total) 1363 } 1364 }