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 := ¶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(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 }