# Transaction Overview In this section we describe the processing of the transactions and the corresponding updates to the state. Transactions: * TxCreateValidator * TxEditValidator * TxDelegation * TxStartUnbonding * TxRedelegate Other important state changes: * Update Validators 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 * triggers: `distribution.CreateValidatorDistribution` A validator is created using the `TxCreateValidator` transaction. ```golang type TxCreateValidator struct { Description Description Commission Commission DelegatorAddr sdk.AccAddress ValidatorAddr sdk.ValAddress PubKey crypto.PubKey Delegation sdk.Coin } 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 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 ``` ## TxEditValidator If either the `Description`, `Commission`, or the `ValidatorAddr` need to be updated, the `TxEditCandidacy` transaction should be sent from the operator account: ```golang type TxEditCandidacy struct { Description Description ValidatorAddr sdk.ValAddress CommissionRate sdk.Dec } 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 ``` ### TxDelegate - triggers: `distribution.CreateOrModDelegationDistribution` 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`. ```golang type TxDelegate struct { DelegatorAddr sdk.Address ValidatorAddr sdk.Address Amount sdk.Coin } delegate(tx TxDelegate): pool = getPool() if validator.Status == Jailed return delegation = getDelegatorBond(DelegatorAddr, ValidatorAddr) if delegation == nil then delegation = NewDelegation(DelegatorAddr, ValidatorAddr) validator, pool, issuedDelegatorShares = validator.addTokensFromDel(tx.Amount, pool) delegation.Shares += issuedDelegatorShares setDelegation(delegation) updateValidator(validator) setPool(pool) return ``` ### TxStartUnbonding Delegator unbonding is defined with the following transaction: ```golang type TxStartUnbonding struct { DelegatorAddr sdk.Address ValidatorAddr sdk.Address Shares string } startUnbonding(tx TxStartUnbonding): delegation, found = getDelegatorBond(store, sender, tx.PubKey) if !found == nil return if bond.Shares < tx.Shares return ErrNotEnoughBondShares validator, found = GetValidator(tx.ValidatorAddr) if !found { return err bond.Shares -= tx.Shares revokeCandidacy = false if bond.Shares.IsZero() { if bond.DelegatorAddr == validator.Operator && validator.Jailed == false revokeCandidacy = true removeDelegation( bond) else bond.Height = currentBlockHeight setDelegation(bond) pool = GetPool() validator, pool, returnAmount = validator.removeDelShares(pool, tx.Shares) setPool( pool) unbondingDelegation = NewUnbondingDelegation(sender, returnAmount, currentHeight/Time, startSlashRatio) setUnbondingDelegation(unbondingDelegation) if revokeCandidacy validator.Jailed = true validator = updateValidator(validator) if validator.Status == Unbonded && validator.DelegatorShares == 0 { removeValidator(validator.Operator) return ``` ### TxRedelegation The redelegation command allows delegators to instantly switch validators. Once the unbonding period has passed, the redelegation is automatically completed in the EndBlocker. ```golang type TxRedelegate struct { DelegatorAddr Address ValidatorFrom Validator ValidatorTo Validator Shares sdk.Dec CompletedTime int64 } redelegate(tx TxRedelegate): pool = getPool() delegation = getDelegatorBond(tx.DelegatorAddr, tx.ValidatorFrom.Operator) if delegation == nil return if delegation.Shares < tx.Shares return 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) setRedelegation(redelegation) return ``` ### 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) kickCliffValidator = false oldCliffValidatorAddr = getCliffValidator(ctx) // add the actual validator power sorted store maxValidators = GetParams(ctx).MaxValidators iterator = ReverseSubspaceIterator(ValidatorsByPowerKey) // largest to smallest bondedValidatorsCount = 0 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) { validator = newValidator else validator = getValidator(operatorAddr) // if not previously a validator (and unjailed), // kick the cliff validator / bond this new validator if validator.Status() != Bonded && !validator.Jailed { kickCliffValidator = true validator = bondValidator(ctx, store, validator) if bytes.Equal(operatorAddr, newValidator.Operator) { updatedVal = validator bondedValidatorsCount++ iterator.Next() // perform the actual kicks if oldCliffValidatorAddr != nil && kickCliffValidator { validator = getValidator(store, oldCliffValidatorAddr) unbondValidator(ctx, store, validator) return // perform all the store operations for when a validator status becomes unbonded unbondValidator(ctx Context, store KVStore, validator Validator) pool = GetPool(ctx) // set the status validator, pool = validator.UpdateStatus(pool, Unbonded) 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 pool = GetPool(ctx) // set the status validator, pool = validator.UpdateStatus(pool, Bonded) 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 ```