
### Transaction Overview

In this section we describe the processing of the transactions and the
corresponding updates to the state. Transactions: 
 - TxCreateValidator
 - TxEditValidator
 - TxDelegation
 - TxStartUnbonding
 - TxCompleteUnbonding
 - TxRedelegate
 - TxCompleteRedelegation

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.Rat` refers to a rational numeric type specified by the SDK.
 
### TxCreateValidator

A validator is created using the `TxCreateValidator` transaction.

```golang
type TxCreateValidator struct {
	OwnerAddr           sdk.Address
    ConsensusPubKey     crypto.PubKey
    GovernancePubKey    crypto.PubKey
    SelfDelegation      coin.Coin       

    Description         Description
    Commission          sdk.Rat
    CommissionMax       sdk.Rat 
    CommissionMaxChange sdk.Rat 
}
	

createValidator(tx TxCreateValidator):
    validator = getValidator(tx.OwnerAddr)
    if validator != nil return // only one validator per address
   	
    validator = NewValidator(OwnerAddr, ConsensusPubKey, GovernancePubKey, Description)
    init validator poolShares, delegatorShares set to 0
    init validator commision fields from tx
    validator.PoolShares = 0
   	
    setValidator(validator)
   
    txDelegate = TxDelegate(tx.OwnerAddr, tx.OwnerAddr, tx.SelfDelegation) 
    delegate(txDelegate, validator) // see delegate function in [TxDelegate](TxDelegate)
    return
``` 

### TxEditValidator

If either the `Description` (excluding `DateBonded` which is constant),
`Commission`, or the `GovernancePubKey` need to be updated, the
`TxEditCandidacy` transaction should be sent from the owner account:

```golang
type TxEditCandidacy struct {
    GovernancePubKey    crypto.PubKey
    Commission          sdk.Rat
    Description         Description
}
 
editCandidacy(tx TxEditCandidacy):
    validator = getValidator(tx.ValidatorAddr)
    
    if tx.Commission > CommissionMax ||  tx.Commission < 0 then fail 
    if rateChange(tx.Commission) > CommissionMaxChange then fail
    validator.Commission = tx.Commission

    if tx.GovernancePubKey != nil validator.GovernancePubKey = tx.GovernancePubKey
    if tx.Description != nil validator.Description = tx.Description
    
    setValidator(store, validator)
    return
```
     	
### TxDelegation

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 == Revoked 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.Owner && validator.Revoked == 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.Revoked = true

	validator = updateValidator(validator)

	if validator.DelegatorShares == 0 {
		removeValidator(validator.Owner)

    return
```

### TxCompleteUnbonding

Complete the unbonding and transfer the coins to the delegate. Perform any
slashing that occurred during the unbonding period.

```golang
type TxUnbondingComplete struct {
    DelegatorAddr sdk.Address
    ValidatorAddr sdk.Address
}

redelegationComplete(tx TxRedelegate):
    unbonding = getUnbondingDelegation(tx.DelegatorAddr, tx.Validator)
    if unbonding.CompleteTime >= CurrentBlockTime && unbonding.CompleteHeight >= CurrentBlockHeight
        validator = GetValidator(tx.ValidatorAddr)
        returnTokens = ExpectedTokens * tx.startSlashRatio/validator.SlashRatio
	    AddCoins(unbonding.DelegatorAddr, returnTokens)
        removeUnbondingDelegation(unbonding)
    return     
```

### TxRedelegation

The redelegation command allows delegators to instantly switch validators. Once
the unbonding period has passed, the redelegation must be completed with
txRedelegationComplete.

```golang
type TxRedelegate struct {
    DelegatorAddr Address
    ValidatorFrom Validator
    ValidatorTo   Validator
    Shares        sdk.Rat 
    CompletedTime int64 
}

redelegate(tx TxRedelegate):

    pool = getPool()
    delegation = getDelegatorBond(tx.DelegatorAddr, tx.ValidatorFrom.Owner)
    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     
```

### TxCompleteRedelegation

Note that unlike TxCompleteUnbonding slashing of redelegating shares does not
take place during completion. Slashing on redelegated shares takes place
actively as a slashing occurs.

```golang
type TxRedelegationComplete struct {
    DelegatorAddr Address
    ValidatorFrom Validator
    ValidatorTo   Validator
}

redelegationComplete(tx TxRedelegate):
    redelegation = getRedelegation(tx.DelegatorAddr, tx.validatorFrom, tx.validatorTo)
    if redelegation.CompleteTime >= CurrentBlockTime && redelegation.CompleteHeight >= CurrentBlockHeight
        removeRedelegation(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

		ownerAddr = iterator.Value()
		if bytes.Equal(ownerAddr, newValidator.Owner) {
			validator = newValidator
        else
			validator = getValidator(ownerAddr)

		// if not previously a validator (and unrevoked),
		// kick the cliff validator / bond this new validator
		if validator.Status() != Bonded && !validator.Revoked {
			kickCliffValidator = true

			validator = bondValidator(ctx, store, validator)
			if bytes.Equal(ownerAddr, newValidator.Owner) {
				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
```
