Merge pull request #1263 from cosmos/bucky/staking-spec-updates
spec updates
This commit is contained in:
commit
d08328761f
|
@ -5,15 +5,14 @@ the Cosmos Hub.
|
|||
|
||||
NOTE: the specifications are not yet complete and very much a work in progress.
|
||||
|
||||
- [Basecoin](basecoin) - Cosmos SDK related specifications and transactions for
|
||||
sending tokens.
|
||||
- [Governance](governance) - Governance related specifications including
|
||||
proposals and voting.
|
||||
- [IBC](ibc) - Specification of the Cosmos inter-blockchain communication (IBC) protocol.
|
||||
- [Staking](staking) - Proof-of-stake related specifications including bonding
|
||||
and delegation transactions, inflation, etc.
|
||||
- [Slashing](slashing) - Specifications of validator punishment mechanisms
|
||||
- [Provisioning](provisioning) - Fee distribution, and atom provision distribution specification
|
||||
- [Store](store) - The core Merkle store that holds the state.
|
||||
- [Auth](auth) - The structure and authnentication of accounts and transactions.
|
||||
- [Bank](bank) - Sending tokens.
|
||||
- [Governance](governance) - Proposals and voting.
|
||||
- [IBC](ibc) - Inter-Blockchain Communication (IBC) protocol.
|
||||
- [Staking](staking) - Proof-of-stake bonding, delegation, etc.
|
||||
- [Slashing](slashing) - Validator punishment mechanisms.
|
||||
- [Provisioning](provisioning) - Fee distribution, and atom provision distribution
|
||||
- [Other](other) - Other components of the Cosmos Hub, including the reserve
|
||||
pool, All in Bits vesting, etc.
|
||||
|
||||
|
|
|
@ -1,100 +0,0 @@
|
|||
# Validator Set Changes
|
||||
|
||||
## Slashing
|
||||
|
||||
Messges which may compromise the safety of the underlying consensus protocol ("equivocations")
|
||||
result in some amount of the offending validator's shares being removed ("slashed").
|
||||
|
||||
Currently, such messages include only the following:
|
||||
|
||||
- prevotes by the same validator for more than one BlockID at the same
|
||||
Height and Round
|
||||
- precommits by the same validator for more than one BlockID at the same
|
||||
Height and Round
|
||||
|
||||
We call any such pair of conflicting votes `Evidence`. Full nodes in the network prioritize the
|
||||
detection and gossipping of `Evidence` so that it may be rapidly included in blocks and the offending
|
||||
validators punished.
|
||||
|
||||
For some `evidence` to be valid, it must satisfy:
|
||||
|
||||
`evidence.Timestamp >= block.Timestamp - MAX_EVIDENCE_AGE`
|
||||
|
||||
where `evidence.Timestamp` is the timestamp in the block at height
|
||||
`evidence.Height` and `block.Timestamp` is the current block timestamp.
|
||||
|
||||
If valid evidence is included in a block, the offending validator loses
|
||||
a constant `SLASH_PROPORTION` of their current stake at the beginning of the block:
|
||||
|
||||
```
|
||||
oldShares = validator.shares
|
||||
validator.shares = oldShares * (1 - SLASH_PROPORTION)
|
||||
```
|
||||
|
||||
This ensures that offending validators are punished the same amount whether they
|
||||
act as a single validator with X stake or as N validators with collectively X
|
||||
stake.
|
||||
|
||||
|
||||
## Automatic Unbonding
|
||||
|
||||
Every block includes a set of precommits by the validators for the previous block,
|
||||
known as the LastCommit. A LastCommit is valid so long as it contains precommits from +2/3 of voting power.
|
||||
|
||||
Proposers are incentivized to include precommits from all
|
||||
validators in the LastCommit by receiving additional fees
|
||||
proportional to the difference between the voting power included in the
|
||||
LastCommit and +2/3 (see [TODO](https://github.com/cosmos/cosmos-sdk/issues/967)).
|
||||
|
||||
Validators are penalized for failing to be included in the LastCommit for some
|
||||
number of blocks by being automatically unbonded.
|
||||
|
||||
The following information is stored with each validator candidate, and is only non-zero if the candidate becomes an active validator:
|
||||
|
||||
```go
|
||||
type ValidatorSigningInfo struct {
|
||||
StartHeight int64
|
||||
IndexOffset int64
|
||||
JailedUntil int64
|
||||
SignedBlocksCounter int64
|
||||
SignedBlocksBitArray BitArray
|
||||
}
|
||||
```
|
||||
|
||||
Where:
|
||||
* `StartHeight` is set to the height that the candidate became an active validator (with non-zero voting power).
|
||||
* `IndexOffset` is incremented each time the candidate was a bonded validator in a block (and may have signed a precommit or not).
|
||||
* `JailedUntil` is set whenever the candidate is revoked due to downtime
|
||||
* `SignedBlocksCounter` is a counter kept to avoid unnecessary array reads. `SignedBlocksBitArray.Sum() == SignedBlocksCounter` always.
|
||||
* `SignedBlocksBitArray` is a bit-array of size `SIGNED_BLOCKS_WINDOW` that records, for each of the last `SIGNED_BLOCKS_WINDOW` blocks,
|
||||
whether or not this validator was included in the LastCommit. It uses a `1` if the validator was included, and a `0` if it was not. Note it is initialized with all 0s.
|
||||
|
||||
At the beginning of each block, we update the signing info for each validator and check if they should be automatically unbonded:
|
||||
|
||||
```
|
||||
height := block.Height
|
||||
|
||||
for val in block.Validators:
|
||||
signInfo = val.SignInfo
|
||||
index := signInfo.IndexOffset % SIGNED_BLOCKS_WINDOW
|
||||
signInfo.IndexOffset++
|
||||
previous = signInfo.SignedBlocksBitArray.Get(index)
|
||||
|
||||
// update counter if array has changed
|
||||
if previous and val in block.AbsentValidators:
|
||||
signInfo.SignedBlocksBitArray.Set(index, 0)
|
||||
signInfo.SignedBlocksCounter--
|
||||
else if !previous and val not in block.AbsentValidators:
|
||||
signInfo.SignedBlocksBitArray.Set(index, 1)
|
||||
signInfo.SignedBlocksCounter++
|
||||
// else previous == val not in block.AbsentValidators, no change
|
||||
|
||||
// validator must be active for at least SIGNED_BLOCKS_WINDOW
|
||||
// before they can be automatically unbonded for failing to be
|
||||
// included in 50% of the recent LastCommits
|
||||
minHeight = signInfo.StartHeight + SIGNED_BLOCKS_WINDOW
|
||||
minSigned = SIGNED_BLOCKS_WINDOW / 2
|
||||
if height > minHeight AND signInfo.SignedBlocksCounter < minSigned:
|
||||
signInfo.JailedUntil = block.Time + DOWNTIME_UNBOND_DURATION
|
||||
slash & unbond the validator
|
||||
```
|
|
@ -0,0 +1,102 @@
|
|||
# End-Block
|
||||
|
||||
## Slashing
|
||||
|
||||
Tendermint blocks can include
|
||||
[Evidence](https://github.com/tendermint/tendermint/blob/develop/docs/spec/blockchain/blockchain.md#evidence), which indicates that a validator
|
||||
committed malicious behaviour. The relevant information is forwarded to the
|
||||
application as [ABCI
|
||||
Evidence](https://github.com/tendermint/abci/blob/develop/types/types.proto#L259), so the validator an be accordingly punished.
|
||||
|
||||
For some `evidence` to be valid, it must satisfy:
|
||||
|
||||
`evidence.Timestamp >= block.Timestamp - MAX_EVIDENCE_AGE`
|
||||
|
||||
where `evidence.Timestamp` is the timestamp in the block at height
|
||||
`evidence.Height` and `block.Timestamp` is the current block timestamp.
|
||||
|
||||
If valid evidence is included in a block, the validator's stake is reduced by `SLASH_PROPORTION` of
|
||||
what their stake was when the equivocation occurred (rather than when the evidence was discovered):
|
||||
|
||||
```
|
||||
curVal := validator
|
||||
oldVal := loadValidator(evidence.Height, evidence.Address)
|
||||
|
||||
slashAmount := SLASH_PROPORTION * oldVal.Shares
|
||||
|
||||
curVal.Shares = max(0, curVal.Shares - slashAmount)
|
||||
```
|
||||
|
||||
This ensures that offending validators are punished the same amount whether they
|
||||
act as a single validator with X stake or as N validators with collectively X
|
||||
stake.
|
||||
|
||||
We also need to loop through the unbondings and redelegations to slash them as
|
||||
well:
|
||||
|
||||
```
|
||||
unbondings := getUnbondings(validator.Address)
|
||||
for unbond in unbondings {
|
||||
if was not bonded before evidence.Height {
|
||||
continue
|
||||
}
|
||||
unbond.InitialTokens
|
||||
burn := unbond.InitialTokens * SLASH_PROPORTION
|
||||
unbond.Tokens = max(0, unbond.Tokens - burn)
|
||||
}
|
||||
|
||||
// only care if source gets slashed because we're already bonded to destination
|
||||
// so if destination validator gets slashed our delegation just has same shares
|
||||
// of smaller pool.
|
||||
redels := getRedelegationsBySource(validator.Address)
|
||||
for redel in redels {
|
||||
|
||||
if was not bonded before evidence.Height {
|
||||
continue
|
||||
}
|
||||
|
||||
burn := redel.InitialTokens * SLASH_PROPORTION
|
||||
|
||||
amount := unbondFromValidator(redel.Destination, burn)
|
||||
destroy(amount)
|
||||
}
|
||||
```
|
||||
|
||||
## Automatic Unbonding
|
||||
|
||||
At the beginning of each block, we update the signing info for each validator and check if they should be automatically unbonded:
|
||||
|
||||
```
|
||||
height := block.Height
|
||||
|
||||
for val in block.Validators:
|
||||
signInfo = SigningInfo.Get(val.Address)
|
||||
if signInfo == nil{
|
||||
signInfo.StartHeight = height
|
||||
}
|
||||
|
||||
index := signInfo.IndexOffset % SIGNED_BLOCKS_WINDOW
|
||||
signInfo.IndexOffset++
|
||||
previous = SigningBitArray.Get(val.Address, index)
|
||||
|
||||
// update counter if array has changed
|
||||
if previous and val in block.AbsentValidators:
|
||||
SigningBitArray.Set(val.Address, index, false)
|
||||
signInfo.SignedBlocksCounter--
|
||||
else if !previous and val not in block.AbsentValidators:
|
||||
SigningBitArray.Set(val.Address, index, true)
|
||||
signInfo.SignedBlocksCounter++
|
||||
// else previous == val not in block.AbsentValidators, no change
|
||||
|
||||
// validator must be active for at least SIGNED_BLOCKS_WINDOW
|
||||
// before they can be automatically unbonded for failing to be
|
||||
// included in 50% of the recent LastCommits
|
||||
minHeight = signInfo.StartHeight + SIGNED_BLOCKS_WINDOW
|
||||
minSigned = SIGNED_BLOCKS_WINDOW / 2
|
||||
if height > minHeight AND signInfo.SignedBlocksCounter < minSigned:
|
||||
signInfo.JailedUntil = block.Time + DOWNTIME_UNBOND_DURATION
|
||||
|
||||
slash & unbond the validator
|
||||
|
||||
SigningInfo.Set(val.Address, signInfo)
|
||||
```
|
|
@ -0,0 +1,51 @@
|
|||
## State
|
||||
|
||||
### Signing Info
|
||||
|
||||
Every block includes a set of precommits by the validators for the previous block,
|
||||
known as the LastCommit. A LastCommit is valid so long as it contains precommits from +2/3 of voting power.
|
||||
|
||||
Proposers are incentivized to include precommits from all
|
||||
validators in the LastCommit by receiving additional fees
|
||||
proportional to the difference between the voting power included in the
|
||||
LastCommit and +2/3 (see [TODO](https://github.com/cosmos/cosmos-sdk/issues/967)).
|
||||
|
||||
Validators are penalized for failing to be included in the LastCommit for some
|
||||
number of blocks by being automatically unbonded.
|
||||
|
||||
Information about validator activity is tracked in a `ValidatorSigningInfo`.
|
||||
It is indexed in the store as follows:
|
||||
|
||||
- SigningInfo: ` 0x01 | ValTendermintAddr -> amino(valSigningInfo)`
|
||||
- SigningBitArray: ` 0x02 | ValTendermintAddr | LittleEndianUint64(signArrayIndex) -> VarInt(didSign)`
|
||||
|
||||
The first map allows us to easily lookup the recent signing info for a
|
||||
validator, according to the Tendermint validator address. The second map acts as
|
||||
a bit-array of size `SIGNED_BLOCKS_WINDOW` that tells us if the validator signed for a given index in the bit-array.
|
||||
|
||||
The index in the bit-array is given as little endian uint64.
|
||||
|
||||
The result is a `varint` that takes on `0` or `1`, where `0` indicates the
|
||||
validator did not sign the corresponding block, and `1` indicates they did.
|
||||
|
||||
Note that the SigningBitArray is not explicitly initialized up-front. Keys are
|
||||
added as we progress through the first `SIGNED_BLOCKS_WINDOW` blocks for a newly
|
||||
bonded validator.
|
||||
|
||||
The information stored for tracking validator liveness is as follows:
|
||||
|
||||
```go
|
||||
type ValidatorSigningInfo struct {
|
||||
StartHeight int64
|
||||
IndexOffset int64
|
||||
JailedUntil int64
|
||||
SignedBlocksCounter int64
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Where:
|
||||
* `StartHeight` is set to the height that the candidate became an active validator (with non-zero voting power).
|
||||
* `IndexOffset` is incremented each time the candidate was a bonded validator in a block (and may have signed a precommit or not).
|
||||
* `JailedUntil` is set whenever the candidate is revoked due to downtime
|
||||
* `SignedBlocksCounter` is a counter kept to avoid unnecessary array reads. `SignedBlocksBitArray.Sum() == SignedBlocksCounter` always.
|
|
@ -1,44 +1,43 @@
|
|||
## State
|
||||
|
||||
### Pool
|
||||
- index: n/a single-record
|
||||
|
||||
- key: `01`
|
||||
- value: `amino(pool)`
|
||||
|
||||
The pool is a space for all dynamic global state of the Cosmos Hub. It tracks
|
||||
information about the total amounts of Atoms in all states, representative
|
||||
validator shares for stake in the global pools, moving Atom inflation
|
||||
information, etc.
|
||||
|
||||
- stored object:
|
||||
|
||||
```golang
|
||||
type Pool struct {
|
||||
LooseUnbondedTokens int64 // tokens not associated with any validator
|
||||
UnbondedTokens int64 // reserve of unbonded tokens held with validators
|
||||
UnbondingTokens int64 // tokens moving from bonded to unbonded pool
|
||||
BondedTokens int64 // reserve of bonded tokens
|
||||
UnbondedShares sdk.Rat // sum of all shares distributed for the Unbonded Pool
|
||||
UnbondingShares sdk.Rat // shares moving from Bonded to Unbonded Pool
|
||||
BondedShares sdk.Rat // sum of all shares distributed for the Bonded Pool
|
||||
InflationLastTime int64 // block which the last inflation was processed // TODO make time
|
||||
Inflation sdk.Rat // current annual inflation rate
|
||||
|
||||
DateLastCommissionReset int64 // unix timestamp for last commission accounting reset (daily)
|
||||
UnbondedTokens int64 // reserve of unbonded tokens held with validators
|
||||
UnbondingTokens int64 // tokens moving from bonded to unbonded pool
|
||||
BondedTokens int64 // reserve of bonded tokens
|
||||
UnbondedShares sdk.Rat // sum of all shares distributed for the Unbonded Pool
|
||||
UnbondingShares sdk.Rat // shares moving from Bonded to Unbonded Pool
|
||||
BondedShares sdk.Rat // sum of all shares distributed for the Bonded Pool
|
||||
InflationLastTime int64 // block which the last inflation was processed // TODO make time
|
||||
Inflation sdk.Rat // current annual inflation rate
|
||||
|
||||
DateLastCommissionReset int64 // unix timestamp for last commission accounting reset (daily)
|
||||
}
|
||||
|
||||
type PoolShares struct {
|
||||
Status sdk.BondStatus // either: unbonded, unbonding, or bonded
|
||||
Amount sdk.Rat // total shares of type ShareKind
|
||||
Status sdk.BondStatus // either: unbonded, unbonding, or bonded
|
||||
Amount sdk.Rat // total shares of type ShareKind
|
||||
}
|
||||
```
|
||||
|
||||
### Params
|
||||
- index: n/a single-record
|
||||
- key: `00`
|
||||
- value: `amino(params)`
|
||||
|
||||
Params is global data structure that stores system parameters and defines
|
||||
overall functioning of the stake module.
|
||||
|
||||
- stored object:
|
||||
|
||||
```golang
|
||||
type Params struct {
|
||||
InflationRateChange sdk.Rat // maximum annual change in inflation rate
|
||||
|
@ -52,40 +51,64 @@ type Params struct {
|
|||
```
|
||||
|
||||
### Validator
|
||||
- index 1: validator owner address
|
||||
- index 2: validator Tendermint PubKey
|
||||
- index 3: bonded validators only
|
||||
- index 4: voting power
|
||||
|
||||
Related Store which holds Validator.ABCIValidator()
|
||||
- index: validator owner address
|
||||
Validators are identified according to the `ValOwnerAddr`,
|
||||
an SDK account address for the owner of the validator.
|
||||
|
||||
Validators also have a `ValTendermintAddr`, the address
|
||||
of the public key of the validator.
|
||||
|
||||
Validators are indexed in the store using the following maps:
|
||||
|
||||
- Validators: `0x02 | ValOwnerAddr -> amino(validator)`
|
||||
- ValidatorsByPubKey: `0x03 | ValTendermintAddr -> ValOwnerAddr`
|
||||
- ValidatorsByPower: `0x05 | power | blockHeight | blockTx -> ValOwnerAddr`
|
||||
|
||||
`Validators` is the primary index - it ensures that each owner can have only one
|
||||
associated validator, where the public key of that validator can change in the
|
||||
future. Delegators can refer to the immutable owner of the validator, without
|
||||
concern for the changing public key.
|
||||
|
||||
`ValidatorsByPubKey` is a secondary index that enables lookups for slashing.
|
||||
When Tendermint reports evidence, it provides the validator address, so this
|
||||
map is needed to find the owner.
|
||||
|
||||
`ValidatorsByPower` is a secondary index that provides a sorted list of
|
||||
potential validators to quickly determine the current active set. For instance,
|
||||
the first 100 validators in this list can be returned with every EndBlock.
|
||||
|
||||
The `Validator` holds the current state and some historical actions of the
|
||||
validator.
|
||||
|
||||
- stored object:
|
||||
|
||||
```golang
|
||||
type Validator struct {
|
||||
Owner sdk.Address // sender of BondTx - UnbondTx returns here
|
||||
ConsensusPubKey crypto.PubKey // Tendermint consensus pubkey of validator
|
||||
Revoked bool // has the validator been revoked?
|
||||
ConsensusPubKey crypto.PubKey // Tendermint consensus pubkey of validator
|
||||
Revoked bool // has the validator been revoked?
|
||||
|
||||
PoolShares PoolShares // total shares for tokens held in the pool
|
||||
DelegatorShares sdk.Rat // total shares issued to a validator's delegators
|
||||
SlashRatio sdk.Rat // increases each time the validator is slashed
|
||||
|
||||
Description Description // description terms for the validator
|
||||
|
||||
// Needed for ordering vals in the bypower key
|
||||
BondHeight int64 // earliest height as a bonded validator
|
||||
BondIntraTxCounter int16 // block-local tx index of validator change
|
||||
|
||||
CommissionInfo CommissionInfo // info about the validator's commission
|
||||
|
||||
ProposerRewardPool sdk.Coins // reward pool collected from being the proposer
|
||||
|
||||
// TODO: maybe this belongs in distribution module ?
|
||||
PrevPoolShares PoolShares // total shares of a global hold pools
|
||||
}
|
||||
|
||||
PoolShares PoolShares // total shares for tokens held in the pool
|
||||
DelegatorShares sdk.Rat // total shares issued to a validator's delegators
|
||||
SlashRatio sdk.Rat // increases each time the validator is slashed
|
||||
|
||||
Description Description // description terms for the validator
|
||||
BondHeight int64 // earliest height as a bonded validator
|
||||
BondIntraTxCounter int16 // block-local tx index of validator change
|
||||
ProposerRewardPool sdk.Coins // reward pool collected from being the proposer
|
||||
|
||||
Commission sdk.Rat // the commission rate of fees charged to any delegators
|
||||
CommissionMax sdk.Rat // maximum commission rate which this validator can ever charge
|
||||
CommissionChangeRate sdk.Rat // maximum daily increase of the validator commission
|
||||
CommissionChangeToday sdk.Rat // commission rate change today, reset each day (UTC time)
|
||||
|
||||
PrevPoolShares PoolShares // total shares of a global hold pools
|
||||
type CommissionInfo struct {
|
||||
Rate sdk.Rat // the commission rate of fees charged to any delegators
|
||||
Max sdk.Rat // maximum commission rate which this validator can ever charge
|
||||
ChangeRate sdk.Rat // maximum daily increase of the validator commission
|
||||
ChangeToday sdk.Rat // commission rate change today, reset each day (UTC time)
|
||||
LastChange int64 // unix timestamp of last commission change
|
||||
}
|
||||
|
||||
type Description struct {
|
||||
|
@ -97,47 +120,71 @@ type Description struct {
|
|||
```
|
||||
|
||||
### Delegation
|
||||
- index: delegation address
|
||||
|
||||
Delegations are identified by combining `DelegatorAddr` (the address of the delegator) with the ValOwnerAddr
|
||||
Delegators are indexed in the store as follows:
|
||||
|
||||
- Delegation: ` 0x0A | DelegatorAddr | ValOwnerAddr -> amino(delegation)`
|
||||
|
||||
Atom 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.
|
||||
|
||||
- stored object:
|
||||
|
||||
```golang
|
||||
type Delegation struct {
|
||||
DelegatorAddr sdk.Address // delegation owner address
|
||||
ValidatorAddr sdk.Address // validator owner address
|
||||
Shares sdk.Rat // delegation shares recieved
|
||||
Height int64 // last height bond updated
|
||||
Shares sdk.Rat // delegation shares recieved
|
||||
Height int64 // last height bond updated
|
||||
}
|
||||
```
|
||||
|
||||
### UnbondingDelegation
|
||||
- index: delegation address
|
||||
|
||||
Shares in a `Delegation` can be unbonded, but they must for some time exist as an `UnbondingDelegation`,
|
||||
where shares can be reduced if Byzantine behaviour is detected.
|
||||
|
||||
`UnbondingDelegation` are indexed in the store as:
|
||||
|
||||
- UnbondingDelegationByDelegator: ` 0x0B | DelegatorAddr | ValOwnerAddr ->
|
||||
amino(unbondingDelegation)`
|
||||
- UnbondingDelegationByValOwner: ` 0x0C | ValOwnerAddr | DelegatorAddr | ValOwnerAddr ->
|
||||
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.
|
||||
The unbond must be completed with a second transaction provided by the
|
||||
delegation owner after the unbonding period has passed.
|
||||
|
||||
- stored object:
|
||||
|
||||
```golang
|
||||
type UnbondingDelegation struct {
|
||||
DelegationKey sdk.Address // key of the delegation
|
||||
ExpectedTokens sdk.Coins // the value in Atoms of the amount of shares which are unbonding
|
||||
StartSlashRatio sdk.Rat // validator slash ratio at unbonding initiation
|
||||
Tokens sdk.Coins // the value in Atoms of the amount of shares which are unbonding
|
||||
CompleteTime int64 // unix time to complete redelegation
|
||||
CompleteHeight int64 // block height to complete redelegation
|
||||
}
|
||||
```
|
||||
|
||||
### Redelegation
|
||||
- index 1: delegation address
|
||||
- index 2: source validator owner address
|
||||
- index 3: destination validator owner address
|
||||
|
||||
Shares in a `Delegation` can be rebonded to a different validator, but they must for some time exist as a `Redelegation`,
|
||||
where shares can be reduced if Byzantine behaviour is detected. This is tracked
|
||||
as moving a delegation from a `FromValOwnerAddr` to a `ToValOwnerAddr`.
|
||||
|
||||
`Redelegation` are indexed in the store as:
|
||||
|
||||
- Redelegations: `0x0D | DelegatorAddr | FromValOwnerAddr | ToValOwnerAddr ->
|
||||
amino(redelegation)`
|
||||
- RedelegationsBySrc: `0x0E | FromValOwnerAddr | ToValOwnerAddr |
|
||||
DelegatorAddr -> nil`
|
||||
- RedelegationsByDst: `0x0F | ToValOwnerAddr | FromValOwnerAddr | 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 FromValOwnerAddr,
|
||||
while the third map is for slashing based on the ToValOwnerAddr.
|
||||
|
||||
A redelegation object is created every time a redelegation occurs. The
|
||||
redelegation must be completed with a second transaction provided by the
|
||||
|
@ -145,16 +192,10 @@ delegation owner after the unbonding period has passed. The destination
|
|||
delegation of a redelegation may not itself undergo a new redelegation until
|
||||
the original redelegation has been completed.
|
||||
|
||||
- stored object:
|
||||
|
||||
```golang
|
||||
type Redelegation struct {
|
||||
SourceDelegation sdk.Address // source delegation key
|
||||
DestinationDelegation sdk.Address // destination delegation key
|
||||
SourceShares sdk.Rat // amount of source shares redelegating
|
||||
DestinationShares sdk.Rat // amount of destination shares created at redelegation
|
||||
SourceStartSlashRatio sdk.Rat // source validator slash ratio at unbonding initiation
|
||||
CompleteTime int64 // unix time to complete redelegation
|
||||
CompleteHeight int64 // block height to complete redelegation
|
||||
}
|
||||
```
|
||||
|
|
Loading…
Reference in New Issue