Proof-of-stake in RChain will be handled by the PoS "blessed" contract within the RChain state. Since all validators must know about each other, this contract will live in the top level namespace (see Powerset shards). This contract will perform the following functions:

Additionally, each namespace will have a local version of the PoS blessed contract which performs the following functions:

Each of these functions will be detailed in the remaining sections of this document.

Bonding

Each region will define the following properties for itself when it is created:

This information will be known by the PoS contract. In order to be considered for becoming a validator, a user invokes the PoS contract as they would any other contract (see Rchain State). When invoking the PoS contract bonding method the user provides the following arguments:

The final two arguments are compared against the requirements of the region specified in the first argument. The identification is used to recognize when messages come from that validator and for the validator to obtain the rewards they earn. If the purse does not contain the correct number of tokens or the evidence is invalid, the bond request is rejected. As a deterrent to DOS attacks, requests with empty purses will be immediately rejected (i.e. no computation will be done to look up region requirements or confirm cryptographic evidence) and tokens will be deduced from the purse if the evidence is invalid for the region. Moreover, no evidence checking is done if the queue for the specified region is already full.

If the purse contents and evidence check out, but there are already the maximum number of active validators in the requested region, then the user is added to the region's queue. The tokens are still taken from the purse and kept in the PoS contract bond holding while the user is in the queue. When an unbonding event occurs in the region, a new validator randomly chosen from the queue becomes active to replace the one which left. Note that since currently active validators and their bonds are stored in the top level namespace, but the weights derived from that information must be used in all namespaces, all blocks in namespaces other than the top must include the hash of the top-level block which contains the current stakes state (in the block proposer's view). Validator weights are derived from the information contained in the parent block; this prevents a validator from changing the consensus on forks which occurred before they joined, as any block they create which points to a block that does not list them as a validator would have 0 weight. In the case of a multi-parent block, all parents must have the same stake state hash.

Unbonding

Unbonding is triggered when the PoS contract is invoked (again in the normal way) with the signature of an existing validator (this signature could be on the hash of the parent of the block after which they want to be unbonded) along with a return channel. On the return channel, an unforgable name is sent, which the now ex-validator can listen on. After the post-unbonding stake holding time has elapsed, a purse containing the ex-validaor's stake is sent on that name, thus allowing the validator to recover their bond. Note that no rewards are distributed at this time, only the exact original stake (minus any slashed amount) is returned. Rewards can be withdrawn from the shard's local PoS contract after unbonding has occurred (see below). The unbonding is successful so long as it does not exceed the unbonding rate specified for the region.

During the post-unbonding stake holding period the validator is not active, but their stake is still held by the PoS contract and they can still be slashed by other validators. The purpose of this holding time is to prevent a variant of the "long range attack" in which a validator "re-writes history" on a separate chain from the main one. If, after a validator unbonds, they get their stake back immediately then they can start producing a different chain off a recent past block where they had stake without fear of being slashed for equivocation because their stake has already been recovered in the main chain. By holding the stake for a period after the validator is no longer active they can still be slashed for attempting a long range attack during that time. If the time is long enough that the network has moved sufficiently far ahead since the validator unbonded then "weak subjectivity" should be enough to combat a long range attack attempted after the holding period.

As mentioned above, when unbonding happens a new validator from the queue will become active if the queue is non-empty. 

Slashing

Slashing is triggered when the PoS contract is invoked with the following arguments:

Any validator can slash any other validator (including those from other regions) because slashing happens at the top level. If the evidence is accepted then the amount which was deduced from the offender is given to the accuser in a purse via the return channel. If the evidence is invalid then the accusers bond is deduced instead. If a validator's stake drops to 0 then they are automatically unbonded. The following are slashable offences:

Rewards Distribution

Rewards distribution is handled by a local PoS contract. When a validator proposes a block they include an additional transaction which invokes the local PoS contract with their validator identity and the fees from user code, this updates their "reward balance" tracked by the local PoS contract. The update also includes some newly minted tokens in addition to the fees. In the case of multi-parent blocks, the reward balances of the other validators who created parent blocks are also updated based on the fees in those blocks (because those transactions have now joined the new main chain). The function to calculate rewards from fees will have the form proposing_discount*tx_fees, where proposing_discount is a function which penalizes a validator from publishing many blocks in a row (i.e. incentivizes building a chain cooperatively with other validators).

An ex-validator can withdraw their rewards from a local PoS contract by invoking it with the following arguments:

The PoS contract sends a purse on the return channel containing all the rewards that have been accumulated on that ID since the last withdraw. Withdraws can only happen in blocks where the validator is no longer active, i.e. a block which includes a withdraw by a validator who is still listed as active in the block's skate state hash is invalid. Note that a validator can still leverage their own weight to perform a withdraw because weights are based on the parent block, but withdraw eligibility is based on the current block.

Open Questions