diff --git a/proposals/art/passive-staking-callflow.msc b/proposals/art/passive-staking-callflow.msc new file mode 100644 index 0000000000..4eaaf8d7d3 --- /dev/null +++ b/proposals/art/passive-staking-callflow.msc @@ -0,0 +1,30 @@ +msc { + hscale="2.2"; + VoteSigner, + Validator, + Cluster, + StakerX, + StakerY; + + |||; + Validator box Validator [label="boot.."]; + + VoteSigner <:> Validator [label="register\n\n(optional)"]; + Validator => Cluster [label="VoteState::Initialize(VoteSigner)"]; + StakerX => Cluster [label="StakeState::Delegate(Validator)"]; + StakerY => Cluster [label="StakeState::Delegate(Validator)"]; + + |||; + Validator box Cluster [label="\nvalidate\n"]; + Validator => VoteSigner [label="sign(vote)"]; + VoteSigner >> Validator [label="signed vote"]; + + Validator => Cluster [label="gossip(vote)"]; + ...; + ... ; + Validator abox Validator [label="\nmax\nlockout\n"]; + |||; + StakerX => Cluster [label="StakeState::RedeemCredits()"]; + StakerY => Cluster [label="StakeState::RedeemCredits()"] ; + +} diff --git a/proposals/makefile b/proposals/makefile index 14a5aeac2d..ab526be7a0 100644 --- a/proposals/makefile +++ b/proposals/makefile @@ -1,7 +1,8 @@ BOB_SRCS=$(wildcard art/*.bob) +MSC_SRCS=$(wildcard art/*.msc) MD_SRCS=$(wildcard src/*.md) -SVG_IMGS=$(BOB_SRCS:art/%.bob=src/img/%.svg) +SVG_IMGS=$(BOB_SRCS:art/%.bob=src/img/%.svg) $(MSC_SRCS:art/%.msc=src/img/%.svg) all: html/index.html @@ -17,6 +18,10 @@ src/img/%.svg: art/%.bob @mkdir -p $(@D) svgbob < $< > $@ +src/img/%.svg: art/%.msc + @mkdir -p $(@D) + mscgen -T svg -i $< -o $@ + src/%.md: %.md @mkdir -p $(@D) @cp $< $@ diff --git a/proposals/src/passive-stake-delegation-and-rewards.md b/proposals/src/passive-stake-delegation-and-rewards.md index c1298e30dc..de5f62f96b 100644 --- a/proposals/src/passive-stake-delegation-and-rewards.md +++ b/proposals/src/passive-stake-delegation-and-rewards.md @@ -5,7 +5,7 @@ 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 +validator, and therefore does not scale to allow replicator clients to automatically delegate their rewards. The design proposes a new set of programs for voting and stake delegation, The @@ -17,8 +17,8 @@ validator. 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. +actively vote for each stake delegated to it, validators 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 @@ -39,14 +39,14 @@ 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 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 +* credits - The total number of rewards this vote program has generated over its lifetime. * root\_slot - The last slot to reach the full lockout commitment necessary for @@ -58,10 +58,27 @@ 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. +* `authorized_vote_signer` - Only this identity is authorized to submit votes, and +this field can only modified by this entity + +### VoteInstruction::Initialize + +* `account[0]` - RW - The VoteState + `VoteState::authorized_vote_signer` is initialized to `account[0]` + other VoteState members defaulted + +### VoteInstruction::AuthorizeVoteSigner(Pubkey) + +* `account[0]` - RW - The VoteState + `VoteState::authorized_vote_signer` is set to to `Pubkey`, instruction must by + signed by Pubkey -### New StakeState +### StakeState + +A StakeState takes one of two forms, StakeState::Delegate and StakeState::MiningPool. + +### StakeState::Delegate StakeState is the current delegation preference of the **staker**. StakeState contains the following state information: @@ -74,14 +91,10 @@ 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 +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. @@ -94,9 +107,9 @@ 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[0]` - RW - The StakeState::Delegate instance. + `StakeState::Delegate::credits_observed` is initialized to `VoteState::credits`. + `StakeState::Delegate::voter_id` is initialized to `account[1]` * `account[1]` - R - The VoteState instance. @@ -107,22 +120,22 @@ 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 +* `account[1]` - RW - The StakeState::Delegate 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 +`StakeState::Delgate.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`. +balance, and the reward is deposited to the `StakeState::Delegate` token balance. The +reward and the commission is weighted by the `StakeState::lamports` divided by total lamports staked. -The Staker, or the owner of the Stake program sends a transaction with this +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. @@ -133,8 +146,8 @@ 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. +`StakeState::Delegate::credits_observed` is updated to the latest +`VoteState::credits` value. ### Collecting network fees into the MiningPool @@ -142,7 +155,7 @@ 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 leader's account. * A portion of the fees are deposited into the smallest StakeState::MiningPool account. @@ -162,14 +175,18 @@ many rewards to be claimed concurrently. ## Passive Delegation -Any number of instances of StakeState programs can delegate to a single +Any number of instances of StakeState::Delegate 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`. - +`StakeState::Delegate::voter_id`. + +## Example Callflow + +Passive Staking Callflow + ## Future work Validators may want to split the stake delegated to them amongst many validator