diff --git a/book/src/stake-delegation-and-rewards.md b/book/src/stake-delegation-and-rewards.md index 89e3ee3f1..f0445c37e 100644 --- a/book/src/stake-delegation-and-rewards.md +++ b/book/src/stake-delegation-and-rewards.md @@ -131,7 +131,9 @@ stake account lamports. * `account[1]` - R - The VoteState instance. -* `account[2]` - R - syscall::current account, carries information about current Bank epoch +* `account[2]` - R - sysvar::current account, carries information about current Bank epoch + +* `account[3]` - R - stake_api::Config accoount, carries warmup, cooldown, and slashing configuration ### StakeInstruction::RedeemVoteCredits @@ -146,10 +148,11 @@ lamport, rewards paid are proportional to the number of lamports staked. * `account[0]` - RW - The StakeState::Stake instance that is redeeming rewards. * `account[1]` - R - The VoteState instance, must be the same as `StakeState::voter_pubkey` * `account[2]` - RW - The StakeState::RewardsPool instance that will fulfill the request (picked at random). -* `account[3]` - R - syscall::rewards account from the Bank that carries point value. +* `account[3]` - R - sysvar::rewards account from the Bank that carries point value. +* `account[4]` - R - sysvar::stake_history account from the Bank that carries stake warmup/cooldown history Reward is paid out for the difference between `VoteState::credits` to -`StakeState::Stake::credits_observed`, multiplied by `syscall::rewards::Rewards::validator_point_value`. +`StakeState::Stake::credits_observed`, multiplied by `sysvar::rewards::Rewards::validator_point_value`. `StakeState::Stake::credits_observed` is updated to`VoteState::credits`. The commission is deposited into the Vote account token balance, and the reward is deposited to the Stake account token balance. @@ -167,7 +170,8 @@ stake_state.credits_observed = vote_state.credits; A staker may wish to withdraw from the network. To do so he must first deactivate his stake, and wait for cool down. * `account[0]` - RW - The StakeState::Stake instance that is deactivating, the transaction must be signed by this key. -* `account[1]` - R - syscall::current account from the Bank that carries current epoch +* `account[1]` - R - The VoteState instance to which this stake is delegated, required in case of slashing +* `account[2]` - R - sysvar::current account from the Bank that carries current epoch StakeState::Stake::deactivated is set to the current epoch + cool down. The account's stake will ramp down to zero by that epoch, and Account::lamports will be available for withdrawal. @@ -178,7 +182,8 @@ Lamports build up over time in a Stake account and any excess over activated sta * `account[0]` - RW - The StakeState::Stake from which to withdraw, the transaction must be signed by this key. * `account[1]` - RW - Account that should be credited with the withdrawn lamports. -* `account[2]` - R - syscall::current account from the Bank that carries current epoch, to calculate stake. +* `account[2]` - R - sysvar::current account from the Bank that carries current epoch, to calculate stake. +* `account[3]` - R - sysvar::stake_history account from the Bank that carries stake warmup/cooldown history ## Benefits of the design @@ -195,3 +200,106 @@ stake. ## Example Callflow Passive Staking Callflow + +## Staking Rewards + +The specific mechanics and rules of the validator rewards regime is outlined +here. Rewards are earned by delegating stake to a validator that is voting +correctly. Voting incorrectly exposes that validator's stakes to +[slashing](staking-and-rewardsg.md). + +### Basics + +The network pays rewards from a portion of network [inflation](inflation.md). +The number of lamports available to pay rewards for an epoch is fixed and +must be evenly divided among all staked nodes according to their relative stake +weight and pariticpation. The weighting unit is called a +[point](terminology.md#point). + +Rewards for an epoch are not available until the end of that epoch. + +At the end of each epoch, the total number of points earned during the epoch is +summed and used to divide the rewards portion of epoch inflation to arrive at a +point value. This value is recorded in the bank in a +[sysvar](terminology.md#sysvar) that maps epochs to point values. + +During redemption, the stake program counts the points earned by the stake for +each epoch, multiplies that by the epoch's point value, and transfers lamports in +that amount from a rewards account into the stake and vote accounts according to +the vote account's commission setting. + +### Economics + +Point value for an epoch depends on aggregate network participation. If participation +in an epoch drops off, point values are higher for those that do participate. + +### Earning credits + +Validators earn one vote credit for every correct vote that exceeds maximum +lockout, i.e. every time the validator's vote account retires a slot from its +lockout list, making that vote a root for the node. + +Stakers who have delegated to that validator earn points in proportion to their +stake. Points earned is the product of vote credits and stake. + +### Stake warmup, cooldown, withdrawal + +Stakes, once delegated, do not become effective immediately. They must first +pass through a warm up period. During this period some portion of the stake is +considered "effective", the rest is considered "activating". Changes occur on +epoch boundaries. + +The stake program limits the rate of change to total network stake, reflected +in the stake program's `config::warmup_rate` (typically 15% per epoch). + +The amount of stake that can be warmed up each epoch is a function of the +previous epoch's total effective stake, total activating stake, and the stake +program's configured warmup rate. + +Cooldown works the same way. Once a stake is deactivated, some part of it +is considered "effective", and also "deactivating". As the stake cools +down, it continues to earn rewards and be exposed to slashing, but it also +becomes available for withdrawal. + +Bootstrap stakes are not subject to warmup. + +Rewards are paid against the "effective" portion of the stake for that epoch. + +#### Warmup example + +Consider the situation of a single stake of 1,000 activated at epoch N, with +network warmup rate of 20%, and a quiescent total network stake at epoch N of 2,000. + +At epoch N+1, the amount available to be activated for the network is 400 (20% +of 200), and at epoch N, this example stake is the only stake activating, and so +is entitled to all of the warmup room available. + + +|epoch | effective | activating | total effective | total activating| +|------|----------:|-----------:|----------------:|----------------:| +|N-1 | | | 2,000 | 0 | +|N | 0 | 1,000 | 2,000 | 1,000 | +|N+1 | 400 | 600 | 2,400 | 600 | +|N+2 | 880 | 120 | 2,880 | 120 | +|N+3 | 1000 | 0 | 3,000 | 0 | + + +Were 2 stakes (X and Y) to activate at epoch N, they would be awarded a portion of the 20% +in proportion to their stakes. At each epoch effective and activating for each stake is +a function of the previous epoch's state. + +|epoch | X eff | X act | Y eff | Y act | total effective | total activating| +|------|----------:|-----------:|----------:|-----------:|----------------:|----------------:| +|N-1 | | | | | 2,000 | 0 | +|N | 0 | 1,000 | 0 | 200 | 2,000 | 1,200 | +|N+1 | 320 | 680 | 80 | 120 | 2,400 | 800 | +|N+2 | 728 | 272 | 152 | 48 | 2,880 | 320 | +|N+3 | 1000 | 0 | 200 | 0 | 3,200 | 0 | + + +### Withdrawal + +As rewards are earned lamports can be withdrawn from a stake account. Only +lamports in excess of effective+activating stake may be withdrawn at any time. +This means that during warmup, effectively no stake can be withdrawn. During +cooldown, any tokens in excess of effective stake may be withdrawn (activating == 0); diff --git a/book/src/terminology.md b/book/src/terminology.md index 2b5d16def..e586ea991 100644 --- a/book/src/terminology.md +++ b/book/src/terminology.md @@ -58,6 +58,10 @@ with a ledger interpretation that matches the leader's. A gossip network connecting all [nodes](#node) of a [cluster](#cluster). +#### credit + +See [vote credit](#vote-credit). + #### data plane A multicast network used to efficiently validate [entries](#entry) and gain @@ -193,6 +197,10 @@ The number of [fullnodes](#fullnode) participating in a [cluster](#cluster). See [Proof of History](#proof-of-history). +#### point + +A weighted [credit](#credit) in a rewards regime. In the validator (rewards regime)[staking-rewards.md], the number of points owed to a stake during redemption is the product of the [vote credits](#vote-credit) earned and the number of lamports staked. + #### program The code that interprets [instructions](#instruction). @@ -276,6 +284,11 @@ hash values and a bit which says if this hash is valid or fake. The number of keys and samples that a validator can verify each storage epoch. +#### sysvar + +A synthetic [account](#account) provided by the runtime to allow programs to +access network state such as current tick height, rewards [points](#point) values, etc. + #### thin client A type of [client](#client) that trusts it is communicating with a valid @@ -323,3 +336,8 @@ that it ran, which can then be verified in less time than it took to produce. #### vote See [ledger vote](#ledger-vote). + +#### vote credit + +A reward tally for validators. A vote credit is awarded to a validator in its +vote account when the validator reaches a [root](#root). diff --git a/book/src/validator-stake.md b/book/src/validator-stake.md index 3250a9831..f91551786 100644 --- a/book/src/validator-stake.md +++ b/book/src/validator-stake.md @@ -13,12 +13,29 @@ and use the wallet's `delegate-stake` command to stake your validator with 42 la $ solana-wallet delegate-stake ~/validator-config/stake-keypair.json ~/validator-vote-keypair.json 42 ``` -Note that stake changes are applied at Epoch boundaries so it can take an hour -or more for the change to take effect. +Note that stakes need to warm up, and warmup increments are applied at Epoch boundaries, so it can take an hour +or more for the change to fully take effect. -Stake can be deactivate by running: +Assuming your node is voting, now you're up and running and generating validator rewards. You'll want +to periodically redeem/claim your rewards: + +```bash +$ solana-wallet redeem-vote-credits ~/validator-config/stake-keypair.json ~/validator-vote-keypair.json +``` + +The rewards lamports earned are split between your stake account and the vote account according to the +commission rate set in the vote account. + +Stake can be deactivated by running: ```bash $ solana-wallet deactivate-stake ~/validator-config/stake-keypair.json ~/validator-vote-keypair.json ``` + +The stake will cool down, deactivate over time. While cooling down, your stake will continue to earn +rewards. + Note that a stake account may only be used once, so after deactivation, use the wallet's `withdraw-stake` command to recover the previously staked lamports. + +Be sure and redeem your credits before withdrawing all your lamports. +Once the account is fully withdrawn, the account is destroyed.