๐Ÿ’ฐ

Staking Reward Logic

// TwoSecStakedBlocks is the flat-rate block reward after epoch 360.
	// 7 ONE per block

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
}