cosmos-sdk/docs/spec/staking/transactions.md

312 lines
8.7 KiB
Markdown
Raw Normal View History

# Transaction Overview
2018-05-08 14:35:24 -07:00
2018-05-25 15:52:34 -07:00
In this section we describe the processing of the transactions and the
corresponding updates to the state. Transactions:
* TxCreateValidator
* TxEditValidator
* TxDelegation
* TxStartUnbonding
* TxRedelegate
2018-05-25 15:52:34 -07:00
2018-05-29 11:50:35 -07:00
Other important state changes:
* Update Validators
2018-05-29 11:50:35 -07:00
2018-05-25 15:52:34 -07:00
Other notes:
* `tx` denotes a reference to the transaction being processed
* `sender` denotes the address of the sender of the transaction
* `getXxx`, `setXxx`, and `removeXxx` functions are used to retrieve and
modify objects from the store
* `sdk.Dec` refers to a decimal type specified by the SDK.
## TxCreateValidator
2018-05-08 14:35:24 -07:00
* triggers: `distribution.CreateValidatorDistribution`
2018-05-25 15:52:34 -07:00
A validator is created using the `TxCreateValidator` transaction.
2018-05-08 14:35:24 -07:00
```golang
2018-05-25 15:52:34 -07:00
type TxCreateValidator struct {
Description Description
Commission Commission
DelegatorAddr sdk.AccAddress
ValidatorAddr sdk.ValAddress
PubKey crypto.PubKey
Delegation sdk.Coin
}
2018-05-08 14:35:24 -07:00
2018-05-25 15:52:34 -07:00
createValidator(tx TxCreateValidator):
ok := validatorExists(tx.ValidatorAddr)
if ok return err // only one validator per address
ok := validatorByPubKeyExists(tx.PubKey)
if ok return err // only one validator per public key
err := validateDenom(tx.Delegation.Denom)
if err != nil return err // denomination must be valid
validator := NewValidator(tx.ValidatorAddr, tx.PubKey, tx.Description)
err := setInitialCommission(validator, tx.Commission, blockTime)
if err != nil return err // must be able to set initial commission correctly
// set the validator and public key
2018-05-25 15:52:34 -07:00
setValidator(validator)
setValidatorByPubKeyIndex(validator)
// delegate coins from tx.DelegatorAddr to the validator
err := delegate(tx.DelegatorAddr, tx.Delegation, validator)
if err != nil return err // must be able to set delegation correctly
tags := createTags(tx)
return tags
```
2018-05-08 14:35:24 -07:00
## TxEditValidator
2018-05-08 14:35:24 -07:00
If either the `Description`, `Commission`, or the `ValidatorAddr` need to be
updated, the `TxEditCandidacy` transaction should be sent from the operator
account:
2018-05-08 14:35:24 -07:00
```golang
type TxEditCandidacy struct {
Description Description
ValidatorAddr sdk.ValAddress
CommissionRate sdk.Dec
2018-05-08 14:35:24 -07:00
}
2018-05-08 14:35:24 -07:00
editCandidacy(tx TxEditCandidacy):
validator, ok := getValidator(tx.ValidatorAddr)
if !ok return err // validator must exist
// Attempt to update the validator's description. The description provided
// must be valid.
description, err := updateDescription(validator, tx.Description)
if err != nil return err
// a validator is not required to update it's commission rate
if tx.CommissionRate != nil {
// Attempt to update a validator's commission rate. The rate provided
// must be valid. It's rate can only be updated once a day.
err := updateValidatorCommission(validator, tx.CommissionRate)
if err != nil return err
}
// set the validator and public key
setValidator(validator)
tags := createTags(tx)
return tags
2018-05-08 14:35:24 -07:00
```
### TxDelegate
- triggers: `distribution.CreateOrModDelegationDistribution`
2018-05-08 14:35:24 -07:00
2018-05-25 15:52:34 -07:00
Within this transaction the delegator provides coins, and in return receives
some amount of their validator's delegator-shares that are assigned to
`Delegation.Shares`.
2018-05-08 14:35:24 -07:00
```golang
type TxDelegate struct {
DelegatorAddr sdk.Address
ValidatorAddr sdk.Address
Amount sdk.Coin
2018-05-08 14:35:24 -07:00
}
delegate(tx TxDelegate):
2018-05-25 15:52:34 -07:00
pool = getPool()
if validator.Status == Jailed return
2018-05-08 14:35:24 -07:00
2018-05-25 15:52:34 -07:00
delegation = getDelegatorBond(DelegatorAddr, ValidatorAddr)
if delegation == nil then delegation = NewDelegation(DelegatorAddr, ValidatorAddr)
2018-05-25 15:52:34 -07:00
validator, pool, issuedDelegatorShares = validator.addTokensFromDel(tx.Amount, pool)
delegation.Shares += issuedDelegatorShares
2018-05-25 15:52:34 -07:00
setDelegation(delegation)
updateValidator(validator)
setPool(pool)
return
2018-05-08 14:35:24 -07:00
```
### TxStartUnbonding
2018-05-08 14:35:24 -07:00
Delegator unbonding is defined with the following transaction:
```golang
type TxStartUnbonding struct {
DelegatorAddr sdk.Address
ValidatorAddr sdk.Address
Shares string
2018-05-08 14:35:24 -07:00
}
startUnbonding(tx TxStartUnbonding):
2018-05-25 15:52:34 -07:00
delegation, found = getDelegatorBond(store, sender, tx.PubKey)
if !found == nil return
2018-06-13 21:58:36 -07:00
if bond.Shares < tx.Shares
return ErrNotEnoughBondShares
2018-05-08 14:35:24 -07:00
2018-06-13 21:58:36 -07:00
validator, found = GetValidator(tx.ValidatorAddr)
2018-05-25 15:52:34 -07:00
if !found {
return err
2018-05-08 14:35:24 -07:00
2018-06-13 21:58:36 -07:00
bond.Shares -= tx.Shares
2018-05-08 14:35:24 -07:00
2018-06-13 21:58:36 -07:00
revokeCandidacy = false
2018-05-25 15:52:34 -07:00
if bond.Shares.IsZero() {
2018-05-08 14:35:24 -07:00
if bond.DelegatorAddr == validator.Operator && validator.Jailed == false
2018-05-25 15:52:34 -07:00
revokeCandidacy = true
2018-05-08 14:35:24 -07:00
removeDelegation( bond)
2018-05-25 15:52:34 -07:00
else
bond.Height = currentBlockHeight
setDelegation(bond)
2018-05-08 14:35:24 -07:00
2018-06-13 21:58:36 -07:00
pool = GetPool()
validator, pool, returnAmount = validator.removeDelShares(pool, tx.Shares)
setPool( pool)
unbondingDelegation = NewUnbondingDelegation(sender, returnAmount, currentHeight/Time, startSlashRatio)
setUnbondingDelegation(unbondingDelegation)
2018-05-08 14:35:24 -07:00
2018-05-25 15:52:34 -07:00
if revokeCandidacy
validator.Jailed = true
2018-05-25 15:52:34 -07:00
validator = updateValidator(validator)
2018-05-08 14:35:24 -07:00
if validator.Status == Unbonded && validator.DelegatorShares == 0 {
removeValidator(validator.Operator)
2018-05-25 15:52:34 -07:00
return
2018-05-08 14:35:24 -07:00
```
2018-05-25 15:52:34 -07:00
### TxRedelegation
2018-05-08 14:35:24 -07:00
The redelegation command allows delegators to instantly switch validators. Once
the unbonding period has passed, the redelegation is automatically completed in the EndBlocker.
2018-05-08 14:35:24 -07:00
```golang
type TxRedelegate struct {
2018-05-25 15:52:34 -07:00
DelegatorAddr Address
ValidatorFrom Validator
ValidatorTo Validator
Shares sdk.Dec
CompletedTime int64
2018-05-08 14:35:24 -07:00
}
redelegate(tx TxRedelegate):
2018-05-25 15:52:34 -07:00
pool = getPool()
delegation = getDelegatorBond(tx.DelegatorAddr, tx.ValidatorFrom.Operator)
if delegation == nil
return
if delegation.Shares < tx.Shares
return
2018-05-25 15:52:34 -07:00
delegation.shares -= Tx.Shares
validator, pool, createdCoins = validator.RemoveShares(pool, tx.Shares)
setPool(pool)
redelegation = newRedelegation(tx.DelegatorAddr, tx.validatorFrom,
tx.validatorTo, tx.Shares, createdCoins, tx.CompletedTime)
2018-05-25 15:52:34 -07:00
setRedelegation(redelegation)
return
2018-05-08 14:35:24 -07:00
```
2018-05-29 11:50:35 -07:00
### Update Validators
Within many transactions the validator set must be updated based on changes in
power to a single validator. This process also updates the Tendermint-Updates
store for use in end-block when validators are either added or kicked from the
Tendermint.
```golang
updateBondedValidators(newValidator Validator) (updatedVal Validator)
2018-06-13 21:58:36 -07:00
kickCliffValidator = false
oldCliffValidatorAddr = getCliffValidator(ctx)
2018-05-29 11:50:35 -07:00
// add the actual validator power sorted store
2018-06-13 21:58:36 -07:00
maxValidators = GetParams(ctx).MaxValidators
iterator = ReverseSubspaceIterator(ValidatorsByPowerKey) // largest to smallest
bondedValidatorsCount = 0
2018-05-29 11:50:35 -07:00
var validator Validator
for {
if !iterator.Valid() || bondedValidatorsCount > int(maxValidators-1) {
if bondedValidatorsCount == int(maxValidators) { // is cliff validator
setCliffValidator(ctx, validator, GetPool(ctx))
iterator.Close()
break
// either retrieve the original validator from the store,
// or under the situation that this is the "new validator" just
// use the validator provided because it has not yet been updated
// in the main validator store
operatorAddr = iterator.Value()
if bytes.Equal(operatorAddr, newValidator.Operator) {
2018-05-29 11:50:35 -07:00
validator = newValidator
else
validator = getValidator(operatorAddr)
2018-05-29 11:50:35 -07:00
// if not previously a validator (and unjailed),
2018-05-29 11:50:35 -07:00
// kick the cliff validator / bond this new validator
if validator.Status() != Bonded && !validator.Jailed {
2018-05-29 11:50:35 -07:00
kickCliffValidator = true
validator = bondValidator(ctx, store, validator)
if bytes.Equal(operatorAddr, newValidator.Operator) {
2018-05-29 11:50:35 -07:00
updatedVal = validator
bondedValidatorsCount++
iterator.Next()
// perform the actual kicks
if oldCliffValidatorAddr != nil && kickCliffValidator {
2018-06-13 21:58:36 -07:00
validator = getValidator(store, oldCliffValidatorAddr)
2018-05-29 11:50:35 -07:00
unbondValidator(ctx, store, validator)
return
// perform all the store operations for when a validator status becomes unbonded
2018-06-13 21:58:36 -07:00
unbondValidator(ctx Context, store KVStore, validator Validator)
pool = GetPool(ctx)
2018-05-29 11:50:35 -07:00
// set the status
2018-06-13 21:58:36 -07:00
validator, pool = validator.UpdateStatus(pool, Unbonded)
2018-05-29 11:50:35 -07:00
setPool(ctx, pool)
// save the now unbonded validator record
setValidator(validator)
// add to accumulated changes for tendermint
setTendermintUpdates(validator.abciValidatorZero)
// also remove from the bonded validators index
removeValidatorsBonded(validator)
}
// perform all the store operations for when a validator status becomes bonded
bondValidator(ctx Context, store KVStore, validator Validator) Validator
2018-06-13 21:58:36 -07:00
pool = GetPool(ctx)
2018-05-29 11:50:35 -07:00
// set the status
2018-06-13 21:58:36 -07:00
validator, pool = validator.UpdateStatus(pool, Bonded)
2018-05-29 11:50:35 -07:00
setPool(ctx, pool)
// save the now bonded validator record to the three referenced stores
setValidator(validator)
setValidatorsBonded(validator)
// add to accumulated changes for tendermint
setTendermintUpdates(validator.abciValidator)
return validator
```