func distributeRewardAfterAggregateEpoch(bc engine.ChainReader, state *state.DB, header *block.Header, beaconChain engine.ChainReader,
defaultReward numeric.Dec) (reward.Reader, error) {
newRewards, payouts :=
big.NewInt(0), []reward.Payout{}
allPayables := []slotPayable{}
curBlockNum := header.Number().Uint64()
allCrossLinks := types.CrossLinks{}
startTime := time.Now()
// loop through [0...63] position in the modulus index of the 64 blocks
// Note the current block is at position 63 of the modulus.
for i := curBlockNum - RewardFrequency + 1; i <= curBlockNum; i++ {
if i < 0 {
continue
}
var curHeader *block.Header
if i == curBlockNum {
// When it's the current block (63th), we should use the provided header since it's not written in db yet.
curHeader = header
} else {
curHeader = bc.GetHeaderByNumber(i)
}
// Put shard 0 signatures as a crosslink for easy and consistent processing as other shards' crosslinks
allCrossLinks = append(allCrossLinks, *types.NewCrossLink(curHeader, bc.GetHeaderByHash(curHeader.ParentHash())))
// Put the real crosslinks in the list
if cxLinks := curHeader.CrossLinks(); len(cxLinks) > 0 {
crossLinks := types.CrossLinks{}
if err := rlp.DecodeBytes(cxLinks, &crossLinks); err != nil {
return network.EmptyPayout, err
}
allCrossLinks = append(allCrossLinks, crossLinks...)
}
}
for i := range allCrossLinks {
cxLink := allCrossLinks[i]
if !bc.Config().IsStaking(cxLink.Epoch()) {
continue
}
utils.Logger().Info().Msg(fmt.Sprintf("allCrossLinks shard %d block %d", cxLink.ShardID(), cxLink.BlockNum()))
payables, _, err := processOneCrossLink(bc, state, cxLink, defaultReward, i)
if err != nil {
return network.EmptyPayout, err
}
allPayables = append(allPayables, payables...)
}
// Aggregate all the rewards for each validator
allValidatorPayable := map[common.Address]*big.Int{}
allAddresses := []common.Address{}
for _, payThem := range allPayables {
if _, ok := allValidatorPayable[payThem.EcdsaAddress]; !ok {
allValidatorPayable[payThem.EcdsaAddress] = big.NewInt(0).SetBytes(payThem.payout.Bytes())
} else {
allValidatorPayable[payThem.EcdsaAddress] = big.NewInt(0).Add(allValidatorPayable[payThem.EcdsaAddress], payThem.payout)
}
payouts = append(payouts, reward.Payout{
Addr: payThem.EcdsaAddress,
NewlyEarned: payThem.payout,
EarningKey: payThem.BLSPublicKey,
})
}
for addr, _ := range allValidatorPayable {
allAddresses = append(allAddresses, addr)
}
// always sort validators by address before rewarding
sort.SliceStable(allAddresses,
func(i, j int) bool {
return bytes.Compare(allAddresses[i][:], allAddresses[j][:]) < 0
},
)
// Finally do the pay
startTimeLocal := time.Now()
for _, addr := range allAddresses {
snapshot, err := bc.ReadValidatorSnapshot(addr)
if err != nil {
return network.EmptyPayout, err
}
due := allValidatorPayable[addr]
newRewards.Add(newRewards, due)
shares, err := lookupDelegatorShares(snapshot)
if err != nil {
return network.EmptyPayout, err
}
if err := state.AddReward(snapshot.Validator, due, shares); err != nil {
return network.EmptyPayout, err
}
}
utils.Logger().Debug().Int64("elapsed time", time.Now().Sub(startTimeLocal).Milliseconds()).Msg("After Chain Reward (AddReward)")
utils.Logger().Debug().Int64("elapsed time", time.Now().Sub(startTime).Milliseconds()).Msg("After Chain Reward")
return network.NewStakingEraRewardForRound(
newRewards, payouts,
), nil
}