github.com/klaytn/klaytn@v1.12.1/reward/reward_distributor.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 "errors" 21 "math/big" 22 "strconv" 23 "strings" 24 "time" 25 26 "github.com/klaytn/klaytn/blockchain/types" 27 "github.com/klaytn/klaytn/common" 28 "github.com/klaytn/klaytn/consensus/istanbul" 29 "github.com/klaytn/klaytn/crypto/sha3" 30 "github.com/klaytn/klaytn/log" 31 "github.com/klaytn/klaytn/params" 32 "github.com/klaytn/klaytn/rlp" 33 ) 34 35 var CalcDeferredRewardTimer time.Duration 36 37 var logger = log.NewModuleLogger(log.Reward) 38 39 var ( 40 errInvalidFormat = errors.New("invalid ratio format") 41 errParsingRatio = errors.New("parsing ratio fail") 42 ) 43 44 type BalanceAdder interface { 45 AddBalance(addr common.Address, v *big.Int) 46 } 47 48 // Cannot use governance.Engine because of cyclic dependency. 49 // Instead declare only the methods used by this package. 50 type governanceHelper interface { 51 CurrentParams() *params.GovParamSet 52 EffectiveParams(num uint64) (*params.GovParamSet, error) 53 } 54 55 type rewardConfig struct { 56 // hardfork rules 57 rules params.Rules 58 59 // values calculated from block header 60 totalFee *big.Int 61 62 // values from GovParamSet 63 mintingAmount *big.Int 64 minimumStake *big.Int 65 deferredTxFee bool 66 67 // parsed ratio 68 cnRatio *big.Int 69 kffRatio *big.Int 70 kcfRatio *big.Int 71 totalRatio *big.Int 72 73 // parsed KIP82 ratio 74 cnProposerRatio *big.Int 75 cnStakingRatio *big.Int 76 cnTotalRatio *big.Int 77 } 78 79 type RewardSpec struct { 80 Minted *big.Int `json:"minted"` // the amount newly minted 81 TotalFee *big.Int `json:"totalFee"` // total tx fee spent 82 BurntFee *big.Int `json:"burntFee"` // the amount burnt 83 Proposer *big.Int `json:"proposer"` // the amount allocated to the block proposer 84 Stakers *big.Int `json:"stakers"` // total amount allocated to stakers 85 KFF *big.Int `json:"kff"` // the amount allocated to KFF 86 KCF *big.Int `json:"kcf"` // the amount allocated to KCF 87 Rewards map[common.Address]*big.Int `json:"rewards"` // mapping from reward recipient to amounts 88 } 89 90 func NewRewardSpec() *RewardSpec { 91 return &RewardSpec{ 92 Minted: big.NewInt(0), 93 TotalFee: big.NewInt(0), 94 BurntFee: big.NewInt(0), 95 Proposer: big.NewInt(0), 96 Stakers: big.NewInt(0), 97 KFF: big.NewInt(0), 98 KCF: big.NewInt(0), 99 Rewards: make(map[common.Address]*big.Int), 100 } 101 } 102 103 func (spec *RewardSpec) Add(delta *RewardSpec) { 104 spec.Minted.Add(spec.Minted, delta.Minted) 105 spec.TotalFee.Add(spec.TotalFee, delta.TotalFee) 106 spec.BurntFee.Add(spec.BurntFee, delta.BurntFee) 107 spec.Proposer.Add(spec.Proposer, delta.Proposer) 108 spec.Stakers.Add(spec.Stakers, delta.Stakers) 109 spec.KFF.Add(spec.KFF, delta.KFF) 110 spec.KCF.Add(spec.KCF, delta.KCF) 111 112 for addr, amount := range delta.Rewards { 113 incrementRewardsMap(spec.Rewards, addr, amount) 114 } 115 } 116 117 // TODO: this is for legacy, will be removed 118 type RewardDistributor struct{} 119 120 func NewRewardDistributor(gh governanceHelper) *RewardDistributor { 121 return &RewardDistributor{} 122 } 123 124 // DistributeBlockReward distributes a given block's reward at the end of block processing 125 func DistributeBlockReward(b BalanceAdder, rewards map[common.Address]*big.Int) { 126 for addr, amount := range rewards { 127 b.AddBalance(addr, amount) 128 } 129 } 130 131 func NewRewardConfig(header *types.Header, rules params.Rules, pset *params.GovParamSet) (*rewardConfig, error) { 132 cnRatio, kffRatio, kcfRatio, totalRatio, err := parseRewardRatio(pset.Ratio()) 133 if err != nil { 134 return nil, err 135 } 136 137 var cnProposerRatio, cnStakingRatio, cnTotalRatio int64 138 if rules.IsKore { 139 cnProposerRatio, cnStakingRatio, cnTotalRatio, err = parseRewardKip82Ratio(pset.Kip82Ratio()) 140 if err != nil { 141 return nil, err 142 } 143 } 144 145 return &rewardConfig{ 146 // hardfork rules 147 rules: rules, 148 149 // values calculated from block header 150 totalFee: GetTotalTxFee(header, rules, pset), 151 152 // values from GovParamSet 153 mintingAmount: new(big.Int).Set(pset.MintingAmountBig()), 154 minimumStake: new(big.Int).Set(pset.MinimumStakeBig()), 155 deferredTxFee: pset.DeferredTxFee(), 156 157 // parsed ratio 158 cnRatio: big.NewInt(cnRatio), 159 kffRatio: big.NewInt(kffRatio), 160 kcfRatio: big.NewInt(kcfRatio), 161 totalRatio: big.NewInt(totalRatio), 162 163 // parsed KIP82 ratio 164 cnProposerRatio: big.NewInt(cnProposerRatio), 165 cnStakingRatio: big.NewInt(cnStakingRatio), 166 cnTotalRatio: big.NewInt(cnTotalRatio), 167 }, nil 168 } 169 170 func GetTotalTxFee(header *types.Header, rules params.Rules, pset *params.GovParamSet) *big.Int { 171 totalFee := new(big.Int).SetUint64(header.GasUsed) 172 if rules.IsMagma { 173 totalFee = totalFee.Mul(totalFee, header.BaseFee) 174 } else { 175 totalFee = totalFee.Mul(totalFee, new(big.Int).SetUint64(pset.UnitPrice())) 176 } 177 return totalFee 178 } 179 180 // config.Istanbul must have been set 181 func IsRewardSimple(pset *params.GovParamSet) bool { 182 return pset.Policy() != uint64(istanbul.WeightedRandom) 183 } 184 185 // CalcRewardParamBlock returns the block number with which governance parameters must be fetched 186 // This mimics the legacy reward config cache before Kore 187 func CalcRewardParamBlock(num, epoch uint64, rules params.Rules) uint64 { 188 if !rules.IsKore && num%epoch == 0 { 189 return num - epoch 190 } 191 return num 192 } 193 194 // GetBlockReward returns the actual reward amounts paid in this block 195 // Used in klay_getReward RPC API 196 func GetBlockReward(header *types.Header, rules params.Rules, pset *params.GovParamSet) (*RewardSpec, error) { 197 var spec *RewardSpec 198 var err error 199 200 if IsRewardSimple(pset) { 201 spec, err = CalcDeferredRewardSimple(header, rules, pset) 202 if err != nil { 203 return nil, err 204 } 205 } else { 206 spec, err = CalcDeferredReward(header, rules, pset) 207 if err != nil { 208 return nil, err 209 } 210 } 211 212 // Compensate the difference between CalcDeferredReward() and actual payment. 213 // If not DeferredTxFee, CalcDeferredReward() assumes 0 total_fee, but 214 // some non-zero fee already has been paid to the proposer. 215 if !pset.DeferredTxFee() { 216 if rules.IsMagma { 217 txFee := GetTotalTxFee(header, rules, pset) 218 txFeeBurn := getBurnAmountMagma(txFee) 219 txFeeRemained := new(big.Int).Sub(txFee, txFeeBurn) 220 spec.BurntFee = txFeeBurn 221 222 spec.Proposer = spec.Proposer.Add(spec.Proposer, txFeeRemained) 223 spec.TotalFee = spec.TotalFee.Add(spec.TotalFee, txFee) 224 incrementRewardsMap(spec.Rewards, header.Rewardbase, txFeeRemained) 225 } else { 226 txFee := GetTotalTxFee(header, rules, pset) 227 spec.Proposer = spec.Proposer.Add(spec.Proposer, txFee) 228 spec.TotalFee = spec.TotalFee.Add(spec.TotalFee, txFee) 229 // get the proposer of this block. 230 proposer, err := ecrecover(header) 231 if err != nil { 232 return nil, err 233 } 234 incrementRewardsMap(spec.Rewards, proposer, txFee) 235 236 } 237 } 238 239 return spec, nil 240 } 241 242 // CalcDeferredRewardSimple distributes rewards to proposer after optional fee burning 243 // this behaves similar to the previous MintKLAY 244 // MintKLAY has been superseded because we need to split reward distribution 245 // logic into (1) calculation, and (2) actual distribution. 246 // CalcDeferredRewardSimple does the former and DistributeBlockReward does the latter 247 func CalcDeferredRewardSimple(header *types.Header, rules params.Rules, pset *params.GovParamSet) (*RewardSpec, error) { 248 rc, err := NewRewardConfig(header, rules, pset) 249 if err != nil { 250 return nil, err 251 } 252 253 minted := rc.mintingAmount 254 255 // If not DeferredTxFee, fees are already added to the proposer during TX execution. 256 // Therefore, there are no fees to distribute here at the end of block processing. 257 // However, before Kore, there was a bug that distributed tx fee regardless 258 // of `deferredTxFee` flag. See https://github.com/klaytn/klaytn/issues/1692. 259 // To maintain backward compatibility, we only fix the buggy logic after Magma 260 // and leave the buggy logic before Magma. 261 // However, the fees must be compensated to calculate actual rewards paid. 262 263 // bug-fixed logic after Magma 264 if !rc.deferredTxFee && rc.rules.IsMagma { 265 proposer := new(big.Int).Set(minted) 266 logger.Debug("CalcDeferredRewardSimple after Kore when deferredTxFee=false returns", 267 "proposer", proposer) 268 spec := NewRewardSpec() 269 spec.Minted = minted 270 spec.TotalFee = big.NewInt(0) 271 spec.BurntFee = big.NewInt(0) 272 spec.Proposer = proposer 273 incrementRewardsMap(spec.Rewards, header.Rewardbase, proposer) 274 return spec, nil 275 } 276 277 totalFee := rc.totalFee 278 rewardFee := new(big.Int).Set(totalFee) 279 burntFee := big.NewInt(0) 280 281 if rc.rules.IsMagma { 282 burnt := getBurnAmountMagma(rewardFee) 283 rewardFee = rewardFee.Sub(rewardFee, burnt) 284 burntFee = burntFee.Add(burntFee, burnt) 285 } 286 287 proposer := big.NewInt(0).Add(minted, rewardFee) 288 289 logger.Debug("CalcDeferredRewardSimple returns", 290 "proposer", proposer.Uint64(), 291 "totalFee", totalFee.Uint64(), 292 "burntFee", burntFee.Uint64(), 293 ) 294 295 spec := NewRewardSpec() 296 spec.Minted = minted 297 spec.TotalFee = totalFee 298 spec.BurntFee = burntFee 299 spec.Proposer = proposer 300 incrementRewardsMap(spec.Rewards, header.Rewardbase, proposer) 301 return spec, nil 302 } 303 304 // CalcDeferredReward calculates the deferred rewards, 305 // which are determined at the end of block processing. 306 func CalcDeferredReward(header *types.Header, rules params.Rules, pset *params.GovParamSet) (*RewardSpec, error) { 307 defer func(start time.Time) { 308 CalcDeferredRewardTimer = time.Since(start) 309 }(time.Now()) 310 311 rc, err := NewRewardConfig(header, rules, pset) 312 if err != nil { 313 return nil, err 314 } 315 316 var ( 317 minted = rc.mintingAmount 318 stakingInfo = GetStakingInfo(header.Number.Uint64()) 319 ) 320 321 totalFee, rewardFee, burntFee := calcDeferredFee(rc) 322 proposer, stakers, kff, kcf, splitRem := calcSplit(rc, minted, rewardFee) 323 shares, shareRem := calcShares(stakingInfo, stakers, rc.minimumStake.Uint64()) 324 325 // Remainder from (CN, KFF, KCF) split goes to KFF 326 kff = kff.Add(kff, splitRem) 327 // Remainder from staker shares goes to Proposer 328 // Then, deduct it from stakers so that `minted + totalFee - burntFee = proposer + stakers + kff + kcf` 329 proposer = proposer.Add(proposer, shareRem) 330 stakers = stakers.Sub(stakers, shareRem) 331 332 // if KFF or KCF is not set, proposer gets the portion 333 if stakingInfo == nil || common.EmptyAddress(stakingInfo.KFFAddr) { 334 logger.Debug("KFF empty, proposer gets its portion", "kff", kff) 335 proposer = proposer.Add(proposer, kff) 336 kff = big.NewInt(0) 337 } 338 if stakingInfo == nil || common.EmptyAddress(stakingInfo.KCFAddr) { 339 logger.Debug("KCF empty, proposer gets its portion", "kcf", kcf) 340 proposer = proposer.Add(proposer, kcf) 341 kcf = big.NewInt(0) 342 } 343 344 spec := NewRewardSpec() 345 spec.Minted = minted 346 spec.TotalFee = totalFee 347 spec.BurntFee = burntFee 348 spec.Proposer = proposer 349 spec.Stakers = stakers 350 spec.KFF = kff 351 spec.KCF = kcf 352 353 incrementRewardsMap(spec.Rewards, header.Rewardbase, proposer) 354 355 if stakingInfo != nil && !common.EmptyAddress(stakingInfo.KFFAddr) { 356 incrementRewardsMap(spec.Rewards, stakingInfo.KFFAddr, kff) 357 } 358 if stakingInfo != nil && !common.EmptyAddress(stakingInfo.KCFAddr) { 359 incrementRewardsMap(spec.Rewards, stakingInfo.KCFAddr, kcf) 360 } 361 362 for rewardAddr, rewardAmount := range shares { 363 incrementRewardsMap(spec.Rewards, rewardAddr, rewardAmount) 364 } 365 logger.Debug("CalcDeferredReward() returns", "spec", spec) 366 367 return spec, nil 368 } 369 370 // calcDeferredFee splits fee into (total, reward, burnt) 371 func calcDeferredFee(rc *rewardConfig) (*big.Int, *big.Int, *big.Int) { 372 // If not DeferredTxFee, fees are already added to the proposer during TX execution. 373 // Therefore, there are no fees to distribute here at the end of block processing. 374 // However, the fees must be compensated to calculate actual rewards paid. 375 if !rc.deferredTxFee { 376 return big.NewInt(0), big.NewInt(0), big.NewInt(0) 377 } 378 379 totalFee := rc.totalFee 380 rewardFee := new(big.Int).Set(totalFee) 381 burntFee := big.NewInt(0) 382 383 // after magma, burn half of gas 384 if rc.rules.IsMagma { 385 burnt := getBurnAmountMagma(rewardFee) 386 rewardFee = rewardFee.Sub(rewardFee, burnt) 387 burntFee = burntFee.Add(burntFee, burnt) 388 } 389 390 // after kore, burn fees up to proposer's minted reward 391 if rc.rules.IsKore { 392 burnt := getBurnAmountKore(rc, rewardFee) 393 rewardFee = rewardFee.Sub(rewardFee, burnt) 394 burntFee = burntFee.Add(burntFee, burnt) 395 } 396 397 logger.Debug("calcDeferredFee()", 398 "totalFee", totalFee.Uint64(), 399 "rewardFee", rewardFee.Uint64(), 400 "burntFee", burntFee.Uint64(), 401 ) 402 return totalFee, rewardFee, burntFee 403 } 404 405 func getBurnAmountMagma(fee *big.Int) *big.Int { 406 return new(big.Int).Div(fee, big.NewInt(2)) 407 } 408 409 func getBurnAmountKore(rc *rewardConfig, fee *big.Int) *big.Int { 410 cn, _, _ := splitByRatio(rc, rc.mintingAmount) 411 proposer, _ := splitByKip82Ratio(rc, cn) 412 413 logger.Debug("getBurnAmountKore()", 414 "fee", fee.Uint64(), 415 "proposer", proposer.Uint64(), 416 ) 417 418 if fee.Cmp(proposer) >= 0 { 419 return proposer 420 } else { 421 return new(big.Int).Set(fee) // return copy of the parameter 422 } 423 } 424 425 // calcSplit splits fee into (proposer, stakers, kff, kcf, remaining) 426 // the sum of the output must be equal to (minted + fee) 427 func calcSplit(rc *rewardConfig, minted, fee *big.Int) (*big.Int, *big.Int, *big.Int, *big.Int, *big.Int) { 428 totalResource := big.NewInt(0) 429 totalResource = totalResource.Add(minted, fee) 430 431 if rc.rules.IsKore { 432 cn, kff, kcf := splitByRatio(rc, minted) 433 proposer, stakers := splitByKip82Ratio(rc, cn) 434 435 proposer = proposer.Add(proposer, fee) 436 437 remaining := new(big.Int).Set(totalResource) 438 remaining = remaining.Sub(remaining, kff) 439 remaining = remaining.Sub(remaining, kcf) 440 remaining = remaining.Sub(remaining, proposer) 441 remaining = remaining.Sub(remaining, stakers) 442 443 logger.Debug("calcSplit() after kore", 444 "[in] minted", minted.Uint64(), 445 "[in] fee", fee.Uint64(), 446 "[out] proposer", proposer.Uint64(), 447 "[out] stakers", stakers.Uint64(), 448 "[out] kff", kff.Uint64(), 449 "[out] kcf", kcf.Uint64(), 450 "[out] remaining", remaining.Uint64(), 451 ) 452 return proposer, stakers, kff, kcf, remaining 453 } else { 454 cn, kff, kcf := splitByRatio(rc, totalResource) 455 456 remaining := new(big.Int).Set(totalResource) 457 remaining = remaining.Sub(remaining, kff) 458 remaining = remaining.Sub(remaining, kcf) 459 remaining = remaining.Sub(remaining, cn) 460 461 logger.Debug("calcSplit() before kore", 462 "[in] minted", minted.Uint64(), 463 "[in] fee", fee.Uint64(), 464 "[out] cn", cn.Uint64(), 465 "[out] kff", kff.Uint64(), 466 "[out] kcf", kcf.Uint64(), 467 "[out] remaining", remaining.Uint64(), 468 ) 469 return cn, big.NewInt(0), kff, kcf, remaining 470 } 471 } 472 473 // splitByRatio splits by `ratio`. It ignores any remaining amounts. 474 func splitByRatio(rc *rewardConfig, source *big.Int) (*big.Int, *big.Int, *big.Int) { 475 cn := new(big.Int).Mul(source, rc.cnRatio) 476 cn = cn.Div(cn, rc.totalRatio) 477 478 kff := new(big.Int).Mul(source, rc.kffRatio) 479 kff = kff.Div(kff, rc.totalRatio) 480 481 kcf := new(big.Int).Mul(source, rc.kcfRatio) 482 kcf = kcf.Div(kcf, rc.totalRatio) 483 484 return cn, kff, kcf 485 } 486 487 // splitByKip82Ratio splits by `kip82ratio`. It ignores any remaining amounts. 488 func splitByKip82Ratio(rc *rewardConfig, source *big.Int) (*big.Int, *big.Int) { 489 proposer := new(big.Int).Mul(source, rc.cnProposerRatio) 490 proposer = proposer.Div(proposer, rc.cnTotalRatio) 491 492 stakers := new(big.Int).Mul(source, rc.cnStakingRatio) 493 stakers = stakers.Div(stakers, rc.cnTotalRatio) 494 495 return proposer, stakers 496 } 497 498 // calcShares distributes stake reward among staked CNs 499 func calcShares(stakingInfo *StakingInfo, stakeReward *big.Int, minStake uint64) (map[common.Address]*big.Int, *big.Int) { 500 // if stakingInfo is nil, stakeReward goes to proposer 501 if stakingInfo == nil { 502 return make(map[common.Address]*big.Int), stakeReward 503 } 504 505 cns := stakingInfo.GetConsolidatedStakingInfo() 506 507 totalStakesInt := uint64(0) 508 509 for _, node := range cns.GetAllNodes() { 510 if node.StakingAmount > minStake { // comparison in Klay 511 totalStakesInt += (node.StakingAmount - minStake) 512 } 513 } 514 515 totalStakes := new(big.Int).SetUint64(totalStakesInt) 516 remaining := new(big.Int).Set(stakeReward) 517 shares := make(map[common.Address]*big.Int) 518 519 for _, node := range cns.GetAllNodes() { 520 if node.StakingAmount > minStake { 521 effectiveStake := new(big.Int).SetUint64(node.StakingAmount - minStake) 522 // The KLAY unit will cancel out: 523 // rewardAmount (peb) = stakeReward (peb) * effectiveStake (KLAY) / totalStakes (KLAY) 524 rewardAmount := new(big.Int).Mul(stakeReward, effectiveStake) 525 rewardAmount = rewardAmount.Div(rewardAmount, totalStakes) 526 remaining = remaining.Sub(remaining, rewardAmount) 527 if rewardAmount.Cmp(big.NewInt(0)) > 0 { 528 shares[node.RewardAddr] = rewardAmount 529 } 530 } 531 } 532 logger.Debug("calcShares()", 533 "[in] stakeReward", stakeReward.Uint64(), 534 "[out] remaining", remaining.Uint64(), 535 "[out] shares", shares, 536 ) 537 538 return shares, remaining 539 } 540 541 // parseRewardRatio parses string `ratio` into ints 542 func parseRewardRatio(ratio string) (int64, int64, int64, int64, error) { 543 s := strings.Split(ratio, "/") 544 if len(s) != params.RewardSliceCount { 545 logger.Error("Invalid ratio format", "ratio", ratio) 546 return 0, 0, 0, 0, errInvalidFormat 547 } 548 cn, err1 := strconv.ParseInt(s[0], 10, 64) 549 kff, err2 := strconv.ParseInt(s[1], 10, 64) 550 kcf, err3 := strconv.ParseInt(s[2], 10, 64) 551 552 if err1 != nil || err2 != nil || err3 != nil { 553 logger.Error("Could not parse ratio", "ratio", ratio) 554 return 0, 0, 0, 0, errParsingRatio 555 } 556 return cn, kff, kcf, cn + kff + kcf, nil 557 } 558 559 // parseRewardKip82Ratio parses string `kip82ratio` into ints 560 func parseRewardKip82Ratio(ratio string) (int64, int64, int64, error) { 561 s := strings.Split(ratio, "/") 562 if len(s) != params.RewardKip82SliceCount { 563 logger.Error("Invalid kip82ratio format", "ratio", ratio) 564 return 0, 0, 0, errInvalidFormat 565 } 566 proposer, err1 := strconv.ParseInt(s[0], 10, 64) 567 stakers, err2 := strconv.ParseInt(s[1], 10, 64) 568 569 if err1 != nil || err2 != nil { 570 logger.Error("Could not parse kip82ratio", "ratio", ratio) 571 return 0, 0, 0, errParsingRatio 572 } 573 return proposer, stakers, proposer + stakers, nil 574 } 575 576 func incrementRewardsMap(m map[common.Address]*big.Int, addr common.Address, amount *big.Int) { 577 _, ok := m[addr] 578 if !ok { 579 m[addr] = big.NewInt(0) 580 } 581 582 m[addr] = m[addr].Add(m[addr], amount) 583 } 584 585 // ecrecover extracts the Klaytn account address from a signed header. 586 func ecrecover(header *types.Header) (common.Address, error) { 587 // Retrieve the signature from the header extra-data 588 istanbulExtra, err := types.ExtractIstanbulExtra(header) 589 if err != nil { 590 return common.Address{}, nil 591 } 592 593 sigHash, err := sigHash(header) 594 if err != nil { 595 return common.Address{}, err 596 } 597 addr, err := istanbul.GetSignatureAddress(sigHash.Bytes(), istanbulExtra.Seal) 598 if err != nil { 599 return addr, err 600 } 601 return addr, nil 602 } 603 604 func sigHash(header *types.Header) (hash common.Hash, err error) { 605 hasher := sha3.NewKeccak256() 606 607 // Clean seal is required for calculating proposer seal. 608 if err := rlp.Encode(hasher, types.IstanbulFilteredHeader(header, false)); err != nil { 609 logger.Error("fail to encode", "err", err) 610 return common.Hash{}, err 611 } 612 hasher.Sum(hash[:0]) 613 return hash, nil 614 }