From 7f789d2ed342de18f4443ae434f3e43f790f1854 Mon Sep 17 00:00:00 2001 From: frog power 4000 Date: Mon, 21 Jan 2019 19:52:03 -0500 Subject: [PATCH] Merge PR #3281: Staking Spec Upgrade * remove kv seperation for marshalling * pending * cleanup * cleanup x2 * pending * working * minor refactors * entry structs defined * uncompiled mechanism written * add many compile fixes * code compiles * fix test compile errors * test cover passes * ... * multiple entries fix * ... * more design fix * working * fix test cover bug * Update PENDING.md * update comment around queue completion for redelegations/ubds * basic spec updates * spec folder cleanup * cleanup docs folder cont. * ... * find-replace and folder rename * supplimentary find/replace * pending * supplimentary * pending * few undos, stakingd -> staked * to staking -> to stake * undos * most staking -> most stake * ... * undos * simplestake->simplestaking * ... * pending update * capital letter replacements * ... * working * staking doc updates from rigel/delegation-index branch * spec-spec * spec-spec * LooseTokens -> NotBondedTokens * staking state.md updates * updates to hook and endblock spec * Update docs/gaia/gaiacli.md Co-Authored-By: rigelrozanski * Update docs/gaia/validators/validator-setup.md Co-Authored-By: rigelrozanski * Update docs/gaia/validators/validator-setup.md Co-Authored-By: rigelrozanski * comment undo * remove ErrConflictingRedelegation * @cwgoes comments are resolved * further updates to endblock and state * msg json update * working transaction updates * working * complete transaction rewrite * PENDING.md * typo * add todo * address @jackzampolin @cwgoes comments * couple leftover comments, rename * Update x/staking/types/pool.go Co-Authored-By: rigelrozanski * cwgoes additions * cwgoes suggestions x2 --- PENDING.md | 11 +- client/lcd/lcd_test.go | 8 +- client/lcd/test_helpers.go | 2 +- cmd/gaia/app/genesis.go | 2 +- cmd/gaia/app/genesis_test.go | 2 +- cmd/gaia/app/sim_test.go | 2 +- docs/gaia/gaiacli.md | 4 +- docs/spec/SPEC-SPEC.md | 45 +++ .../{ics => _ics}/ics-030-signed-messages.md | 0 .../f1-fee-distribution/f1_fee_distr.pdf | Bin .../f1-fee-distribution/f1_fee_distr.tex | 0 docs/spec/{other => addresses}/bech32.md | 0 .../bank/{transactions.md => messages.md} | 2 +- .../{transactions.md => messages.md} | 2 +- .../{transactions.md => messages.md} | 2 +- docs/spec/inflation/end_block.md | 52 --- docs/spec/inflation/state.md | 21 -- docs/spec/other/other.md | 2 - docs/spec/reserve-pool/TODO.md | 5 + .../slashing/{transactions.md => messages.md} | 4 +- docs/spec/staking/TODO.md | 7 + docs/spec/staking/end_block.md | 106 +++--- docs/spec/staking/hooks.md | 40 ++- docs/spec/staking/messages.md | 167 ++++++++++ docs/spec/staking/{README.md => overview.md} | 38 ++- docs/spec/staking/state.md | 125 ++++--- docs/spec/staking/transactions.md | 312 ------------------ x/distribution/keeper/test_common.go | 2 +- x/gov/test_common.go | 2 +- x/slashing/app_test.go | 2 +- x/slashing/test_common.go | 2 +- x/staking/app_test.go | 2 +- x/staking/handler.go | 8 +- x/staking/keeper/delegation.go | 5 +- x/staking/keeper/delegation_test.go | 20 +- x/staking/keeper/sdk_types.go | 2 +- x/staking/keeper/slash.go | 12 +- x/staking/keeper/slash_test.go | 8 +- x/staking/keeper/test_common.go | 2 +- x/staking/keeper/val_state_change.go | 2 +- x/staking/keeper/validator.go | 2 +- x/staking/keeper/validator_test.go | 4 +- x/staking/simulation/invariants.go | 10 +- x/staking/types/msg.go | 9 +- x/staking/types/params.go | 7 +- x/staking/types/pool.go | 20 +- x/staking/types/pool_test.go | 12 +- x/staking/types/validator.go | 12 +- x/staking/types/validator_test.go | 38 +-- 49 files changed, 496 insertions(+), 648 deletions(-) create mode 100644 docs/spec/SPEC-SPEC.md rename docs/spec/{ics => _ics}/ics-030-signed-messages.md (100%) rename docs/spec/{spec-proposals => _proposals}/f1-fee-distribution/f1_fee_distr.pdf (100%) rename docs/spec/{spec-proposals => _proposals}/f1-fee-distribution/f1_fee_distr.tex (100%) rename docs/spec/{other => addresses}/bech32.md (100%) rename docs/spec/bank/{transactions.md => messages.md} (96%) rename docs/spec/distribution/{transactions.md => messages.md} (99%) rename docs/spec/governance/{transactions.md => messages.md} (99%) delete mode 100644 docs/spec/inflation/end_block.md delete mode 100644 docs/spec/inflation/state.md delete mode 100644 docs/spec/other/other.md create mode 100644 docs/spec/reserve-pool/TODO.md rename docs/spec/slashing/{transactions.md => messages.md} (90%) create mode 100644 docs/spec/staking/TODO.md create mode 100644 docs/spec/staking/messages.md rename docs/spec/staking/{README.md => overview.md} (63%) delete mode 100644 docs/spec/staking/transactions.md diff --git a/PENDING.md b/PENDING.md index b80973b83f..5b9941d8ef 100644 --- a/PENDING.md +++ b/PENDING.md @@ -6,6 +6,7 @@ BREAKING CHANGES * [gaia-lite] [\#2182] Renamed and merged all redelegations endpoints into `/staking/redelegations` * [\#3176](https://github.com/cosmos/cosmos-sdk/issues/3176) `tx/sign` endpoint now expects `BaseReq` fields as nested object. * [\#2222] all endpoints renamed from `/stake` -> `/staking` + * [\#1268] `LooseTokens` -> `NotBondedTokens` * [\#3289] misc renames: * `Validator.UnbondingMinTime` -> `Validator.UnbondingCompletionTime` * `Delegation` -> `Value` in `MsgCreateValidator` and `MsgDelegate` @@ -31,9 +32,10 @@ BREAKING CHANGES * [\#3064](https://github.com/cosmos/cosmos-sdk/issues/3064) Sanitize `sdk.Coin` denom. Coins denoms are now case insensitive, i.e. 100fooToken equals to 100FOOTOKEN. * [\#3195](https://github.com/cosmos/cosmos-sdk/issues/3195) Allows custom configuration for syncable strategy * [\#3242](https://github.com/cosmos/cosmos-sdk/issues/3242) Fix infinite gas - meter utilization during aborted ante handler executions. - * [\#2222] [x/staking] `/stake` -> `/staking` module rename - * \#3292 [x/distribution] Enable or disable withdraw addresses with a parameter in the param store + meter utilization during aborted ante handler executions. + * [x/distribution] \#3292 Enable or disable withdraw addresses with a parameter in the param store + * [staking] \#2222 `/stake` -> `/staking` module rename + * [staking] \#1268 `LooseTokens` -> `NotBondedTokens` * [staking] \#1402 Redelegation and unbonding-delegation structs changed to include multiple an array of entries * [staking] \#3289 misc renames: * `Validator.UnbondingMinTime` -> `Validator.UnbondingCompletionTime` @@ -110,7 +112,8 @@ IMPROVEMENTS slashing, and staking modules. * [\#3093](https://github.com/cosmos/cosmos-sdk/issues/3093) Ante handler does no longer read all accounts in one go when processing signatures as signature verification may fail before last signature is checked. - * [x/stake] \#1402 Add for multiple simultaneous redelegations or unbonding-delegations within an unbonding period + * [staking] \#1402 Add for multiple simultaneous redelegations or unbonding-delegations within an unbonding period + * [staking] \#1268 staking spec rewrite * Tendermint diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index 4dcd4cea7d..0d680ada44 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -347,12 +347,12 @@ func TestPoolParamsQuery(t *testing.T) { pool := getStakingPool(t, port) initialPool := staking.InitialPool() - initialPool.LooseTokens = initialPool.LooseTokens.Add(sdk.NewInt(100)) - initialPool.BondedTokens = initialPool.BondedTokens.Add(sdk.NewInt(100)) // Delegate tx on GaiaAppGenState - initialPool.LooseTokens = initialPool.LooseTokens.Add(sdk.NewInt(50)) // freeFermionsAcc = 50 on GaiaAppGenState + initialPool.NotBondedTokens = initialPool.NotBondedTokens.Add(sdk.NewInt(100)) + initialPool.BondedTokens = initialPool.BondedTokens.Add(sdk.NewInt(100)) // Delegate tx on GaiaAppGenState + initialPool.NotBondedTokens = initialPool.NotBondedTokens.Add(sdk.NewInt(50)) // freeFermionsAcc = 50 on GaiaAppGenState require.Equal(t, initialPool.BondedTokens, pool.BondedTokens) - require.Equal(t, initialPool.LooseTokens, pool.LooseTokens) + require.Equal(t, initialPool.NotBondedTokens, pool.NotBondedTokens) } func TestValidatorsQuery(t *testing.T) { diff --git a/client/lcd/test_helpers.go b/client/lcd/test_helpers.go index 6cc3309586..da41e196b2 100644 --- a/client/lcd/test_helpers.go +++ b/client/lcd/test_helpers.go @@ -291,7 +291,7 @@ func InitializeTestLCD( accAuth.Coins = sdk.Coins{sdk.NewInt64Coin(stakingTypes.DefaultBondDenom, 100)} acc := gapp.NewGenesisAccount(&accAuth) genesisState.Accounts = append(genesisState.Accounts, acc) - genesisState.StakingData.Pool.LooseTokens = genesisState.StakingData.Pool.LooseTokens.Add(sdk.NewInt(100)) + genesisState.StakingData.Pool.NotBondedTokens = genesisState.StakingData.Pool.NotBondedTokens.Add(sdk.NewInt(100)) } appState, err := codec.MarshalJSONIndent(cdc, genesisState) diff --git a/cmd/gaia/app/genesis.go b/cmd/gaia/app/genesis.go index fe39bb598a..7c4790de12 100644 --- a/cmd/gaia/app/genesis.go +++ b/cmd/gaia/app/genesis.go @@ -154,7 +154,7 @@ func GaiaAppGenState(cdc *codec.Codec, genDoc tmtypes.GenesisDoc, appGenTxs []js for _, acc := range genesisState.Accounts { for _, coin := range acc.Coins { if coin.Denom == bondDenom { - stakingData.Pool.LooseTokens = stakingData.Pool.LooseTokens. + stakingData.Pool.NotBondedTokens = stakingData.Pool.NotBondedTokens. Add(coin.Amount) // increase the supply } } diff --git a/cmd/gaia/app/genesis_test.go b/cmd/gaia/app/genesis_test.go index 889b74188e..59872e8018 100644 --- a/cmd/gaia/app/genesis_test.go +++ b/cmd/gaia/app/genesis_test.go @@ -44,7 +44,7 @@ func makeGenesisState(t *testing.T, genTxs []auth.StdTx) GenesisState { acc := auth.NewBaseAccountWithAddress(sdk.AccAddress(msg.ValidatorAddr)) acc.Coins = sdk.Coins{sdk.NewInt64Coin(bondDenom, 150)} genAccs[i] = NewGenesisAccount(&acc) - stakingData.Pool.LooseTokens = stakingData.Pool.LooseTokens.Add(sdk.NewInt(150)) // increase the supply + stakingData.Pool.NotBondedTokens = stakingData.Pool.NotBondedTokens.Add(sdk.NewInt(150)) // increase the supply } // create the final app state diff --git a/cmd/gaia/app/sim_test.go b/cmd/gaia/app/sim_test.go index fdacc04c50..a5070a8a70 100644 --- a/cmd/gaia/app/sim_test.go +++ b/cmd/gaia/app/sim_test.go @@ -188,7 +188,7 @@ func appStateFn(r *rand.Rand, accs []simulation.Account, genesisTimestamp time.T delegations = append(delegations, delegation) } - stakingGenesis.Pool.LooseTokens = sdk.NewInt((amount * numAccs) + (numInitiallyBonded * amount)) + stakingGenesis.Pool.NotBondedTokens = sdk.NewInt((amount * numAccs) + (numInitiallyBonded * amount)) stakingGenesis.Validators = validators stakingGenesis.Bonds = delegations diff --git a/docs/gaia/gaiacli.md b/docs/gaia/gaiacli.md index 0ec271b68b..bdc0af58cc 100644 --- a/docs/gaia/gaiacli.md +++ b/docs/gaia/gaiacli.md @@ -499,9 +499,9 @@ gaiacli query staking pool With the `pool` command you will get the values for: -- Loose and bonded tokens +- Not-bonded and bonded tokens - Token supply -- Current anual inflation and the block in which the last inflation was processed +- Current annual inflation and the block in which the last inflation was processed - Last recorded bonded shares ##### Query Delegations To Validator diff --git a/docs/spec/SPEC-SPEC.md b/docs/spec/SPEC-SPEC.md new file mode 100644 index 0000000000..e53fe74b32 --- /dev/null +++ b/docs/spec/SPEC-SPEC.md @@ -0,0 +1,45 @@ +# Specification of Specifications + +This file intends to outline the common structure for specifications within +this directory. + +## Tense + +For consistency, specs should be written in passive present tense. + +## Common Layout + +The following generalized structure should be used to breakdown specifications +for modules. Note that not all files may be required depending on the modules +function + + - `overview.md` - describe module + - `state.md` - specify and describe structures expected to marshalled into the store, and their keys + - `state_transitions.md` - standard state transition operations triggered by by hooks, messages, etc. + - `end_block.md` - specify any end-block operations + - `begin_block.md` - specify any begin-block operations + - `messages.md` - specify message structure and expected state machine behaviour + - `hooks.md` - describe available hooks to be called by/from this module + - `tags.md` - list and describe event tags used + +### Notation for key-value mapping + +Within `state.md` the following notation `->` should be used to describe key to +value mapping: + +``` +key -> value +``` + +to represent byte concatenation the `|` may be used. In addition, encoding +type may be specified, for example: + +``` +0x00 | addressBytes | address2Bytes -> amino(value_object) +``` + +Additionally, index mappings may be specified by mapping to the `nil` value, for example: + +``` +0x01 | address2Bytes | addressBytes -> nil +``` diff --git a/docs/spec/ics/ics-030-signed-messages.md b/docs/spec/_ics/ics-030-signed-messages.md similarity index 100% rename from docs/spec/ics/ics-030-signed-messages.md rename to docs/spec/_ics/ics-030-signed-messages.md diff --git a/docs/spec/spec-proposals/f1-fee-distribution/f1_fee_distr.pdf b/docs/spec/_proposals/f1-fee-distribution/f1_fee_distr.pdf similarity index 100% rename from docs/spec/spec-proposals/f1-fee-distribution/f1_fee_distr.pdf rename to docs/spec/_proposals/f1-fee-distribution/f1_fee_distr.pdf diff --git a/docs/spec/spec-proposals/f1-fee-distribution/f1_fee_distr.tex b/docs/spec/_proposals/f1-fee-distribution/f1_fee_distr.tex similarity index 100% rename from docs/spec/spec-proposals/f1-fee-distribution/f1_fee_distr.tex rename to docs/spec/_proposals/f1-fee-distribution/f1_fee_distr.tex diff --git a/docs/spec/other/bech32.md b/docs/spec/addresses/bech32.md similarity index 100% rename from docs/spec/other/bech32.md rename to docs/spec/addresses/bech32.md diff --git a/docs/spec/bank/transactions.md b/docs/spec/bank/messages.md similarity index 96% rename from docs/spec/bank/transactions.md rename to docs/spec/bank/messages.md index 7cb512405e..fd9331763e 100644 --- a/docs/spec/bank/transactions.md +++ b/docs/spec/bank/messages.md @@ -1,4 +1,4 @@ -## Transactions +## Messages ### MsgSend diff --git a/docs/spec/distribution/transactions.md b/docs/spec/distribution/messages.md similarity index 99% rename from docs/spec/distribution/transactions.md rename to docs/spec/distribution/messages.md index 57c4d31035..32de590f6e 100644 --- a/docs/spec/distribution/transactions.md +++ b/docs/spec/distribution/messages.md @@ -1,4 +1,4 @@ -# Transactions +# Messages ## MsgWithdrawDelegationRewardsAll diff --git a/docs/spec/governance/transactions.md b/docs/spec/governance/messages.md similarity index 99% rename from docs/spec/governance/transactions.md rename to docs/spec/governance/messages.md index 68966bcfc4..17004e4b87 100644 --- a/docs/spec/governance/transactions.md +++ b/docs/spec/governance/messages.md @@ -1,6 +1,6 @@ # Implementation (2/2) -## Transactions +## Messages ### Proposal Submission diff --git a/docs/spec/inflation/end_block.md b/docs/spec/inflation/end_block.md deleted file mode 100644 index 49408a3f06..0000000000 --- a/docs/spec/inflation/end_block.md +++ /dev/null @@ -1,52 +0,0 @@ -# End Block - -Validator provisions are minted on an hourly basis (the first block of a new -hour). The annual target of between 7% and 20%. The long-term target ratio of -bonded tokens to unbonded tokens is 67%. - -The target annual inflation rate is recalculated for each provisions cycle. The -inflation is also subject to a rate change (positive or negative) depending on -the distance from the target ratio (67%). The maximum rate change possible is -defined to be 13% per year, however the annual inflation is capped as between -7% and 20%. - -Within the inflation module the tokens are created, and fed to the distribution -module to be further processed and distributed similarly to fee distribution (with -the exception that there are no special rewards for the block proposer) - -Note that params are global params (TODO: link to the global params spec) - -``` -EndBlock(): - - //process provisions - hrsPerYr = 8766 // as defined by a julian year of 365.25 days - precision = 10000 - - time = BFTTime() // time is in seconds - if time > GetInflationLastTime() + 3600 - SetInflationLastTime(InflationLastTime + 3600) - inflation = nextInflation(hrsPerYr).Round(precision) - SetInflation(inflation) - - provisions = inflation * (pool.TotalSupply() / hrsPerYr) - pool.LooseTokens += provisions - - distribution.AddInflation(provisions) - -nextInflation(hrsPerYr rational.Rat): - - bondedRatio = pool.BondedPool / pool.TotalSupply() - - inflationRateChangePerYear = (1 - bondedRatio / params.GoalBonded) * params.InflationRateChange - inflationRateChange = inflationRateChangePerYear / hrsPerYr - - inflation = GetInflation() + inflationRateChange - switch inflation - case > params.InflationMax - return params.InflationMax - case < params.InflationMin - return params.InflationMin - default - return inflation -``` diff --git a/docs/spec/inflation/state.md b/docs/spec/inflation/state.md deleted file mode 100644 index c16286804a..0000000000 --- a/docs/spec/inflation/state.md +++ /dev/null @@ -1,21 +0,0 @@ -## State - -### Inflation - - key: `0x00` - - value: `amino(Inflation)` - -The current annual inflation rate. - -```golang -type Inflation sdk.Dec -``` - -### InflationLastTime - - key: `0x01` - - value: `amino(InflationLastTime)` - -The last unix time which the inflation was processed for. - -```golang -type InflationLastTime int64 -``` diff --git a/docs/spec/other/other.md b/docs/spec/other/other.md deleted file mode 100644 index 0ba8e612ca..0000000000 --- a/docs/spec/other/other.md +++ /dev/null @@ -1,2 +0,0 @@ -- reserve pool -- AiB vesting diff --git a/docs/spec/reserve-pool/TODO.md b/docs/spec/reserve-pool/TODO.md new file mode 100644 index 0000000000..b3232fef32 --- /dev/null +++ b/docs/spec/reserve-pool/TODO.md @@ -0,0 +1,5 @@ +TODO + +The reserve pool is the pool of collected funds for use by governance taken via the `CommunityTax`. +Currently with the SDK, tokens collected by the CommunityTax are accounted for but unspendable. + diff --git a/docs/spec/slashing/transactions.md b/docs/spec/slashing/messages.md similarity index 90% rename from docs/spec/slashing/transactions.md rename to docs/spec/slashing/messages.md index 6642acbb8e..342f3468bd 100644 --- a/docs/spec/slashing/transactions.md +++ b/docs/spec/slashing/messages.md @@ -1,6 +1,6 @@ -## Transactions +## Messages -In this section we describe the processing of transactions for the `slashing` module. +In this section we describe the processing of messages for the `slashing` module. ### Unjail diff --git a/docs/spec/staking/TODO.md b/docs/spec/staking/TODO.md new file mode 100644 index 0000000000..efef4991c0 --- /dev/null +++ b/docs/spec/staking/TODO.md @@ -0,0 +1,7 @@ + + - `state.md` needs updates to include + - LastValidatorPower + - LastTotalPower + - state for the queues: UnbondingDelegation, UnbondingValidator, Redelegation + - introduce `state_transitions.md` to describe validator/delegator state + transitions which are called from transactions diff --git a/docs/spec/staking/end_block.md b/docs/spec/staking/end_block.md index e1d769ed46..a6cb307658 100644 --- a/docs/spec/staking/end_block.md +++ b/docs/spec/staking/end_block.md @@ -1,68 +1,62 @@ # End-Block -## Unbonding Validator Queue - -For all unbonding validators that have finished their unbonding period, this switches their validator.Status -from sdk.Unbonding to sdk.Unbonded if they still have any delegation left. Otherwise, it deletes it from state. - -```golang -validatorQueue(currTime time.Time): - // unbonding validators are in ordered queue from oldest to newest - for all unbondingValidators whose CompleteTime < currTime: - validator = GetValidator(unbondingValidator.ValidatorAddr) - if validator.DelegatorShares == 0 { - RemoveValidator(unbondingValidator) - } else { - validator.Status = sdk.Unbonded - SetValidator(unbondingValidator) - } - return -``` +Each abci end block call, the operations to update queues and validator set +changes are specified to execute. ## Validator Set Changes -The Tendermint validator set may be updated by state transitions that run at -the end of every block. The Tendermint validator set may be changed by -validators either being jailed due to inactivity/unexpected behaviour (covered -in slashing) or changed in validator power. Determining which validator set -changes must be made occurs during staking transactions (and slashing -transactions) - during end-block the already accounted changes are applied and -the changes cleared +The staking validator set is updated during this process by state transitions +that run at the end of every block. As a part of this process any updated +validators are also returned back to Tendermint for inclusion in the Tendermint +validator set which is responsible for validating Tendermint messages at the +consensus layer. Operations are as following: -```golang -EndBlock() ValidatorSetChanges - vsc = GetValidTendermintUpdates() - ClearTendermintUpdates() - return vsc -``` + - the new validator set is taken as the top `params.MaxValidators` number of + validators retrieved from the ValidatorsByPower index + - the previous validator set is compared with the new validator set + - missing validators begin unbonding + - new validator are instantly bonded -## CompleteUnbonding +In all cases, any validators leaving or entering the bonded validator set or +changing balances and staying within the bonded validator set incur an update +message which is passed back to Tendermint. -Complete the unbonding and transfer the coins to the delegate. Realize any -slashing that occurred during the unbonding period. +## Queues -```golang -unbondingQueue(currTime time.Time): - // unbondings are in ordered queue from oldest to newest - for all unbondings whose CompleteTime < currTime: - validator = GetValidator(unbonding.ValidatorAddr) - AddCoins(unbonding.DelegatorAddr, unbonding.Balance) - removeUnbondingDelegation(unbonding) - return -``` +Within staking, certain state-transitions are not instantaneous but take place +over a duration of time (typically the unbonding period). When these +transitions are mature certain operations must take place in order to complete +the state operation. This is achieved through the use of queues which are +checked/processed at the end of each block. -## CompleteRedelegation +### Unbonding Validators -Note that unlike CompleteUnbonding slashing of redelegating shares does not -take place during completion. Slashing on redelegated shares takes place -actively as a slashing occurs. The redelegation completion queue serves simply to -clean up state, as redelegations older than an unbonding period need not be kept, -as that is the max time that their old validator's evidence can be used to slash them. +When a validator is kicked out of the bonded validator set (either through +being jailed, or not having sufficient bonded tokens) it begins the unbonding +process along with all its delegations begin unbonding (while still being +delegated to this validator). At this point the validator is said to be an +unbonding validator, whereby it will mature to become an "unbonded validator" +after the unbonding period has passed. -```golang -redelegationQueue(currTime time.Time): - // redelegations are in ordered queue from oldest to newest - for all redelegations whose CompleteTime < currTime: - removeRedelegation(redelegation) - return -``` +Each block the validator queue is to be checked for mature unbonding +validators. For all unbonding validators that have finished their unbonding +period, the validator.Status is switched from sdk.Unbonding to sdk.Unbonded. +If at this switch they do not have any delegation left the validator object +instead just deleted from state. + +### Unbonding Delegations + +Complete the unbonding of all mature `UnbondingDelegations.Entries` within the +`UnbondingDelegations` queue with the following procedure: + - transfer the balance coins to the delegator's wallet address + - remove the mature entry from `UnbondingDelegation.Entries` + - remove the `UnbondingDelegation` object from the store if there are no + remaining entries. + +### Redelegations + +Complete the unbonding of all mature `Redelegation.Entries` within the +`Redelegations` queue with the following procedure: + - remove the mature entry from `Redelegation.Entries` + - remove the `Redelegation` object from the store if there are no + remaining entries. diff --git a/docs/spec/staking/hooks.md b/docs/spec/staking/hooks.md index 3644155a67..85fcc69cc4 100644 --- a/docs/spec/staking/hooks.md +++ b/docs/spec/staking/hooks.md @@ -1,19 +1,25 @@ -## Receiver Hooks +# Hooks -The staking module allow for the following hooks to be registered with staking events: +Other modules may register operations to execute when a certain event has +occurred within staking. These events can be registered to execute either +right `Before` or `After` the staking event (as per the hook name). The +following hooks can registered with staking: -``` golang -// event hooks for staking validator object -type StakingHooks interface { - OnValidatorCreated(ctx Context, address ValAddress) // Must be called when a validator is created - OnValidatorModified(ctx Context, address ValAddress) // Must be called when a validator's state changes - OnValidatorRemoved(ctx Context, address ConsAddress, operator ValAddress) // Must be called when a validator is deleted - - OnValidatorBonded(ctx Context, address ConsAddress) // called when a validator is bonded - OnValidatorBeginUnbonding(ctx Context, address ConsAddress, operator ValAddress) // called when a validator begins unbonding - - OnDelegationCreated(ctx Context, delAddr AccAddress, valAddr ValAddress) // called when a delegation is created - OnDelegationSharesModified(ctx Context, delAddr AccAddress, valAddr ValAddress) // called when a delegation's shares are modified - OnDelegationRemoved(ctx Context, delAddr AccAddress, valAddr ValAddress) // called when a delegation is removed -} -``` + - `AfterValidatorCreated(Context, ValAddress)` + - called when a validator is created + - `BeforeValidatorModified(Context, ValAddress)` + - called when a validator's state is changed + - `AfterValidatorRemoved(Context, ConsAddress, ValAddress)` + - called when a validator is deleted + - `AfterValidatorBonded(Context, ConsAddress, ValAddress)` + - called when a validator is bonded + - `AfterValidatorBeginUnbonding(Context, ConsAddress, ValAddress)` + - called when a validator begins unbonding + - `AfterValidatorPowerDidChange(Context, ConsAddress, ValAddress)` + - called at EndBlock when a validator's power is changed + - `BeforeDelegationCreated(Context, AccAddress, ValAddress)` + - called when a delegation is created + - `BeforeDelegationSharesModified(Context, AccAddress, ValAddress)` + - called when a delegation's shares are modified + - `BeforeDelegationRemoved(Context, AccAddress, ValAddress)` + - called when a delegation is removed diff --git a/docs/spec/staking/messages.md b/docs/spec/staking/messages.md new file mode 100644 index 0000000000..7af6e6cccb --- /dev/null +++ b/docs/spec/staking/messages.md @@ -0,0 +1,167 @@ +# Messages + +In this section we describe the processing of the staking messages and the +corresponding updates to the state. All created/modified state objects +specified by each message are defined within [state.md](state.md). + +## MsgCreateValidator + +A validator is created using the `MsgCreateValidator` message. + +```golang +type MsgCreateValidator struct { + Description Description + Commission Commission + + DelegatorAddr sdk.AccAddress + ValidatorAddr sdk.ValAddress + PubKey crypto.PubKey + Delegation sdk.Coin +} +``` + +This message is expected to fail if: + + - another validator with this operator address is already registered + - another validator with this pubkey is already registered + - the initial self-delegation tokens are of a denom not specified as the + bonding denom + - the commission parameters are faulty, namely: + - `MaxRate` is either > 1 or < 0 + - the initial `Rate` is either negative or > `MaxRate` + - the initial `MaxChangeRate` is either negative or > `MaxRate` + - the description fields are too large + +This message creates and stores the `Validator` object at appropriate indexes. +Additionally a self-delegation is made with the initial tokens delegation +tokens `Delegation`. The validator always starts as unbonded but may be bonded +in the first end-block. + + +## MsgEditValidator + +The `Description`, `CommissionRate` of a validator can be updated using the +`MsgEditCandidacy`. + +```golang +type MsgEditCandidacy struct { + Description Description + ValidatorAddr sdk.ValAddress + CommissionRate sdk.Dec +} +``` + +This message is expected to fail if: + + - the initial `CommissionRate` is either negative or > `MaxRate` + - the `CommissionRate` has already been updated within the previous 24 hours + - the `CommissionRate` is > `MaxChangeRate` + - the description fields are too large + +This message stores the updated `Validator` object. + +## MsgDelegate + +Within this message the delegator provides coins, and in return receives +some amount of their validator's (newly created) delegator-shares that are +assigned to `Delegation.Shares`. + +```golang +type MsgDelegate struct { + DelegatorAddr sdk.AccAddress + ValidatorAddr sdk.ValAddress + Delegation sdk.Coin +} +``` + +This message is expected to fail if: + + - the validator is does not exist + - the validator is jailed + +If an existing `Delegation` object for provided addresses does not already +exist than it is created as part of this message otherwise the existing +`Delegation` is updated to include the newly received shares. + +## MsgBeginUnbonding + +The begin unbonding message allows delegators to undelegate their tokens from +validator. + +```golang +type MsgBeginUnbonding struct { + DelegatorAddr sdk.AccAddress + ValidatorAddr sdk.ValAddress + SharesAmount sdk.Dec +} +``` + +This message is expected to fail if: + + - the delegation doesn't exist + - the validator doesn't exist + - the delegation has less shares than `SharesAmount` + +When this message is processed the following actions occur: + - validator's `DelegatorShares` and the delegation's `Shares` are both reduced + by the message `SharesAmount` + - calculate the token worth of the shares remove that amount tokens held + within the validator + - with those removed tokens, if the validator is: + - bonded - add them to an entry in `UnbondingDelegation` (create + `UnbondingDelegation` if it doesn't exist) with a completion time a full + unbonding period from the current time. Update pool shares to reduce + BondedTokens and increase NotBondedTokens by token worth of the shares. + - unbonding - add them to an entry in `UnbondingDelegation` (create + `UnbondingDelegation` if it doesn't exist) with the same completion time + as the validator (`UnbondingMinTime`). + - unbonded - then send the coins the message `DelegatorAddr` + - if there are no more `Shares` in the delegation, then the delegation object + is removed from the store + - under this situation if the delegation is the validator's self-delegation + then also jail the validator. + +## MsgBeginRedelegate + +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 MsgBeginRedelegate struct { + DelegatorAddr sdk.AccAddress + ValidatorSrcAddr sdk.ValAddress + ValidatorDstAddr sdk.ValAddress + SharesAmount sdk.Dec +} +``` + +This message is expected to fail if: + + - the delegation doesn't exist + - the source or destination validators don't exist + - the delegation has less shares than `SharesAmount` + - the source validator has a receiving redelegation which + is not matured (aka. the redelegation may be transitive) + +When this message is processed the following actions occur: + - the source validator's `DelegatorShares` and the delegations `Shares` are + both reduced by the message `SharesAmount` + - calculate the token worth of the shares remove that amount tokens held + within the source validator. + - if the source validator is: + - bonded - add an entry to the `Redelegation` (create + `Redelegation` if it doesn't exist) with a completion time a full + unbonding period from the current time. Update pool shares to reduce + BondedTokens and increase NotBondedTokens by token worth of the shares + (this may be effectively reversed in the next step however). + - unbonding - add an entry to the `Redelegation` (create `Redelegation` if + it doesn't exist) with the same completion time as the validator + (`UnbondingMinTime`). + - unbonded - no action required in this step + - Delegate the token worth to the destination validator, possibly moving + tokens back to the bonded state. + - if there are no more `Shares` in the source delegation, then the source + delegation object is removed from the store + - under this situation if the delegation is the validator's self-delegation + then also jail the validator. diff --git a/docs/spec/staking/README.md b/docs/spec/staking/overview.md similarity index 63% rename from docs/spec/staking/README.md rename to docs/spec/staking/overview.md index 16ce96a05d..02a0b3b02b 100644 --- a/docs/spec/staking/README.md +++ b/docs/spec/staking/overview.md @@ -20,19 +20,25 @@ The following specification uses *Atom* as the native staking token. The module can be adapted to any Proof-Of-Stake blockchain by replacing *Atom* with the native staking token of the chain. -1. **[State](state.md)** - 1. Params - 1. Pool - 2. Validators - 3. Delegations -2. **[Transactions](transactions.md)** - 1. Create-Validator - 2. Edit-Validator - 3. Repeal-Revocation - 4. Delegate - 5. Unbond - 6. Redelegate -3. **[Validator Set Changes](valset-changes.md)** - 1. Validator set updates - 2. Slashing - 3. Automatic Unbonding + 1. **[State](state.md)** + - Pool + - Params + - Validator + - Delegation + - UnbondingDelegation + - Redelegation + 2. **[Messages](messages.md)** + - MsgCreateValidator + - MsgEditValidator + - MsgDelegate + - MsgBeginUnbonding + - MsgBeginRedelegate + 3. **[End-Block](end_block.md)** + - Validator Set Changes + - Queues + - Unbonding Validators + - Unbonding Delegations + - Redelegations + 4. **[Hooks](hooks.md)** + 5. **[Tags](tags.md)** + diff --git a/docs/spec/staking/state.md b/docs/spec/staking/state.md index 9cecf1c361..5e8f4d3277 100644 --- a/docs/spec/staking/state.md +++ b/docs/spec/staking/state.md @@ -1,66 +1,67 @@ -## State +# State -### Pool +## 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, moving Atom -inflation information, etc. +The pool tracks the total amounts of tokens (each staking denom is tracked +separately) and their state (bonded or loose). + +Note: `NotBondedTokens` _includes_ both tokens in an `unbonding` state as well +as fully `unbonded` state. - Pool: `0x01 -> amino(pool)` ```golang type Pool struct { - LooseTokens sdk.Int // tokens not associated with any bonded validator - BondedTokens sdk.Int // reserve of bonded tokens + NotBondedTokens sdk.Int // tokens not associated with any bonded validator + BondedTokens sdk.Int // reserve of bonded tokens } ``` -### Params +## Params -Params is global data structure that stores system parameters and defines -overall functioning of the staking module. +Params is a module-wide configuration structure that stores system parameters +and defines overall functioning of the staking module. - - Params: `0x00 -> amino(params)` + - Params: `Paramsspace("staking") -> amino(params)` ```golang type Params struct { - MaxValidators uint16 // maximum number of validators - BondDenom string // bondable coin denomination + UnbondingTime time.Duration // time duration of unbonding + MaxValidators uint16 // maximum number of validators + BondDenom string // bondable coin denomination } ``` -### Validator +## Validator -Validators are identified according to the `OperatorAddr`, an SDK validator -address for the operator of the validator. +Validators objects should be primarily stored and accessed by the +`OperatorAddr`, an SDK validator address for the operator of the validator. Two +additional indexes are maintained in order to fulfill required lookups for +slashing and validator-set updates. -Validators also have a `ConsPubKey`, the public key of the validator used in -Tendermint consensus. The validator can be retrieved from it's `ConsPubKey` -once it can be converted into the corresponding `ConsAddr`. Validators are -indexed in the store using the following maps: - -- Validators: `0x02 | OperatorAddr -> amino(validator)` -- ValidatorsByConsAddr: `0x03 | ConsAddr -> OperatorAddr` -- ValidatorsByPower: `0x05 | power | blockHeight | blockTx -> OperatorAddr` +- Validators: `0x21 | OperatorAddr -> amino(validator)` +- ValidatorsByConsAddr: `0x22 | ConsAddr -> OperatorAddr` +- ValidatorsByPower: `0x23 | BigEndian(Tokens) | OperatorAddr -> OperatorAddr` `Validators` is the primary index - it ensures that each operator can have only one associated validator, where the public key of that validator can change in the future. Delegators can refer to the immutable operator of the validator, without concern for the changing public key. -`ValidatorsByPubKey` is a secondary index that enables lookups for slashing. +`ValidatorByConsAddr` 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 operator. +map is needed to find the operator. Note that the `ConsAddr` corresponds to the +address which can be derived from the validator's `ConsPubKey`. `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. +potential validators to quickly determine the current active set. Note +that all validators where `Jailed` is true are not stored within this index. -The `Validator` holds the current state and some historical actions of the -validator. +Each validator's state is stored in a `Validator` struct: ```golang type Validator struct { + OperatorAddr sdk.ValAddress // address of the validator's operator; bech encoded in JSON ConsPubKey crypto.PubKey // Tendermint consensus pubkey of validator Jailed bool // has the validator been jailed? @@ -68,21 +69,20 @@ type Validator struct { Tokens sdk.Int // delegated tokens (incl. self-delegation) DelegatorShares sdk.Dec // total shares issued to a validator's delegators - Description Description // description terms for the validator + Description Description // description terms for the validator // Needed for ordering vals in the by-power key - BondHeight int64 // earliest height as a bonded validator - BondIntraTxCounter int16 // block-local tx index of validator change + UnbondingHeight int64 // if unbonding, height at which this validator has begun unbonding + UnbondingMinTime time.Time // if unbonding, min time for the validator to complete unbonding - CommissionInfo CommissionInfo // info about the validator's commission + Commission Commission // info about the validator's commission } -type CommissionInfo struct { - Rate sdk.Dec // the commission rate of fees charged to any delegators - Max sdk.Dec // maximum commission rate which this validator can ever charge - ChangeRate sdk.Dec // maximum daily increase of the validator commission - ChangeToday sdk.Dec // commission rate change today, reset each day (UTC time) - LastChange int64 // unix timestamp of last commission change +type Commission struct { + Rate sdk.Dec // the commission rate charged to delegators + MaxRate sdk.Dec // maximum commission rate which this validator can ever charge + MaxChangeRate sdk.Dec // maximum daily increase of the validator commission + UpdateTime time.Time // the last time the commission rate was changed } type Description struct { @@ -93,12 +93,12 @@ type Description struct { } ``` -### Delegation +## Delegation Delegations are identified by combining `DelegatorAddr` (the address of the delegator) with the `ValidatorAddr` Delegators are indexed in the store as follows: -- Delegation: ` 0x0A | DelegatorAddr | ValidatorAddr -> amino(delegation)` +- Delegation: ` 0x31 | DelegatorAddr | ValidatorAddr -> 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 @@ -113,7 +113,7 @@ type Delegation struct { } ``` -### UnbondingDelegation +## UnbondingDelegation Shares in a `Delegation` can be unbonded, but they must for some time exist as an `UnbondingDelegation`, where shares can be reduced if Byzantine behavior is @@ -121,9 +121,9 @@ detected. `UnbondingDelegation` are indexed in the store as: -- UnbondingDelegationByDelegator: ` 0x0B | DelegatorAddr | ValidatorAddr -> +- UnbondingDelegation: ` 0x32 | DelegatorAddr | ValidatorAddr -> amino(unbondingDelegation)` -- UnbondingDelegationByValOwner: ` 0x0C | ValidatorAddr | DelegatorAddr | ValidatorAddr -> +- UnbondingDelegationsFromValidator: ` 0x33 | ValidatorAddr | DelegatorAddr -> nil` The first map here is used in queries, to lookup all unbonding delegations for @@ -132,8 +132,6 @@ 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. ```golang type UnbondingDelegation struct { @@ -150,31 +148,30 @@ type UnbondingDelegationEntry struct { } ``` -### Redelegation +## Redelegation -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 -behavior is detected. This is tracked as moving a delegation from a `ValidatorSrcAddr` -to a `ValidatorDstAddr`. +The bonded tokens worth of a `Delegation` may be instantly redelegated from a +source validator to a different validator (destination validator). However when +this occurs they must be tracked in a `Redelegation` object, whereby their +shares can be slashed if their tokens have contributed to a Byzantine fault +committed by the source validator. `Redelegation` are indexed in the store as: - - Redelegations: `0x0D | DelegatorAddr | ValidatorSrcAddr | ValidatorDstAddr -> - amino(redelegation)` - - RedelegationsBySrc: `0x0E | ValidatorSrcAddr | ValidatorDstAddr | - DelegatorAddr -> nil` - - RedelegationsByDst: `0x0F | ValidatorDstAddr | ValidatorSrcAddr | DelegatorAddr - -> nil` + - Redelegations: `0x34 | DelegatorAddr | ValidatorSrcAddr | ValidatorDstAddr -> amino(redelegation)` + - RedelegationsBySrc: `0x35 | ValidatorSrcAddr | ValidatorDstAddr | DelegatorAddr -> nil` + - RedelegationsByDst: `0x36 | ValidatorDstAddr | ValidatorSrcAddr | 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 `ValidatorSrcAddr`, -while the third map is for slashing based on the ToValOwnerAddr. +while the third map is for slashing based on the `ValidatorDstAddr`. -A redelegation object is created every time a redelegation occurs. The -redelegation must be completed with a second transaction provided by the -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. +A redelegation object is created every time a redelegation occurs. To prevent +"redelegation hopping" redelegations may not occure under the situation that: + - the (re)delegator already has another unmature redelegation in progress + with a destination to a validator (let's call it `Validator X`) + - and, the (re)delegator is attempting to create a _new_ redelegation + where the source validator for this new redelegation is `Validator-X`. ```golang type Redelegation struct { diff --git a/docs/spec/staking/transactions.md b/docs/spec/staking/transactions.md deleted file mode 100644 index 55dc2deb3d..0000000000 --- a/docs/spec/staking/transactions.md +++ /dev/null @@ -1,312 +0,0 @@ -# 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. -* `sdk.Int` refers to an integer 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 -``` diff --git a/x/distribution/keeper/test_common.go b/x/distribution/keeper/test_common.go index 793f557738..420f40ac49 100644 --- a/x/distribution/keeper/test_common.go +++ b/x/distribution/keeper/test_common.go @@ -122,7 +122,7 @@ func CreateTestInputAdvanced(t *testing.T, isCheckTx bool, initCoins int64, {sk.GetParams(ctx).BondDenom, sdk.NewInt(initCoins)}, }) require.Nil(t, err) - pool.LooseTokens = pool.LooseTokens.Add(sdk.NewInt(initCoins)) + pool.NotBondedTokens = pool.NotBondedTokens.Add(sdk.NewInt(initCoins)) sk.SetPool(ctx, pool) } diff --git a/x/gov/test_common.go b/x/gov/test_common.go index 4c6c2607d0..f030d7b84c 100644 --- a/x/gov/test_common.go +++ b/x/gov/test_common.go @@ -68,7 +68,7 @@ func getInitChainer(mapp *mock.App, keeper Keeper, stakingKeeper staking.Keeper, mapp.InitChainer(ctx, req) stakingGenesis := staking.DefaultGenesisState() - stakingGenesis.Pool.LooseTokens = sdk.NewInt(100000) + stakingGenesis.Pool.NotBondedTokens = sdk.NewInt(100000) validators, err := staking.InitGenesis(ctx, stakingKeeper, stakingGenesis) if err != nil { diff --git a/x/slashing/app_test.go b/x/slashing/app_test.go index b198aaa248..3662d7faaf 100644 --- a/x/slashing/app_test.go +++ b/x/slashing/app_test.go @@ -60,7 +60,7 @@ func getInitChainer(mapp *mock.App, keeper staking.Keeper) sdk.InitChainer { return func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { mapp.InitChainer(ctx, req) stakingGenesis := staking.DefaultGenesisState() - stakingGenesis.Pool.LooseTokens = sdk.NewInt(100000) + stakingGenesis.Pool.NotBondedTokens = sdk.NewInt(100000) validators, err := staking.InitGenesis(ctx, keeper, stakingGenesis) if err != nil { panic(err) diff --git a/x/slashing/test_common.go b/x/slashing/test_common.go index 97bd477e9b..c2e7c2e87f 100644 --- a/x/slashing/test_common.go +++ b/x/slashing/test_common.go @@ -76,7 +76,7 @@ func createTestInput(t *testing.T, defaults Params) (sdk.Context, bank.Keeper, s sk := staking.NewKeeper(cdc, keyStaking, tkeyStaking, ck, paramsKeeper.Subspace(staking.DefaultParamspace), staking.DefaultCodespace) genesis := staking.DefaultGenesisState() - genesis.Pool.LooseTokens = sdk.NewInt(initCoins.MulRaw(int64(len(addrs))).Int64()) + genesis.Pool.NotBondedTokens = sdk.NewInt(initCoins.MulRaw(int64(len(addrs))).Int64()) _, err = staking.InitGenesis(ctx, sk, genesis) require.Nil(t, err) diff --git a/x/staking/app_test.go b/x/staking/app_test.go index f4c35d2450..f95bce1326 100644 --- a/x/staking/app_test.go +++ b/x/staking/app_test.go @@ -52,7 +52,7 @@ func getInitChainer(mapp *mock.App, keeper Keeper) sdk.InitChainer { mapp.InitChainer(ctx, req) stakingGenesis := DefaultGenesisState() - stakingGenesis.Pool.LooseTokens = sdk.NewInt(100000) + stakingGenesis.Pool.NotBondedTokens = sdk.NewInt(100000) validators, err := InitGenesis(ctx, keeper, stakingGenesis) if err != nil { diff --git a/x/staking/handler.go b/x/staking/handler.go index bfb50898f0..1b8813a191 100644 --- a/x/staking/handler.go +++ b/x/staking/handler.go @@ -108,10 +108,16 @@ func handleMsgCreateValidator(ctx sdk.Context, msg types.MsgCreateValidator, k k return ErrBadDenom(k.Codespace()).Result() } + if _, err := msg.Description.EnsureLength(); err != nil { + return err.Result() + } + if ctx.ConsensusParams() != nil { tmPubKey := tmtypes.TM2PB.PubKey(msg.PubKey) if !common.StringInSlice(tmPubKey.Type, ctx.ConsensusParams().Validator.PubKeyTypes) { - return ErrValidatorPubKeyTypeUnsupported(k.Codespace(), tmPubKey.Type, ctx.ConsensusParams().Validator.PubKeyTypes).Result() + return ErrValidatorPubKeyTypeUnsupported(k.Codespace(), + tmPubKey.Type, + ctx.ConsensusParams().Validator.PubKeyTypes).Result() } } diff --git a/x/staking/keeper/delegation.go b/x/staking/keeper/delegation.go index 619a05e694..553f4097b8 100644 --- a/x/staking/keeper/delegation.go +++ b/x/staking/keeper/delegation.go @@ -308,11 +308,10 @@ func (k Keeper) HasReceivingRedelegation(ctx sdk.Context, iterator := sdk.KVStorePrefixIterator(store, prefix) defer iterator.Close() - found := false if iterator.Valid() { - found = true + return true } - return found + return false } // set a redelegation and associated index diff --git a/x/staking/keeper/delegation_test.go b/x/staking/keeper/delegation_test.go index 84b4581e0e..3b4243319a 100644 --- a/x/staking/keeper/delegation_test.go +++ b/x/staking/keeper/delegation_test.go @@ -176,7 +176,7 @@ func TestUnbondingDelegation(t *testing.T) { func TestUnbondDelegation(t *testing.T) { ctx, _, keeper := CreateTestInput(t, false, 0) pool := keeper.GetPool(ctx) - pool.LooseTokens = sdk.NewInt(10) + pool.NotBondedTokens = sdk.NewInt(10) //create a validator and a delegator to that validator validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) @@ -208,7 +208,7 @@ func TestUnbondDelegation(t *testing.T) { require.Equal(t, int64(4), delegation.Shares.RoundInt64()) require.Equal(t, int64(4), validator.BondedTokens().Int64()) - require.Equal(t, int64(6), pool.LooseTokens.Int64(), "%v", pool) + require.Equal(t, int64(6), pool.NotBondedTokens.Int64(), "%v", pool) require.Equal(t, int64(4), pool.BondedTokens.Int64()) } @@ -218,7 +218,7 @@ func TestUndelegateSelfDelegation(t *testing.T) { ctx, _, keeper := CreateTestInput(t, false, 0) pool := keeper.GetPool(ctx) - pool.LooseTokens = sdk.NewInt(20) + pool.NotBondedTokens = sdk.NewInt(20) //create a validator with a self-delegation validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) @@ -265,7 +265,7 @@ func TestUndelegateSelfDelegation(t *testing.T) { func TestUndelegateFromUnbondingValidator(t *testing.T) { ctx, _, keeper := CreateTestInput(t, false, 0) pool := keeper.GetPool(ctx) - pool.LooseTokens = sdk.NewInt(20) + pool.NotBondedTokens = sdk.NewInt(20) //create a validator with a self-delegation validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) @@ -342,7 +342,7 @@ func TestUndelegateFromUnbondingValidator(t *testing.T) { func TestUndelegateFromUnbondedValidator(t *testing.T) { ctx, _, keeper := CreateTestInput(t, false, 0) pool := keeper.GetPool(ctx) - pool.LooseTokens = sdk.NewInt(20) + pool.NotBondedTokens = sdk.NewInt(20) //create a validator with a self-delegation validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) @@ -421,7 +421,7 @@ func TestUndelegateFromUnbondedValidator(t *testing.T) { func TestUnbondingAllDelegationFromValidator(t *testing.T) { ctx, _, keeper := CreateTestInput(t, false, 0) pool := keeper.GetPool(ctx) - pool.LooseTokens = sdk.NewInt(20) + pool.NotBondedTokens = sdk.NewInt(20) //create a validator with a self-delegation validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) @@ -571,7 +571,7 @@ func TestRedelegation(t *testing.T) { func TestRedelegateToSameValidator(t *testing.T) { ctx, _, keeper := CreateTestInput(t, false, 0) pool := keeper.GetPool(ctx) - pool.LooseTokens = sdk.NewInt(30) + pool.NotBondedTokens = sdk.NewInt(30) // create a validator with a self-delegation validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) @@ -596,7 +596,7 @@ func TestRedelegateToSameValidator(t *testing.T) { func TestRedelegateSelfDelegation(t *testing.T) { ctx, _, keeper := CreateTestInput(t, false, 0) pool := keeper.GetPool(ctx) - pool.LooseTokens = sdk.NewInt(30) + pool.NotBondedTokens = sdk.NewInt(30) //create a validator with a self-delegation validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) @@ -651,7 +651,7 @@ func TestRedelegateSelfDelegation(t *testing.T) { func TestRedelegateFromUnbondingValidator(t *testing.T) { ctx, _, keeper := CreateTestInput(t, false, 0) pool := keeper.GetPool(ctx) - pool.LooseTokens = sdk.NewInt(30) + pool.NotBondedTokens = sdk.NewInt(30) //create a validator with a self-delegation validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) @@ -735,7 +735,7 @@ func TestRedelegateFromUnbondingValidator(t *testing.T) { func TestRedelegateFromUnbondedValidator(t *testing.T) { ctx, _, keeper := CreateTestInput(t, false, 0) pool := keeper.GetPool(ctx) - pool.LooseTokens = sdk.NewInt(30) + pool.NotBondedTokens = sdk.NewInt(30) //create a validator with a self-delegation validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) diff --git a/x/staking/keeper/sdk_types.go b/x/staking/keeper/sdk_types.go index 265ee4c798..7e610360a5 100644 --- a/x/staking/keeper/sdk_types.go +++ b/x/staking/keeper/sdk_types.go @@ -102,7 +102,7 @@ func (k Keeper) BondedRatio(ctx sdk.Context) sdk.Dec { // when minting new tokens func (k Keeper) InflateSupply(ctx sdk.Context, newTokens sdk.Int) { pool := k.GetPool(ctx) - pool.LooseTokens = pool.LooseTokens.Add(newTokens) + pool.NotBondedTokens = pool.NotBondedTokens.Add(newTokens) k.SetPool(ctx, pool) } diff --git a/x/staking/keeper/slash.go b/x/staking/keeper/slash.go index e747d0dcf4..17c4c644eb 100644 --- a/x/staking/keeper/slash.go +++ b/x/staking/keeper/slash.go @@ -108,11 +108,11 @@ func (k Keeper) Slash(ctx sdk.Context, consAddr sdk.ConsAddress, infractionHeigh tokensToBurn = sdk.MaxInt(tokensToBurn, sdk.ZeroInt()) // defensive. // Deduct from validator's bonded tokens and update the validator. - // The deducted tokens are returned to pool.LooseTokens. + // The deducted tokens are returned to pool.NotBondedTokens. validator = k.RemoveValidatorTokens(ctx, validator, tokensToBurn) pool := k.GetPool(ctx) // Burn the slashed tokens, which are now loose. - pool.LooseTokens = pool.LooseTokens.Sub(tokensToBurn) + pool.NotBondedTokens = pool.NotBondedTokens.Sub(tokensToBurn) k.SetPool(ctx, pool) // Log that a slash occurred! @@ -188,9 +188,9 @@ func (k Keeper) slashUnbondingDelegation(ctx sdk.Context, unbondingDelegation ty k.SetUnbondingDelegation(ctx, unbondingDelegation) pool := k.GetPool(ctx) - // Burn loose tokens + // Burn not-bonded tokens // Ref https://github.com/cosmos/cosmos-sdk/pull/1278#discussion_r198657760 - pool.LooseTokens = pool.LooseTokens.Sub(unbondingSlashAmount) + pool.NotBondedTokens = pool.NotBondedTokens.Sub(unbondingSlashAmount) k.SetPool(ctx, pool) } @@ -259,9 +259,9 @@ func (k Keeper) slashRedelegation(ctx sdk.Context, validator types.Validator, re panic(fmt.Errorf("error unbonding delegator: %v", err)) } - // Burn loose tokens + // Burn not-bonded tokens pool := k.GetPool(ctx) - pool.LooseTokens = pool.LooseTokens.Sub(tokensToBurn) + pool.NotBondedTokens = pool.NotBondedTokens.Sub(tokensToBurn) k.SetPool(ctx, pool) } diff --git a/x/staking/keeper/slash_test.go b/x/staking/keeper/slash_test.go index 3ce69b7803..3dc5e1364e 100644 --- a/x/staking/keeper/slash_test.go +++ b/x/staking/keeper/slash_test.go @@ -21,7 +21,7 @@ func setupHelper(t *testing.T, amt int64) (sdk.Context, Keeper, types.Params) { params := keeper.GetParams(ctx) pool := keeper.GetPool(ctx) numVals := 3 - pool.LooseTokens = sdk.NewInt(amt * int64(numVals)) + pool.NotBondedTokens = sdk.NewInt(amt * int64(numVals)) // add numVals validators for i := 0; i < numVals; i++ { @@ -103,7 +103,7 @@ func TestSlashUnbondingDelegation(t *testing.T) { // balance decreased require.Equal(t, sdk.NewInt64Coin(params.BondDenom, 5), ubd.Entries[0].Balance) newPool := keeper.GetPool(ctx) - require.Equal(t, int64(5), oldPool.LooseTokens.Sub(newPool.LooseTokens).Int64()) + require.Equal(t, int64(5), oldPool.NotBondedTokens.Sub(newPool.NotBondedTokens).Int64()) } // tests slashRedelegation @@ -503,8 +503,8 @@ func TestSlashBoth(t *testing.T) { require.Equal(t, sdk.NewInt(3), rdA.Entries[0].Balance.Amount) // read updated pool newPool := keeper.GetPool(ctx) - // loose tokens burned - require.Equal(t, int64(2), oldPool.LooseTokens.Sub(newPool.LooseTokens).Int64()) + // not-bonded tokens burned + require.Equal(t, int64(2), oldPool.NotBondedTokens.Sub(newPool.NotBondedTokens).Int64()) // bonded tokens burned require.Equal(t, int64(3), oldPool.BondedTokens.Sub(newPool.BondedTokens).Int64()) // read updated validator diff --git a/x/staking/keeper/test_common.go b/x/staking/keeper/test_common.go index 9e583790f2..057b82a2a0 100644 --- a/x/staking/keeper/test_common.go +++ b/x/staking/keeper/test_common.go @@ -125,7 +125,7 @@ func CreateTestInput(t *testing.T, isCheckTx bool, initCoins int64) (sdk.Context {keeper.BondDenom(ctx), sdk.NewInt(initCoins)}, }) require.Nil(t, err) - pool.LooseTokens = pool.LooseTokens.Add(sdk.NewInt(initCoins)) + pool.NotBondedTokens = pool.NotBondedTokens.Add(sdk.NewInt(initCoins)) keeper.SetPool(ctx, pool) } diff --git a/x/staking/keeper/val_state_change.go b/x/staking/keeper/val_state_change.go index 1900c589c3..3ddb995fc0 100644 --- a/x/staking/keeper/val_state_change.go +++ b/x/staking/keeper/val_state_change.go @@ -15,7 +15,7 @@ import ( // * Updates the active valset as keyed by LastValidatorPowerKey. // * Updates the total power as keyed by LastTotalPowerKey. // * Updates validator status' according to updated powers. -// * Updates the fee pool bonded vs loose tokens. +// * Updates the fee pool bonded vs not-bonded tokens. // * Updates relevant indices. // It gets called once after genesis, another time maybe after genesis transactions, // then once at every EndBlock. diff --git a/x/staking/keeper/validator.go b/x/staking/keeper/validator.go index 159330cd91..d218ca966c 100644 --- a/x/staking/keeper/validator.go +++ b/x/staking/keeper/validator.go @@ -191,7 +191,7 @@ func (k Keeper) RemoveValidator(ctx sdk.Context, address sdk.ValAddress) { // this happens if shares are zero but tokens are not. // TODO: Remove once https://github.com/cosmos/cosmos-sdk/pull/2958 is merged pool := k.GetPool(ctx) - pool.LooseTokens = pool.LooseTokens.Sub(validator.Tokens) + pool.NotBondedTokens = pool.NotBondedTokens.Sub(validator.Tokens) k.SetPool(ctx, pool) // delete the old validator record diff --git a/x/staking/keeper/validator_test.go b/x/staking/keeper/validator_test.go index 69b0782225..9f605312ae 100644 --- a/x/staking/keeper/validator_test.go +++ b/x/staking/keeper/validator_test.go @@ -75,7 +75,7 @@ func TestUpdateValidatorByPowerIndex(t *testing.T) { pool := keeper.GetPool(ctx) // create a random pool - pool.LooseTokens = sdk.NewInt(10000) + pool.NotBondedTokens = sdk.NewInt(10000) pool.BondedTokens = sdk.NewInt(1234) keeper.SetPool(ctx, pool) @@ -123,7 +123,7 @@ func TestUpdateBondedValidatorsDecreaseCliff(t *testing.T) { keeper.SetParams(ctx, params) // create a random pool - pool.LooseTokens = sdk.NewInt(10000) + pool.NotBondedTokens = sdk.NewInt(10000) pool.BondedTokens = sdk.NewInt(1234) keeper.SetPool(ctx, pool) diff --git a/x/staking/simulation/invariants.go b/x/staking/simulation/invariants.go index 04871240c4..a5759483eb 100644 --- a/x/staking/simulation/invariants.go +++ b/x/staking/simulation/invariants.go @@ -45,7 +45,7 @@ func AllInvariants(ck bank.Keeper, k staking.Keeper, } } -// SupplyInvariants checks that the total supply reflects all held loose tokens, bonded tokens, and unbonding delegations +// SupplyInvariants checks that the total supply reflects all held not-bonded tokens, bonded tokens, and unbonding delegations // nolint: unparam func SupplyInvariants(ck bank.Keeper, k staking.Keeper, f auth.FeeCollectionKeeper, d distribution.Keeper, am auth.AccountKeeper) simulation.Invariant { @@ -85,12 +85,12 @@ func SupplyInvariants(ck bank.Keeper, k staking.Keeper, // add yet-to-be-withdrawn loose = loose.Add(d.GetOutstandingRewards(ctx).AmountOf(stakingTypes.DefaultBondDenom)) - // Loose tokens should equal coin supply plus unbonding delegations + // Not-bonded tokens should equal coin supply plus unbonding delegations // plus tokens on unbonded validators - if !sdk.NewDecFromInt(pool.LooseTokens).Equal(loose) { + if !sdk.NewDecFromInt(pool.NotBondedTokens).Equal(loose) { return fmt.Errorf("loose token invariance:\n"+ - "\tpool.LooseTokens: %v\n"+ - "\tsum of account tokens: %v", pool.LooseTokens, loose) + "\tpool.NotBondedTokens: %v\n"+ + "\tsum of account tokens: %v", pool.NotBondedTokens, loose) } // Bonded tokens should equal sum of tokens with bonded validators diff --git a/x/staking/types/msg.go b/x/staking/types/msg.go index f2f7176fff..7fe7418dda 100644 --- a/x/staking/types/msg.go +++ b/x/staking/types/msg.go @@ -15,8 +15,8 @@ var _, _, _ sdk.Msg = &MsgCreateValidator{}, &MsgEditValidator{}, &MsgDelegate{} // MsgCreateValidator - struct for bonding transactions type MsgCreateValidator struct { - Description - Commission CommissionMsg + Description Description `json:"description"` + Commission CommissionMsg `json:"commission"` DelegatorAddr sdk.AccAddress `json:"delegator_address"` ValidatorAddr sdk.ValAddress `json:"validator_address"` PubKey crypto.PubKey `json:"pubkey"` @@ -62,11 +62,12 @@ func (msg MsgCreateValidator) GetSigners() []sdk.AccAddress { return addrs } +// TODO Remove use of custom struct (no longer necessary) // get the bytes for the message signer to sign on func (msg MsgCreateValidator) GetSignBytes() []byte { b, err := MsgCdc.MarshalJSON(struct { - Description - Commission CommissionMsg + Description Description `json:"description"` + Commission CommissionMsg `json:"commission"` DelegatorAddr sdk.AccAddress `json:"delegator_address"` ValidatorAddr sdk.ValAddress `json:"validator_address"` PubKey string `json:"pubkey"` diff --git a/x/staking/types/params.go b/x/staking/types/params.go index e51d597dae..481390bda2 100644 --- a/x/staking/types/params.go +++ b/x/staking/types/params.go @@ -35,10 +35,9 @@ var _ params.ParamSet = (*Params)(nil) // Params defines the high level settings for staking type Params struct { - UnbondingTime time.Duration `json:"unbonding_time"` - - MaxValidators uint16 `json:"max_validators"` // maximum number of validators - BondDenom string `json:"bond_denom"` // bondable coin denomination + UnbondingTime time.Duration `json:"unbonding_time"` // time duration of unbonding + MaxValidators uint16 `json:"max_validators"` // maximum number of validators + BondDenom string `json:"bond_denom"` // bondable coin denomination } // Implements params.ParamSet diff --git a/x/staking/types/pool.go b/x/staking/types/pool.go index b6b86cfa94..0ae9f26c4e 100644 --- a/x/staking/types/pool.go +++ b/x/staking/types/pool.go @@ -10,7 +10,7 @@ import ( // Pool - dynamic parameters of the current state type Pool struct { - LooseTokens sdk.Int `json:"loose_tokens"` // tokens which are not bonded in a validator + NotBondedTokens sdk.Int `json:"not_bonded_tokens"` // tokens which are not bonded in a validator BondedTokens sdk.Int `json:"bonded_tokens"` // reserve of bonded tokens } @@ -24,7 +24,7 @@ func (p Pool) Equal(p2 Pool) bool { // initial pool for testing func InitialPool() Pool { return Pool{ - LooseTokens: sdk.ZeroInt(), + NotBondedTokens: sdk.ZeroInt(), BondedTokens: sdk.ZeroInt(), } } @@ -33,7 +33,7 @@ func InitialPool() Pool { // Sum total of all staking tokens in the pool func (p Pool) TokenSupply() sdk.Int { - return p.LooseTokens.Add(p.BondedTokens) + return p.NotBondedTokens.Add(p.BondedTokens) } //____________________________________________________________________ @@ -50,18 +50,18 @@ func (p Pool) BondedRatio() sdk.Dec { //_______________________________________________________________________ -func (p Pool) looseTokensToBonded(bondedTokens sdk.Int) Pool { +func (p Pool) notBondedTokensToBonded(bondedTokens sdk.Int) Pool { p.BondedTokens = p.BondedTokens.Add(bondedTokens) - p.LooseTokens = p.LooseTokens.Sub(bondedTokens) - if p.LooseTokens.IsNegative() { - panic(fmt.Sprintf("sanity check: loose tokens negative, pool: %v", p)) + p.NotBondedTokens = p.NotBondedTokens.Sub(bondedTokens) + if p.NotBondedTokens.IsNegative() { + panic(fmt.Sprintf("sanity check: not-bonded tokens negative, pool: %v", p)) } return p } -func (p Pool) bondedTokensToLoose(bondedTokens sdk.Int) Pool { +func (p Pool) bondedTokensToNotBonded(bondedTokens sdk.Int) Pool { p.BondedTokens = p.BondedTokens.Sub(bondedTokens) - p.LooseTokens = p.LooseTokens.Add(bondedTokens) + p.NotBondedTokens = p.NotBondedTokens.Add(bondedTokens) if p.BondedTokens.IsNegative() { panic(fmt.Sprintf("sanity check: bonded tokens negative, pool: %v", p)) } @@ -73,7 +73,7 @@ func (p Pool) bondedTokensToLoose(bondedTokens sdk.Int) Pool { func (p Pool) HumanReadableString() string { resp := "Pool \n" - resp += fmt.Sprintf("Loose Tokens: %s\n", p.LooseTokens) + resp += fmt.Sprintf("Not-Bonded Tokens: %s\n", p.NotBondedTokens) resp += fmt.Sprintf("Bonded Tokens: %s\n", p.BondedTokens) resp += fmt.Sprintf("Token Supply: %s\n", p.TokenSupply()) resp += fmt.Sprintf("Bonded Ratio: %v\n", p.BondedRatio()) diff --git a/x/staking/types/pool_test.go b/x/staking/types/pool_test.go index a7b05d95ac..ab0838fa6f 100644 --- a/x/staking/types/pool_test.go +++ b/x/staking/types/pool_test.go @@ -18,22 +18,22 @@ func TestPoolEqual(t *testing.T) { func TestAddBondedTokens(t *testing.T) { pool := InitialPool() - pool.LooseTokens = sdk.NewInt(10) + pool.NotBondedTokens = sdk.NewInt(10) pool.BondedTokens = sdk.NewInt(10) - pool = pool.looseTokensToBonded(sdk.NewInt(10)) + pool = pool.notBondedTokensToBonded(sdk.NewInt(10)) require.True(sdk.IntEq(t, sdk.NewInt(20), pool.BondedTokens)) - require.True(sdk.IntEq(t, sdk.NewInt(0), pool.LooseTokens)) + require.True(sdk.IntEq(t, sdk.NewInt(0), pool.NotBondedTokens)) } func TestRemoveBondedTokens(t *testing.T) { pool := InitialPool() - pool.LooseTokens = sdk.NewInt(10) + pool.NotBondedTokens = sdk.NewInt(10) pool.BondedTokens = sdk.NewInt(10) - pool = pool.bondedTokensToLoose(sdk.NewInt(5)) + pool = pool.bondedTokensToNotBonded(sdk.NewInt(5)) require.True(sdk.IntEq(t, sdk.NewInt(5), pool.BondedTokens)) - require.True(sdk.IntEq(t, sdk.NewInt(15), pool.LooseTokens)) + require.True(sdk.IntEq(t, sdk.NewInt(15), pool.NotBondedTokens)) } diff --git a/x/staking/types/validator.go b/x/staking/types/validator.go index 684df919db..8333ebbb52 100644 --- a/x/staking/types/validator.go +++ b/x/staking/types/validator.go @@ -279,7 +279,7 @@ func (v Validator) UpdateStatus(pool Pool, NewStatus sdk.BondStatus) (Validator, case sdk.Unbonded: return v, pool case sdk.Bonded: - pool = pool.looseTokensToBonded(v.Tokens) + pool = pool.notBondedTokensToBonded(v.Tokens) } case sdk.Unbonding: @@ -287,7 +287,7 @@ func (v Validator) UpdateStatus(pool Pool, NewStatus sdk.BondStatus) (Validator, case sdk.Unbonding: return v, pool case sdk.Bonded: - pool = pool.looseTokensToBonded(v.Tokens) + pool = pool.notBondedTokensToBonded(v.Tokens) } case sdk.Bonded: @@ -295,7 +295,7 @@ func (v Validator) UpdateStatus(pool Pool, NewStatus sdk.BondStatus) (Validator, case sdk.Bonded: return v, pool default: - pool = pool.bondedTokensToLoose(v.Tokens) + pool = pool.bondedTokensToNotBonded(v.Tokens) } } @@ -313,7 +313,7 @@ func (v Validator) RemoveTokens(pool Pool, tokens sdk.Int) (Validator, Pool) { } v.Tokens = v.Tokens.Sub(tokens) if v.Status == sdk.Bonded { - pool = pool.bondedTokensToLoose(tokens) + pool = pool.bondedTokensToNotBonded(tokens) } return v, pool } @@ -341,7 +341,7 @@ func (v Validator) AddTokensFromDel(pool Pool, amount sdk.Int) (Validator, Pool, } if v.Status == sdk.Bonded { - pool = pool.looseTokensToBonded(amount) + pool = pool.notBondedTokensToBonded(amount) } v.Tokens = v.Tokens.Add(amount) @@ -376,7 +376,7 @@ func (v Validator) RemoveDelShares(pool Pool, delShares sdk.Dec) (Validator, Poo v.DelegatorShares = remainingShares if v.Status == sdk.Bonded { - pool = pool.bondedTokensToLoose(issuedTokens) + pool = pool.bondedTokensToNotBonded(issuedTokens) } return v, pool, issuedTokens diff --git a/x/staking/types/validator_test.go b/x/staking/types/validator_test.go index 9fd76b9db4..1094222cec 100644 --- a/x/staking/types/validator_test.go +++ b/x/staking/types/validator_test.go @@ -81,7 +81,7 @@ func TestRemoveTokens(t *testing.T) { } pool := InitialPool() - pool.LooseTokens = sdk.NewInt(10) + pool.NotBondedTokens = sdk.NewInt(10) pool.BondedTokens = validator.BondedTokens() validator, pool = validator.UpdateStatus(pool, sdk.Bonded) @@ -91,23 +91,23 @@ func TestRemoveTokens(t *testing.T) { validator, pool = validator.RemoveTokens(pool, sdk.NewInt(10)) require.Equal(t, int64(90), validator.Tokens.Int64()) require.Equal(t, int64(90), pool.BondedTokens.Int64()) - require.Equal(t, int64(20), pool.LooseTokens.Int64()) + require.Equal(t, int64(20), pool.NotBondedTokens.Int64()) // update validator to unbonded and remove some more tokens validator, pool = validator.UpdateStatus(pool, sdk.Unbonded) require.Equal(t, sdk.Unbonded, validator.Status) require.Equal(t, int64(0), pool.BondedTokens.Int64()) - require.Equal(t, int64(110), pool.LooseTokens.Int64()) + require.Equal(t, int64(110), pool.NotBondedTokens.Int64()) validator, pool = validator.RemoveTokens(pool, sdk.NewInt(10)) require.Equal(t, int64(80), validator.Tokens.Int64()) require.Equal(t, int64(0), pool.BondedTokens.Int64()) - require.Equal(t, int64(110), pool.LooseTokens.Int64()) + require.Equal(t, int64(110), pool.NotBondedTokens.Int64()) } func TestAddTokensValidatorBonded(t *testing.T) { pool := InitialPool() - pool.LooseTokens = sdk.NewInt(10) + pool.NotBondedTokens = sdk.NewInt(10) validator := NewValidator(addr1, pk1, Description{}) validator, pool = validator.UpdateStatus(pool, sdk.Bonded) validator, pool, delShares := validator.AddTokensFromDel(pool, sdk.NewInt(10)) @@ -120,7 +120,7 @@ func TestAddTokensValidatorBonded(t *testing.T) { func TestAddTokensValidatorUnbonding(t *testing.T) { pool := InitialPool() - pool.LooseTokens = sdk.NewInt(10) + pool.NotBondedTokens = sdk.NewInt(10) validator := NewValidator(addr1, pk1, Description{}) validator, pool = validator.UpdateStatus(pool, sdk.Unbonding) validator, pool, delShares := validator.AddTokensFromDel(pool, sdk.NewInt(10)) @@ -134,7 +134,7 @@ func TestAddTokensValidatorUnbonding(t *testing.T) { func TestAddTokensValidatorUnbonded(t *testing.T) { pool := InitialPool() - pool.LooseTokens = sdk.NewInt(10) + pool.NotBondedTokens = sdk.NewInt(10) validator := NewValidator(addr1, pk1, Description{}) validator, pool = validator.UpdateStatus(pool, sdk.Unbonded) validator, pool, delShares := validator.AddTokensFromDel(pool, sdk.NewInt(10)) @@ -156,7 +156,7 @@ func TestRemoveDelShares(t *testing.T) { DelegatorShares: sdk.NewDec(100), } poolA := InitialPool() - poolA.LooseTokens = sdk.NewInt(10) + poolA.NotBondedTokens = sdk.NewInt(10) poolA.BondedTokens = valA.BondedTokens() require.Equal(t, valA.DelegatorShareExRate(), sdk.OneDec()) @@ -166,12 +166,12 @@ func TestRemoveDelShares(t *testing.T) { require.Equal(t, int64(90), valB.DelegatorShares.RoundInt64()) require.Equal(t, int64(90), valB.BondedTokens().Int64()) require.Equal(t, int64(90), poolB.BondedTokens.Int64()) - require.Equal(t, int64(20), poolB.LooseTokens.Int64()) + require.Equal(t, int64(20), poolB.NotBondedTokens.Int64()) // conservation of tokens require.True(sdk.IntEq(t, - poolB.LooseTokens.Add(poolB.BondedTokens), - poolA.LooseTokens.Add(poolA.BondedTokens))) + poolB.NotBondedTokens.Add(poolB.BondedTokens), + poolA.NotBondedTokens.Add(poolA.BondedTokens))) // specific case from random tests poolTokens := sdk.NewInt(5102) @@ -185,7 +185,7 @@ func TestRemoveDelShares(t *testing.T) { } pool := Pool{ BondedTokens: sdk.NewInt(248305), - LooseTokens: sdk.NewInt(232147), + NotBondedTokens: sdk.NewInt(232147), } shares := sdk.NewDec(29) _, newPool, tokens := validator.RemoveDelShares(pool, shares) @@ -193,32 +193,32 @@ func TestRemoveDelShares(t *testing.T) { require.True(sdk.IntEq(t, sdk.NewInt(1286), tokens)) require.True(sdk.IntEq(t, - newPool.LooseTokens.Add(newPool.BondedTokens), - pool.LooseTokens.Add(pool.BondedTokens))) + newPool.NotBondedTokens.Add(newPool.BondedTokens), + pool.NotBondedTokens.Add(pool.BondedTokens))) } func TestUpdateStatus(t *testing.T) { pool := InitialPool() - pool.LooseTokens = sdk.NewInt(100) + pool.NotBondedTokens = sdk.NewInt(100) validator := NewValidator(addr1, pk1, Description{}) validator, pool, _ = validator.AddTokensFromDel(pool, sdk.NewInt(100)) require.Equal(t, sdk.Unbonded, validator.Status) require.Equal(t, int64(100), validator.Tokens.Int64()) require.Equal(t, int64(0), pool.BondedTokens.Int64()) - require.Equal(t, int64(100), pool.LooseTokens.Int64()) + require.Equal(t, int64(100), pool.NotBondedTokens.Int64()) validator, pool = validator.UpdateStatus(pool, sdk.Bonded) require.Equal(t, sdk.Bonded, validator.Status) require.Equal(t, int64(100), validator.Tokens.Int64()) require.Equal(t, int64(100), pool.BondedTokens.Int64()) - require.Equal(t, int64(0), pool.LooseTokens.Int64()) + require.Equal(t, int64(0), pool.NotBondedTokens.Int64()) validator, pool = validator.UpdateStatus(pool, sdk.Unbonding) require.Equal(t, sdk.Unbonding, validator.Status) require.Equal(t, int64(100), validator.Tokens.Int64()) require.Equal(t, int64(0), pool.BondedTokens.Int64()) - require.Equal(t, int64(100), pool.LooseTokens.Int64()) + require.Equal(t, int64(100), pool.NotBondedTokens.Int64()) } func TestPossibleOverflow(t *testing.T) { @@ -232,7 +232,7 @@ func TestPossibleOverflow(t *testing.T) { DelegatorShares: delShares, } pool := Pool{ - LooseTokens: sdk.NewInt(100), + NotBondedTokens: sdk.NewInt(100), BondedTokens: poolTokens, } tokens := int64(71)