From 9eb7e638194210b1f6504c93fae4b9ae80b04ee4 Mon Sep 17 00:00:00 2001 From: anatoly yakovenko Date: Mon, 11 Mar 2019 16:35:42 -0700 Subject: [PATCH] Add staking rewards design proposal for delegation (#3148) * proposal for single vote many delegators --- book/src/SUMMARY.md | 1 + .../passive-stake-delegation-and-rewards.md | 195 ++++++++++++++++++ 2 files changed, 196 insertions(+) create mode 100644 book/src/passive-stake-delegation-and-rewards.md diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index aef62463df..1240a168fd 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -38,6 +38,7 @@ - [Ledger Replication](ledger-replication-to-implement.md) - [Secure Vote Signing](vote-signing-to-implement.md) - [Staking Rewards](staking-rewards.md) + - [Passive Staking Delegation and Rewards](passive-stake-delegation-and-rewards.md) - [Fork Selection](fork-selection.md) - [Reliable Vote Transmission](reliable-vote-transmission.md) - [Persistent Account Storage](persistent-account-storage.md) diff --git a/book/src/passive-stake-delegation-and-rewards.md b/book/src/passive-stake-delegation-and-rewards.md new file mode 100644 index 0000000000..c1298e30dc --- /dev/null +++ b/book/src/passive-stake-delegation-and-rewards.md @@ -0,0 +1,195 @@ +# Stake Delegation and Reward + +This design proposal focuses on the software architecture for the on-chain +voting and staking programs. Incentives for staking is covered in [staking +rewards](staking-rewards.md). + +The current architecture requires a vote for each delegated stake from the +validator, and therefore does not scale to allow for replicator clients +automatically delegate their rewards. + +The design proposes a new set of programs for voting and stake delegation, The +proposed programs allow many stake accounts to passively earn rewards with a +single validator vote without permission or active involvement from the +validator. + +## Current Design Problems + +In the current design each staker creates their own VoteState, and assigns a +**delegate** in the VoteState that can submit votes. Since the validator has to +actively vote for each stake delegated to it, it can censor stakes by not voting +for them. + +The number of votes is equal to the number of stakers, and not the number of +validators. Replicator clients are expected to delegate their replication +rewards as they are earned, and therefore the number of stakes is expected to be +large compared to the number of validators in a long running cluster. + +## Proposed changes to the current design. + +The general idea is that instead of the staker, the validator will own the +VoteState program. In this proposal the VoteState program is there to track +validator votes, count validator generated credits and to provide any +additional validator specific state. The VoteState program is not aware of any +stakes delegated to it, and has no staking weight. + +The rewards generated are proportional to the amount of lamports staked. In +this proposal stake state is stored as part of the StakeState program. This +program is owned by the staker only. Lamports stored in this program are the +stake. Unlike the current design, this program contains a new field to indicate +which VoteState program the stake is delegated to. + +### New VoteState + +VoteState is the current state of all the votes the **delegate** has submitted +to the bank. VoteState contains the following state information: + +* votes - The submitted votes data structure. + +* credits - The total number of rewards this vote program generated over its +lifetime. + +* root\_slot - The last slot to reach the full lockout commitment necessary for +rewards. + +* commission - The commission taken by this VoteState for any rewards claimed by +staker's StakeState accounts. This is the percentage ceiling of the reward. + +* Account::lamports - The accumulated lamports from the commission. These do not +count as stakes. + +* `authorized_voter_id` - Only this identity is authorized to submit votes. + + +### New StakeState + +StakeState is the current delegation preference of the **staker**. StakeState +contains the following state information: + +* Account::lamports - The staked lamports. + +* `voter_id` - The pubkey of the VoteState instance the lamports are +delegated to. + +* `credits_observed` - The total credits claimed over the lifetime of the +program. + +## RewardsState + +This program is removed + +### StakeState::MiningPool + +There are two approaches to the mining pool. The bank could allow the +StakeState program to bypass the token balance check. Or a program representing +the mining pool could run on the network. To avoid a single network wide lock, +the pool can be split into several mining pools. This design focuses on using a +StakeState::MiningPool as the cluster wide mining pools. + +* 256 StakeState::MiningPool are initialized, each with 1/256 number of mining pool +tokens stored as `Account::lamports`. + +The stakes and the MiningPool are accounts that are owned by the same `Stake` +program. + +### StakeInstruction::Initialize + +* `account[0]` - RW - The StakeState::Stake instance. + `StakeState::credits_observed` is initialized to `VoteState::credits`. + `StakeState::voter_id` is initialized to `account[1]` + +* `account[1]` - R - The VoteState instance. + +### StakeInstruction::RedeemVoteCredits + +The VoteState program and the StakeState programs maintain a lifetime counter +of total rewards generated and claimed. Therefore an explicit `Clear` +instruction is not necessary. When claiming rewards, the total lamports +deposited into the StakeState and as validator commission is proportional to +`VoteState::credits - StakeState::credits_observed`. + + +* `account[0]` - RW - The StakeState::MiningPool instance that will fulfill the +reward. +* `account[1]` - RW - The StakeState::State instance that is redeeming votes +credits. +* `account[2]` - R - The VoteState instance, must be the same as +`StakeState::voter_id` + +Reward is payed out for the difference between `VoteState::credits` to +`StakeState::credits_observed`, and `credits_observed` is updated to +`VoteState::credits`. The commission is deposited into the `VoteState` token +balance, and the reward is deposited to the `StakeState` token balance. The +reward and the commission is weighted by the `StakeState::lamports`. + +The Staker, or the owner of the Stake program sends a transaction with this +instruction to claim the reward. + +Any random MiningPool can be used to redeem the credits. + +```rust,ignore +let credits_to_claim = vote_state.credits - stake_state.credits_observed; +stake_state.credits_observed = vote_state.credits; +``` + +`credits_to_claim` is used to compute the reward and commission, and +`StakeState::Stake.credits_observed` is updated to the latest +`VoteState.credits` value. + +### Collecting network fees into the MiningPool + +At the end of the block, before the bank is frozen, but after it processed all +the transactions for the block, a virtual instruction is executed to collect +the transaction fees. + +* A portion of the fees are deposited into the leader's account. +* A portion of the fees are deposited into the smallest StakeState::MiningPool +account. + +### Benefits + +* Single vote for all the stakers. + +* Clearing of the credit variable is not necessary for claiming rewards. + +* Each delegated stake can claim its rewards independently. + +* Commission for the work is deposited when a reward is claimed by the delegated +stake. + +This proposal would benefit from the `read-only` accounts proposal to allow for +many rewards to be claimed concurrently. + +## Passive Delegation + +Any number of instances of StakeState programs can delegate to a single +VoteState program without an interactive action from the identity controlling +the VoteState program or submitting votes to the program. + +The total stake allocated to a VoteState program can be calculated by the sum of +all the StakeState programs that have the VoteState pubkey as the +`StakeState::voter_id`. + +## Future work + +Validators may want to split the stake delegated to them amongst many validator +nodes since stake is used as weight in the network control and data planes. One +way to implement this would be for the StakeState to delegate to a pool of +validators instead of a single one. + +Instead of a single `vote_id` and `credits_observed` entry in the StakeState +program, the program can be initialized with a vector of tuples. + +```rust,ignore +Voter { + voter_id: Pubkey, + credits_observed: u64, + weight: u8, +} +``` + +* voters: Vec - Array of VoteState accounts that are voting rewards with +this stake. + +A StakeState program would claim a fraction of the reward from each voter in +the `voters` array, and each voter would be delegated a fraction of the stake.