livepeer / protocol

Livepeer protocol
MIT License
154 stars 45 forks source link

Batch reward calls on round initialization #482

Open yondonfu opened 2 years ago

yondonfu commented 2 years ago

I thought of another approach for calculating and distributing rewards. This approach has a change in the mechanism of how rewards are called. 2 new variables are introduced in each delegation pool - prevRoundRewards, claimedPrevRoundRewards + orchestratorCutForTheRound (which can be read from the staking manager).

[⛔️ After writing this I realized that I completely missed that there is a need to track if individual delegator has claimed reward, still keeping this comment here for reference]

step 1 - instead of each orchestrator calling reward individually, rewards for all the orchestrators will be called at the same time when initializeRound is called [1] end of round [this comment] (https://github.com/livepeer/protocol/issues/463#issuecomment-922581787).

step 2 - Now instead of calculating cuts for orchestrator and delegators individually, the total value of reward is simply added to the respective pool and the prevRoundRewards is overwritten with the value and claimedPrevRoundRewards is set to 0 [2]. However, Before the overwrite the unclaimed rewards from previous round is calculated as prevRoundRewards - claimedPrevRoundRewards which can be used as per [3]

step 3 - Now, each delegator and orchestrator can individually call a claimReward function which will use the current shares, prevRoundRewards and orchestratorCutForTheRound to calculate respective rewards [4]. delegator rewards = prevRoundRewards * (1-orchestratorCutForTheRound) * delegator's share orchestrator rewards = prevRoundRewards * orchestratorCutForTheRound * orchestrator's share

then the delegator's and orchestrator's stakes are updated.

step 4 - for each claim, update claimedPrevRoundRewards

notes -

  1. Since there are a fixed number of orchestrators that is 100, calling reward for all the orchestrators will be a constant time function
  2. due to overwrite there won't be an unbonded growth for the storage
  3. The unclaimed rewards can be used for a variety of purposed. eg - can be given to orchestrator, can be used for governance etc. A part of this can even be used to reward the account which calls initializeRound as it now has a greater gas usage.
  4. This also solves the problem where delegators are dependant upon orchestrators for calling reward, now they don't lose reward even if the orchestrator doesn't call reward. Also, if the user does not call reward, they lose the reward, which is similar to the current approach.

additional notes -

  1. The first step does increase gas usage as the rewards are calculated for each orchestrator but for individual users the gas will be much lower
  2. This solves the problem of instant eligibility, dilution before reward call and also dilution after reward call

Originally posted by @kautukkundan in https://github.com/livepeer/protocol/issues/463#issuecomment-927912360

yondonfu commented 2 years ago

From @kautukkundan in https://github.com/livepeer/protocol/issues/463#issuecomment-927939556

possible fix to the problem in my previous comment add a lastClaimedRound variable in the delegation struct and check it before calling claimReward https://github.com/livepeer/protocol/blob/next/contracts/bonding/Delegations.sol#L28-L31

kyriediculous commented 2 years ago

From a high level the proposal and some iterations I've done myself on this boil down to:

  1. Keep track of a reward pool across orchestrators accruing each round based on each Os equity share of stake
  2. Keep track of a delegation pool per orchestrators
  3. When commission rates are changed move accrued rewards from pool in [1] to the delegation pool minus orchestrator commissions

After reviewing the above proposal, going through some design iterations with the same purpose myself and discussing it with @kautukkundan we concluded the following things:

However the argument above might not be entirely valid anymore as in the current confluence design we already socialize the cost of some state progression based on who takes the first delegation action (or rewards/fees added) in a round. So I think this is definitely an interesting problem area to put some more thought in if we are okay with the cost of some state progressions being socialised.