From 25ae0269586e20b15c3789b666bd8656c1ea22f0 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Tue, 29 May 2018 16:03:13 -0400 Subject: [PATCH] spec complete unbonding, redelegation txs --- docs/spec/staking/state.md | 93 +++++++++++++++--------------- docs/spec/staking/transactions.md | 96 +++++++++++++++++++++++-------- x/stake/delegation.go | 1 - 3 files changed, 120 insertions(+), 70 deletions(-) diff --git a/docs/spec/staking/state.md b/docs/spec/staking/state.md index 72cda1bb4..82a22dc65 100644 --- a/docs/spec/staking/state.md +++ b/docs/spec/staking/state.md @@ -10,22 +10,22 @@ information, etc. ```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 + 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) } 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 } ``` @@ -37,13 +37,13 @@ overall functioning of the stake module. ```golang type Params struct { - InflationRateChange sdk.Rat // maximum annual change in inflation rate - InflationMax sdk.Rat // maximum inflation rate - InflationMin sdk.Rat // minimum inflation rate - GoalBonded sdk.Rat // Goal of percent bonded atoms + InflationRateChange sdk.Rat // maximum annual change in inflation rate + InflationMax sdk.Rat // maximum inflation rate + InflationMin sdk.Rat // minimum inflation rate + GoalBonded sdk.Rat // Goal of percent bonded atoms - MaxValidators uint16 // maximum number of validators - BondDenom string // bondable coin denomination + MaxValidators uint16 // maximum number of validators + BondDenom string // bondable coin denomination } ``` @@ -65,27 +65,28 @@ type Validator struct { 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 + 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 + 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 + PrevPoolShares PoolShares // total shares of a global hold pools } type Description struct { - Moniker string // name - Identity string // optional identity signature (ex. UPort or Keybase) - Website string // optional website link - Details string // optional details + Moniker string // name + Identity string // optional identity signature (ex. UPort or Keybase) + Website string // optional website link + Details string // optional details } ``` @@ -99,10 +100,10 @@ the transaction is the owner of the bond. ```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 + DelegatorAddr sdk.Address // delegation owner address + ValidatorAddr sdk.Address // validator owner address + Shares sdk.Rat // delegation shares recieved + Height int64 // last height bond updated } ``` @@ -110,17 +111,16 @@ type Delegation struct { - index: delegation address 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. - +The unbond must be completed with a second transaction provided by the +delegation owner after the unbonding period has passed. ```golang type UnbondingDelegation struct { - DelegationKey []byte // key of the delegation - InitTime int64 // unix time at unbonding initation - InitHeight int64 // block height at unbonding initation - ExpectedTokens sdk.Coins // the value in Atoms of the amount of shares which are unbonding - StartSlashRatio sdk.Rat // validator slash ratio at unbonding initiation + 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 + CompleteTime int64 // unix time to complete redelegation + CompleteHeight int64 // block height to complete redelegation } ``` @@ -135,13 +135,14 @@ 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. - ```golang type Redelegation struct { - SourceDelegation []byte // source delegation key - DestinationDelegation []byte // destination delegation key - InitTime int64 // unix time at redelegation - InitHeight int64 // block height at redelegation - Shares sdk.Rat // amount of shares redelegating + 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 } ``` diff --git a/docs/spec/staking/transactions.md b/docs/spec/staking/transactions.md index b59077314..8013829ec 100644 --- a/docs/spec/staking/transactions.md +++ b/docs/spec/staking/transactions.md @@ -6,8 +6,10 @@ corresponding updates to the state. Transactions: - TxCreateValidator - TxEditValidator - TxDelegation - - TxRedelegation - - TxUnbond + - TxStartUnbonding + - TxCompleteUnbonding + - TxRedelegate + - TxCompleteRedelegation Other important state changes: - Update Validators @@ -109,43 +111,41 @@ delegate(tx TxDelegate): return ``` -### TxUnbond +### TxStartUnbonding Delegator unbonding is defined with the following transaction: ```golang -type TxUnbond struct { +type TxStartUnbonding struct { DelegatorAddr sdk.Address ValidatorAddr sdk.Address Shares string } -unbond(tx TxUnbond): +startUnbonding(tx TxStartUnbonding): delegation, found = getDelegatorBond(store, sender, tx.PubKey) if !found == nil return - if msg.Shares == "MAX" { + if tx.Shares == "MAX" { if !bond.Shares.GT(sdk.ZeroRat()) { - return ErrNotEnoughBondShares(k.codespace, msg.Shares).Result() + return ErrNotEnoughBondShares else var err sdk.Error - delShares, err = sdk.NewRatFromDecimal(msg.Shares) + delShares, err = sdk.NewRatFromDecimal(tx.Shares) if err != nil return err if bond.Shares.LT(delShares) - return ErrNotEnoughBondShares(k.codespace, msg.Shares).Result() + return ErrNotEnoughBondShares - validator, found := k.GetValidator(ctx, msg.ValidatorAddr) + validator, found := GetValidator(tx.ValidatorAddr) if !found { return err - if msg.Shares == "MAX" + if tx.Shares == "MAX" delShares = bond.Shares bond.Shares -= delShares - unbondingDelegation = NewUnbondingDelegation(sender, delShares, currentHeight/Time, startSlashRatio) - setUnbondingDelegation(unbondingDelegation) revokeCandidacy := false if bond.Shares.IsZero() { @@ -153,30 +153,55 @@ unbond(tx TxUnbond): if bond.DelegatorAddr == validator.Owner && validator.Revoked == false revokeCandidacy = true - k.removeDelegation(ctx, bond) + removeDelegation( bond) else bond.Height = currentBlockHeight setDelegation(bond) - pool := k.GetPool(ctx) + pool := GetPool() validator, pool, returnAmount := validator.removeDelShares(pool, delShares) - k.setPool(ctx, pool) - AddCoins(ctx, bond.DelegatorAddr, returnAmount) + setPool( pool) + + unbondingDelegation = NewUnbondingDelegation(sender, returnAmount, currentHeight/Time, startSlashRatio) + setUnbondingDelegation(unbondingDelegation) if revokeCandidacy validator.Revoked = true - validator = updateValidator(ctx, validator) + validator = updateValidator(validator) if validator.DelegatorShares == 0 { - removeValidator(ctx, validator.Owner) + removeValidator(validator.Owner) return ``` +### TxCompleteUnbonding + +Complete the unbonding and transfer the coins to the delegate. Perform any +slashing that occured 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. +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 { @@ -184,23 +209,48 @@ type TxRedelegate struct { ValidatorFrom Validator ValidatorTo Validator Shares sdk.Rat + CompletedTime int64 } redelegate(tx TxRedelegate): + pool = getPool() delegation = getDelegatorBond(tx.DelegatorAddr, tx.ValidatorFrom.Owner) - if delegation == nil then return + if delegation == nil + return - if delegation.Shares < tx.Shares return + if delegation.Shares < tx.Shares + return delegation.shares -= Tx.Shares validator, pool, createdCoins = validator.RemoveShares(pool, tx.Shares) setPool(pool) - redelegation = newRedelegation(validatorFrom, validatorTo, Shares, createdCoins) + 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 diff --git a/x/stake/delegation.go b/x/stake/delegation.go index ae08e0867..8b047acce 100644 --- a/x/stake/delegation.go +++ b/x/stake/delegation.go @@ -49,5 +49,4 @@ func (b Delegation) HumanReadableString() (string, error) { resp += fmt.Sprintf("Height: %d", b.Height) return resp, nil - }