# State ## LastTotalPower LastTotalPower tracks the total amounts of bonded tokens recorded during the previous end block. - LastTotalPower: `0x12 -> amino(sdk.Int)` ## Params Params is a module-wide configuration structure that stores system parameters and defines overall functioning of the staking module. - Params: `Paramsspace("staking") -> amino(params)` ```go type Params struct { UnbondingTime time.Duration // time duration of unbonding MaxValidators uint16 // maximum number of validators MaxEntries uint16 // max entries for either unbonding delegation or redelegation (per pair/trio) BondDenom string // bondable coin denomination } ``` ## Validator Validators can have one of three statuses - `Unbonded`: The validator is not in the active set. They cannot sign blocks and do not earn rewards. They can receive delegations. - `Bonded`": Once the validator receives sufficient bonded tokens they automtically join the active set during [`EndBlock`](./05_end_block.md#validator-set-changes) and their status is updated to `Bonded`. They are signing blocks and receiving rewards. They can receive further delegations. They can be slashed for misbehavior. Delegators to this validator who unbond their delegation must wait the duration of the UnbondingTime, a chain-specific param. during which time they are still slashable for offences of the source validator if those offences were committed during the period of time that the tokens were bonded. - `Unbonding`: When a validator leaves the active set, either by choice or due to slashing or tombstoning, an unbonding of all their delegations begins. All delegations must then wait the UnbondingTime before moving receiving their tokens to their accounts from the `BondedPool`. Validators objects should be primarily stored and accessed by the `OperatorAddr`, an SDK validator address for the operator of the validator. Two additional indices are maintained per validator object in order to fulfill required lookups for slashing and validator-set updates. A third special index (`LastValidatorPower`) is also maintained which however remains constant throughout each block, unlike the first two indices which mirror the validator records within a block. - Validators: `0x21 | OperatorAddr -> amino(validator)` - ValidatorsByConsAddr: `0x22 | ConsAddr -> OperatorAddr` - ValidatorsByPower: `0x23 | BigEndian(ConsensusPower) | OperatorAddr -> OperatorAddr` - LastValidatorsPower: `0x11 OperatorAddr -> amino(ConsensusPower)` `Validators` is the primary index - it ensures that each operator can have only one associated validator, where the public key of that validator can change in the future. Delegators can refer to the immutable operator of the validator, without concern for the changing public key. `ValidatorByConsAddr` is an additional index that enables lookups for slashing. When Tendermint reports evidence, it provides the validator address, so this map is needed to find the operator. Note that the `ConsAddr` corresponds to the address which can be derived from the validator's `ConsPubKey`. `ValidatorsByPower` is an additional index that provides a sorted list o potential validators to quickly determine the current active set. Here ConsensusPower is validator.Tokens/10^6. Note that all validators where `Jailed` is true are not stored within this index. `LastValidatorsPower` is a special index that provides a historical list of the last-block's bonded validators. This index remains constant during a block but is updated during the validator set update process which takes place in [`EndBlock`](./05_end_block.md). Each validator's state is stored in a `Validator` struct: ```go type Validator struct { OperatorAddress sdk.ValAddress // address of the validator's operator; bech encoded in JSON ConsPubKey crypto.PubKey // the consensus public key of the validator; bech encoded in JSON Jailed bool // has the validator been jailed from bonded status? Status sdk.BondStatus // validator status (bonded/unbonding/unbonded) Tokens sdk.Int // delegated tokens (incl. self-delegation) DelegatorShares sdk.Dec // total shares issued to a validator's delegators Description Description // description terms for the validator UnbondingHeight int64 // if unbonding, height at which this validator has begun unbonding UnbondingCompletionTime time.Time // if unbonding, min time for the validator to complete unbonding Commission Commission // commission parameters MinSelfDelegation sdk.Int // validator's self declared minimum self delegation } type Commission struct { CommissionRates UpdateTime time.Time // the last time the commission rate was changed } CommissionRates struct { Rate sdk.Dec // the commission rate charged to delegators, as a fraction MaxRate sdk.Dec // maximum commission rate which validator can ever charge, as a fraction MaxChangeRate sdk.Dec // maximum daily increase of the validator commission, as a fraction } type Description struct { Moniker string // name Identity string // optional identity signature (ex. UPort or Keybase) Website string // optional website link SecurityContact string // optional email for security contact Details string // optional details } ``` ## Delegation Delegations are identified by combining `DelegatorAddr` (the address of the delegator) with the `ValidatorAddr` Delegators are indexed in the store as follows: - Delegation: `0x31 | DelegatorAddr | ValidatorAddr -> amino(delegation)` Stake holders may delegate coins to validators; under this circumstance their funds are held in a `Delegation` data structure. It is owned by one delegator, and is associated with the shares for one validator. The sender of the transaction is the owner of the bond. ```go type Delegation struct { DelegatorAddr sdk.AccAddress ValidatorAddr sdk.ValAddress Shares sdk.Dec // delegation shares received } ``` ### Delegator Shares When one Delegates tokens to a Validator they are issued a number of delegator shares based on a dynamic exchange rate, calculated as follows from the total number of tokens delegated to the validator and the number of shares issued so far: `Shares per Token = validator.TotalShares() / validator.Tokens()` Only the number of shares received is stored on the DelegationEntry. When a delegator then Undelegates, the token amount they receive is calculated from the number of shares they currently hold and the inverse exchange rate: `Tokens per Share = validator.Tokens() / validatorShares()` These `Shares` are simply an accounting mechanism. They are not a fungible asset. The reason for this mechanism is to simplify the accounting around slashing. Rather than iteratively slashing the tokens of every delegation entry, instead the Validators total bonded tokens can be slashed, effectively reducing the value of each issued delegator share. ## UnbondingDelegation Shares in a `Delegation` can be unbonded, but they must for some time exist as an `UnbondingDelegation`, where shares can be reduced if Byzantine behavior is detected. `UnbondingDelegation` are indexed in the store as: - UnbondingDelegation: `0x32 | DelegatorAddr | ValidatorAddr -> amino(unbondingDelegation)` - UnbondingDelegationsFromValidator: `0x33 | ValidatorAddr | DelegatorAddr -> nil` The first map here is used in queries, to lookup all unbonding delegations for a given delegator, while the second map is used in slashing, to lookup all unbonding delegations associated with a given validator that need to be slashed. A UnbondingDelegation object is created every time an unbonding is initiated. ```go type UnbondingDelegation struct { DelegatorAddr sdk.AccAddress // delegator ValidatorAddr sdk.ValAddress // validator unbonding from operator addr Entries []UnbondingDelegationEntry // unbonding delegation entries } type UnbondingDelegationEntry struct { CreationHeight int64 // height which the unbonding took place CompletionTime time.Time // unix time for unbonding completion InitialBalance sdk.Coin // atoms initially scheduled to receive at completion Balance sdk.Coin // atoms to receive at completion } ``` ## Redelegation The bonded tokens worth of a `Delegation` may be instantly redelegated from a source validator to a different validator (destination validator). However when this occurs they must be tracked in a `Redelegation` object, whereby their shares can be slashed if their tokens have contributed to a Byzantine fault committed by the source validator. `Redelegation` are indexed in the store as: - Redelegations: `0x34 | DelegatorAddr | ValidatorSrcAddr | ValidatorDstAddr -> amino(redelegation)` - RedelegationsBySrc: `0x35 | ValidatorSrcAddr | ValidatorDstAddr | DelegatorAddr -> nil` - RedelegationsByDst: `0x36 | ValidatorDstAddr | ValidatorSrcAddr | DelegatorAddr -> nil` The first map here is used for queries, to lookup all redelegations for a given delegator. The second map is used for slashing based on the `ValidatorSrcAddr`, while the third map is for slashing based on the `ValidatorDstAddr`. A redelegation object is created every time a redelegation occurs. To prevent "redelegation hopping" redelegations may not occur under the situation that: - the (re)delegator already has another immature redelegation in progress with a destination to a validator (let's call it `Validator X`) - and, the (re)delegator is attempting to create a _new_ redelegation where the source validator for this new redelegation is `Validator-X`. ```go type Redelegation struct { DelegatorAddr sdk.AccAddress // delegator ValidatorSrcAddr sdk.ValAddress // validator redelegation source operator addr ValidatorDstAddr sdk.ValAddress // validator redelegation destination operator addr Entries []RedelegationEntry // redelegation entries } type RedelegationEntry struct { CreationHeight int64 // height which the redelegation took place CompletionTime time.Time // unix time for redelegation completion InitialBalance sdk.Coin // initial balance when redelegation started Balance sdk.Coin // current balance (current value held in destination validator) SharesDst sdk.Dec // amount of destination-validator shares created by redelegation } ``` ## Queues All queues objects are sorted by timestamp. The time used within any queue is first rounded to the nearest nanosecond then sorted. The sortable time format used is a slight modification of the RFC3339Nano and uses the the format string `"2006-01-02T15:04:05.000000000"`. Notably this format: - right pads all zeros - drops the time zone info (uses UTC) In all cases, the stored timestamp represents the maturation time of the queue element. ### UnbondingDelegationQueue For the purpose of tracking progress of unbonding delegations the unbonding delegations queue is kept. - UnbondingDelegation: `0x41 | format(time) -> []DVPair` ```go type DVPair struct { DelegatorAddr sdk.AccAddress ValidatorAddr sdk.ValAddress } ``` ### RedelegationQueue For the purpose of tracking progress of redelegations the redelegation queue is kept. - UnbondingDelegation: `0x42 | format(time) -> []DVVTriplet` ```go type DVVTriplet struct { DelegatorAddr sdk.AccAddress ValidatorSrcAddr sdk.ValAddress ValidatorDstAddr sdk.ValAddress } ``` ### ValidatorQueue For the purpose of tracking progress of unbonding validators the validator queue is kept. - ValidatorQueueTime: `0x43 | format(time) -> []sdk.ValAddress` The stored object as each key is an array of validator operator addresses from which the validator object can be accessed. Typically it is expected that only a single validator record will be associated with a given timestamp however it is possible that multiple validators exist in the queue at the same location. ## HistoricalInfo HistoricalInfo objects are stored and pruned at each block such that the staking keeper persists the `n` most recent historical info defined by staking module parameter: `HistoricalEntries`. ```go type HistoricalInfo struct { Header abci.Header ValSet []types.Validator } ``` At each BeginBlock, the staking keeper will persist the current Header and the Validators that committed the current block in a `HistoricalInfo` object. The Validators are sorted on their address to ensure that they are in a determisnistic order. The oldest HistoricalEntries will be pruned to ensure that there only exist the parameter-defined number of historical entries.