From 77a0041f54ffd0090fe8b814e16b6a9a443df7c6 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Tue, 11 Sep 2018 18:26:10 +0800 Subject: [PATCH 01/44] Work in progress --- Makefile | 2 +- x/slashing/keys.go | 2 +- x/slashing/slashing_period.go | 21 ++++++++++++++++----- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 88ead03e6a99..95affa4edca6 100644 --- a/Makefile +++ b/Makefile @@ -157,7 +157,7 @@ test_sim_gaia_nondeterminism: test_sim_gaia_fast: @echo "Running quick Gaia simulation. This may take several minutes..." - @go test ./cmd/gaia/app -run TestFullGaiaSimulation -SimulationEnabled=true -SimulationNumBlocks=200 -v -timeout 24h + @go test ./cmd/gaia/app -run TestFullGaiaSimulation -SimulationEnabled=true -SimulationNumBlocks=500 -v -timeout 24h test_sim_gaia_slow: @echo "Running full Gaia simulation. This may take awhile!" diff --git a/x/slashing/keys.go b/x/slashing/keys.go index 1f84a285dd7c..5cd3dfbfa5a0 100644 --- a/x/slashing/keys.go +++ b/x/slashing/keys.go @@ -34,7 +34,7 @@ func GetValidatorSlashingPeriodPrefix(v sdk.ConsAddress) []byte { // stored by *Tendermint* address (not operator address) followed by start height func GetValidatorSlashingPeriodKey(v sdk.ConsAddress, startHeight int64) []byte { b := make([]byte, 8) - binary.LittleEndian.PutUint64(b, uint64(startHeight)) + binary.LittleEndian.PutUint64(b, ^uint64(startHeight)) // Newest-first, invert the height return append(GetValidatorSlashingPeriodPrefix(v), b...) } diff --git a/x/slashing/slashing_period.go b/x/slashing/slashing_period.go index fc57e663ae4a..0474042562c8 100644 --- a/x/slashing/slashing_period.go +++ b/x/slashing/slashing_period.go @@ -15,7 +15,7 @@ func (k Keeper) capBySlashingPeriod(ctx sdk.Context, address sdk.ConsAddress, fr // Sanity check if slashingPeriod.EndHeight > 0 && slashingPeriod.EndHeight < infractionHeight { - panic(fmt.Sprintf("slashing period ended before infraction: infraction height %d, slashing period ended at %d", infractionHeight, slashingPeriod.EndHeight)) + panic(fmt.Sprintf("slashing period ended before infraction: validator %s, infraction height %d, slashing period ended at %d", address, infractionHeight, slashingPeriod.EndHeight)) } // Calculate the updated total slash amount @@ -38,12 +38,22 @@ func (k Keeper) capBySlashingPeriod(ctx sdk.Context, address sdk.ConsAddress, fr // at the time of an infraction committed at that height. func (k Keeper) getValidatorSlashingPeriodForHeight(ctx sdk.Context, address sdk.ConsAddress, height int64) (slashingPeriod ValidatorSlashingPeriod) { store := ctx.KVStore(k.storeKey) + // TODO + itr := store.Prefix(ValidatorSlashingPeriodKey).Iterator(nil, nil) + for itr.Valid() { + fmt.Printf("Key: %X\n", itr.Key()) + period := k.unmarshalSlashingPeriodKeyValue(itr.Key(), itr.Value()) + fmt.Printf("Key: %X, period: %v\n", itr.Key(), period) + itr.Next() + } + // TODO // Get the most recent slashing period at or before the infraction height - start := GetValidatorSlashingPeriodPrefix(address) + start := GetValidatorSlashingPeriodKey(address, height) end := sdk.PrefixEndBytes(GetValidatorSlashingPeriodKey(address, height)) - iterator := store.ReverseIterator(start, end) + fmt.Printf("start: %X, end: %X\n", start, end) + iterator := store.Iterator(start, end) if !iterator.Valid() { - panic("expected to find slashing period, but none was found") + panic(fmt.Sprintf("expected to find slashing period for validator %s before height %d, but none was found", address, height)) } slashingPeriod = k.unmarshalSlashingPeriodKeyValue(iterator.Key(), iterator.Value()) return @@ -60,6 +70,7 @@ func (k Keeper) addOrUpdateValidatorSlashingPeriod(ctx sdk.Context, slashingPeri } store := ctx.KVStore(k.storeKey) bz := k.cdc.MustMarshalBinary(slashingPeriodValue) + fmt.Printf("Set slashing period for validator: %s\n", slashingPeriod.ValidatorAddr) store.Set(GetValidatorSlashingPeriodKey(slashingPeriod.ValidatorAddr, slashingPeriod.StartHeight), bz) } @@ -68,7 +79,7 @@ func (k Keeper) unmarshalSlashingPeriodKeyValue(key []byte, value []byte) Valida var slashingPeriodValue ValidatorSlashingPeriodValue k.cdc.MustUnmarshalBinary(value, &slashingPeriodValue) address := sdk.ConsAddress(key[1 : 1+sdk.AddrLen]) - startHeight := int64(binary.LittleEndian.Uint64(key[1+sdk.AddrLen : 1+sdk.AddrLen+8])) + startHeight := int64(^binary.LittleEndian.Uint64(key[1+sdk.AddrLen : 1+sdk.AddrLen+8])) return ValidatorSlashingPeriod{ ValidatorAddr: address, StartHeight: startHeight, From af1cb43da8aaddc849fd408972c2ee2f3f13dd43 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Wed, 12 Sep 2018 00:33:52 +0800 Subject: [PATCH 02/44] Isolate iteration issue --- types/store.go | 24 ++++++++++++++++++++++++ x/slashing/keys.go | 2 +- x/slashing/slashing_period.go | 21 +++++++++++---------- 3 files changed, 36 insertions(+), 11 deletions(-) diff --git a/types/store.go b/types/store.go index e895b24c94d8..4aa195d9851f 100644 --- a/types/store.go +++ b/types/store.go @@ -306,6 +306,30 @@ func PrefixEndBytes(prefix []byte) []byte { return end } +// PrefixStartBytes returns the []byte that would start a +// range query for all []byte with a certain prefix +func PrefixStartBytes(prefix []byte) []byte { + if prefix == nil { + return nil + } + + end := make([]byte, len(prefix)) + copy(end, prefix) + + for { + if end[len(end)-1] != byte(0) { + end[len(end)-1]-- + break + } else { + end = end[:len(end)-1] + if len(end) == 0 { + panic("could not subtract") + } + } + } + return end +} + // TransientStoreKey is used for indexing transient stores in a MultiStore type TransientStoreKey struct { name string diff --git a/x/slashing/keys.go b/x/slashing/keys.go index 5cd3dfbfa5a0..1f84a285dd7c 100644 --- a/x/slashing/keys.go +++ b/x/slashing/keys.go @@ -34,7 +34,7 @@ func GetValidatorSlashingPeriodPrefix(v sdk.ConsAddress) []byte { // stored by *Tendermint* address (not operator address) followed by start height func GetValidatorSlashingPeriodKey(v sdk.ConsAddress, startHeight int64) []byte { b := make([]byte, 8) - binary.LittleEndian.PutUint64(b, ^uint64(startHeight)) // Newest-first, invert the height + binary.LittleEndian.PutUint64(b, uint64(startHeight)) return append(GetValidatorSlashingPeriodPrefix(v), b...) } diff --git a/x/slashing/slashing_period.go b/x/slashing/slashing_period.go index 0474042562c8..44e5a6242d41 100644 --- a/x/slashing/slashing_period.go +++ b/x/slashing/slashing_period.go @@ -1,6 +1,7 @@ package slashing import ( + "bytes" "encoding/binary" "fmt" @@ -38,20 +39,20 @@ func (k Keeper) capBySlashingPeriod(ctx sdk.Context, address sdk.ConsAddress, fr // at the time of an infraction committed at that height. func (k Keeper) getValidatorSlashingPeriodForHeight(ctx sdk.Context, address sdk.ConsAddress, height int64) (slashingPeriod ValidatorSlashingPeriod) { store := ctx.KVStore(k.storeKey) + // Get the most recent slashing period at or before the infraction height + start := GetValidatorSlashingPeriodPrefix(address) + end := sdk.PrefixEndBytes(GetValidatorSlashingPeriodKey(address, height)) + fmt.Printf("start: %X, end: %X, diff: %v\n", start, end, bytes.Compare(start, end)) // TODO - itr := store.Prefix(ValidatorSlashingPeriodKey).Iterator(nil, nil) + itr := sdk.KVStorePrefixIterator(store, GetValidatorSlashingPeriodPrefix(address)) for itr.Valid() { fmt.Printf("Key: %X\n", itr.Key()) period := k.unmarshalSlashingPeriodKeyValue(itr.Key(), itr.Value()) - fmt.Printf("Key: %X, period: %v\n", itr.Key(), period) + fmt.Printf("Found %X => %v\n", address, period) itr.Next() } - // TODO - // Get the most recent slashing period at or before the infraction height - start := GetValidatorSlashingPeriodKey(address, height) - end := sdk.PrefixEndBytes(GetValidatorSlashingPeriodKey(address, height)) - fmt.Printf("start: %X, end: %X\n", start, end) - iterator := store.Iterator(start, end) + // END TODO + iterator := store.ReverseIterator(start, end) if !iterator.Valid() { panic(fmt.Sprintf("expected to find slashing period for validator %s before height %d, but none was found", address, height)) } @@ -70,7 +71,7 @@ func (k Keeper) addOrUpdateValidatorSlashingPeriod(ctx sdk.Context, slashingPeri } store := ctx.KVStore(k.storeKey) bz := k.cdc.MustMarshalBinary(slashingPeriodValue) - fmt.Printf("Set slashing period for validator: %s\n", slashingPeriod.ValidatorAddr) + fmt.Printf("Set slashing period for validator: %X => %s\n", GetValidatorSlashingPeriodKey(slashingPeriod.ValidatorAddr, slashingPeriod.StartHeight), slashingPeriod.ValidatorAddr) store.Set(GetValidatorSlashingPeriodKey(slashingPeriod.ValidatorAddr, slashingPeriod.StartHeight), bz) } @@ -79,7 +80,7 @@ func (k Keeper) unmarshalSlashingPeriodKeyValue(key []byte, value []byte) Valida var slashingPeriodValue ValidatorSlashingPeriodValue k.cdc.MustUnmarshalBinary(value, &slashingPeriodValue) address := sdk.ConsAddress(key[1 : 1+sdk.AddrLen]) - startHeight := int64(^binary.LittleEndian.Uint64(key[1+sdk.AddrLen : 1+sdk.AddrLen+8])) + startHeight := int64(binary.LittleEndian.Uint64(key[1+sdk.AddrLen : 1+sdk.AddrLen+8])) return ValidatorSlashingPeriod{ ValidatorAddr: address, StartHeight: startHeight, From 19080d0733fc1fa2684675c617be65453cb8e771 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Tue, 25 Sep 2018 00:13:29 -0400 Subject: [PATCH 03/44] pulling in issue code --- x/stake/keeper/_store.md | 6 ---- x/stake/keeper/key.go | 10 +----- x/stake/keeper/validator.go | 72 ++++++++++++++++++++++++------------- 3 files changed, 48 insertions(+), 40 deletions(-) diff --git a/x/stake/keeper/_store.md b/x/stake/keeper/_store.md index 5c070b9e0930..d569389417c3 100644 --- a/x/stake/keeper/_store.md +++ b/x/stake/keeper/_store.md @@ -41,9 +41,3 @@ prefixed areas of the staking store which are accessed in `x/stake/keeper.go`. The transient store persists between transations but not between blocks -## Tendermint Updates - - Prefix Key Space: TendermintUpdatesTKey - - Key/Sort: Validator Operator Address - - Value: Tendermint ABCI Validator - - Contains: Validators are queued to affect the consensus validation set in Tendermint - - Used For: Informing Tendermint of the validator set updates diff --git a/x/stake/keeper/key.go b/x/stake/keeper/key.go index c445e255246e..370fb8d305bd 100644 --- a/x/stake/keeper/key.go +++ b/x/stake/keeper/key.go @@ -30,8 +30,7 @@ var ( RedelegationByValSrcIndexKey = []byte{0x0D} // prefix for each key for an redelegation, by source validator operator RedelegationByValDstIndexKey = []byte{0x0E} // prefix for each key for an redelegation, by destination validator operator - // Keys for store prefixes (transient) - TendermintUpdatesTKey = []byte{0x00} // prefix for each key to a validator which is being updated + // XXX remove this comment? Keys for store prefixes (transient) ) const maxDigitsForAccount = 12 // ~220,000,000 atoms created at launch @@ -97,13 +96,6 @@ func getValidatorPowerRank(validator types.Validator, pool types.Pool) []byte { counterBytes...) } -// get the key for the accumulated update validators -// VALUE: abci.Validator -// note records using these keys should never persist between blocks -func GetTendermintUpdatesTKey(operatorAddr sdk.ValAddress) []byte { - return append(TendermintUpdatesTKey, operatorAddr.Bytes()...) -} - //______________________________________________________________________________ // gets the key for delegator bond with validator diff --git a/x/stake/keeper/validator.go b/x/stake/keeper/validator.go index de4c4a187c80..29f1250af8be 100644 --- a/x/stake/keeper/validator.go +++ b/x/stake/keeper/validator.go @@ -8,6 +8,7 @@ import ( abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto" + "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/stake/types" ) @@ -195,38 +196,59 @@ func (k Keeper) GetValidatorsByPower(ctx sdk.Context) []types.Validator { // at the previous block height or were removed from the validator set entirely // are returned to Tendermint. func (k Keeper) GetValidTendermintUpdates(ctx sdk.Context) (updates []abci.Validator) { - tstore := ctx.TransientStore(k.storeTKey) - - iterator := sdk.KVStorePrefixIterator(tstore, TendermintUpdatesTKey) - defer iterator.Close() - - for ; iterator.Valid(); iterator.Next() { - var abciVal abci.Validator - - abciValBytes := iterator.Value() - k.cdc.MustUnmarshalBinary(abciValBytes, &abciVal) - val, found := k.GetValidator(ctx, abciVal.GetAddress()) - if found { - // The validator is new or already exists in the store and must adhere to - // Tendermint invariants. - prevBonded := val.BondHeight < ctx.BlockHeight() && val.BondHeight > val.UnbondingHeight - zeroPower := val.GetPower().Equal(sdk.ZeroDec()) - - if !zeroPower || zeroPower && prevBonded { - updates = append(updates, abciVal) + last := fetchOldValidatorSet() + tendermintUpdates := make(map[sdk.ValAddress]uint64) + + for _, validator := range topvalidator { //(iterate(top hundred)) { + switch validator.State { + case Unbonded: + unbondedToBonded(ctx, validator.Addr) + tendermintUpdates[validator.Addr] = validator.Power + case Unbonding: + unbondingToBonded(ctx, validator.Addr) + tendermintUpdates[validator.Addr] = validator.Power + case Bonded: // do nothing + store.delete(last[validator.Addr]) + // jailed validators are ranked last, so if we get to a jailed validator + // we have no more bonded validators + if validator.Jailed { + break } - } else { - // Add the ABCI validator in such a case where the validator was removed - // from the store as it must have existed before. - updates = append(updates, abciVal) } } - return + + for _, validator := range previousValidators { + bondedToUnbonding(ctx, validator.Addr) + tendermintUpdates[validator.Addr] = 0 + } + + return tendermintUpdates } //___________________________________________________________________________ +func (ctx sdk.Context, addr sdk.ValAddress) bondedToUnbonding() { + // perform appropriate store updates +} + +func (ctx sdk.Context, addr sdk.ValAddress) unbondingToBonded() { + // perform appropriate store updates +} + +func (ctx sdk.Context, addr sdk.ValAddress) unbondedToBonded() { + // perform appropriate store updates +} + +func (ctx sdk.Context, addr sdk.ValAddress) unbondingToUnbonded() { + // perform appropriate store updates +} + +func (ctx sdk.Context, addr sdk.ValAddress) jailValidator() { + // perform appropriate store updates +} + +// XXX delete // Perform all the necessary steps for when a validator changes its power. This // function updates all validator stores as well as tendermint update store. // It may kick out validators if a new validator is entering the bonded validator @@ -234,7 +256,7 @@ func (k Keeper) GetValidTendermintUpdates(ctx sdk.Context) (updates []abci.Valid // // nolint: gocyclo // TODO: Remove above nolint, function needs to be simplified! -func (k Keeper) UpdateValidator(ctx sdk.Context, validator types.Validator) types.Validator { +func (k Keeper) REFERENCEXXXDELETEUpdateValidator(ctx sdk.Context, validator types.Validator) types.Validator { tstore := ctx.TransientStore(k.storeTKey) pool := k.GetPool(ctx) oldValidator, oldFound := k.GetValidator(ctx, validator.OperatorAddr) From 1aa65e4eaa92d194e172a954d58c724f3c814c99 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Tue, 25 Sep 2018 20:34:40 -0400 Subject: [PATCH 04/44] replace ensureValidatorFound with mustGetValidator --- x/stake/keeper/validator.go | 70 ++++++++++--------------------------- 1 file changed, 19 insertions(+), 51 deletions(-) diff --git a/x/stake/keeper/validator.go b/x/stake/keeper/validator.go index 464e96d61f2e..37dfa67db9e3 100644 --- a/x/stake/keeper/validator.go +++ b/x/stake/keeper/validator.go @@ -58,6 +58,14 @@ func (k Keeper) GetValidator(ctx sdk.Context, addr sdk.ValAddress) (validator ty return validator, true } +func (k Keeper) mustGetValidator(ctx sdk.Context, addr sdk.ValAddress) types.Validator { + validator, found := GetValidator(ctx, addr) + if !found { + panic(fmt.Sprintf("validator record not found for address: %X\n", ownerAddr)) + } + return validator +} + // get a single validator by consensus address func (k Keeper) GetValidatorByConsAddr(ctx sdk.Context, consAddr sdk.ConsAddress) (validator types.Validator, found bool) { store := ctx.KVStore(k.storeKey) @@ -153,8 +161,7 @@ func (k Keeper) GetValidatorsBonded(ctx sdk.Context) (validators []types.Validat panic("maxValidators is less than the number of records in ValidatorsBonded Store, store should have been updated") } address := GetAddressFromValBondedIndexKey(iterator.Key()) - validator, found := k.GetValidator(ctx, address) - ensureValidatorFound(found, address) + validator := k.mustGetValidator(ctx, address) validators[i] = validator i++ @@ -176,8 +183,7 @@ func (k Keeper) GetValidatorsByPower(ctx sdk.Context) []types.Validator { i := 0 for ; iterator.Valid() && i < int(maxValidators); iterator.Next() { address := iterator.Value() - validator, found := k.GetValidator(ctx, address) - ensureValidatorFound(found, address) + validator := k.mustGetValidator(ctx, address) if validator.Status == sdk.Bonded { validators[i] = validator @@ -227,6 +233,7 @@ func (k Keeper) GetValidTendermintUpdates(ctx sdk.Context) (updates []abci.Valid } //___________________________________________________________________________ +// State transitions func (ctx sdk.Context, addr sdk.ValAddress) bondedToUnbonding() { // perform appropriate store updates @@ -248,7 +255,7 @@ func (ctx sdk.Context, addr sdk.ValAddress) jailValidator() { // perform appropriate store updates } -// XXX delete +// XXX Delete this reference function before merge // Perform all the necessary steps for when a validator changes its power. This // function updates all validator stores as well as tendermint update store. // It may kick out validators if a new validator is entering the bonded validator @@ -349,8 +356,7 @@ func (k Keeper) updateCliffValidator(ctx sdk.Context, affectedVal types.Validato if iterator.Valid() { ownerAddr := iterator.Value() - currVal, found := k.GetValidator(ctx, ownerAddr) - ensureValidatorFound(found, ownerAddr) + currVal := k.mustGetValidator(ctx, ownerAddr) if currVal.Status != sdk.Bonded || currVal.Jailed { panic(fmt.Sprintf("unexpected jailed or unbonded validator for address: %X\n", ownerAddr)) @@ -432,6 +438,7 @@ func (k Keeper) updateValidatorPower(ctx sdk.Context, oldFound bool, oldValidato return valPower } +// XXX Delete this reference function before merge // Update the bonded validator group based on a change to the validator // affectedValidator. This function potentially adds the affectedValidator to // the bonded validator group which kicks out the cliff validator. Under this @@ -443,7 +450,7 @@ func (k Keeper) updateValidatorPower(ctx sdk.Context, oldFound bool, oldValidato // updated in store with the ValidatorsBondedIndexKey. This store is used to // determine if a validator is a validator without needing to iterate over all // validators. -func (k Keeper) UpdateBondedValidators( +func (k Keeper) XXXREFERENCEUpdateBondedValidators( ctx sdk.Context, affectedValidator types.Validator) ( updatedVal types.Validator, updated bool) { @@ -467,8 +474,7 @@ func (k Keeper) UpdateBondedValidators( validator = affectedValidator } else { var found bool - validator, found = k.GetValidator(ctx, ownerAddr) - ensureValidatorFound(found, ownerAddr) + validator = k.mustGetValidator(ctx, ownerAddr) } // if we've reached jailed validators no further bonded validators exist @@ -510,8 +516,7 @@ func (k Keeper) UpdateBondedValidators( // was bonded if newValidatorBonded { if oldCliffValidatorAddr != nil { - oldCliffVal, found := k.GetValidator(ctx, oldCliffValidatorAddr) - ensureValidatorFound(found, oldCliffValidatorAddr) + oldCliffVal := k.mustGetValidator(ctx, oldCliffValidatorAddr) if bytes.Equal(validatorToBond.OperatorAddr, affectedValidator.OperatorAddr) { @@ -561,8 +566,7 @@ func (k Keeper) UpdateBondedValidatorsFull(ctx sdk.Context) { var found bool ownerAddr := iterator.Value() - validator, found = k.GetValidator(ctx, ownerAddr) - ensureValidatorFound(found, ownerAddr) + validator = k.mustGetValidator(ctx, ownerAddr) _, found = toKickOut[string(ownerAddr)] if found { @@ -602,8 +606,7 @@ func (k Keeper) UpdateBondedValidatorsFull(ctx sdk.Context) { func kickOutValidators(k Keeper, ctx sdk.Context, toKickOut map[string]byte) { for key := range toKickOut { ownerAddr := []byte(key) - validator, found := k.GetValidator(ctx, ownerAddr) - ensureValidatorFound(found, ownerAddr) + validator := k.mustGetValidator(ctx, ownerAddr) k.beginUnbondingValidator(ctx, validator) } } @@ -727,38 +730,3 @@ func (k Keeper) UpdateValidatorCommission(ctx sdk.Context, validator types.Valid k.SetValidator(ctx, validator) return nil } - -//__________________________________________________________________________ - -// get the current validator on the cliff -func (k Keeper) GetCliffValidator(ctx sdk.Context) []byte { - store := ctx.KVStore(k.storeKey) - return store.Get(ValidatorCliffIndexKey) -} - -// get the current power of the validator on the cliff -func (k Keeper) GetCliffValidatorPower(ctx sdk.Context) []byte { - store := ctx.KVStore(k.storeKey) - return store.Get(ValidatorPowerCliffKey) -} - -// set the current validator and power of the validator on the cliff -func (k Keeper) setCliffValidator(ctx sdk.Context, validator types.Validator, pool types.Pool) { - store := ctx.KVStore(k.storeKey) - bz := GetValidatorsByPowerIndexKey(validator, pool) - store.Set(ValidatorPowerCliffKey, bz) - store.Set(ValidatorCliffIndexKey, validator.OperatorAddr) -} - -// clear the current validator and power of the validator on the cliff -func (k Keeper) clearCliffValidator(ctx sdk.Context) { - store := ctx.KVStore(k.storeKey) - store.Delete(ValidatorPowerCliffKey) - store.Delete(ValidatorCliffIndexKey) -} - -func ensureValidatorFound(found bool, ownerAddr []byte) { - if !found { - panic(fmt.Sprintf("validator record not found for address: %X\n", ownerAddr)) - } -} From 8d394f6360052f10d4673c5446428f85e9883819 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Tue, 25 Sep 2018 20:43:53 -0400 Subject: [PATCH 05/44] split up keeper/validator.go --- x/stake/keeper/val_state_change.go | 453 +++++++++++++++++++++++++ x/stake/keeper/validator.go | 517 +---------------------------- 2 files changed, 463 insertions(+), 507 deletions(-) create mode 100644 x/stake/keeper/val_state_change.go diff --git a/x/stake/keeper/val_state_change.go b/x/stake/keeper/val_state_change.go new file mode 100644 index 000000000000..39719cf6d213 --- /dev/null +++ b/x/stake/keeper/val_state_change.go @@ -0,0 +1,453 @@ +package keeper + +import ( + "bytes" + "fmt" + + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/store" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/stake/types" +) + +//_________________________________________________________________________ +// Accumulated updates to the active/bonded validator set for tendermint + +// get the most recently updated validators +// +// CONTRACT: Only validators with non-zero power or zero-power that were bonded +// at the previous block height or were removed from the validator set entirely +// are returned to Tendermint. +func (k Keeper) GetValidTendermintUpdates(ctx sdk.Context) (updates []abci.Validator) { + + last := fetchOldValidatorSet() + tendermintUpdates := make(map[sdk.ValAddress]uint64) + + for _, validator := range topvalidator { //(iterate(top hundred)) { + switch validator.State { + case Unbonded: + unbondedToBonded(ctx, validator.Addr) + tendermintUpdates[validator.Addr] = validator.Power + case Unbonding: + unbondingToBonded(ctx, validator.Addr) + tendermintUpdates[validator.Addr] = validator.Power + case Bonded: // do nothing + store.delete(last[validator.Addr]) + // jailed validators are ranked last, so if we get to a jailed validator + // we have no more bonded validators + if validator.Jailed { + break + } + } + } + + for _, validator := range previousValidators { + bondedToUnbonding(ctx, validator.Addr) + tendermintUpdates[validator.Addr] = 0 + } + + return tendermintUpdates +} + +//___________________________________________________________________________ +// State transitions + +func (ctx sdk.Context, addr sdk.ValAddress) bondedToUnbonding() { + // perform appropriate store updates +} + +func (ctx sdk.Context, addr sdk.ValAddress) unbondingToBonded() { + // perform appropriate store updates +} + +func (ctx sdk.Context, addr sdk.ValAddress) unbondedToBonded() { + // perform appropriate store updates +} + +func (ctx sdk.Context, addr sdk.ValAddress) unbondingToUnbonded() { + // perform appropriate store updates +} + +func (ctx sdk.Context, addr sdk.ValAddress) jailValidator() { + // perform appropriate store updates +} + +// XXX Delete this reference function before merge +// Perform all the necessary steps for when a validator changes its power. This +// function updates all validator stores as well as tendermint update store. +// It may kick out validators if a new validator is entering the bonded validator +// group. +// +// TODO: Remove above nolint, function needs to be simplified! +func (k Keeper) REFERENCEXXXDELETEUpdateValidator(ctx sdk.Context, validator types.Validator) types.Validator { + tstore := ctx.TransientStore(k.storeTKey) + pool := k.GetPool(ctx) + oldValidator, oldFound := k.GetValidator(ctx, validator.OperatorAddr) + + validator = k.updateForJailing(ctx, oldFound, oldValidator, validator) + powerIncreasing := k.getPowerIncreasing(ctx, oldFound, oldValidator, validator) + validator.BondHeight, validator.BondIntraTxCounter = k.bondIncrement(ctx, oldFound, oldValidator) + valPower := k.updateValidatorPower(ctx, oldFound, oldValidator, validator, pool) + cliffPower := k.GetCliffValidatorPower(ctx) + cliffValExists := (cliffPower != nil) + var valPowerLTcliffPower bool + if cliffValExists { + valPowerLTcliffPower = (bytes.Compare(valPower, cliffPower) == -1) + } + + switch { + + // if the validator is already bonded and the power is increasing, we need + // perform the following: + // a) update Tendermint + // b) check if the cliff validator needs to be updated + case powerIncreasing && !validator.Jailed && + (oldFound && oldValidator.Status == sdk.Bonded): + + bz := k.cdc.MustMarshalBinary(validator.ABCIValidator()) + tstore.Set(GetTendermintUpdatesTKey(validator.OperatorAddr), bz) + + if cliffValExists { + cliffAddr := sdk.ValAddress(k.GetCliffValidator(ctx)) + if bytes.Equal(cliffAddr, validator.OperatorAddr) { + k.updateCliffValidator(ctx, validator) + } + } + + // if is a new validator and the new power is less than the cliff validator + case cliffValExists && !oldFound && valPowerLTcliffPower: + // skip to completion + + // if was unbonded and the new power is less than the cliff validator + case cliffValExists && + (oldFound && oldValidator.Status == sdk.Unbonded) && + valPowerLTcliffPower: //(valPower < cliffPower + // skip to completion + + default: + // default case - validator was either: + // a) not-bonded and now has power-rank greater than cliff validator + // b) bonded and now has decreased in power + + // update the validator set for this validator + updatedVal, updated := k.UpdateBondedValidators(ctx, validator) + if updated { + // the validator has changed bonding status + validator = updatedVal + break + } + + // if decreased in power but still bonded, update Tendermint validator + if oldFound && oldValidator.BondedTokens().GT(validator.BondedTokens()) { + bz := k.cdc.MustMarshalBinary(validator.ABCIValidator()) + tstore.Set(GetTendermintUpdatesTKey(validator.OperatorAddr), bz) + } + } + + k.SetValidator(ctx, validator) + return validator +} + +func (k Keeper) updateForJailing(ctx sdk.Context, oldFound bool, oldValidator, newValidator types.Validator) types.Validator { + if newValidator.Jailed && oldFound && oldValidator.Status == sdk.Bonded { + newValidator = k.beginUnbondingValidator(ctx, newValidator) + + // need to also clear the cliff validator spot because the jail has + // opened up a new spot which will be filled when + // updateValidatorsBonded is called + k.clearCliffValidator(ctx) + } + return newValidator +} + +// nolint: unparam +func (k Keeper) getPowerIncreasing(ctx sdk.Context, oldFound bool, oldValidator, newValidator types.Validator) bool { + if oldFound && oldValidator.BondedTokens().LT(newValidator.BondedTokens()) { + return true + } + return false +} + +// get the bond height and incremented intra-tx counter +// nolint: unparam +func (k Keeper) bondIncrement( + ctx sdk.Context, found bool, oldValidator types.Validator) (height int64, intraTxCounter int16) { + + // if already a validator, copy the old block height and counter + if found && oldValidator.Status == sdk.Bonded { + height = oldValidator.BondHeight + intraTxCounter = oldValidator.BondIntraTxCounter + return + } + + height = ctx.BlockHeight() + counter := k.GetIntraTxCounter(ctx) + intraTxCounter = counter + + k.SetIntraTxCounter(ctx, counter+1) + return +} + +func (k Keeper) updateValidatorPower(ctx sdk.Context, oldFound bool, oldValidator, + newValidator types.Validator, pool types.Pool) (valPower []byte) { + store := ctx.KVStore(k.storeKey) + + // update the list ordered by voting power + if oldFound { + store.Delete(GetValidatorsByPowerIndexKey(oldValidator, pool)) + } + valPower = GetValidatorsByPowerIndexKey(newValidator, pool) + store.Set(valPower, newValidator.OperatorAddr) + + return valPower +} + +// XXX Delete this reference function before merge +// Update the bonded validator group based on a change to the validator +// affectedValidator. This function potentially adds the affectedValidator to +// the bonded validator group which kicks out the cliff validator. Under this +// situation this function returns the updated affectedValidator. +// +// The correct bonded subset of validators is retrieved by iterating through an +// index of the validators sorted by power, stored using the +// ValidatorsByPowerIndexKey. Simultaneously the current validator records are +// updated in store with the ValidatorsBondedIndexKey. This store is used to +// determine if a validator is a validator without needing to iterate over all +// validators. +func (k Keeper) XXXREFERENCEUpdateBondedValidators( + ctx sdk.Context, affectedValidator types.Validator) ( + updatedVal types.Validator, updated bool) { + + store := ctx.KVStore(k.storeKey) + + oldCliffValidatorAddr := k.GetCliffValidator(ctx) + maxValidators := k.GetParams(ctx).MaxValidators + bondedValidatorsCount := 0 + var validator, validatorToBond types.Validator + newValidatorBonded := false + + // create a validator iterator ranging from largest to smallest by power + iterator := sdk.KVStoreReversePrefixIterator(store, ValidatorsByPowerIndexKey) + for ; iterator.Valid() && bondedValidatorsCount < int(maxValidators); iterator.Next() { + + // either retrieve the original validator from the store, or under the + // situation that this is the "affected validator" just use the + // validator provided because it has not yet been updated in the store + ownerAddr := iterator.Value() + if bytes.Equal(ownerAddr, affectedValidator.OperatorAddr) { + validator = affectedValidator + } else { + var found bool + validator = k.mustGetValidator(ctx, ownerAddr) + } + + // if we've reached jailed validators no further bonded validators exist + if validator.Jailed { + if validator.Status == sdk.Bonded { + panic(fmt.Sprintf("jailed validator cannot be bonded, address: %X\n", ownerAddr)) + } + + break + } + + // increment the total number of bonded validators and potentially mark + // the validator to bond + if validator.Status != sdk.Bonded { + validatorToBond = validator + if newValidatorBonded { + panic("already decided to bond a validator, can't bond another!") + } + newValidatorBonded = true + } + + bondedValidatorsCount++ + } + + iterator.Close() + + if newValidatorBonded && bytes.Equal(oldCliffValidatorAddr, validator.OperatorAddr) { + panic("cliff validator has not been changed, yet we bonded a new validator") + } + + // clear or set the cliff validator + if bondedValidatorsCount == int(maxValidators) { + k.setCliffValidator(ctx, validator, k.GetPool(ctx)) + } else if len(oldCliffValidatorAddr) > 0 { + k.clearCliffValidator(ctx) + } + + // swap the cliff validator for a new validator if the affected validator + // was bonded + if newValidatorBonded { + if oldCliffValidatorAddr != nil { + oldCliffVal := k.mustGetValidator(ctx, oldCliffValidatorAddr) + + if bytes.Equal(validatorToBond.OperatorAddr, affectedValidator.OperatorAddr) { + + // begin unbonding the old cliff validator iff the affected + // validator was newly bonded and has greater power + k.beginUnbondingValidator(ctx, oldCliffVal) + } else { + // otherwise begin unbonding the affected validator, which must + // have been kicked out + affectedValidator = k.beginUnbondingValidator(ctx, affectedValidator) + } + } + + validator = k.bondValidator(ctx, validatorToBond) + if bytes.Equal(validator.OperatorAddr, affectedValidator.OperatorAddr) { + return validator, true + } + + return affectedValidator, true + } + + return types.Validator{}, false +} + +// XXX Delete this reference function before merge +// full update of the bonded validator set, many can be added/kicked +func (k Keeper) XXXREFERENCEUpdateBondedValidatorsFull(ctx sdk.Context) { + store := ctx.KVStore(k.storeKey) + + // clear the current validators store, add to the ToKickOut temp store + toKickOut := make(map[string]byte) + iterator := sdk.KVStorePrefixIterator(store, ValidatorsBondedIndexKey) + for ; iterator.Valid(); iterator.Next() { + ownerAddr := GetAddressFromValBondedIndexKey(iterator.Key()) + toKickOut[string(ownerAddr)] = 0 + } + + iterator.Close() + + var validator types.Validator + + oldCliffValidatorAddr := k.GetCliffValidator(ctx) + maxValidators := k.GetParams(ctx).MaxValidators + bondedValidatorsCount := 0 + + iterator = sdk.KVStoreReversePrefixIterator(store, ValidatorsByPowerIndexKey) + for ; iterator.Valid() && bondedValidatorsCount < int(maxValidators); iterator.Next() { + var found bool + + ownerAddr := iterator.Value() + validator = k.mustGetValidator(ctx, ownerAddr) + + _, found = toKickOut[string(ownerAddr)] + if found { + delete(toKickOut, string(ownerAddr)) + } else { + // If the validator wasn't in the toKickOut group it means it wasn't + // previously a validator, therefor update the validator to enter + // the validator group. + validator = k.bondValidator(ctx, validator) + } + + if validator.Jailed { + // we should no longer consider jailed validators as they are ranked + // lower than any non-jailed/bonded validators + if validator.Status == sdk.Bonded { + panic(fmt.Sprintf("jailed validator cannot be bonded for address: %s\n", ownerAddr)) + } + break + } + + bondedValidatorsCount++ + } + + iterator.Close() + + // clear or set the cliff validator + if bondedValidatorsCount == int(maxValidators) { + k.setCliffValidator(ctx, validator, k.GetPool(ctx)) + } else if len(oldCliffValidatorAddr) > 0 { + k.clearCliffValidator(ctx) + } + + kickOutValidators(k, ctx, toKickOut) + return +} + +func kickOutValidators(k Keeper, ctx sdk.Context, toKickOut map[string]byte) { + for key := range toKickOut { + ownerAddr := []byte(key) + validator := k.mustGetValidator(ctx, ownerAddr) + k.beginUnbondingValidator(ctx, validator) + } +} + +// perform all the store operations for when a validator status becomes unbonded +func (k Keeper) beginUnbondingValidator(ctx sdk.Context, validator types.Validator) types.Validator { + + store := ctx.KVStore(k.storeKey) + pool := k.GetPool(ctx) + params := k.GetParams(ctx) + + // sanity check + if validator.Status == sdk.Unbonded || + validator.Status == sdk.Unbonding { + panic(fmt.Sprintf("should not already be unbonded or unbonding, validator: %v\n", validator)) + } + + // set the status + validator, pool = validator.UpdateStatus(pool, sdk.Unbonding) + k.SetPool(ctx, pool) + + validator.UnbondingMinTime = ctx.BlockHeader().Time.Add(params.UnbondingTime) + validator.UnbondingHeight = ctx.BlockHeader().Height + + // save the now unbonded validator record + k.SetValidator(ctx, validator) + + // add to accumulated changes for tendermint + bzABCI := k.cdc.MustMarshalBinary(validator.ABCIValidatorZero()) + tstore := ctx.TransientStore(k.storeTKey) + tstore.Set(GetTendermintUpdatesTKey(validator.OperatorAddr), bzABCI) + + // also remove from the Bonded types.Validators Store + store.Delete(GetValidatorsBondedIndexKey(validator.OperatorAddr)) + + // call the unbond hook if present + if k.hooks != nil { + k.hooks.OnValidatorBeginUnbonding(ctx, validator.ConsAddress()) + } + + // return updated validator + return validator +} + +// perform all the store operations for when a validator status becomes bonded +func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) types.Validator { + + store := ctx.KVStore(k.storeKey) + pool := k.GetPool(ctx) + + // sanity check + if validator.Status == sdk.Bonded { + panic(fmt.Sprintf("should not already be bonded, validator: %v\n", validator)) + } + + validator.BondHeight = ctx.BlockHeight() + + // set the status + validator, pool = validator.UpdateStatus(pool, sdk.Bonded) + k.SetPool(ctx, pool) + + // save the now bonded validator record to the three referenced stores + k.SetValidator(ctx, validator) + store.Set(GetValidatorsBondedIndexKey(validator.OperatorAddr), []byte{}) + + // add to accumulated changes for tendermint + bzABCI := k.cdc.MustMarshalBinary(validator.ABCIValidator()) + tstore := ctx.TransientStore(k.storeTKey) + tstore.Set(GetTendermintUpdatesTKey(validator.OperatorAddr), bzABCI) + + // call the bond hook if present + if k.hooks != nil { + k.hooks.OnValidatorBonded(ctx, validator.ConsAddress()) + } + + // return updated validator + return validator +} diff --git a/x/stake/keeper/validator.go b/x/stake/keeper/validator.go index 37dfa67db9e3..3e68474cd0de 100644 --- a/x/stake/keeper/validator.go +++ b/x/stake/keeper/validator.go @@ -1,13 +1,9 @@ package keeper import ( - "bytes" "container/list" "fmt" - abci "github.com/tendermint/tendermint/abci/types" - - "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/stake/types" ) @@ -193,497 +189,21 @@ func (k Keeper) GetValidatorsByPower(ctx sdk.Context) []types.Validator { return validators[:i] // trim } -//_________________________________________________________________________ -// Accumulated updates to the active/bonded validator set for tendermint - -// get the most recently updated validators -// -// CONTRACT: Only validators with non-zero power or zero-power that were bonded -// at the previous block height or were removed from the validator set entirely -// are returned to Tendermint. -func (k Keeper) GetValidTendermintUpdates(ctx sdk.Context) (updates []abci.Validator) { - - last := fetchOldValidatorSet() - tendermintUpdates := make(map[sdk.ValAddress]uint64) - - for _, validator := range topvalidator { //(iterate(top hundred)) { - switch validator.State { - case Unbonded: - unbondedToBonded(ctx, validator.Addr) - tendermintUpdates[validator.Addr] = validator.Power - case Unbonding: - unbondingToBonded(ctx, validator.Addr) - tendermintUpdates[validator.Addr] = validator.Power - case Bonded: // do nothing - store.delete(last[validator.Addr]) - // jailed validators are ranked last, so if we get to a jailed validator - // we have no more bonded validators - if validator.Jailed { - break - } - } - } - - for _, validator := range previousValidators { - bondedToUnbonding(ctx, validator.Addr) - tendermintUpdates[validator.Addr] = 0 - } - - return tendermintUpdates -} - -//___________________________________________________________________________ -// State transitions - -func (ctx sdk.Context, addr sdk.ValAddress) bondedToUnbonding() { - // perform appropriate store updates -} - -func (ctx sdk.Context, addr sdk.ValAddress) unbondingToBonded() { - // perform appropriate store updates -} - -func (ctx sdk.Context, addr sdk.ValAddress) unbondedToBonded() { - // perform appropriate store updates -} - -func (ctx sdk.Context, addr sdk.ValAddress) unbondingToUnbonded() { - // perform appropriate store updates -} - -func (ctx sdk.Context, addr sdk.ValAddress) jailValidator() { - // perform appropriate store updates -} - -// XXX Delete this reference function before merge -// Perform all the necessary steps for when a validator changes its power. This -// function updates all validator stores as well as tendermint update store. -// It may kick out validators if a new validator is entering the bonded validator -// group. -// -// TODO: Remove above nolint, function needs to be simplified! -func (k Keeper) REFERENCEXXXDELETEUpdateValidator(ctx sdk.Context, validator types.Validator) types.Validator { - tstore := ctx.TransientStore(k.storeTKey) - pool := k.GetPool(ctx) - oldValidator, oldFound := k.GetValidator(ctx, validator.OperatorAddr) - - validator = k.updateForJailing(ctx, oldFound, oldValidator, validator) - powerIncreasing := k.getPowerIncreasing(ctx, oldFound, oldValidator, validator) - validator.BondHeight, validator.BondIntraTxCounter = k.bondIncrement(ctx, oldFound, oldValidator) - valPower := k.updateValidatorPower(ctx, oldFound, oldValidator, validator, pool) - cliffPower := k.GetCliffValidatorPower(ctx) - cliffValExists := (cliffPower != nil) - var valPowerLTcliffPower bool - if cliffValExists { - valPowerLTcliffPower = (bytes.Compare(valPower, cliffPower) == -1) - } - - switch { - - // if the validator is already bonded and the power is increasing, we need - // perform the following: - // a) update Tendermint - // b) check if the cliff validator needs to be updated - case powerIncreasing && !validator.Jailed && - (oldFound && oldValidator.Status == sdk.Bonded): - - bz := k.cdc.MustMarshalBinary(validator.ABCIValidator()) - tstore.Set(GetTendermintUpdatesTKey(validator.OperatorAddr), bz) - - if cliffValExists { - cliffAddr := sdk.ValAddress(k.GetCliffValidator(ctx)) - if bytes.Equal(cliffAddr, validator.OperatorAddr) { - k.updateCliffValidator(ctx, validator) - } - } - - // if is a new validator and the new power is less than the cliff validator - case cliffValExists && !oldFound && valPowerLTcliffPower: - // skip to completion - - // if was unbonded and the new power is less than the cliff validator - case cliffValExists && - (oldFound && oldValidator.Status == sdk.Unbonded) && - valPowerLTcliffPower: //(valPower < cliffPower - // skip to completion - - default: - // default case - validator was either: - // a) not-bonded and now has power-rank greater than cliff validator - // b) bonded and now has decreased in power - - // update the validator set for this validator - updatedVal, updated := k.UpdateBondedValidators(ctx, validator) - if updated { - // the validator has changed bonding status - validator = updatedVal - break - } - - // if decreased in power but still bonded, update Tendermint validator - if oldFound && oldValidator.BondedTokens().GT(validator.BondedTokens()) { - bz := k.cdc.MustMarshalBinary(validator.ABCIValidator()) - tstore.Set(GetTendermintUpdatesTKey(validator.OperatorAddr), bz) - } - } - - k.SetValidator(ctx, validator) - return validator -} - -// updateCliffValidator determines if the current cliff validator needs to be -// updated or swapped. If the provided affected validator is the current cliff -// validator before it's power was increased, either the cliff power key will -// be updated or if it's power is greater than the next bonded validator by -// power, it'll be swapped. -func (k Keeper) updateCliffValidator(ctx sdk.Context, affectedVal types.Validator) { - var newCliffVal types.Validator - - store := ctx.KVStore(k.storeKey) - pool := k.GetPool(ctx) - cliffAddr := sdk.ValAddress(k.GetCliffValidator(ctx)) - - oldCliffVal, found := k.GetValidator(ctx, cliffAddr) - if !found { - panic(fmt.Sprintf("cliff validator record not found for address: %X\n", cliffAddr)) - } - - // Create a validator iterator ranging from smallest to largest by power - // starting the current cliff validator's power. - start := GetValidatorsByPowerIndexKey(oldCliffVal, pool) - end := sdk.PrefixEndBytes(ValidatorsByPowerIndexKey) - iterator := store.Iterator(start, end) - - if iterator.Valid() { - ownerAddr := iterator.Value() - currVal := k.mustGetValidator(ctx, ownerAddr) - - if currVal.Status != sdk.Bonded || currVal.Jailed { - panic(fmt.Sprintf("unexpected jailed or unbonded validator for address: %X\n", ownerAddr)) - } - - newCliffVal = currVal - iterator.Close() - } else { - panic("failed to create valid validator power iterator") - } - - affectedValRank := GetValidatorsByPowerIndexKey(affectedVal, pool) - newCliffValRank := GetValidatorsByPowerIndexKey(newCliffVal, pool) - - if bytes.Equal(affectedVal.OperatorAddr, newCliffVal.OperatorAddr) { - // The affected validator remains the cliff validator, however, since - // the store does not contain the new power, update the new power rank. - store.Set(ValidatorPowerCliffKey, affectedValRank) - } else if bytes.Compare(affectedValRank, newCliffValRank) > 0 { - // The affected validator no longer remains the cliff validator as it's - // power is greater than the new cliff validator. - k.setCliffValidator(ctx, newCliffVal, pool) - } else { - panic("invariant broken: the cliff validator should change or it should remain the same") - } -} - -func (k Keeper) updateForJailing(ctx sdk.Context, oldFound bool, oldValidator, newValidator types.Validator) types.Validator { - if newValidator.Jailed && oldFound && oldValidator.Status == sdk.Bonded { - newValidator = k.beginUnbondingValidator(ctx, newValidator) - - // need to also clear the cliff validator spot because the jail has - // opened up a new spot which will be filled when - // updateValidatorsBonded is called - k.clearCliffValidator(ctx) - } - return newValidator -} - -// nolint: unparam -func (k Keeper) getPowerIncreasing(ctx sdk.Context, oldFound bool, oldValidator, newValidator types.Validator) bool { - if oldFound && oldValidator.BondedTokens().LT(newValidator.BondedTokens()) { - return true - } - return false -} - -// get the bond height and incremented intra-tx counter -// nolint: unparam -func (k Keeper) bondIncrement( - ctx sdk.Context, found bool, oldValidator types.Validator) (height int64, intraTxCounter int16) { - - // if already a validator, copy the old block height and counter - if found && oldValidator.Status == sdk.Bonded { - height = oldValidator.BondHeight - intraTxCounter = oldValidator.BondIntraTxCounter - return - } - - height = ctx.BlockHeight() - counter := k.GetIntraTxCounter(ctx) - intraTxCounter = counter - - k.SetIntraTxCounter(ctx, counter+1) - return -} - -func (k Keeper) updateValidatorPower(ctx sdk.Context, oldFound bool, oldValidator, - newValidator types.Validator, pool types.Pool) (valPower []byte) { - store := ctx.KVStore(k.storeKey) - - // update the list ordered by voting power - if oldFound { - store.Delete(GetValidatorsByPowerIndexKey(oldValidator, pool)) - } - valPower = GetValidatorsByPowerIndexKey(newValidator, pool) - store.Set(valPower, newValidator.OperatorAddr) - - return valPower -} - -// XXX Delete this reference function before merge -// Update the bonded validator group based on a change to the validator -// affectedValidator. This function potentially adds the affectedValidator to -// the bonded validator group which kicks out the cliff validator. Under this -// situation this function returns the updated affectedValidator. -// -// The correct bonded subset of validators is retrieved by iterating through an -// index of the validators sorted by power, stored using the -// ValidatorsByPowerIndexKey. Simultaneously the current validator records are -// updated in store with the ValidatorsBondedIndexKey. This store is used to -// determine if a validator is a validator without needing to iterate over all -// validators. -func (k Keeper) XXXREFERENCEUpdateBondedValidators( - ctx sdk.Context, affectedValidator types.Validator) ( - updatedVal types.Validator, updated bool) { - - store := ctx.KVStore(k.storeKey) - - oldCliffValidatorAddr := k.GetCliffValidator(ctx) - maxValidators := k.GetParams(ctx).MaxValidators - bondedValidatorsCount := 0 - var validator, validatorToBond types.Validator - newValidatorBonded := false - - // create a validator iterator ranging from largest to smallest by power - iterator := sdk.KVStoreReversePrefixIterator(store, ValidatorsByPowerIndexKey) - for ; iterator.Valid() && bondedValidatorsCount < int(maxValidators); iterator.Next() { - - // either retrieve the original validator from the store, or under the - // situation that this is the "affected validator" just use the - // validator provided because it has not yet been updated in the store - ownerAddr := iterator.Value() - if bytes.Equal(ownerAddr, affectedValidator.OperatorAddr) { - validator = affectedValidator - } else { - var found bool - validator = k.mustGetValidator(ctx, ownerAddr) - } - - // if we've reached jailed validators no further bonded validators exist - if validator.Jailed { - if validator.Status == sdk.Bonded { - panic(fmt.Sprintf("jailed validator cannot be bonded, address: %X\n", ownerAddr)) - } - - break - } - - // increment the total number of bonded validators and potentially mark - // the validator to bond - if validator.Status != sdk.Bonded { - validatorToBond = validator - if newValidatorBonded { - panic("already decided to bond a validator, can't bond another!") - } - newValidatorBonded = true - } - - bondedValidatorsCount++ - } - - iterator.Close() - - if newValidatorBonded && bytes.Equal(oldCliffValidatorAddr, validator.OperatorAddr) { - panic("cliff validator has not been changed, yet we bonded a new validator") - } - - // clear or set the cliff validator - if bondedValidatorsCount == int(maxValidators) { - k.setCliffValidator(ctx, validator, k.GetPool(ctx)) - } else if len(oldCliffValidatorAddr) > 0 { - k.clearCliffValidator(ctx) - } - - // swap the cliff validator for a new validator if the affected validator - // was bonded - if newValidatorBonded { - if oldCliffValidatorAddr != nil { - oldCliffVal := k.mustGetValidator(ctx, oldCliffValidatorAddr) - - if bytes.Equal(validatorToBond.OperatorAddr, affectedValidator.OperatorAddr) { - - // begin unbonding the old cliff validator iff the affected - // validator was newly bonded and has greater power - k.beginUnbondingValidator(ctx, oldCliffVal) - } else { - // otherwise begin unbonding the affected validator, which must - // have been kicked out - affectedValidator = k.beginUnbondingValidator(ctx, affectedValidator) - } - } - - validator = k.bondValidator(ctx, validatorToBond) - if bytes.Equal(validator.OperatorAddr, affectedValidator.OperatorAddr) { - return validator, true - } - - return affectedValidator, true - } - - return types.Validator{}, false -} - -// full update of the bonded validator set, many can be added/kicked -func (k Keeper) UpdateBondedValidatorsFull(ctx sdk.Context) { - store := ctx.KVStore(k.storeKey) - - // clear the current validators store, add to the ToKickOut temp store - toKickOut := make(map[string]byte) - iterator := sdk.KVStorePrefixIterator(store, ValidatorsBondedIndexKey) - for ; iterator.Valid(); iterator.Next() { - ownerAddr := GetAddressFromValBondedIndexKey(iterator.Key()) - toKickOut[string(ownerAddr)] = 0 - } - - iterator.Close() - - var validator types.Validator - - oldCliffValidatorAddr := k.GetCliffValidator(ctx) - maxValidators := k.GetParams(ctx).MaxValidators - bondedValidatorsCount := 0 - - iterator = sdk.KVStoreReversePrefixIterator(store, ValidatorsByPowerIndexKey) - for ; iterator.Valid() && bondedValidatorsCount < int(maxValidators); iterator.Next() { - var found bool - - ownerAddr := iterator.Value() - validator = k.mustGetValidator(ctx, ownerAddr) - - _, found = toKickOut[string(ownerAddr)] - if found { - delete(toKickOut, string(ownerAddr)) - } else { - // If the validator wasn't in the toKickOut group it means it wasn't - // previously a validator, therefor update the validator to enter - // the validator group. - validator = k.bondValidator(ctx, validator) - } - - if validator.Jailed { - // we should no longer consider jailed validators as they are ranked - // lower than any non-jailed/bonded validators - if validator.Status == sdk.Bonded { - panic(fmt.Sprintf("jailed validator cannot be bonded for address: %s\n", ownerAddr)) - } - break - } - - bondedValidatorsCount++ - } - - iterator.Close() - - // clear or set the cliff validator - if bondedValidatorsCount == int(maxValidators) { - k.setCliffValidator(ctx, validator, k.GetPool(ctx)) - } else if len(oldCliffValidatorAddr) > 0 { - k.clearCliffValidator(ctx) - } - - kickOutValidators(k, ctx, toKickOut) - return -} - -func kickOutValidators(k Keeper, ctx sdk.Context, toKickOut map[string]byte) { - for key := range toKickOut { - ownerAddr := []byte(key) - validator := k.mustGetValidator(ctx, ownerAddr) - k.beginUnbondingValidator(ctx, validator) - } -} - -// perform all the store operations for when a validator status becomes unbonded -func (k Keeper) beginUnbondingValidator(ctx sdk.Context, validator types.Validator) types.Validator { - - store := ctx.KVStore(k.storeKey) - pool := k.GetPool(ctx) - params := k.GetParams(ctx) - - // sanity check - if validator.Status == sdk.Unbonded || - validator.Status == sdk.Unbonding { - panic(fmt.Sprintf("should not already be unbonded or unbonding, validator: %v\n", validator)) - } - - // set the status - validator, pool = validator.UpdateStatus(pool, sdk.Unbonding) - k.SetPool(ctx, pool) - - validator.UnbondingMinTime = ctx.BlockHeader().Time.Add(params.UnbondingTime) - validator.UnbondingHeight = ctx.BlockHeader().Height - - // save the now unbonded validator record - k.SetValidator(ctx, validator) - - // add to accumulated changes for tendermint - bzABCI := k.cdc.MustMarshalBinary(validator.ABCIValidatorZero()) - tstore := ctx.TransientStore(k.storeTKey) - tstore.Set(GetTendermintUpdatesTKey(validator.OperatorAddr), bzABCI) - - // also remove from the Bonded types.Validators Store - store.Delete(GetValidatorsBondedIndexKey(validator.OperatorAddr)) - - // call the unbond hook if present - if k.hooks != nil { - k.hooks.OnValidatorBeginUnbonding(ctx, validator.ConsAddress()) - } - - // return updated validator - return validator -} - -// perform all the store operations for when a validator status becomes bonded -func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) types.Validator { - - store := ctx.KVStore(k.storeKey) - pool := k.GetPool(ctx) +// UpdateValidatorCommission attempts to update a validator's commission rate. +// An error is returned if the new commission rate is invalid. +func (k Keeper) UpdateValidatorCommission(ctx sdk.Context, validator types.Validator, newRate sdk.Dec) sdk.Error { + commission := validator.Commission + blockTime := ctx.BlockHeader().Time - // sanity check - if validator.Status == sdk.Bonded { - panic(fmt.Sprintf("should not already be bonded, validator: %v\n", validator)) + if err := commission.ValidateNewRate(newRate, blockTime); err != nil { + return err } - validator.BondHeight = ctx.BlockHeight() - - // set the status - validator, pool = validator.UpdateStatus(pool, sdk.Bonded) - k.SetPool(ctx, pool) + validator.Commission.Rate = newRate + validator.Commission.UpdateTime = blockTime - // save the now bonded validator record to the three referenced stores k.SetValidator(ctx, validator) - store.Set(GetValidatorsBondedIndexKey(validator.OperatorAddr), []byte{}) - - // add to accumulated changes for tendermint - bzABCI := k.cdc.MustMarshalBinary(validator.ABCIValidator()) - tstore := ctx.TransientStore(k.storeTKey) - tstore.Set(GetTendermintUpdatesTKey(validator.OperatorAddr), bzABCI) - - // call the bond hook if present - if k.hooks != nil { - k.hooks.OnValidatorBonded(ctx, validator.ConsAddress()) - } - - // return updated validator - return validator + return nil } // remove the validator record and associated indexes @@ -713,20 +233,3 @@ func (k Keeper) RemoveValidator(ctx sdk.Context, address sdk.ValAddress) { tstore := ctx.TransientStore(k.storeTKey) tstore.Set(GetTendermintUpdatesTKey(address), bz) } - -// UpdateValidatorCommission attempts to update a validator's commission rate. -// An error is returned if the new commission rate is invalid. -func (k Keeper) UpdateValidatorCommission(ctx sdk.Context, validator types.Validator, newRate sdk.Dec) sdk.Error { - commission := validator.Commission - blockTime := ctx.BlockHeader().Time - - if err := commission.ValidateNewRate(newRate, blockTime); err != nil { - return err - } - - validator.Commission.Rate = newRate - validator.Commission.UpdateTime = blockTime - - k.SetValidator(ctx, validator) - return nil -} From 8373329f9964e04b7757d66553b3f278600b7761 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 26 Sep 2018 00:16:48 -0400 Subject: [PATCH 06/44] move validatorByPowerIndexExists from keeper to test file --- x/stake/keeper/val_state_change.go | 376 ++++++++++++----------------- x/stake/keeper/validator.go | 36 ++- x/stake/keeper/validator_test.go | 11 +- x/stake/types/validator.go | 1 + 4 files changed, 172 insertions(+), 252 deletions(-) diff --git a/x/stake/keeper/val_state_change.go b/x/stake/keeper/val_state_change.go index 39719cf6d213..88c6a6a9053c 100644 --- a/x/stake/keeper/val_state_change.go +++ b/x/stake/keeper/val_state_change.go @@ -19,7 +19,13 @@ import ( // CONTRACT: Only validators with non-zero power or zero-power that were bonded // at the previous block height or were removed from the validator set entirely // are returned to Tendermint. -func (k Keeper) GetValidTendermintUpdates(ctx sdk.Context) (updates []abci.Validator) { +func (k Keeper) GetTendermintUpdates(ctx sdk.Context) (updates []abci.Validator) { + + // REF CODE + //// add to accumulated changes for tendermint + //bzABCI := k.cdc.MustMarshalBinary(validator.ABCIValidator()) + //tstore := ctx.TransientStore(k.storeTKey) + //tstore.Set(GetTendermintUpdatesTKey(validator.OperatorAddr), bzABCI) last := fetchOldValidatorSet() tendermintUpdates := make(map[sdk.ValAddress]uint64) @@ -50,29 +56,160 @@ func (k Keeper) GetValidTendermintUpdates(ctx sdk.Context) (updates []abci.Valid return tendermintUpdates } +func kickOutValidators(k Keeper, ctx sdk.Context, toKickOut map[string]byte) { + for key := range toKickOut { + ownerAddr := []byte(key) + validator := k.mustGetValidator(ctx, ownerAddr) + k.beginUnbondingValidator(ctx, validator) + } +} + //___________________________________________________________________________ // State transitions -func (ctx sdk.Context, addr sdk.ValAddress) bondedToUnbonding() { - // perform appropriate store updates +func (k Keeper) bondedToUnbonding(ctx sdk.Context, validator types.Validator) { + if validator.Status != sdk.Bonded { + panic(fmt.Sprintf("bad state transition bondedToUnbonded, validator: %v\n", validator)) + } + beginUnbondingValidator(ctx, validator) } -func (ctx sdk.Context, addr sdk.ValAddress) unbondingToBonded() { - // perform appropriate store updates +func (k Keeper) unbondingToBonded(ctx sdk.Context, validator types.Validator) { + if validator.Status != sdk.Unbonding { + panic(fmt.Sprintf("bad state transition unbondingToBonded, validator: %v\n", validator)) + } + bondValidator(ctx, validator) } -func (ctx sdk.Context, addr sdk.ValAddress) unbondedToBonded() { - // perform appropriate store updates +func (k Keeper) unbondedToBonded(ctx sdk.Context, validator types.Validator) { + if validator.Status != sdk.Unbonded { + panic(fmt.Sprintf("bad state transition unbondedToBonded, validator: %v\n", validator)) + } + bondValidator(ctx, validator) } -func (ctx sdk.Context, addr sdk.ValAddress) unbondingToUnbonded() { - // perform appropriate store updates +func (k Keeper) unbondingToUnbonded(ctx sdk.Context, validator types.Validator) { + if validator.Status != sdk.Unbonded { + panic(fmt.Sprintf("bad state transition unbondingToBonded, validator: %v\n", validator)) + } + completeUnbondingValidator(ctx, validator) } -func (ctx sdk.Context, addr sdk.ValAddress) jailValidator() { - // perform appropriate store updates +func (k Keeper) jailValidator(ctx sdk.Context, validator types.Validator) { + if validator.Jailed { + panic(fmt.Sprintf("cannot jail already jailed validator, validator: %v\n", validator)) + } + + validator.Jailed = true + + if validator.Status == sdk.Bonded { + validator = k.beginUnbondingValidator(ctx, newValidator) + } } +//________________________________________________________________________________________________ + +// perform all the store operations for when a validator status becomes bonded +func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) { + + store := ctx.KVStore(k.storeKey) + pool := k.GetPool(ctx) + + validator.BondHeight = ctx.BlockHeight() + + // set the status + validator, pool = validator.UpdateStatus(pool, sdk.Bonded) + k.SetPool(ctx, pool) + + // save the now bonded validator record to the three referenced stores + k.SetValidator(ctx, validator) + store.Set(GetValidatorsBondedIndexKey(validator.OperatorAddr), []byte{}) + + // call the bond hook if present + if k.hooks != nil { + k.hooks.OnValidatorBonded(ctx, validator.ConsAddress()) + } +} + +// perform all the store operations for when a validator status begins unbonding +func (k Keeper) beginUnbondingValidator(ctx sdk.Context, validator types.Validator) { + + store := ctx.KVStore(k.storeKey) + pool := k.GetPool(ctx) + params := k.GetParams(ctx) + + // sanity check + if validator.Status == sdk.Unbonded || + validator.Status == sdk.Unbonding { + panic(fmt.Sprintf("should not already be unbonded or unbonding, validator: %v\n", validator)) + } + + // set the status + validator, pool = validator.UpdateStatus(pool, sdk.Unbonding) + k.SetPool(ctx, pool) + + validator.UnbondingMinTime = ctx.BlockHeader().Time.Add(params.UnbondingTime) + validator.UnbondingHeight = ctx.BlockHeader().Height + + // save the now unbonded validator record + k.SetValidator(ctx, validator) + + // also remove from the Bonded types.Validators Store + store.Delete(GetValidatorsBondedIndexKey(validator.OperatorAddr)) + + // call the unbond hook if present + if k.hooks != nil { + k.hooks.OnValidatorBeginUnbonding(ctx, validator.ConsAddress()) + } +} + +// perform all the store operations for when a validator status becomes unbonded +func (k Keeper) completeUnbondingValidator(ctx sdk.Context, validator types.Validator) { + store := ctx.KVStore(k.storeKey) + pool := k.GetPool(ctx) + validator, pool = validator.UpdateStatus(pool, sdk.Unbonded) + k.SetPool(ctx, pool) + k.SetValidator(ctx, validator) +} + +//______________________________________________________________________________________________________ + +func (k Keeper) updateValidatorPower(ctx sdk.Context, oldFound bool, oldValidator, + newValidator types.Validator, pool types.Pool) (valPower []byte) { + store := ctx.KVStore(k.storeKey) + + // update the list ordered by voting power + if oldFound { + store.Delete(GetValidatorsByPowerIndexKey(oldValidator, pool)) + } + valPower = GetValidatorsByPowerIndexKey(newValidator, pool) + store.Set(valPower, newValidator.OperatorAddr) + + return valPower +} + +// get the bond height and incremented intra-tx counter +// nolint: unparam +func (k Keeper) bondIncrement(ctx sdk.Context, isNewValidator bool, validator types.Validator) ( + height int64, intraTxCounter int16) { + + // if already a validator, copy the old block height and counter + if !isNewValidator && validator.Status == sdk.Bonded { + height = validator.BondHeight + intraTxCounter = validator.BondIntraTxCounter + return + } + + height = ctx.BlockHeight() + counter := k.GetIntraTxCounter(ctx) + intraTxCounter = counter + + k.SetIntraTxCounter(ctx, counter+1) + return +} + +//______________________________________________________________________________________________________ + // XXX Delete this reference function before merge // Perform all the necessary steps for when a validator changes its power. This // function updates all validator stores as well as tendermint update store. @@ -89,12 +226,6 @@ func (k Keeper) REFERENCEXXXDELETEUpdateValidator(ctx sdk.Context, validator typ powerIncreasing := k.getPowerIncreasing(ctx, oldFound, oldValidator, validator) validator.BondHeight, validator.BondIntraTxCounter = k.bondIncrement(ctx, oldFound, oldValidator) valPower := k.updateValidatorPower(ctx, oldFound, oldValidator, validator, pool) - cliffPower := k.GetCliffValidatorPower(ctx) - cliffValExists := (cliffPower != nil) - var valPowerLTcliffPower bool - if cliffValExists { - valPowerLTcliffPower = (bytes.Compare(valPower, cliffPower) == -1) - } switch { @@ -149,60 +280,6 @@ func (k Keeper) REFERENCEXXXDELETEUpdateValidator(ctx sdk.Context, validator typ return validator } -func (k Keeper) updateForJailing(ctx sdk.Context, oldFound bool, oldValidator, newValidator types.Validator) types.Validator { - if newValidator.Jailed && oldFound && oldValidator.Status == sdk.Bonded { - newValidator = k.beginUnbondingValidator(ctx, newValidator) - - // need to also clear the cliff validator spot because the jail has - // opened up a new spot which will be filled when - // updateValidatorsBonded is called - k.clearCliffValidator(ctx) - } - return newValidator -} - -// nolint: unparam -func (k Keeper) getPowerIncreasing(ctx sdk.Context, oldFound bool, oldValidator, newValidator types.Validator) bool { - if oldFound && oldValidator.BondedTokens().LT(newValidator.BondedTokens()) { - return true - } - return false -} - -// get the bond height and incremented intra-tx counter -// nolint: unparam -func (k Keeper) bondIncrement( - ctx sdk.Context, found bool, oldValidator types.Validator) (height int64, intraTxCounter int16) { - - // if already a validator, copy the old block height and counter - if found && oldValidator.Status == sdk.Bonded { - height = oldValidator.BondHeight - intraTxCounter = oldValidator.BondIntraTxCounter - return - } - - height = ctx.BlockHeight() - counter := k.GetIntraTxCounter(ctx) - intraTxCounter = counter - - k.SetIntraTxCounter(ctx, counter+1) - return -} - -func (k Keeper) updateValidatorPower(ctx sdk.Context, oldFound bool, oldValidator, - newValidator types.Validator, pool types.Pool) (valPower []byte) { - store := ctx.KVStore(k.storeKey) - - // update the list ordered by voting power - if oldFound { - store.Delete(GetValidatorsByPowerIndexKey(oldValidator, pool)) - } - valPower = GetValidatorsByPowerIndexKey(newValidator, pool) - store.Set(valPower, newValidator.OperatorAddr) - - return valPower -} - // XXX Delete this reference function before merge // Update the bonded validator group based on a change to the validator // affectedValidator. This function potentially adds the affectedValidator to @@ -266,17 +343,6 @@ func (k Keeper) XXXREFERENCEUpdateBondedValidators( iterator.Close() - if newValidatorBonded && bytes.Equal(oldCliffValidatorAddr, validator.OperatorAddr) { - panic("cliff validator has not been changed, yet we bonded a new validator") - } - - // clear or set the cliff validator - if bondedValidatorsCount == int(maxValidators) { - k.setCliffValidator(ctx, validator, k.GetPool(ctx)) - } else if len(oldCliffValidatorAddr) > 0 { - k.clearCliffValidator(ctx) - } - // swap the cliff validator for a new validator if the affected validator // was bonded if newValidatorBonded { @@ -305,149 +371,3 @@ func (k Keeper) XXXREFERENCEUpdateBondedValidators( return types.Validator{}, false } - -// XXX Delete this reference function before merge -// full update of the bonded validator set, many can be added/kicked -func (k Keeper) XXXREFERENCEUpdateBondedValidatorsFull(ctx sdk.Context) { - store := ctx.KVStore(k.storeKey) - - // clear the current validators store, add to the ToKickOut temp store - toKickOut := make(map[string]byte) - iterator := sdk.KVStorePrefixIterator(store, ValidatorsBondedIndexKey) - for ; iterator.Valid(); iterator.Next() { - ownerAddr := GetAddressFromValBondedIndexKey(iterator.Key()) - toKickOut[string(ownerAddr)] = 0 - } - - iterator.Close() - - var validator types.Validator - - oldCliffValidatorAddr := k.GetCliffValidator(ctx) - maxValidators := k.GetParams(ctx).MaxValidators - bondedValidatorsCount := 0 - - iterator = sdk.KVStoreReversePrefixIterator(store, ValidatorsByPowerIndexKey) - for ; iterator.Valid() && bondedValidatorsCount < int(maxValidators); iterator.Next() { - var found bool - - ownerAddr := iterator.Value() - validator = k.mustGetValidator(ctx, ownerAddr) - - _, found = toKickOut[string(ownerAddr)] - if found { - delete(toKickOut, string(ownerAddr)) - } else { - // If the validator wasn't in the toKickOut group it means it wasn't - // previously a validator, therefor update the validator to enter - // the validator group. - validator = k.bondValidator(ctx, validator) - } - - if validator.Jailed { - // we should no longer consider jailed validators as they are ranked - // lower than any non-jailed/bonded validators - if validator.Status == sdk.Bonded { - panic(fmt.Sprintf("jailed validator cannot be bonded for address: %s\n", ownerAddr)) - } - break - } - - bondedValidatorsCount++ - } - - iterator.Close() - - // clear or set the cliff validator - if bondedValidatorsCount == int(maxValidators) { - k.setCliffValidator(ctx, validator, k.GetPool(ctx)) - } else if len(oldCliffValidatorAddr) > 0 { - k.clearCliffValidator(ctx) - } - - kickOutValidators(k, ctx, toKickOut) - return -} - -func kickOutValidators(k Keeper, ctx sdk.Context, toKickOut map[string]byte) { - for key := range toKickOut { - ownerAddr := []byte(key) - validator := k.mustGetValidator(ctx, ownerAddr) - k.beginUnbondingValidator(ctx, validator) - } -} - -// perform all the store operations for when a validator status becomes unbonded -func (k Keeper) beginUnbondingValidator(ctx sdk.Context, validator types.Validator) types.Validator { - - store := ctx.KVStore(k.storeKey) - pool := k.GetPool(ctx) - params := k.GetParams(ctx) - - // sanity check - if validator.Status == sdk.Unbonded || - validator.Status == sdk.Unbonding { - panic(fmt.Sprintf("should not already be unbonded or unbonding, validator: %v\n", validator)) - } - - // set the status - validator, pool = validator.UpdateStatus(pool, sdk.Unbonding) - k.SetPool(ctx, pool) - - validator.UnbondingMinTime = ctx.BlockHeader().Time.Add(params.UnbondingTime) - validator.UnbondingHeight = ctx.BlockHeader().Height - - // save the now unbonded validator record - k.SetValidator(ctx, validator) - - // add to accumulated changes for tendermint - bzABCI := k.cdc.MustMarshalBinary(validator.ABCIValidatorZero()) - tstore := ctx.TransientStore(k.storeTKey) - tstore.Set(GetTendermintUpdatesTKey(validator.OperatorAddr), bzABCI) - - // also remove from the Bonded types.Validators Store - store.Delete(GetValidatorsBondedIndexKey(validator.OperatorAddr)) - - // call the unbond hook if present - if k.hooks != nil { - k.hooks.OnValidatorBeginUnbonding(ctx, validator.ConsAddress()) - } - - // return updated validator - return validator -} - -// perform all the store operations for when a validator status becomes bonded -func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) types.Validator { - - store := ctx.KVStore(k.storeKey) - pool := k.GetPool(ctx) - - // sanity check - if validator.Status == sdk.Bonded { - panic(fmt.Sprintf("should not already be bonded, validator: %v\n", validator)) - } - - validator.BondHeight = ctx.BlockHeight() - - // set the status - validator, pool = validator.UpdateStatus(pool, sdk.Bonded) - k.SetPool(ctx, pool) - - // save the now bonded validator record to the three referenced stores - k.SetValidator(ctx, validator) - store.Set(GetValidatorsBondedIndexKey(validator.OperatorAddr), []byte{}) - - // add to accumulated changes for tendermint - bzABCI := k.cdc.MustMarshalBinary(validator.ABCIValidator()) - tstore := ctx.TransientStore(k.storeTKey) - tstore.Set(GetTendermintUpdatesTKey(validator.OperatorAddr), bzABCI) - - // call the bond hook if present - if k.hooks != nil { - k.hooks.OnValidatorBonded(ctx, validator.ConsAddress()) - } - - // return updated validator - return validator -} diff --git a/x/stake/keeper/validator.go b/x/stake/keeper/validator.go index 3e68474cd0de..b3f2075fd99d 100644 --- a/x/stake/keeper/validator.go +++ b/x/stake/keeper/validator.go @@ -98,10 +98,21 @@ func (k Keeper) SetValidatorBondedIndex(ctx sdk.Context, validator types.Validat store.Set(GetValidatorsBondedIndexKey(validator.OperatorAddr), []byte{}) } -// used in testing -func (k Keeper) validatorByPowerIndexExists(ctx sdk.Context, power []byte) bool { - store := ctx.KVStore(k.storeKey) - return store.Get(power) != nil +// UpdateValidatorCommission attempts to update a validator's commission rate. +// An error is returned if the new commission rate is invalid. +func (k Keeper) UpdateValidatorCommission(ctx sdk.Context, validator types.Validator, newRate sdk.Dec) sdk.Error { + commission := validator.Commission + blockTime := ctx.BlockHeader().Time + + if err := commission.ValidateNewRate(newRate, blockTime); err != nil { + return err + } + + validator.Commission.Rate = newRate + validator.Commission.UpdateTime = blockTime + + k.SetValidator(ctx, validator) + return nil } // Get the set of all validators with no limits, used during genesis dump @@ -189,23 +200,6 @@ func (k Keeper) GetValidatorsByPower(ctx sdk.Context) []types.Validator { return validators[:i] // trim } -// UpdateValidatorCommission attempts to update a validator's commission rate. -// An error is returned if the new commission rate is invalid. -func (k Keeper) UpdateValidatorCommission(ctx sdk.Context, validator types.Validator, newRate sdk.Dec) sdk.Error { - commission := validator.Commission - blockTime := ctx.BlockHeader().Time - - if err := commission.ValidateNewRate(newRate, blockTime); err != nil { - return err - } - - validator.Commission.Rate = newRate - validator.Commission.UpdateTime = blockTime - - k.SetValidator(ctx, validator) - return nil -} - // remove the validator record and associated indexes func (k Keeper) RemoveValidator(ctx sdk.Context, address sdk.ValAddress) { diff --git a/x/stake/keeper/validator_test.go b/x/stake/keeper/validator_test.go index 73a391acc70a..e018fa41097a 100644 --- a/x/stake/keeper/validator_test.go +++ b/x/stake/keeper/validator_test.go @@ -25,6 +25,11 @@ func clearTendermintUpdates(ctx sdk.Context, k Keeper) { iterator.Close() } +func validatorByPowerIndexExists(k Keeper, ctx sdk.Context, power []byte) bool { + store := ctx.KVStore(k.storeKey) + return store.Get(power) != nil +} + //_______________________________________________________ func TestSetValidator(t *testing.T) { @@ -101,20 +106,20 @@ func TestUpdateValidatorByPowerIndex(t *testing.T) { pool = keeper.GetPool(ctx) power := GetValidatorsByPowerIndexKey(validator, pool) - require.True(t, keeper.validatorByPowerIndexExists(ctx, power)) + require.True(t, validatorByPowerIndexExists(keeper, ctx, power)) // burn half the delegator shares validator, pool, burned := validator.RemoveDelShares(pool, delSharesCreated.Quo(sdk.NewDec(2))) require.Equal(t, int64(50), burned.RoundInt64()) keeper.SetPool(ctx, pool) // update the pool keeper.UpdateValidator(ctx, validator) // update the validator, possibly kicking it out - require.False(t, keeper.validatorByPowerIndexExists(ctx, power)) + require.False(t, validatorByPowerIndexExists(keeper, ctx, power)) pool = keeper.GetPool(ctx) validator, found = keeper.GetValidator(ctx, addrVals[0]) require.True(t, found) power = GetValidatorsByPowerIndexKey(validator, pool) - require.True(t, keeper.validatorByPowerIndexExists(ctx, power)) + require.True(t, validatorByPowerIndexExists(keeper, ctx, power)) } func TestUpdateBondedValidatorsDecreaseCliff(t *testing.T) { diff --git a/x/stake/types/validator.go b/x/stake/types/validator.go index 051ffa9e5168..345df1bf95f1 100644 --- a/x/stake/types/validator.go +++ b/x/stake/types/validator.go @@ -430,6 +430,7 @@ func (v Validator) BondedTokens() sdk.Dec { return sdk.ZeroDec() } +// TODO remove this once the validator queue logic is implemented // Returns if the validator should be considered unbonded func (v Validator) IsUnbonded(ctx sdk.Context) bool { switch v.Status { From b6575bb15be583c188dea182ce82e61fa2963997 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 26 Sep 2018 01:36:20 -0400 Subject: [PATCH 07/44] reorganizing --- x/stake/keeper/validator.go | 78 ++++++++++++++++++++++--------------- 1 file changed, 47 insertions(+), 31 deletions(-) diff --git a/x/stake/keeper/validator.go b/x/stake/keeper/validator.go index b3f2075fd99d..c1d518ae8e7c 100644 --- a/x/stake/keeper/validator.go +++ b/x/stake/keeper/validator.go @@ -92,6 +92,21 @@ func (k Keeper) SetValidatorByPowerIndex(ctx sdk.Context, validator types.Valida store.Set(GetValidatorsByPowerIndexKey(validator, pool), validator.OperatorAddr) } +// Update the validators power index key +func (k Keeper) updateValidatorPower(ctx sdk.Context, + oldFound bool, oldValidator, newValidator types.Validator) { + + store := ctx.KVStore(k.storeKey) + pool := store.GetPool(ctx) + + // update the list ordered by voting power + if oldFound { + store.Delete(GetValidatorsByPowerIndexKey(oldValidator, pool)) + } + valPower = GetValidatorsByPowerIndexKey(newValidator, pool) + store.Set(valPower, newValidator.OperatorAddr) +} + // validator index func (k Keeper) SetValidatorBondedIndex(ctx sdk.Context, validator types.Validator) { store := ctx.KVStore(k.storeKey) @@ -115,7 +130,38 @@ func (k Keeper) UpdateValidatorCommission(ctx sdk.Context, validator types.Valid return nil } -// Get the set of all validators with no limits, used during genesis dump +// remove the validator record and associated indexes +func (k Keeper) RemoveValidator(ctx sdk.Context, address sdk.ValAddress) { + + // first retrieve the old validator record + validator, found := k.GetValidator(ctx, address) + if !found { + return + } + + // delete the old validator record + store := ctx.KVStore(k.storeKey) + pool := k.GetPool(ctx) + store.Delete(GetValidatorKey(address)) + store.Delete(GetValidatorByConsAddrKey(sdk.ConsAddress(validator.ConsPubKey.Address()))) + store.Delete(GetValidatorsByPowerIndexKey(validator, pool)) + + // delete from the current and power weighted validator groups if the validator + // is bonded - and add validator with zero power to the validator updates + if store.Get(GetValidatorsBondedIndexKey(validator.OperatorAddr)) == nil { + return + } + store.Delete(GetValidatorsBondedIndexKey(validator.OperatorAddr)) + + bz := k.cdc.MustMarshalBinary(validator.ABCIValidatorZero()) + tstore := ctx.TransientStore(k.storeTKey) + tstore.Set(GetTendermintUpdatesTKey(address), bz) +} + +//___________________________________________________________________________ +// get groups of validators + +// get the set of all validators with no limits, used during genesis dump func (k Keeper) GetAllValidators(ctx sdk.Context) (validators []types.Validator) { store := ctx.KVStore(k.storeKey) iterator := sdk.KVStorePrefixIterator(store, ValidatorsKey) @@ -147,8 +193,6 @@ func (k Keeper) GetValidators(ctx sdk.Context, maxRetrieve uint16) (validators [ return validators[:i] // trim if the array length < maxRetrieve } -//___________________________________________________________________________ - // get the group of the bonded validators func (k Keeper) GetValidatorsBonded(ctx sdk.Context) (validators []types.Validator) { store := ctx.KVStore(k.storeKey) @@ -199,31 +243,3 @@ func (k Keeper) GetValidatorsByPower(ctx sdk.Context) []types.Validator { } return validators[:i] // trim } - -// remove the validator record and associated indexes -func (k Keeper) RemoveValidator(ctx sdk.Context, address sdk.ValAddress) { - - // first retrieve the old validator record - validator, found := k.GetValidator(ctx, address) - if !found { - return - } - - // delete the old validator record - store := ctx.KVStore(k.storeKey) - pool := k.GetPool(ctx) - store.Delete(GetValidatorKey(address)) - store.Delete(GetValidatorByConsAddrKey(sdk.ConsAddress(validator.ConsPubKey.Address()))) - store.Delete(GetValidatorsByPowerIndexKey(validator, pool)) - - // delete from the current and power weighted validator groups if the validator - // is bonded - and add validator with zero power to the validator updates - if store.Get(GetValidatorsBondedIndexKey(validator.OperatorAddr)) == nil { - return - } - store.Delete(GetValidatorsBondedIndexKey(validator.OperatorAddr)) - - bz := k.cdc.MustMarshalBinary(validator.ABCIValidatorZero()) - tstore := ctx.TransientStore(k.storeTKey) - tstore.Set(GetTendermintUpdatesTKey(address), bz) -} From 52c413f582f4d5d9a09d2156fb1d660eb1bf12be Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 26 Sep 2018 01:37:17 -0400 Subject: [PATCH 08/44] GetValidatorsByPower -> GetBondedValidatorsByPower --- x/stake/handler_test.go | 6 ++-- x/stake/keeper/key.go | 2 +- x/stake/keeper/val_state_change.go | 4 +-- x/stake/keeper/validator.go | 12 +++---- x/stake/keeper/validator_test.go | 50 +++++++++++++++--------------- x/stake/stake.go | 2 +- 6 files changed, 38 insertions(+), 38 deletions(-) diff --git a/x/stake/handler_test.go b/x/stake/handler_test.go index 5780bf5431bb..91fd51c2527e 100644 --- a/x/stake/handler_test.go +++ b/x/stake/handler_test.go @@ -75,7 +75,7 @@ func TestValidatorByPowerIndex(t *testing.T) { validator, found := keeper.GetValidator(ctx, validatorAddr) require.True(t, found) pool := keeper.GetPool(ctx) - power := keep.GetValidatorsByPowerIndexKey(validator, pool) + power := keep.GetBondedValidatorsByPowerIndexKey(validator, pool) require.True(t, keep.ValidatorByPowerIndexExists(ctx, keeper, power)) // create a second validator keep it bonded @@ -99,7 +99,7 @@ func TestValidatorByPowerIndex(t *testing.T) { validator, found = keeper.GetValidator(ctx, validatorAddr) require.True(t, found) pool = keeper.GetPool(ctx) - power2 := GetValidatorsByPowerIndexKey(validator, pool) + power2 := GetBondedValidatorsByPowerIndexKey(validator, pool) require.True(t, keep.ValidatorByPowerIndexExists(ctx, keeper, power2)) // inflate a bunch @@ -110,7 +110,7 @@ func TestValidatorByPowerIndex(t *testing.T) { } // now the new record power index should be the same as the original record - power3 := GetValidatorsByPowerIndexKey(validator, pool) + power3 := GetBondedValidatorsByPowerIndexKey(validator, pool) require.Equal(t, power2, power3) // unbond self-delegation diff --git a/x/stake/keeper/key.go b/x/stake/keeper/key.go index 3de145c91f33..8bd0de35ad40 100644 --- a/x/stake/keeper/key.go +++ b/x/stake/keeper/key.go @@ -60,7 +60,7 @@ func GetAddressFromValBondedIndexKey(IndexKey []byte) []byte { // Power index is the key used in the power-store, and represents the relative // power ranking of the validator. // VALUE: validator operator address ([]byte) -func GetValidatorsByPowerIndexKey(validator types.Validator, pool types.Pool) []byte { +func GetBondedValidatorsByPowerIndexKey(validator types.Validator, pool types.Pool) []byte { // NOTE the address doesn't need to be stored because counter bytes must always be different return getValidatorPowerRank(validator, pool) } diff --git a/x/stake/keeper/val_state_change.go b/x/stake/keeper/val_state_change.go index 88c6a6a9053c..551340a64e91 100644 --- a/x/stake/keeper/val_state_change.go +++ b/x/stake/keeper/val_state_change.go @@ -180,9 +180,9 @@ func (k Keeper) updateValidatorPower(ctx sdk.Context, oldFound bool, oldValidato // update the list ordered by voting power if oldFound { - store.Delete(GetValidatorsByPowerIndexKey(oldValidator, pool)) + store.Delete(GetBondedValidatorsByPowerIndexKey(oldValidator, pool)) } - valPower = GetValidatorsByPowerIndexKey(newValidator, pool) + valPower = GetBondedValidatorsByPowerIndexKey(newValidator, pool) store.Set(valPower, newValidator.OperatorAddr) return valPower diff --git a/x/stake/keeper/validator.go b/x/stake/keeper/validator.go index c1d518ae8e7c..ccda8b81e77b 100644 --- a/x/stake/keeper/validator.go +++ b/x/stake/keeper/validator.go @@ -89,7 +89,7 @@ func (k Keeper) SetValidatorByConsAddr(ctx sdk.Context, validator types.Validato // validator index func (k Keeper) SetValidatorByPowerIndex(ctx sdk.Context, validator types.Validator, pool types.Pool) { store := ctx.KVStore(k.storeKey) - store.Set(GetValidatorsByPowerIndexKey(validator, pool), validator.OperatorAddr) + store.Set(GetBondedValidatorsByPowerIndexKey(validator, pool), validator.OperatorAddr) } // Update the validators power index key @@ -101,9 +101,9 @@ func (k Keeper) updateValidatorPower(ctx sdk.Context, // update the list ordered by voting power if oldFound { - store.Delete(GetValidatorsByPowerIndexKey(oldValidator, pool)) + store.Delete(GetBondedValidatorsByPowerIndexKey(oldValidator, pool)) } - valPower = GetValidatorsByPowerIndexKey(newValidator, pool) + valPower = GetBondedValidatorsByPowerIndexKey(newValidator, pool) store.Set(valPower, newValidator.OperatorAddr) } @@ -144,7 +144,7 @@ func (k Keeper) RemoveValidator(ctx sdk.Context, address sdk.ValAddress) { pool := k.GetPool(ctx) store.Delete(GetValidatorKey(address)) store.Delete(GetValidatorByConsAddrKey(sdk.ConsAddress(validator.ConsPubKey.Address()))) - store.Delete(GetValidatorsByPowerIndexKey(validator, pool)) + store.Delete(GetBondedValidatorsByPowerIndexKey(validator, pool)) // delete from the current and power weighted validator groups if the validator // is bonded - and add validator with zero power to the validator updates @@ -222,8 +222,8 @@ func (k Keeper) GetValidatorsBonded(ctx sdk.Context) (validators []types.Validat // get the group of bonded validators sorted by power-rank // -// TODO: Rename to GetBondedValidatorsByPower or GetValidatorsByPower(ctx, status) -func (k Keeper) GetValidatorsByPower(ctx sdk.Context) []types.Validator { +// TODO: Rename to GetBondedValidatorsByPower or GetBondedValidatorsByPower(ctx, status) +func (k Keeper) GetBondedValidatorsByPower(ctx sdk.Context) []types.Validator { store := ctx.KVStore(k.storeKey) maxValidators := k.GetParams(ctx).MaxValidators validators := make([]types.Validator, maxValidators) diff --git a/x/stake/keeper/validator_test.go b/x/stake/keeper/validator_test.go index e018fa41097a..ab6ac7e72520 100644 --- a/x/stake/keeper/validator_test.go +++ b/x/stake/keeper/validator_test.go @@ -64,7 +64,7 @@ func TestSetValidator(t *testing.T) { require.Equal(t, 1, len(resVals)) assert.True(ValEq(t, validator, resVals[0])) - resVals = keeper.GetValidatorsByPower(ctx) + resVals = keeper.GetBondedValidatorsByPower(ctx) require.Equal(t, 1, len(resVals)) require.True(ValEq(t, validator, resVals[0])) @@ -105,7 +105,7 @@ func TestUpdateValidatorByPowerIndex(t *testing.T) { require.Equal(t, int64(100), validator.Tokens.RoundInt64(), "\nvalidator %v\npool %v", validator, pool) pool = keeper.GetPool(ctx) - power := GetValidatorsByPowerIndexKey(validator, pool) + power := GetBondedValidatorsByPowerIndexKey(validator, pool) require.True(t, validatorByPowerIndexExists(keeper, ctx, power)) // burn half the delegator shares @@ -118,7 +118,7 @@ func TestUpdateValidatorByPowerIndex(t *testing.T) { pool = keeper.GetPool(ctx) validator, found = keeper.GetValidator(ctx, addrVals[0]) require.True(t, found) - power = GetValidatorsByPowerIndexKey(validator, pool) + power = GetBondedValidatorsByPowerIndexKey(validator, pool) require.True(t, validatorByPowerIndexExists(keeper, ctx, power)) } @@ -167,7 +167,7 @@ func TestUpdateBondedValidatorsDecreaseCliff(t *testing.T) { // require the cliff validator power has changed cliffPower := keeper.GetCliffValidatorPower(ctx) - require.Equal(t, GetValidatorsByPowerIndexKey(cliffVal, pool), cliffPower) + require.Equal(t, GetBondedValidatorsByPowerIndexKey(cliffVal, pool), cliffPower) expectedValStatus := map[int]sdk.BondStatus{ 9: sdk.Bonded, 8: sdk.Bonded, 7: sdk.Bonded, 5: sdk.Bonded, 4: sdk.Bonded, @@ -230,7 +230,7 @@ func TestCliffValidatorChange(t *testing.T) { // assert cliff validator power should have been updated cliffPower := keeper.GetCliffValidatorPower(ctx) - require.Equal(t, GetValidatorsByPowerIndexKey(newCliffVal, pool), cliffPower) + require.Equal(t, GetBondedValidatorsByPowerIndexKey(newCliffVal, pool), cliffPower) // add small amount of tokens to new current cliff validator newCliffVal, pool, _ = newCliffVal.AddTokensFromDel(pool, sdk.NewInt(1)) @@ -240,7 +240,7 @@ func TestCliffValidatorChange(t *testing.T) { // assert cliff validator has not change but increased in power cliffPower = keeper.GetCliffValidatorPower(ctx) require.Equal(t, newCliffVal.OperatorAddr, sdk.ValAddress(keeper.GetCliffValidator(ctx))) - require.Equal(t, GetValidatorsByPowerIndexKey(newCliffVal, pool), cliffPower) + require.Equal(t, GetBondedValidatorsByPowerIndexKey(newCliffVal, pool), cliffPower) // add enough power to cliff validator to be equal in rank to next validator newCliffVal, pool, _ = newCliffVal.AddTokensFromDel(pool, sdk.NewInt(9)) @@ -253,7 +253,7 @@ func TestCliffValidatorChange(t *testing.T) { // assert cliff validator power should have been updated cliffPower = keeper.GetCliffValidatorPower(ctx) - require.Equal(t, GetValidatorsByPowerIndexKey(newCliffVal, pool), cliffPower) + require.Equal(t, GetBondedValidatorsByPowerIndexKey(newCliffVal, pool), cliffPower) } func TestSlashToZeroPowerRemoved(t *testing.T) { @@ -369,7 +369,7 @@ func TestValidatorBasics(t *testing.T) { require.False(t, found) } -// test how the validators are sorted, tests GetValidatorsByPower +// test how the validators are sorted, tests GetBondedValidatorsByPower func GetValidatorSortingUnmixed(t *testing.T) { ctx, _, keeper := CreateTestInput(t, false, 1000) @@ -386,7 +386,7 @@ func GetValidatorSortingUnmixed(t *testing.T) { } // first make sure everything made it in to the gotValidator group - resValidators := keeper.GetValidatorsByPower(ctx) + resValidators := keeper.GetBondedValidatorsByPower(ctx) assert.Equal(t, n, len(resValidators)) assert.Equal(t, sdk.NewDec(400), resValidators[0].BondedTokens(), "%v", resValidators) assert.Equal(t, sdk.NewDec(200), resValidators[1].BondedTokens(), "%v", resValidators) @@ -402,14 +402,14 @@ func GetValidatorSortingUnmixed(t *testing.T) { // test a basic increase in voting power validators[3].Tokens = sdk.NewDec(500) keeper.UpdateValidator(ctx, validators[3]) - resValidators = keeper.GetValidatorsByPower(ctx) + resValidators = keeper.GetBondedValidatorsByPower(ctx) require.Equal(t, len(resValidators), n) assert.True(ValEq(t, validators[3], resValidators[0])) // test a decrease in voting power validators[3].Tokens = sdk.NewDec(300) keeper.UpdateValidator(ctx, validators[3]) - resValidators = keeper.GetValidatorsByPower(ctx) + resValidators = keeper.GetBondedValidatorsByPower(ctx) require.Equal(t, len(resValidators), n) assert.True(ValEq(t, validators[3], resValidators[0])) assert.True(ValEq(t, validators[4], resValidators[1])) @@ -418,7 +418,7 @@ func GetValidatorSortingUnmixed(t *testing.T) { validators[3].Tokens = sdk.NewDec(200) ctx = ctx.WithBlockHeight(10) keeper.UpdateValidator(ctx, validators[3]) - resValidators = keeper.GetValidatorsByPower(ctx) + resValidators = keeper.GetBondedValidatorsByPower(ctx) require.Equal(t, len(resValidators), n) assert.True(ValEq(t, validators[3], resValidators[0])) assert.True(ValEq(t, validators[4], resValidators[1])) @@ -428,7 +428,7 @@ func GetValidatorSortingUnmixed(t *testing.T) { // no change in voting power - no change in sort ctx = ctx.WithBlockHeight(20) keeper.UpdateValidator(ctx, validators[4]) - resValidators = keeper.GetValidatorsByPower(ctx) + resValidators = keeper.GetBondedValidatorsByPower(ctx) require.Equal(t, len(resValidators), n) assert.True(ValEq(t, validators[3], resValidators[0])) assert.True(ValEq(t, validators[4], resValidators[1])) @@ -437,11 +437,11 @@ func GetValidatorSortingUnmixed(t *testing.T) { validators[3].Tokens = sdk.NewDec(300) validators[4].Tokens = sdk.NewDec(300) keeper.UpdateValidator(ctx, validators[3]) - resValidators = keeper.GetValidatorsByPower(ctx) + resValidators = keeper.GetBondedValidatorsByPower(ctx) require.Equal(t, len(resValidators), n) ctx = ctx.WithBlockHeight(30) keeper.UpdateValidator(ctx, validators[4]) - resValidators = keeper.GetValidatorsByPower(ctx) + resValidators = keeper.GetBondedValidatorsByPower(ctx) require.Equal(t, len(resValidators), n, "%v", resValidators) assert.True(ValEq(t, validators[3], resValidators[0])) assert.True(ValEq(t, validators[4], resValidators[1])) @@ -497,7 +497,7 @@ func GetValidatorSortingMixed(t *testing.T) { require.Equal(t, sdk.Bonded, val4.Status) // first make sure everything made it in to the gotValidator group - resValidators := keeper.GetValidatorsByPower(ctx) + resValidators := keeper.GetBondedValidatorsByPower(ctx) assert.Equal(t, n, len(resValidators)) assert.Equal(t, sdk.NewDec(400), resValidators[0].BondedTokens(), "%v", resValidators) assert.Equal(t, sdk.NewDec(200), resValidators[1].BondedTokens(), "%v", resValidators) @@ -538,7 +538,7 @@ func TestGetValidatorsEdgeCases(t *testing.T) { validators[i], found = keeper.GetValidator(ctx, validators[i].OperatorAddr) require.True(t, found) } - resValidators := keeper.GetValidatorsByPower(ctx) + resValidators := keeper.GetBondedValidatorsByPower(ctx) require.Equal(t, nMax, uint16(len(resValidators))) assert.True(ValEq(t, validators[2], resValidators[0])) assert.True(ValEq(t, validators[3], resValidators[1])) @@ -547,7 +547,7 @@ func TestGetValidatorsEdgeCases(t *testing.T) { validators[0], pool, _ = validators[0].AddTokensFromDel(pool, sdk.NewInt(500)) keeper.SetPool(ctx, pool) validators[0] = keeper.UpdateValidator(ctx, validators[0]) - resValidators = keeper.GetValidatorsByPower(ctx) + resValidators = keeper.GetBondedValidatorsByPower(ctx) require.Equal(t, nMax, uint16(len(resValidators))) assert.True(ValEq(t, validators[0], resValidators[0])) assert.True(ValEq(t, validators[2], resValidators[1])) @@ -564,7 +564,7 @@ func TestGetValidatorsEdgeCases(t *testing.T) { validators[3], pool, _ = validators[3].AddTokensFromDel(pool, sdk.NewInt(1)) keeper.SetPool(ctx, pool) validators[3] = keeper.UpdateValidator(ctx, validators[3]) - resValidators = keeper.GetValidatorsByPower(ctx) + resValidators = keeper.GetBondedValidatorsByPower(ctx) require.Equal(t, nMax, uint16(len(resValidators))) assert.True(ValEq(t, validators[0], resValidators[0])) assert.True(ValEq(t, validators[3], resValidators[1])) @@ -573,7 +573,7 @@ func TestGetValidatorsEdgeCases(t *testing.T) { validators[3], pool, _ = validators[3].RemoveDelShares(pool, sdk.NewDec(201)) keeper.SetPool(ctx, pool) validators[3] = keeper.UpdateValidator(ctx, validators[3]) - resValidators = keeper.GetValidatorsByPower(ctx) + resValidators = keeper.GetBondedValidatorsByPower(ctx) require.Equal(t, nMax, uint16(len(resValidators))) assert.True(ValEq(t, validators[0], resValidators[0])) assert.True(ValEq(t, validators[2], resValidators[1])) @@ -582,7 +582,7 @@ func TestGetValidatorsEdgeCases(t *testing.T) { validators[3], pool, _ = validators[3].AddTokensFromDel(pool, sdk.NewInt(200)) keeper.SetPool(ctx, pool) validators[3] = keeper.UpdateValidator(ctx, validators[3]) - resValidators = keeper.GetValidatorsByPower(ctx) + resValidators = keeper.GetBondedValidatorsByPower(ctx) require.Equal(t, nMax, uint16(len(resValidators))) assert.True(ValEq(t, validators[0], resValidators[0])) assert.True(ValEq(t, validators[2], resValidators[1])) @@ -621,7 +621,7 @@ func TestValidatorBondHeight(t *testing.T) { pool = keeper.GetPool(ctx) - resValidators := keeper.GetValidatorsByPower(ctx) + resValidators := keeper.GetBondedValidatorsByPower(ctx) require.Equal(t, uint16(len(resValidators)), params.MaxValidators) assert.True(ValEq(t, validators[0], resValidators[0])) @@ -630,7 +630,7 @@ func TestValidatorBondHeight(t *testing.T) { validators[2], pool, _ = validators[2].AddTokensFromDel(pool, sdk.NewInt(50)) keeper.SetPool(ctx, pool) validators[2] = keeper.UpdateValidator(ctx, validators[2]) - resValidators = keeper.GetValidatorsByPower(ctx) + resValidators = keeper.GetBondedValidatorsByPower(ctx) require.Equal(t, params.MaxValidators, uint16(len(resValidators))) validators[1] = keeper.UpdateValidator(ctx, validators[1]) assert.True(ValEq(t, validators[0], resValidators[0])) @@ -664,7 +664,7 @@ func TestFullValidatorSetPowerChange(t *testing.T) { assert.Equal(t, sdk.Bonded, validators[2].Status) assert.Equal(t, sdk.Bonded, validators[3].Status) assert.Equal(t, sdk.Unbonded, validators[4].Status) - resValidators := keeper.GetValidatorsByPower(ctx) + resValidators := keeper.GetBondedValidatorsByPower(ctx) assert.Equal(t, max, len(resValidators)) assert.True(ValEq(t, validators[2], resValidators[0])) // in the order of txs assert.True(ValEq(t, validators[3], resValidators[1])) @@ -674,7 +674,7 @@ func TestFullValidatorSetPowerChange(t *testing.T) { validators[0], pool, _ = validators[0].AddTokensFromDel(pool, sdk.NewInt(600)) keeper.SetPool(ctx, pool) validators[0] = keeper.UpdateValidator(ctx, validators[0]) - resValidators = keeper.GetValidatorsByPower(ctx) + resValidators = keeper.GetBondedValidatorsByPower(ctx) assert.Equal(t, max, len(resValidators)) assert.True(ValEq(t, validators[0], resValidators[0])) assert.True(ValEq(t, validators[2], resValidators[1])) diff --git a/x/stake/stake.go b/x/stake/stake.go index 7e60b3113a83..5da9b0083ca1 100644 --- a/x/stake/stake.go +++ b/x/stake/stake.go @@ -38,7 +38,7 @@ var ( GetValidatorKey = keeper.GetValidatorKey GetValidatorByConsAddrKey = keeper.GetValidatorByConsAddrKey GetValidatorsBondedIndexKey = keeper.GetValidatorsBondedIndexKey - GetValidatorsByPowerIndexKey = keeper.GetValidatorsByPowerIndexKey + GetBondedValidatorsByPowerIndexKey = keeper.GetBondedValidatorsByPowerIndexKey GetTendermintUpdatesTKey = keeper.GetTendermintUpdatesTKey GetDelegationKey = keeper.GetDelegationKey GetDelegationsKey = keeper.GetDelegationsKey From 7debae02889951b9c535fc889ada20782f8dab3f Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 26 Sep 2018 02:09:58 -0400 Subject: [PATCH 09/44] remove duplicate SetValidator in handleMsgEditValidator --- x/stake/handler.go | 4 +-- x/stake/keeper/validator.go | 50 +++++++++++++++++++++++-------------- 2 files changed, 33 insertions(+), 21 deletions(-) diff --git a/x/stake/handler.go b/x/stake/handler.go index 0524b2c117b7..94e2381e114f 100644 --- a/x/stake/handler.go +++ b/x/stake/handler.go @@ -126,13 +126,13 @@ func handleMsgEditValidator(ctx sdk.Context, msg types.MsgEditValidator, k keepe validator.Description = description if msg.CommissionRate != nil { + commission, err := k.UpdateValidatorCommission(ctx, validator, *msg.CommissionRate) if err := k.UpdateValidatorCommission(ctx, validator, *msg.CommissionRate); err != nil { return err.Result() } + validator.Commission = commission } - // We don't need to run through all the power update logic within k.UpdateValidator - // We just need to override the entry in state, since only the description has changed. k.SetValidator(ctx, validator) tags := sdk.NewTags( diff --git a/x/stake/keeper/validator.go b/x/stake/keeper/validator.go index ccda8b81e77b..c45ef0d708b3 100644 --- a/x/stake/keeper/validator.go +++ b/x/stake/keeper/validator.go @@ -72,6 +72,8 @@ func (k Keeper) GetValidatorByConsAddr(ctx sdk.Context, consAddr sdk.ConsAddress return k.GetValidator(ctx, opAddr) } +//___________________________________________________________________________ + // set the main record holding validator details func (k Keeper) SetValidator(ctx sdk.Context, validator types.Validator) { store := ctx.KVStore(k.storeKey) @@ -92,42 +94,54 @@ func (k Keeper) SetValidatorByPowerIndex(ctx sdk.Context, validator types.Valida store.Set(GetBondedValidatorsByPowerIndexKey(validator, pool), validator.OperatorAddr) } -// Update the validators power index key -func (k Keeper) updateValidatorPower(ctx sdk.Context, - oldFound bool, oldValidator, newValidator types.Validator) { +// validator index +func (k Keeper) SetValidatorBondedIndex(ctx sdk.Context, validator types.Validator) { + store := ctx.KVStore(k.storeKey) + store.Set(GetValidatorsBondedIndexKey(validator.OperatorAddr), []byte{}) +} +//___________________________________________________________________________ + +// Update the tokens of an existing validator, update the validators power index key +func (k Keeper) UpdateValidatorTokens(ctx sdk.Context, validator types.Validator, newTokens sdk.Dec) sdk.Error { store := ctx.KVStore(k.storeKey) pool := store.GetPool(ctx) - // update the list ordered by voting power - if oldFound { - store.Delete(GetBondedValidatorsByPowerIndexKey(oldValidator, pool)) - } - valPower = GetBondedValidatorsByPowerIndexKey(newValidator, pool) + store.Delete(GetBondedValidatorsByPowerIndexKey(oldValidator, pool)) + + k.SetValidator(ctx, validator) store.Set(valPower, newValidator.OperatorAddr) + + validator.Tokens = validator.Tokens.Add(newTokens) + valPower = GetBondedValidatorsByPowerIndexKey(newValidator, pool) } -// validator index -func (k Keeper) SetValidatorBondedIndex(ctx sdk.Context, validator types.Validator) { +// Update the tokens for a new validator, create the validators power index key +func (k Keeper) NewValidatorTokens(ctx sdk.Context, validator types.Validator, newTokens sdk.Dec) sdk.Error { store := ctx.KVStore(k.storeKey) - store.Set(GetValidatorsBondedIndexKey(validator.OperatorAddr), []byte{}) + + validator.Tokens = validator.Tokens.Add(newTokens) + k.SetValidator(ctx, validator) + + pool := store.GetPool(ctx) + valPower = GetBondedValidatorsByPowerIndexKey(newValidator, pool) + store.Set(valPower, newValidator.OperatorAddr) } // UpdateValidatorCommission attempts to update a validator's commission rate. // An error is returned if the new commission rate is invalid. -func (k Keeper) UpdateValidatorCommission(ctx sdk.Context, validator types.Validator, newRate sdk.Dec) sdk.Error { +func (k Keeper) UpdateValidatorCommission(ctx sdk.Context, validator types.Validator, newRate sdk.Dec) (types.Commission, sdk.Error) { commission := validator.Commission blockTime := ctx.BlockHeader().Time if err := commission.ValidateNewRate(newRate, blockTime); err != nil { - return err + return commission, err } - validator.Commission.Rate = newRate - validator.Commission.UpdateTime = blockTime + commission.Rate = newRate + commission.UpdateTime = blockTime - k.SetValidator(ctx, validator) - return nil + return commission, nil } // remove the validator record and associated indexes @@ -221,8 +235,6 @@ func (k Keeper) GetValidatorsBonded(ctx sdk.Context) (validators []types.Validat } // get the group of bonded validators sorted by power-rank -// -// TODO: Rename to GetBondedValidatorsByPower or GetBondedValidatorsByPower(ctx, status) func (k Keeper) GetBondedValidatorsByPower(ctx sdk.Context) []types.Validator { store := ctx.KVStore(k.storeKey) maxValidators := k.GetParams(ctx).MaxValidators From e838a024f2561a259f5aeff7f95a68bfa595ed96 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 26 Sep 2018 02:35:35 -0400 Subject: [PATCH 10/44] Added missing by-power index at validator creation --- x/stake/handler.go | 2 +- x/stake/keeper/slash.go | 18 +++--------------- x/stake/keeper/val_state_change.go | 18 +++++++++++++++++- x/stake/keeper/validator.go | 27 ++++++++++++++++++++------- 4 files changed, 41 insertions(+), 24 deletions(-) diff --git a/x/stake/handler.go b/x/stake/handler.go index 94e2381e114f..b40b7b98d8fc 100644 --- a/x/stake/handler.go +++ b/x/stake/handler.go @@ -82,7 +82,6 @@ func handleMsgCreateValidator(ctx sdk.Context, msg types.MsgCreateValidator, k k msg.Commission.Rate, msg.Commission.MaxChangeRate, msg.Commission.MaxChangeRate, ctx.BlockHeader().Time, ) - validator, err := validator.SetInitialCommission(commission) if err != nil { return err.Result() @@ -90,6 +89,7 @@ func handleMsgCreateValidator(ctx sdk.Context, msg types.MsgCreateValidator, k k k.SetValidator(ctx, validator) k.SetValidatorByConsAddr(ctx, validator) + k.SetNewValidatorByPowerIndex(ctx, validator) // move coins from the msg.Address account to a (self-delegation) delegator account // the validator account and global shares are updated within here diff --git a/x/stake/keeper/slash.go b/x/stake/keeper/slash.go index 486dc328695c..7c48c6085cfc 100644 --- a/x/stake/keeper/slash.go +++ b/x/stake/keeper/slash.go @@ -99,13 +99,12 @@ func (k Keeper) Slash(ctx sdk.Context, consAddr sdk.ConsAddress, infractionHeigh tokensToBurn := sdk.MinDec(remainingSlashAmount, validator.Tokens) // burn validator's tokens + validator = k.RemoveValidatorTokens(ctx, validator, tokensToBurn) pool := k.GetPool(ctx) - validator, pool = validator.RemoveTokens(pool, tokensToBurn) pool.LooseTokens = pool.LooseTokens.Sub(tokensToBurn) k.SetPool(ctx, pool) // update the validator, possibly kicking it out - validator = k.UpdateValidator(ctx, validator) // remove validator if it has no more tokens if validator.Tokens.IsZero() { @@ -123,7 +122,7 @@ func (k Keeper) Slash(ctx sdk.Context, consAddr sdk.ConsAddress, infractionHeigh // jail a validator func (k Keeper) Jail(ctx sdk.Context, consAddr sdk.ConsAddress) { - k.setJailed(ctx, consAddr, true) + k.JailValidator(ctx, validator) logger := ctx.Logger().With("module", "x/stake") logger.Info(fmt.Sprintf("validator %s jailed", consAddr)) // TODO Return event(s), blocked on https://github.com/tendermint/tendermint/pull/1803 @@ -132,24 +131,13 @@ func (k Keeper) Jail(ctx sdk.Context, consAddr sdk.ConsAddress) { // unjail a validator func (k Keeper) Unjail(ctx sdk.Context, consAddr sdk.ConsAddress) { - k.setJailed(ctx, consAddr, false) + k.UnjailValidator(ctx, validator) logger := ctx.Logger().With("module", "x/stake") logger.Info(fmt.Sprintf("validator %s unjailed", consAddr)) // TODO Return event(s), blocked on https://github.com/tendermint/tendermint/pull/1803 return } -// set the jailed flag on a validator -func (k Keeper) setJailed(ctx sdk.Context, consAddr sdk.ConsAddress, isJailed bool) { - validator, found := k.GetValidatorByConsAddr(ctx, consAddr) - if !found { - panic(fmt.Errorf("validator with consensus-Address %s not found, cannot set jailed to %v", consAddr, isJailed)) - } - validator.Jailed = isJailed - k.UpdateValidator(ctx, validator) // update validator, possibly unbonding or bonding it - return -} - // slash an unbonding delegation and update the pool // return the amount that would have been slashed assuming // the unbonding delegation had enough stake to slash diff --git a/x/stake/keeper/val_state_change.go b/x/stake/keeper/val_state_change.go index 551340a64e91..d8ce0c0cd639 100644 --- a/x/stake/keeper/val_state_change.go +++ b/x/stake/keeper/val_state_change.go @@ -95,7 +95,8 @@ func (k Keeper) unbondingToUnbonded(ctx sdk.Context, validator types.Validator) completeUnbondingValidator(ctx, validator) } -func (k Keeper) jailValidator(ctx sdk.Context, validator types.Validator) { +// send a validator to jail +func (k Keeper) JailValidator(ctx sdk.Context, validator types.Validator) { if validator.Jailed { panic(fmt.Sprintf("cannot jail already jailed validator, validator: %v\n", validator)) } @@ -107,6 +108,21 @@ func (k Keeper) jailValidator(ctx sdk.Context, validator types.Validator) { } } +// remove a validator from jail +func (k Keeper) UnjailValidator(ctx sdk.Context, validator types.Validator) { + if !validator.Jailed { + panic(fmt.Sprintf("cannot jail already jailed validator, validator: %v\n", validator)) + } + + store.Delete(GetBondedValidatorsByPowerIndexKey(validator, pool)) + + validator.Jailed = false + k.SetValidator(ctx, validator) + + valPower = GetBondedValidatorsByPowerIndexKey(validator, pool) + store.Set(valPower, validator.OperatorAddr) +} + //________________________________________________________________________________________________ // perform all the store operations for when a validator status becomes bonded diff --git a/x/stake/keeper/validator.go b/x/stake/keeper/validator.go index c45ef0d708b3..a590bc2a770e 100644 --- a/x/stake/keeper/validator.go +++ b/x/stake/keeper/validator.go @@ -94,6 +94,13 @@ func (k Keeper) SetValidatorByPowerIndex(ctx sdk.Context, validator types.Valida store.Set(GetBondedValidatorsByPowerIndexKey(validator, pool), validator.OperatorAddr) } +// validator index +func (k Keeper) SetNewValidatorByPowerIndex(ctx sdk.Context, validator types.Validator) { + store := ctx.KVStore(k.storeKey) + pool := store.GetPool(ctx) + store.Set(GetBondedValidatorsByPowerIndexKey(validator, pool), validator.OperatorAddr) +} + // validator index func (k Keeper) SetValidatorBondedIndex(ctx sdk.Context, validator types.Validator) { store := ctx.KVStore(k.storeKey) @@ -103,29 +110,35 @@ func (k Keeper) SetValidatorBondedIndex(ctx sdk.Context, validator types.Validat //___________________________________________________________________________ // Update the tokens of an existing validator, update the validators power index key -func (k Keeper) UpdateValidatorTokens(ctx sdk.Context, validator types.Validator, newTokens sdk.Dec) sdk.Error { +func (k Keeper) AddValidatorTokens(ctx sdk.Context, validator types.Validator, newTokens sdk.Dec) types.Validator { store := ctx.KVStore(k.storeKey) pool := store.GetPool(ctx) store.Delete(GetBondedValidatorsByPowerIndexKey(oldValidator, pool)) + validator, pool = validator.AddTokens(pool, newTokens) k.SetValidator(ctx, validator) - store.Set(valPower, newValidator.OperatorAddr) + k.SetPool(ctx, pool) - validator.Tokens = validator.Tokens.Add(newTokens) valPower = GetBondedValidatorsByPowerIndexKey(newValidator, pool) + store.Set(valPower, newValidator.OperatorAddr) + return validator } -// Update the tokens for a new validator, create the validators power index key -func (k Keeper) NewValidatorTokens(ctx sdk.Context, validator types.Validator, newTokens sdk.Dec) sdk.Error { +// Update the tokens of an existing validator, update the validators power index key +func (k Keeper) RemoveValidatorTokens(ctx sdk.Context, validator types.Validator, tokensToRemove sdk.Dec) types.Validator { store := ctx.KVStore(k.storeKey) + pool := store.GetPool(ctx) - validator.Tokens = validator.Tokens.Add(newTokens) + store.Delete(GetBondedValidatorsByPowerIndexKey(oldValidator, pool)) + + validator, pool = validator.RemoveTokens(pool, tokensToBurn) k.SetValidator(ctx, validator) + k.SetPool(ctx, pool) - pool := store.GetPool(ctx) valPower = GetBondedValidatorsByPowerIndexKey(newValidator, pool) store.Set(valPower, newValidator.OperatorAddr) + return validator } // UpdateValidatorCommission attempts to update a validator's commission rate. From 0e91227da8aa11bdbef3ca3596b56dd95ec6bf0f Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 26 Sep 2018 03:00:58 -0400 Subject: [PATCH 11/44] removed codebase use of UpdateValidator --- x/stake/keeper/delegation.go | 20 +++------ x/stake/keeper/val_state_change.go | 71 +++++++++++++++--------------- x/stake/keeper/validator.go | 26 +++++++++-- 3 files changed, 63 insertions(+), 54 deletions(-) diff --git a/x/stake/keeper/delegation.go b/x/stake/keeper/delegation.go index 6efa4c8ed3b3..0bf3b4032d6a 100644 --- a/x/stake/keeper/delegation.go +++ b/x/stake/keeper/delegation.go @@ -265,18 +265,13 @@ func (k Keeper) Delegate(ctx sdk.Context, delAddr sdk.AccAddress, bondAmt sdk.Co } } - pool := k.GetPool(ctx) - validator, pool, newShares = validator.AddTokensFromDel(pool, bondAmt.Amount) - delegation.Shares = delegation.Shares.Add(newShares) + validator, newShares = k.AddValidatorTokensAndShares(ctx, validator) - // Update delegation height + // Update delegation + delegation.Shares = delegation.Shares.Add(newShares) delegation.Height = ctx.BlockHeight() - - k.SetPool(ctx, pool) k.SetDelegation(ctx, delegation) - k.UpdateValidator(ctx, validator) - - return + return newShares, nil } // unbond the the delegation return @@ -323,13 +318,8 @@ func (k Keeper) unbond(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValA } // remove the coins from the validator - pool := k.GetPool(ctx) - validator, pool, amount = validator.RemoveDelShares(pool, shares) - - k.SetPool(ctx, pool) + validator, amount = k.RemoveValidatorTokensAndShares(ctx, validator, shares) - // update then remove validator if necessary - validator = k.UpdateValidator(ctx, validator) if validator.DelegatorShares.IsZero() { k.RemoveValidator(ctx, validator.OperatorAddr) } diff --git a/x/stake/keeper/val_state_change.go b/x/stake/keeper/val_state_change.go index d8ce0c0cd639..10b10db0cb8d 100644 --- a/x/stake/keeper/val_state_change.go +++ b/x/stake/keeper/val_state_change.go @@ -27,35 +27,41 @@ func (k Keeper) GetTendermintUpdates(ctx sdk.Context) (updates []abci.Validator) //tstore := ctx.TransientStore(k.storeTKey) //tstore.Set(GetTendermintUpdatesTKey(validator.OperatorAddr), bzABCI) - last := fetchOldValidatorSet() - tendermintUpdates := make(map[sdk.ValAddress]uint64) - - for _, validator := range topvalidator { //(iterate(top hundred)) { - switch validator.State { - case Unbonded: - unbondedToBonded(ctx, validator.Addr) - tendermintUpdates[validator.Addr] = validator.Power - case Unbonding: - unbondingToBonded(ctx, validator.Addr) - tendermintUpdates[validator.Addr] = validator.Power - case Bonded: // do nothing - store.delete(last[validator.Addr]) - // jailed validators are ranked last, so if we get to a jailed validator - // we have no more bonded validators - if validator.Jailed { - break + // XXX code from issue + /* + last := fetchOldValidatorSet() + tendermintUpdates := make(map[sdk.ValAddress]uint64) + + for _, validator := range topvalidator { //(iterate(top hundred)) { + switch validator.State { + case Unbonded: + unbondedToBonded(ctx, validator.Addr) + tendermintUpdates[validator.Addr] = validator.Power + case Unbonding: + unbondingToBonded(ctx, validator.Addr) + tendermintUpdates[validator.Addr] = validator.Power + case Bonded: // do nothing + store.delete(last[validator.Addr]) + // jailed validators are ranked last, so if we get to a jailed validator + // we have no more bonded validators + if validator.Jailed { + break + } } } - } - for _, validator := range previousValidators { - bondedToUnbonding(ctx, validator.Addr) - tendermintUpdates[validator.Addr] = 0 - } + for _, validator := range previousValidators { + bondedToUnbonding(ctx, validator.Addr) + tendermintUpdates[validator.Addr] = 0 + } - return tendermintUpdates + return tendermintUpdates + */ + + return updates } +// XXX FOR REFERENCE USE OR DELETED func kickOutValidators(k Keeper, ctx sdk.Context, toKickOut map[string]byte) { for key := range toKickOut { ownerAddr := []byte(key) @@ -95,6 +101,8 @@ func (k Keeper) unbondingToUnbonded(ctx sdk.Context, validator types.Validator) completeUnbondingValidator(ctx, validator) } +//________________________________________________________________________________________________ + // send a validator to jail func (k Keeper) JailValidator(ctx sdk.Context, validator types.Validator) { if validator.Jailed { @@ -131,6 +139,8 @@ func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) { store := ctx.KVStore(k.storeKey) pool := k.GetPool(ctx) + // XXX WHAT DO WE DO FOR BondIntraTxCounter Height Now?????????????????????????? + validator.BondHeight = ctx.BlockHeight() // set the status @@ -190,19 +200,8 @@ func (k Keeper) completeUnbondingValidator(ctx sdk.Context, validator types.Vali //______________________________________________________________________________________________________ -func (k Keeper) updateValidatorPower(ctx sdk.Context, oldFound bool, oldValidator, - newValidator types.Validator, pool types.Pool) (valPower []byte) { - store := ctx.KVStore(k.storeKey) - - // update the list ordered by voting power - if oldFound { - store.Delete(GetBondedValidatorsByPowerIndexKey(oldValidator, pool)) - } - valPower = GetBondedValidatorsByPowerIndexKey(newValidator, pool) - store.Set(valPower, newValidator.OperatorAddr) - - return valPower -} +// XXX need to figure out how to set a validator's BondIntraTxCounter - probably during delegation bonding? +// or keep track of tx for final bonding and set during endblock??? wish we could reduce this complexity // get the bond height and incremented intra-tx counter // nolint: unparam diff --git a/x/stake/keeper/validator.go b/x/stake/keeper/validator.go index a590bc2a770e..0cabdfa96e46 100644 --- a/x/stake/keeper/validator.go +++ b/x/stake/keeper/validator.go @@ -110,19 +110,39 @@ func (k Keeper) SetValidatorBondedIndex(ctx sdk.Context, validator types.Validat //___________________________________________________________________________ // Update the tokens of an existing validator, update the validators power index key -func (k Keeper) AddValidatorTokens(ctx sdk.Context, validator types.Validator, newTokens sdk.Dec) types.Validator { +func (k Keeper) AddValidatorTokensAndShares(ctx sdk.Context, validator types.Validator, + tokensToAdd sdk.Dec) (valOut types.Validator, addedShares sdk.Dec) { + store := ctx.KVStore(k.storeKey) pool := store.GetPool(ctx) store.Delete(GetBondedValidatorsByPowerIndexKey(oldValidator, pool)) - validator, pool = validator.AddTokens(pool, newTokens) + validator, pool, addedShares = validator.AddTokensFromDel(pool, tokensToAdd) k.SetValidator(ctx, validator) k.SetPool(ctx, pool) valPower = GetBondedValidatorsByPowerIndexKey(newValidator, pool) store.Set(valPower, newValidator.OperatorAddr) - return validator + return validator, addedShares +} + +// Update the tokens of an existing validator, update the validators power index key +func (k Keeper) RemoveValidatorTokensAndShares(ctx sdk.Context, validator types.Validator, + sharesToRemove sdk.Dec) (valOut types.Validator, removedTokens sdk.Dec) { + + store := ctx.KVStore(k.storeKey) + pool := store.GetPool(ctx) + + store.Delete(GetBondedValidatorsByPowerIndexKey(oldValidator, pool)) + + validator, pool, removedTokens = validator.RemoveDelShares(pool, sharesToRemove) + k.SetValidator(ctx, validator) + k.SetPool(ctx, pool) + + valPower = GetBondedValidatorsByPowerIndexKey(newValidator, pool) + store.Set(valPower, newValidator.OperatorAddr) + return validator, removedTokens } // Update the tokens of an existing validator, update the validators power index key From cd9a9fb295a431aed171d1f7f3fa8d3be3d0da42 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 26 Sep 2018 03:04:29 -0400 Subject: [PATCH 12/44] SetParams now doesnt update validator set as happens at endblock --- x/stake/keeper/delegation.go | 2 +- x/stake/keeper/keeper.go | 16 ---------------- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/x/stake/keeper/delegation.go b/x/stake/keeper/delegation.go index 0bf3b4032d6a..81842b463c7b 100644 --- a/x/stake/keeper/delegation.go +++ b/x/stake/keeper/delegation.go @@ -265,7 +265,7 @@ func (k Keeper) Delegate(ctx sdk.Context, delAddr sdk.AccAddress, bondAmt sdk.Co } } - validator, newShares = k.AddValidatorTokensAndShares(ctx, validator) + validator, newShares = k.AddValidatorTokensAndShares(ctx, validator, bondAmt) // Update delegation delegation.Shares = delegation.Shares.Add(newShares) diff --git a/x/stake/keeper/keeper.go b/x/stake/keeper/keeper.go index 0f700f9ab824..c443389de42d 100644 --- a/x/stake/keeper/keeper.go +++ b/x/stake/keeper/keeper.go @@ -64,25 +64,9 @@ func (k Keeper) GetParams(ctx sdk.Context) (params types.Params) { return } -// Need a distinct function because setParams depends on an existing previous -// record of params to exist (to check if maxValidators has changed) - and we -// panic on retrieval if it doesn't exist - hence if we use setParams for the very -// first params set it will panic. -func (k Keeper) SetNewParams(ctx sdk.Context, params types.Params) { - store := ctx.KVStore(k.storeKey) - b := k.cdc.MustMarshalBinary(params) - store.Set(ParamKey, b) -} - // set the params func (k Keeper) SetParams(ctx sdk.Context, params types.Params) { store := ctx.KVStore(k.storeKey) - exParams := k.GetParams(ctx) - - // if max validator count changes, must recalculate validator set - if exParams.MaxValidators != params.MaxValidators { - k.UpdateBondedValidatorsFull(ctx) - } b := k.cdc.MustMarshalBinary(params) store.Set(ParamKey, b) } From 76f18fd020a00af54d33018aaed02b41f6693c2a Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 26 Sep 2018 03:34:23 -0400 Subject: [PATCH 13/44] got non-test code compiling --- x/stake/genesis.go | 4 +- x/stake/handler.go | 4 +- x/stake/keeper/delegation.go | 2 +- x/stake/keeper/slash.go | 2 + x/stake/keeper/test_common.go | 2 +- x/stake/keeper/val_state_change.go | 44 +++++++++++---------- x/stake/keeper/validator.go | 61 ++++++++++++++---------------- x/stake/stake.go | 54 +++++++++++++------------- 8 files changed, 87 insertions(+), 86 deletions(-) diff --git a/x/stake/genesis.go b/x/stake/genesis.go index 58b7ed1b4f25..1f1d1d9f8a70 100644 --- a/x/stake/genesis.go +++ b/x/stake/genesis.go @@ -17,7 +17,7 @@ import ( // Returns final validator set after applying all declaration and delegations func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) (res []abci.Validator, err error) { keeper.SetPool(ctx, data.Pool) - keeper.SetNewParams(ctx, data.Params) + keeper.SetParams(ctx, data.Params) keeper.InitIntraTxCounter(ctx) for i, validator := range data.Validators { @@ -44,7 +44,7 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) (res [ keeper.SetDelegation(ctx, bond) } - keeper.UpdateBondedValidatorsFull(ctx) + //keeper.UpdateBondedValidatorsFull(ctx) // XXX TODO must calculate the genesis validator set vals := keeper.GetValidatorsBonded(ctx) res = make([]abci.Validator, len(vals)) diff --git a/x/stake/handler.go b/x/stake/handler.go index b40b7b98d8fc..3f10fb93dc05 100644 --- a/x/stake/handler.go +++ b/x/stake/handler.go @@ -52,7 +52,7 @@ func EndBlocker(ctx sdk.Context, k keeper.Keeper) (ValidatorUpdates []abci.Valid k.SetIntraTxCounter(ctx, 0) // calculate validator set changes - ValidatorUpdates = k.GetValidTendermintUpdates(ctx) + ValidatorUpdates = k.GetTendermintUpdates(ctx) return } @@ -127,7 +127,7 @@ func handleMsgEditValidator(ctx sdk.Context, msg types.MsgEditValidator, k keepe if msg.CommissionRate != nil { commission, err := k.UpdateValidatorCommission(ctx, validator, *msg.CommissionRate) - if err := k.UpdateValidatorCommission(ctx, validator, *msg.CommissionRate); err != nil { + if err != nil { return err.Result() } validator.Commission = commission diff --git a/x/stake/keeper/delegation.go b/x/stake/keeper/delegation.go index 81842b463c7b..9e1687d596b0 100644 --- a/x/stake/keeper/delegation.go +++ b/x/stake/keeper/delegation.go @@ -265,7 +265,7 @@ func (k Keeper) Delegate(ctx sdk.Context, delAddr sdk.AccAddress, bondAmt sdk.Co } } - validator, newShares = k.AddValidatorTokensAndShares(ctx, validator, bondAmt) + validator, newShares = k.AddValidatorTokensAndShares(ctx, validator, bondAmt.Amount) // Update delegation delegation.Shares = delegation.Shares.Add(newShares) diff --git a/x/stake/keeper/slash.go b/x/stake/keeper/slash.go index 7c48c6085cfc..f32122df236e 100644 --- a/x/stake/keeper/slash.go +++ b/x/stake/keeper/slash.go @@ -122,6 +122,7 @@ func (k Keeper) Slash(ctx sdk.Context, consAddr sdk.ConsAddress, infractionHeigh // jail a validator func (k Keeper) Jail(ctx sdk.Context, consAddr sdk.ConsAddress) { + validator := k.mustGetValidatorByConsAddr(ctx, consAddr) k.JailValidator(ctx, validator) logger := ctx.Logger().With("module", "x/stake") logger.Info(fmt.Sprintf("validator %s jailed", consAddr)) @@ -131,6 +132,7 @@ func (k Keeper) Jail(ctx sdk.Context, consAddr sdk.ConsAddress) { // unjail a validator func (k Keeper) Unjail(ctx sdk.Context, consAddr sdk.ConsAddress) { + validator := k.mustGetValidatorByConsAddr(ctx, consAddr) k.UnjailValidator(ctx, validator) logger := ctx.Logger().With("module", "x/stake") logger.Info(fmt.Sprintf("validator %s unjailed", consAddr)) diff --git a/x/stake/keeper/test_common.go b/x/stake/keeper/test_common.go index 03d4642b671b..388e7e247045 100644 --- a/x/stake/keeper/test_common.go +++ b/x/stake/keeper/test_common.go @@ -111,7 +111,7 @@ func CreateTestInput(t *testing.T, isCheckTx bool, initCoins int64) (sdk.Context ck := bank.NewBaseKeeper(accountMapper) keeper := NewKeeper(cdc, keyStake, tkeyStake, ck, types.DefaultCodespace) keeper.SetPool(ctx, types.InitialPool()) - keeper.SetNewParams(ctx, types.DefaultParams()) + keeper.SetParams(ctx, types.DefaultParams()) keeper.InitIntraTxCounter(ctx) // fill all the addresses with some coins, set the loose pool tokens simultaneously diff --git a/x/stake/keeper/val_state_change.go b/x/stake/keeper/val_state_change.go index 10b10db0cb8d..10c65bb98caf 100644 --- a/x/stake/keeper/val_state_change.go +++ b/x/stake/keeper/val_state_change.go @@ -1,12 +1,10 @@ package keeper import ( - "bytes" "fmt" abci "github.com/tendermint/tendermint/abci/types" - "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/stake/types" ) @@ -77,28 +75,28 @@ func (k Keeper) bondedToUnbonding(ctx sdk.Context, validator types.Validator) { if validator.Status != sdk.Bonded { panic(fmt.Sprintf("bad state transition bondedToUnbonded, validator: %v\n", validator)) } - beginUnbondingValidator(ctx, validator) + k.beginUnbondingValidator(ctx, validator) } func (k Keeper) unbondingToBonded(ctx sdk.Context, validator types.Validator) { if validator.Status != sdk.Unbonding { panic(fmt.Sprintf("bad state transition unbondingToBonded, validator: %v\n", validator)) } - bondValidator(ctx, validator) + k.bondValidator(ctx, validator) } func (k Keeper) unbondedToBonded(ctx sdk.Context, validator types.Validator) { if validator.Status != sdk.Unbonded { panic(fmt.Sprintf("bad state transition unbondedToBonded, validator: %v\n", validator)) } - bondValidator(ctx, validator) + k.bondValidator(ctx, validator) } func (k Keeper) unbondingToUnbonded(ctx sdk.Context, validator types.Validator) { if validator.Status != sdk.Unbonded { panic(fmt.Sprintf("bad state transition unbondingToBonded, validator: %v\n", validator)) } - completeUnbondingValidator(ctx, validator) + k.completeUnbondingValidator(ctx, validator) } //________________________________________________________________________________________________ @@ -109,11 +107,11 @@ func (k Keeper) JailValidator(ctx sdk.Context, validator types.Validator) { panic(fmt.Sprintf("cannot jail already jailed validator, validator: %v\n", validator)) } + pool := k.GetPool(ctx) + k.DeleteValidatorByPowerIndex(ctx, validator, pool) validator.Jailed = true - - if validator.Status == sdk.Bonded { - validator = k.beginUnbondingValidator(ctx, newValidator) - } + k.SetValidator(ctx, validator) + k.SetValidatorByPowerIndex(ctx, validator, pool) } // remove a validator from jail @@ -122,13 +120,11 @@ func (k Keeper) UnjailValidator(ctx sdk.Context, validator types.Validator) { panic(fmt.Sprintf("cannot jail already jailed validator, validator: %v\n", validator)) } - store.Delete(GetBondedValidatorsByPowerIndexKey(validator, pool)) - + pool := k.GetPool(ctx) + k.DeleteValidatorByPowerIndex(ctx, validator, pool) validator.Jailed = false k.SetValidator(ctx, validator) - - valPower = GetBondedValidatorsByPowerIndexKey(validator, pool) - store.Set(valPower, validator.OperatorAddr) + k.SetValidatorByPowerIndex(ctx, validator, pool) } //________________________________________________________________________________________________ @@ -139,6 +135,8 @@ func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) { store := ctx.KVStore(k.storeKey) pool := k.GetPool(ctx) + k.DeleteValidatorByPowerIndex(ctx, validator, pool) + // XXX WHAT DO WE DO FOR BondIntraTxCounter Height Now?????????????????????????? validator.BondHeight = ctx.BlockHeight() @@ -151,6 +149,8 @@ func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) { k.SetValidator(ctx, validator) store.Set(GetValidatorsBondedIndexKey(validator.OperatorAddr), []byte{}) + k.SetValidatorByPowerIndex(ctx, validator, pool) + // call the bond hook if present if k.hooks != nil { k.hooks.OnValidatorBonded(ctx, validator.ConsAddress()) @@ -158,12 +158,14 @@ func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) { } // perform all the store operations for when a validator status begins unbonding -func (k Keeper) beginUnbondingValidator(ctx sdk.Context, validator types.Validator) { +func (k Keeper) beginUnbondingValidator(ctx sdk.Context, validator types.Validator) types.Validator { store := ctx.KVStore(k.storeKey) pool := k.GetPool(ctx) params := k.GetParams(ctx) + k.DeleteValidatorByPowerIndex(ctx, validator, pool) + // sanity check if validator.Status == sdk.Unbonded || validator.Status == sdk.Unbonding { @@ -183,15 +185,18 @@ func (k Keeper) beginUnbondingValidator(ctx sdk.Context, validator types.Validat // also remove from the Bonded types.Validators Store store.Delete(GetValidatorsBondedIndexKey(validator.OperatorAddr)) + k.SetValidatorByPowerIndex(ctx, validator, pool) + // call the unbond hook if present if k.hooks != nil { k.hooks.OnValidatorBeginUnbonding(ctx, validator.ConsAddress()) } + + return validator } // perform all the store operations for when a validator status becomes unbonded func (k Keeper) completeUnbondingValidator(ctx sdk.Context, validator types.Validator) { - store := ctx.KVStore(k.storeKey) pool := k.GetPool(ctx) validator, pool = validator.UpdateStatus(pool, sdk.Unbonded) k.SetPool(ctx, pool) @@ -224,7 +229,7 @@ func (k Keeper) bondIncrement(ctx sdk.Context, isNewValidator bool, validator ty } //______________________________________________________________________________________________________ - +/* // XXX Delete this reference function before merge // Perform all the necessary steps for when a validator changes its power. This // function updates all validator stores as well as tendermint update store. @@ -317,7 +322,7 @@ func (k Keeper) XXXREFERENCEUpdateBondedValidators( maxValidators := k.GetParams(ctx).MaxValidators bondedValidatorsCount := 0 var validator, validatorToBond types.Validator - newValidatorBonded := false + //newValidatorBonded := false // create a validator iterator ranging from largest to smallest by power iterator := sdk.KVStoreReversePrefixIterator(store, ValidatorsByPowerIndexKey) @@ -386,3 +391,4 @@ func (k Keeper) XXXREFERENCEUpdateBondedValidators( return types.Validator{}, false } +*/ diff --git a/x/stake/keeper/validator.go b/x/stake/keeper/validator.go index 0cabdfa96e46..5024ba17e4e6 100644 --- a/x/stake/keeper/validator.go +++ b/x/stake/keeper/validator.go @@ -55,9 +55,9 @@ func (k Keeper) GetValidator(ctx sdk.Context, addr sdk.ValAddress) (validator ty } func (k Keeper) mustGetValidator(ctx sdk.Context, addr sdk.ValAddress) types.Validator { - validator, found := GetValidator(ctx, addr) + validator, found := k.GetValidator(ctx, addr) if !found { - panic(fmt.Sprintf("validator record not found for address: %X\n", ownerAddr)) + panic(fmt.Sprintf("validator record not found for address: %X\n", addr)) } return validator } @@ -72,6 +72,14 @@ func (k Keeper) GetValidatorByConsAddr(ctx sdk.Context, consAddr sdk.ConsAddress return k.GetValidator(ctx, opAddr) } +func (k Keeper) mustGetValidatorByConsAddr(ctx sdk.Context, consAddr sdk.ConsAddress) types.Validator { + validator, found := k.GetValidatorByConsAddr(ctx, consAddr) + if !found { + panic(fmt.Errorf("validator with consensus-Address %s not found", consAddr)) + } + return validator +} + //___________________________________________________________________________ // set the main record holding validator details @@ -94,10 +102,16 @@ func (k Keeper) SetValidatorByPowerIndex(ctx sdk.Context, validator types.Valida store.Set(GetBondedValidatorsByPowerIndexKey(validator, pool), validator.OperatorAddr) } +// validator index +func (k Keeper) DeleteValidatorByPowerIndex(ctx sdk.Context, validator types.Validator, pool types.Pool) { + store := ctx.KVStore(k.storeKey) + store.Delete(GetBondedValidatorsByPowerIndexKey(validator, pool)) +} + // validator index func (k Keeper) SetNewValidatorByPowerIndex(ctx sdk.Context, validator types.Validator) { store := ctx.KVStore(k.storeKey) - pool := store.GetPool(ctx) + pool := k.GetPool(ctx) store.Set(GetBondedValidatorsByPowerIndexKey(validator, pool), validator.OperatorAddr) } @@ -111,19 +125,14 @@ func (k Keeper) SetValidatorBondedIndex(ctx sdk.Context, validator types.Validat // Update the tokens of an existing validator, update the validators power index key func (k Keeper) AddValidatorTokensAndShares(ctx sdk.Context, validator types.Validator, - tokensToAdd sdk.Dec) (valOut types.Validator, addedShares sdk.Dec) { - - store := ctx.KVStore(k.storeKey) - pool := store.GetPool(ctx) - - store.Delete(GetBondedValidatorsByPowerIndexKey(oldValidator, pool)) + tokensToAdd sdk.Int) (valOut types.Validator, addedShares sdk.Dec) { + pool := k.GetPool(ctx) + k.DeleteValidatorByPowerIndex(ctx, validator, pool) validator, pool, addedShares = validator.AddTokensFromDel(pool, tokensToAdd) k.SetValidator(ctx, validator) k.SetPool(ctx, pool) - - valPower = GetBondedValidatorsByPowerIndexKey(newValidator, pool) - store.Set(valPower, newValidator.OperatorAddr) + k.SetValidatorByPowerIndex(ctx, validator, pool) return validator, addedShares } @@ -131,33 +140,23 @@ func (k Keeper) AddValidatorTokensAndShares(ctx sdk.Context, validator types.Val func (k Keeper) RemoveValidatorTokensAndShares(ctx sdk.Context, validator types.Validator, sharesToRemove sdk.Dec) (valOut types.Validator, removedTokens sdk.Dec) { - store := ctx.KVStore(k.storeKey) - pool := store.GetPool(ctx) - - store.Delete(GetBondedValidatorsByPowerIndexKey(oldValidator, pool)) - + pool := k.GetPool(ctx) + k.DeleteValidatorByPowerIndex(ctx, validator, pool) validator, pool, removedTokens = validator.RemoveDelShares(pool, sharesToRemove) k.SetValidator(ctx, validator) k.SetPool(ctx, pool) - - valPower = GetBondedValidatorsByPowerIndexKey(newValidator, pool) - store.Set(valPower, newValidator.OperatorAddr) + k.SetValidatorByPowerIndex(ctx, validator, pool) return validator, removedTokens } // Update the tokens of an existing validator, update the validators power index key func (k Keeper) RemoveValidatorTokens(ctx sdk.Context, validator types.Validator, tokensToRemove sdk.Dec) types.Validator { - store := ctx.KVStore(k.storeKey) - pool := store.GetPool(ctx) - - store.Delete(GetBondedValidatorsByPowerIndexKey(oldValidator, pool)) - - validator, pool = validator.RemoveTokens(pool, tokensToBurn) + pool := k.GetPool(ctx) + k.DeleteValidatorByPowerIndex(ctx, validator, pool) + validator, pool = validator.RemoveTokens(pool, tokensToRemove) k.SetValidator(ctx, validator) k.SetPool(ctx, pool) - - valPower = GetBondedValidatorsByPowerIndexKey(newValidator, pool) - store.Set(valPower, newValidator.OperatorAddr) + k.SetValidatorByPowerIndex(ctx, validator, pool) return validator } @@ -199,10 +198,6 @@ func (k Keeper) RemoveValidator(ctx sdk.Context, address sdk.ValAddress) { return } store.Delete(GetValidatorsBondedIndexKey(validator.OperatorAddr)) - - bz := k.cdc.MustMarshalBinary(validator.ABCIValidatorZero()) - tstore := ctx.TransientStore(k.storeTKey) - tstore.Set(GetTendermintUpdatesTKey(address), bz) } //___________________________________________________________________________ diff --git a/x/stake/stake.go b/x/stake/stake.go index 5da9b0083ca1..e1d6f091a745 100644 --- a/x/stake/stake.go +++ b/x/stake/stake.go @@ -35,35 +35,33 @@ type ( var ( NewKeeper = keeper.NewKeeper - GetValidatorKey = keeper.GetValidatorKey - GetValidatorByConsAddrKey = keeper.GetValidatorByConsAddrKey - GetValidatorsBondedIndexKey = keeper.GetValidatorsBondedIndexKey + GetValidatorKey = keeper.GetValidatorKey + GetValidatorByConsAddrKey = keeper.GetValidatorByConsAddrKey + GetValidatorsBondedIndexKey = keeper.GetValidatorsBondedIndexKey GetBondedValidatorsByPowerIndexKey = keeper.GetBondedValidatorsByPowerIndexKey - GetTendermintUpdatesTKey = keeper.GetTendermintUpdatesTKey - GetDelegationKey = keeper.GetDelegationKey - GetDelegationsKey = keeper.GetDelegationsKey - ParamKey = keeper.ParamKey - PoolKey = keeper.PoolKey - ValidatorsKey = keeper.ValidatorsKey - ValidatorsByConsAddrKey = keeper.ValidatorsByConsAddrKey - ValidatorsBondedIndexKey = keeper.ValidatorsBondedIndexKey - ValidatorsByPowerIndexKey = keeper.ValidatorsByPowerIndexKey - ValidatorCliffIndexKey = keeper.ValidatorCliffIndexKey - ValidatorPowerCliffKey = keeper.ValidatorPowerCliffKey - TendermintUpdatesTKey = keeper.TendermintUpdatesTKey - DelegationKey = keeper.DelegationKey - IntraTxCounterKey = keeper.IntraTxCounterKey - GetUBDKey = keeper.GetUBDKey - GetUBDByValIndexKey = keeper.GetUBDByValIndexKey - GetUBDsKey = keeper.GetUBDsKey - GetUBDsByValIndexKey = keeper.GetUBDsByValIndexKey - GetREDKey = keeper.GetREDKey - GetREDByValSrcIndexKey = keeper.GetREDByValSrcIndexKey - GetREDByValDstIndexKey = keeper.GetREDByValDstIndexKey - GetREDsKey = keeper.GetREDsKey - GetREDsFromValSrcIndexKey = keeper.GetREDsFromValSrcIndexKey - GetREDsToValDstIndexKey = keeper.GetREDsToValDstIndexKey - GetREDsByDelToValDstIndexKey = keeper.GetREDsByDelToValDstIndexKey + GetDelegationKey = keeper.GetDelegationKey + GetDelegationsKey = keeper.GetDelegationsKey + ParamKey = keeper.ParamKey + PoolKey = keeper.PoolKey + ValidatorsKey = keeper.ValidatorsKey + ValidatorsByConsAddrKey = keeper.ValidatorsByConsAddrKey + ValidatorsBondedIndexKey = keeper.ValidatorsBondedIndexKey + ValidatorsByPowerIndexKey = keeper.ValidatorsByPowerIndexKey + ValidatorCliffIndexKey = keeper.ValidatorCliffIndexKey + ValidatorPowerCliffKey = keeper.ValidatorPowerCliffKey + DelegationKey = keeper.DelegationKey + IntraTxCounterKey = keeper.IntraTxCounterKey + GetUBDKey = keeper.GetUBDKey + GetUBDByValIndexKey = keeper.GetUBDByValIndexKey + GetUBDsKey = keeper.GetUBDsKey + GetUBDsByValIndexKey = keeper.GetUBDsByValIndexKey + GetREDKey = keeper.GetREDKey + GetREDByValSrcIndexKey = keeper.GetREDByValSrcIndexKey + GetREDByValDstIndexKey = keeper.GetREDByValDstIndexKey + GetREDsKey = keeper.GetREDsKey + GetREDsFromValSrcIndexKey = keeper.GetREDsFromValSrcIndexKey + GetREDsToValDstIndexKey = keeper.GetREDsToValDstIndexKey + GetREDsByDelToValDstIndexKey = keeper.GetREDsByDelToValDstIndexKey DefaultParams = types.DefaultParams InitialPool = types.InitialPool From 54098df12ed5481c9381802f05478bd7ea7afaf9 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Thu, 27 Sep 2018 15:51:36 +0200 Subject: [PATCH 14/44] Remove old code, minor cleanup of existing work --- x/stake/genesis.go | 8 +- x/stake/keeper/val_state_change.go | 183 +---------------------------- x/stake/keeper/validator_test.go | 2 +- 3 files changed, 4 insertions(+), 189 deletions(-) diff --git a/x/stake/genesis.go b/x/stake/genesis.go index 1f1d1d9f8a70..908c56e88385 100644 --- a/x/stake/genesis.go +++ b/x/stake/genesis.go @@ -44,13 +44,7 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) (res [ keeper.SetDelegation(ctx, bond) } - //keeper.UpdateBondedValidatorsFull(ctx) // XXX TODO must calculate the genesis validator set - - vals := keeper.GetValidatorsBonded(ctx) - res = make([]abci.Validator, len(vals)) - for i, val := range vals { - res[i] = sdk.ABCIValidator(val) - } + res = keeper.GetTendermintUpdates(ctx) return } diff --git a/x/stake/keeper/val_state_change.go b/x/stake/keeper/val_state_change.go index 10c65bb98caf..de8873346643 100644 --- a/x/stake/keeper/val_state_change.go +++ b/x/stake/keeper/val_state_change.go @@ -59,17 +59,7 @@ func (k Keeper) GetTendermintUpdates(ctx sdk.Context) (updates []abci.Validator) return updates } -// XXX FOR REFERENCE USE OR DELETED -func kickOutValidators(k Keeper, ctx sdk.Context, toKickOut map[string]byte) { - for key := range toKickOut { - ownerAddr := []byte(key) - validator := k.mustGetValidator(ctx, ownerAddr) - k.beginUnbondingValidator(ctx, validator) - } -} - -//___________________________________________________________________________ -// State transitions +// Validator state transitions func (k Keeper) bondedToUnbonding(ctx sdk.Context, validator types.Validator) { if validator.Status != sdk.Bonded { @@ -99,8 +89,6 @@ func (k Keeper) unbondingToUnbonded(ctx sdk.Context, validator types.Validator) k.completeUnbondingValidator(ctx, validator) } -//________________________________________________________________________________________________ - // send a validator to jail func (k Keeper) JailValidator(ctx sdk.Context, validator types.Validator) { if validator.Jailed { @@ -117,7 +105,7 @@ func (k Keeper) JailValidator(ctx sdk.Context, validator types.Validator) { // remove a validator from jail func (k Keeper) UnjailValidator(ctx sdk.Context, validator types.Validator) { if !validator.Jailed { - panic(fmt.Sprintf("cannot jail already jailed validator, validator: %v\n", validator)) + panic(fmt.Sprintf("cannot unjail already unjailed validator, validator: %v\n", validator)) } pool := k.GetPool(ctx) @@ -203,8 +191,6 @@ func (k Keeper) completeUnbondingValidator(ctx sdk.Context, validator types.Vali k.SetValidator(ctx, validator) } -//______________________________________________________________________________________________________ - // XXX need to figure out how to set a validator's BondIntraTxCounter - probably during delegation bonding? // or keep track of tx for final bonding and set during endblock??? wish we could reduce this complexity @@ -227,168 +213,3 @@ func (k Keeper) bondIncrement(ctx sdk.Context, isNewValidator bool, validator ty k.SetIntraTxCounter(ctx, counter+1) return } - -//______________________________________________________________________________________________________ -/* -// XXX Delete this reference function before merge -// Perform all the necessary steps for when a validator changes its power. This -// function updates all validator stores as well as tendermint update store. -// It may kick out validators if a new validator is entering the bonded validator -// group. -// -// TODO: Remove above nolint, function needs to be simplified! -func (k Keeper) REFERENCEXXXDELETEUpdateValidator(ctx sdk.Context, validator types.Validator) types.Validator { - tstore := ctx.TransientStore(k.storeTKey) - pool := k.GetPool(ctx) - oldValidator, oldFound := k.GetValidator(ctx, validator.OperatorAddr) - - validator = k.updateForJailing(ctx, oldFound, oldValidator, validator) - powerIncreasing := k.getPowerIncreasing(ctx, oldFound, oldValidator, validator) - validator.BondHeight, validator.BondIntraTxCounter = k.bondIncrement(ctx, oldFound, oldValidator) - valPower := k.updateValidatorPower(ctx, oldFound, oldValidator, validator, pool) - - switch { - - // if the validator is already bonded and the power is increasing, we need - // perform the following: - // a) update Tendermint - // b) check if the cliff validator needs to be updated - case powerIncreasing && !validator.Jailed && - (oldFound && oldValidator.Status == sdk.Bonded): - - bz := k.cdc.MustMarshalBinary(validator.ABCIValidator()) - tstore.Set(GetTendermintUpdatesTKey(validator.OperatorAddr), bz) - - if cliffValExists { - cliffAddr := sdk.ValAddress(k.GetCliffValidator(ctx)) - if bytes.Equal(cliffAddr, validator.OperatorAddr) { - k.updateCliffValidator(ctx, validator) - } - } - - // if is a new validator and the new power is less than the cliff validator - case cliffValExists && !oldFound && valPowerLTcliffPower: - // skip to completion - - // if was unbonded and the new power is less than the cliff validator - case cliffValExists && - (oldFound && oldValidator.Status == sdk.Unbonded) && - valPowerLTcliffPower: //(valPower < cliffPower - // skip to completion - - default: - // default case - validator was either: - // a) not-bonded and now has power-rank greater than cliff validator - // b) bonded and now has decreased in power - - // update the validator set for this validator - updatedVal, updated := k.UpdateBondedValidators(ctx, validator) - if updated { - // the validator has changed bonding status - validator = updatedVal - break - } - - // if decreased in power but still bonded, update Tendermint validator - if oldFound && oldValidator.BondedTokens().GT(validator.BondedTokens()) { - bz := k.cdc.MustMarshalBinary(validator.ABCIValidator()) - tstore.Set(GetTendermintUpdatesTKey(validator.OperatorAddr), bz) - } - } - - k.SetValidator(ctx, validator) - return validator -} - -// XXX Delete this reference function before merge -// Update the bonded validator group based on a change to the validator -// affectedValidator. This function potentially adds the affectedValidator to -// the bonded validator group which kicks out the cliff validator. Under this -// situation this function returns the updated affectedValidator. -// -// The correct bonded subset of validators is retrieved by iterating through an -// index of the validators sorted by power, stored using the -// ValidatorsByPowerIndexKey. Simultaneously the current validator records are -// updated in store with the ValidatorsBondedIndexKey. This store is used to -// determine if a validator is a validator without needing to iterate over all -// validators. -func (k Keeper) XXXREFERENCEUpdateBondedValidators( - ctx sdk.Context, affectedValidator types.Validator) ( - updatedVal types.Validator, updated bool) { - - store := ctx.KVStore(k.storeKey) - - oldCliffValidatorAddr := k.GetCliffValidator(ctx) - maxValidators := k.GetParams(ctx).MaxValidators - bondedValidatorsCount := 0 - var validator, validatorToBond types.Validator - //newValidatorBonded := false - - // create a validator iterator ranging from largest to smallest by power - iterator := sdk.KVStoreReversePrefixIterator(store, ValidatorsByPowerIndexKey) - for ; iterator.Valid() && bondedValidatorsCount < int(maxValidators); iterator.Next() { - - // either retrieve the original validator from the store, or under the - // situation that this is the "affected validator" just use the - // validator provided because it has not yet been updated in the store - ownerAddr := iterator.Value() - if bytes.Equal(ownerAddr, affectedValidator.OperatorAddr) { - validator = affectedValidator - } else { - var found bool - validator = k.mustGetValidator(ctx, ownerAddr) - } - - // if we've reached jailed validators no further bonded validators exist - if validator.Jailed { - if validator.Status == sdk.Bonded { - panic(fmt.Sprintf("jailed validator cannot be bonded, address: %X\n", ownerAddr)) - } - - break - } - - // increment the total number of bonded validators and potentially mark - // the validator to bond - if validator.Status != sdk.Bonded { - validatorToBond = validator - if newValidatorBonded { - panic("already decided to bond a validator, can't bond another!") - } - newValidatorBonded = true - } - - bondedValidatorsCount++ - } - - iterator.Close() - - // swap the cliff validator for a new validator if the affected validator - // was bonded - if newValidatorBonded { - if oldCliffValidatorAddr != nil { - oldCliffVal := k.mustGetValidator(ctx, oldCliffValidatorAddr) - - if bytes.Equal(validatorToBond.OperatorAddr, affectedValidator.OperatorAddr) { - - // begin unbonding the old cliff validator iff the affected - // validator was newly bonded and has greater power - k.beginUnbondingValidator(ctx, oldCliffVal) - } else { - // otherwise begin unbonding the affected validator, which must - // have been kicked out - affectedValidator = k.beginUnbondingValidator(ctx, affectedValidator) - } - } - - validator = k.bondValidator(ctx, validatorToBond) - if bytes.Equal(validator.OperatorAddr, affectedValidator.OperatorAddr) { - return validator, true - } - - return affectedValidator, true - } - - return types.Validator{}, false -} -*/ diff --git a/x/stake/keeper/validator_test.go b/x/stake/keeper/validator_test.go index ab6ac7e72520..b5f1bc07fa3e 100644 --- a/x/stake/keeper/validator_test.go +++ b/x/stake/keeper/validator_test.go @@ -27,7 +27,7 @@ func clearTendermintUpdates(ctx sdk.Context, k Keeper) { func validatorByPowerIndexExists(k Keeper, ctx sdk.Context, power []byte) bool { store := ctx.KVStore(k.storeKey) - return store.Get(power) != nil + return store.Has(power) } //_______________________________________________________ From e2200a250356ef08bd9456e73ed4365f92036d92 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Thu, 27 Sep 2018 16:02:35 +0200 Subject: [PATCH 15/44] Fixes from merge --- x/stake/keeper/val_state_change.go | 2 +- x/stake/keeper/validator.go | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/x/stake/keeper/val_state_change.go b/x/stake/keeper/val_state_change.go index de8873346643..c0c880a1bc23 100644 --- a/x/stake/keeper/val_state_change.go +++ b/x/stake/keeper/val_state_change.go @@ -17,7 +17,7 @@ import ( // CONTRACT: Only validators with non-zero power or zero-power that were bonded // at the previous block height or were removed from the validator set entirely // are returned to Tendermint. -func (k Keeper) GetTendermintUpdates(ctx sdk.Context) (updates []abci.Validator) { +func (k Keeper) GetTendermintUpdates(ctx sdk.Context) (updates []abci.ValidatorUpdate) { // REF CODE //// add to accumulated changes for tendermint diff --git a/x/stake/keeper/validator.go b/x/stake/keeper/validator.go index c2b9b862125a..5024ba17e4e6 100644 --- a/x/stake/keeper/validator.go +++ b/x/stake/keeper/validator.go @@ -3,9 +3,7 @@ package keeper import ( "container/list" "fmt" - - abci "github.com/tendermint/tendermint/abci/types" - tmtypes "github.com/tendermint/tendermint/types" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/stake/types" ) @@ -284,4 +282,4 @@ func (k Keeper) GetBondedValidatorsByPower(ctx sdk.Context) []types.Validator { } } return validators[:i] // trim -} \ No newline at end of file +} From 174b321d401383f5199cdcee9aaea6828ab1d292 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Thu, 27 Sep 2018 16:36:00 +0200 Subject: [PATCH 16/44] Pseudocode to real-ish code --- x/stake/keeper/val_state_change.go | 47 ++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/x/stake/keeper/val_state_change.go b/x/stake/keeper/val_state_change.go index c0c880a1bc23..8bfc64c6a930 100644 --- a/x/stake/keeper/val_state_change.go +++ b/x/stake/keeper/val_state_change.go @@ -19,6 +19,53 @@ import ( // are returned to Tendermint. func (k Keeper) GetTendermintUpdates(ctx sdk.Context) (updates []abci.ValidatorUpdate) { + var last map[string]interface{} + + store := ctx.KVStore(k.storeKey) + maxValidators := k.GetParams(ctx).MaxValidators + + iterator := sdk.KVStoreReversePrefixIterator(store, ValidatorsByPowerIndexKey) + count := 0 + for ; iterator.Valid() && count < int(maxValidators); iterator.Next() { + + // fetch the validator + operator := sdk.ValAddress(iterator.Value()) + validator := k.mustGetValidator(ctx, operator) + + // jailed validators are ranked last, so if we get to a jailed validator + // we have no more bonded validators + if validator.Jailed { + break + } + + // apply the appropriate state change if necessary + switch validator.Status { + case sdk.Unbonded: + k.unbondedToBonded(ctx, validator) + case sdk.Unbonding: + k.unbondingToBonded(ctx, validator) + case sdk.Bonded: + // no state change + } + + // update the validator (power might have changed) + updates = append(updates, validator.ABCIValidatorUpdate()) + + // validator still in the validator set + delete(last, string(operator)) + + // keep count + count++ + + } + + // any validators left in `last` are no longer bonded + for operator, _ := range last { + validator := k.mustGetValidator(ctx, []byte(operator)) + k.bondedToUnbonding(ctx, validator) + updates = append(updates, validator.ABCIValidatorUpdateZero()) + } + // REF CODE //// add to accumulated changes for tendermint //bzABCI := k.cdc.MustMarshalBinary(validator.ABCIValidator()) From 715ad0425f0209ed06a9a22277e1847527229421 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Thu, 27 Sep 2018 17:58:18 +0200 Subject: [PATCH 17/44] Remove cliff validator key (no longer used) --- x/stake/keeper/key.go | 24 +++++++++++++----------- x/stake/stake.go | 2 -- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/x/stake/keeper/key.go b/x/stake/keeper/key.go index 8bd0de35ad40..2de4ac37c794 100644 --- a/x/stake/keeper/key.go +++ b/x/stake/keeper/key.go @@ -18,17 +18,14 @@ var ( ValidatorsByConsAddrKey = []byte{0x03} // prefix for each key to a validator index, by pubkey ValidatorsBondedIndexKey = []byte{0x04} // prefix for each key to a validator index, for bonded validators ValidatorsByPowerIndexKey = []byte{0x05} // prefix for each key to a validator index, sorted by power - ValidatorCliffIndexKey = []byte{0x06} // key for the validator index of the cliff validator - ValidatorPowerCliffKey = []byte{0x07} // key for the power of the validator on the cliff - IntraTxCounterKey = []byte{0x08} // key for intra-block tx index - DelegationKey = []byte{0x09} // key for a delegation - UnbondingDelegationKey = []byte{0x0A} // key for an unbonding-delegation - UnbondingDelegationByValIndexKey = []byte{0x0B} // prefix for each key for an unbonding-delegation, by validator operator - RedelegationKey = []byte{0x0C} // key for a redelegation - RedelegationByValSrcIndexKey = []byte{0x0D} // prefix for each key for an redelegation, by source validator operator - RedelegationByValDstIndexKey = []byte{0x0E} // prefix for each key for an redelegation, by destination validator operator - - // XXX remove this comment? Keys for store prefixes (transient) + IntraTxCounterKey = []byte{0x06} // key for intra-block tx index + DelegationKey = []byte{0x07} // key for a delegation + UnbondingDelegationKey = []byte{0x08} // key for an unbonding-delegation + UnbondingDelegationByValIndexKey = []byte{0x09} // prefix for each key for an unbonding-delegation, by validator operator + RedelegationKey = []byte{0x0A} // key for a redelegation + RedelegationByValSrcIndexKey = []byte{0x0B} // prefix for each key for an redelegation, by source validator operator + RedelegationByValDstIndexKey = []byte{0x0C} // prefix for each key for an redelegation, by destination validator operator + BondedValidatorsIndexKey = []byte{0x0D} // prefix for each key to the bonded validator set ) const maxDigitsForAccount = 12 // ~220,000,000 atoms created at launch @@ -65,6 +62,11 @@ func GetBondedValidatorsByPowerIndexKey(validator types.Validator, pool types.Po return getValidatorPowerRank(validator, pool) } +// get the bonded validator index key for an operator address +func GetBondedValidatorIndexKey(operator sdk.ValAddress) []byte { + return append(BondedValidatorsIndexKey, operator...) +} + // get the power ranking of a validator // NOTE the larger values are of higher value // nolint: unparam diff --git a/x/stake/stake.go b/x/stake/stake.go index e1d6f091a745..817f73ca311d 100644 --- a/x/stake/stake.go +++ b/x/stake/stake.go @@ -47,8 +47,6 @@ var ( ValidatorsByConsAddrKey = keeper.ValidatorsByConsAddrKey ValidatorsBondedIndexKey = keeper.ValidatorsBondedIndexKey ValidatorsByPowerIndexKey = keeper.ValidatorsByPowerIndexKey - ValidatorCliffIndexKey = keeper.ValidatorCliffIndexKey - ValidatorPowerCliffKey = keeper.ValidatorPowerCliffKey DelegationKey = keeper.DelegationKey IntraTxCounterKey = keeper.IntraTxCounterKey GetUBDKey = keeper.GetUBDKey From ba3c1f53770b294ace4691111378551fded95e59 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Fri, 28 Sep 2018 13:48:51 +0200 Subject: [PATCH 18/44] GetTendermintUpdates continued --- x/stake/keeper/val_state_change.go | 83 ++++++++++++++---------------- 1 file changed, 40 insertions(+), 43 deletions(-) diff --git a/x/stake/keeper/val_state_change.go b/x/stake/keeper/val_state_change.go index 8bfc64c6a930..022c5030f7b8 100644 --- a/x/stake/keeper/val_state_change.go +++ b/x/stake/keeper/val_state_change.go @@ -1,7 +1,9 @@ package keeper import ( + "bytes" "fmt" + "sort" abci "github.com/tendermint/tendermint/abci/types" @@ -19,12 +21,19 @@ import ( // are returned to Tendermint. func (k Keeper) GetTendermintUpdates(ctx sdk.Context) (updates []abci.ValidatorUpdate) { - var last map[string]interface{} - store := ctx.KVStore(k.storeKey) maxValidators := k.GetParams(ctx).MaxValidators - iterator := sdk.KVStoreReversePrefixIterator(store, ValidatorsByPowerIndexKey) + // copy last validator set + var last map[[sdk.AddrLen]byte]interface{} + iterator := sdk.KVStorePrefixIterator(store, BondedValidatorsIndexKey) + for ; iterator.Valid(); iterator.Next() { + var operator [sdk.AddrLen]byte + copy(operator[:], iterator.Key()) + last[operator] = nil + } + + iterator = sdk.KVStoreReversePrefixIterator(store, ValidatorsByPowerIndexKey) count := 0 for ; iterator.Valid() && count < int(maxValidators); iterator.Next() { @@ -52,56 +61,44 @@ func (k Keeper) GetTendermintUpdates(ctx sdk.Context) (updates []abci.ValidatorU updates = append(updates, validator.ABCIValidatorUpdate()) // validator still in the validator set - delete(last, string(operator)) + var opbytes [sdk.AddrLen]byte + copy(opbytes[:], operator) + delete(last, opbytes) + + // set the bonded validator index + store.Set(GetBondedValidatorIndexKey(operator), []byte{}) // keep count count++ } - // any validators left in `last` are no longer bonded - for operator, _ := range last { - validator := k.mustGetValidator(ctx, []byte(operator)) - k.bondedToUnbonding(ctx, validator) - updates = append(updates, validator.ABCIValidatorUpdateZero()) + // sort the map keys for determinism + noLongerBonded := make([][]byte, len(last)) + for oper, _ := range last { + var operator []byte + copy(operator[:], oper[:]) + noLongerBonded = append(noLongerBonded, operator) } + sort.SliceStable(noLongerBonded, func(i, j int) bool { + return bytes.Compare(noLongerBonded[i], noLongerBonded[j]) == -1 + }) - // REF CODE - //// add to accumulated changes for tendermint - //bzABCI := k.cdc.MustMarshalBinary(validator.ABCIValidator()) - //tstore := ctx.TransientStore(k.storeTKey) - //tstore.Set(GetTendermintUpdatesTKey(validator.OperatorAddr), bzABCI) - - // XXX code from issue - /* - last := fetchOldValidatorSet() - tendermintUpdates := make(map[sdk.ValAddress]uint64) - - for _, validator := range topvalidator { //(iterate(top hundred)) { - switch validator.State { - case Unbonded: - unbondedToBonded(ctx, validator.Addr) - tendermintUpdates[validator.Addr] = validator.Power - case Unbonding: - unbondingToBonded(ctx, validator.Addr) - tendermintUpdates[validator.Addr] = validator.Power - case Bonded: // do nothing - store.delete(last[validator.Addr]) - // jailed validators are ranked last, so if we get to a jailed validator - // we have no more bonded validators - if validator.Jailed { - break - } - } - } + // iterate through the sorted no-longer-bonded validators + // any validators left in `last` are no longer bonded + for _, operator := range noLongerBonded { + // fetch the validator + validator := k.mustGetValidator(ctx, sdk.ValAddress(operator)) - for _, validator := range previousValidators { - bondedToUnbonding(ctx, validator.Addr) - tendermintUpdates[validator.Addr] = 0 - } + // bonded to unbonding + k.bondedToUnbonding(ctx, validator) - return tendermintUpdates - */ + // delete from the bonded validator index + store.Delete(GetBondedValidatorIndexKey(operator)) + + // update the validator + updates = append(updates, validator.ABCIValidatorUpdateZero()) + } return updates } From ebc59ae3f8076af99ae48bf1d9d77ec48f2384ac Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Fri, 28 Sep 2018 19:06:15 +0200 Subject: [PATCH 19/44] Works with simulation --- x/stake/keeper/val_state_change.go | 51 ++++++++++++++++++------------ x/stake/simulation/invariants.go | 1 + 2 files changed, 32 insertions(+), 20 deletions(-) diff --git a/x/stake/keeper/val_state_change.go b/x/stake/keeper/val_state_change.go index 022c5030f7b8..eba626af10fa 100644 --- a/x/stake/keeper/val_state_change.go +++ b/x/stake/keeper/val_state_change.go @@ -21,15 +21,17 @@ import ( // are returned to Tendermint. func (k Keeper) GetTendermintUpdates(ctx sdk.Context) (updates []abci.ValidatorUpdate) { + fmt.Printf("GetTendermintUpdates\n") + store := ctx.KVStore(k.storeKey) maxValidators := k.GetParams(ctx).MaxValidators // copy last validator set - var last map[[sdk.AddrLen]byte]interface{} + last := make(map[[sdk.AddrLen]byte]interface{}) iterator := sdk.KVStorePrefixIterator(store, BondedValidatorsIndexKey) for ; iterator.Valid(); iterator.Next() { var operator [sdk.AddrLen]byte - copy(operator[:], iterator.Key()) + copy(operator[:], iterator.Key()[1:]) last[operator] = nil } @@ -43,6 +45,7 @@ func (k Keeper) GetTendermintUpdates(ctx sdk.Context) (updates []abci.ValidatorU // jailed validators are ranked last, so if we get to a jailed validator // we have no more bonded validators + // TODO we can remove this if we remove jailed validators from the power store if validator.Jailed { break } @@ -50,9 +53,9 @@ func (k Keeper) GetTendermintUpdates(ctx sdk.Context) (updates []abci.ValidatorU // apply the appropriate state change if necessary switch validator.Status { case sdk.Unbonded: - k.unbondedToBonded(ctx, validator) + validator = k.unbondedToBonded(ctx, validator) case sdk.Unbonding: - k.unbondingToBonded(ctx, validator) + validator = k.unbondingToBonded(ctx, validator) case sdk.Bonded: // no state change } @@ -62,10 +65,11 @@ func (k Keeper) GetTendermintUpdates(ctx sdk.Context) (updates []abci.ValidatorU // validator still in the validator set var opbytes [sdk.AddrLen]byte - copy(opbytes[:], operator) + copy(opbytes[:], operator[:]) delete(last, opbytes) // set the bonded validator index + // TODO move me store.Set(GetBondedValidatorIndexKey(operator), []byte{}) // keep count @@ -75,10 +79,12 @@ func (k Keeper) GetTendermintUpdates(ctx sdk.Context) (updates []abci.ValidatorU // sort the map keys for determinism noLongerBonded := make([][]byte, len(last)) - for oper, _ := range last { - var operator []byte + index := 0 + for oper := range last { + operator := make([]byte, sdk.AddrLen) copy(operator[:], oper[:]) - noLongerBonded = append(noLongerBonded, operator) + noLongerBonded[index] = operator + index++ } sort.SliceStable(noLongerBonded, func(i, j int) bool { return bytes.Compare(noLongerBonded[i], noLongerBonded[j]) == -1 @@ -88,12 +94,14 @@ func (k Keeper) GetTendermintUpdates(ctx sdk.Context) (updates []abci.ValidatorU // any validators left in `last` are no longer bonded for _, operator := range noLongerBonded { // fetch the validator + // TODO might it have been deleted in RemoveValidator? validator := k.mustGetValidator(ctx, sdk.ValAddress(operator)) // bonded to unbonding k.bondedToUnbonding(ctx, validator) // delete from the bonded validator index + // TODO move me store.Delete(GetBondedValidatorIndexKey(operator)) // update the validator @@ -105,32 +113,32 @@ func (k Keeper) GetTendermintUpdates(ctx sdk.Context) (updates []abci.ValidatorU // Validator state transitions -func (k Keeper) bondedToUnbonding(ctx sdk.Context, validator types.Validator) { +func (k Keeper) bondedToUnbonding(ctx sdk.Context, validator types.Validator) types.Validator { if validator.Status != sdk.Bonded { panic(fmt.Sprintf("bad state transition bondedToUnbonded, validator: %v\n", validator)) } - k.beginUnbondingValidator(ctx, validator) + return k.beginUnbondingValidator(ctx, validator) } -func (k Keeper) unbondingToBonded(ctx sdk.Context, validator types.Validator) { +func (k Keeper) unbondingToBonded(ctx sdk.Context, validator types.Validator) types.Validator { if validator.Status != sdk.Unbonding { panic(fmt.Sprintf("bad state transition unbondingToBonded, validator: %v\n", validator)) } - k.bondValidator(ctx, validator) + return k.bondValidator(ctx, validator) } -func (k Keeper) unbondedToBonded(ctx sdk.Context, validator types.Validator) { +func (k Keeper) unbondedToBonded(ctx sdk.Context, validator types.Validator) types.Validator { if validator.Status != sdk.Unbonded { panic(fmt.Sprintf("bad state transition unbondedToBonded, validator: %v\n", validator)) } - k.bondValidator(ctx, validator) + return k.bondValidator(ctx, validator) } -func (k Keeper) unbondingToUnbonded(ctx sdk.Context, validator types.Validator) { +func (k Keeper) unbondingToUnbonded(ctx sdk.Context, validator types.Validator) types.Validator { if validator.Status != sdk.Unbonded { panic(fmt.Sprintf("bad state transition unbondingToBonded, validator: %v\n", validator)) } - k.completeUnbondingValidator(ctx, validator) + return k.completeUnbondingValidator(ctx, validator) } // send a validator to jail @@ -144,6 +152,7 @@ func (k Keeper) JailValidator(ctx sdk.Context, validator types.Validator) { validator.Jailed = true k.SetValidator(ctx, validator) k.SetValidatorByPowerIndex(ctx, validator, pool) + // TODO we should be able to just delete the index, and only set it again once unjailed } // remove a validator from jail @@ -162,7 +171,7 @@ func (k Keeper) UnjailValidator(ctx sdk.Context, validator types.Validator) { //________________________________________________________________________________________________ // perform all the store operations for when a validator status becomes bonded -func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) { +func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) types.Validator { store := ctx.KVStore(k.storeKey) pool := k.GetPool(ctx) @@ -187,6 +196,8 @@ func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) { if k.hooks != nil { k.hooks.OnValidatorBonded(ctx, validator.ConsAddress()) } + + return validator } // perform all the store operations for when a validator status begins unbonding @@ -199,8 +210,7 @@ func (k Keeper) beginUnbondingValidator(ctx sdk.Context, validator types.Validat k.DeleteValidatorByPowerIndex(ctx, validator, pool) // sanity check - if validator.Status == sdk.Unbonded || - validator.Status == sdk.Unbonding { + if validator.Status != sdk.Bonded { panic(fmt.Sprintf("should not already be unbonded or unbonding, validator: %v\n", validator)) } @@ -228,11 +238,12 @@ func (k Keeper) beginUnbondingValidator(ctx sdk.Context, validator types.Validat } // perform all the store operations for when a validator status becomes unbonded -func (k Keeper) completeUnbondingValidator(ctx sdk.Context, validator types.Validator) { +func (k Keeper) completeUnbondingValidator(ctx sdk.Context, validator types.Validator) types.Validator { pool := k.GetPool(ctx) validator, pool = validator.UpdateStatus(pool, sdk.Unbonded) k.SetPool(ctx, pool) k.SetValidator(ctx, validator) + return validator } // XXX need to figure out how to set a validator's BondIntraTxCounter - probably during delegation bonding? diff --git a/x/stake/simulation/invariants.go b/x/stake/simulation/invariants.go index 2866f6292fef..b06c7bb7cce3 100644 --- a/x/stake/simulation/invariants.go +++ b/x/stake/simulation/invariants.go @@ -76,6 +76,7 @@ func SupplyInvariants(ck bank.Keeper, k stake.Keeper, am auth.AccountMapper) sim // PositivePowerInvariant checks that all stored validators have > 0 power func PositivePowerInvariant(k stake.Keeper) simulation.Invariant { return func(app *baseapp.BaseApp) error { + // TODO Reenable but only check after EndBlock, is this accurate now? ctx := app.NewContext(false, abci.Header{}) var err error k.IterateValidatorsBonded(ctx, func(_ int64, validator sdk.Validator) bool { From cfb12dab335969ded776ba60a31d482cb6ef4e44 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Mon, 1 Oct 2018 12:55:49 +0200 Subject: [PATCH 20/44] Refactor testcases in progress --- x/stake/handler_test.go | 136 ---------------- x/stake/keeper/delegation_test.go | 38 ++--- x/stake/keeper/slash_test.go | 2 +- x/stake/keeper/test_common.go | 17 +- x/stake/keeper/val_state_change.go | 2 - x/stake/keeper/validator_test.go | 240 ++++++++--------------------- x/stake/querier/queryable_test.go | 4 +- 7 files changed, 105 insertions(+), 334 deletions(-) diff --git a/x/stake/handler_test.go b/x/stake/handler_test.go index 91fd51c2527e..7d51aa90ec77 100644 --- a/x/stake/handler_test.go +++ b/x/stake/handler_test.go @@ -777,142 +777,6 @@ func TestUnbondingWhenExcessValidators(t *testing.T) { require.Equal(t, sdk.Bonded, val1.Status, "%v", val1) } -func TestJoiningAsCliffValidator(t *testing.T) { - ctx, _, keeper := keep.CreateTestInput(t, false, 1000) - validatorAddr1, validatorAddr2 := sdk.ValAddress(keep.Addrs[0]), sdk.ValAddress(keep.Addrs[1]) - - // make sure that the cliff validator is nil to begin with - cliffVal := keeper.GetCliffValidator(ctx) - require.Equal(t, []byte(nil), cliffVal) - - // set the unbonding time - params := keeper.GetParams(ctx) - params.UnbondingTime = 0 - params.MaxValidators = 2 - keeper.SetParams(ctx, params) - - // add the first validator - msgCreateValidator := newTestMsgCreateValidator(validatorAddr1, keep.PKs[0], 50) - got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") - - // cliff validator should still be nil - cliffVal = keeper.GetCliffValidator(ctx) - require.Equal(t, []byte(nil), cliffVal) - - // Add the second validator - msgCreateValidator = newTestMsgCreateValidator(validatorAddr2, keep.PKs[1], 30) - got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") - - // now that we've reached maximum validators, the val-2 should be added to the cliff (top) - cliffVal = keeper.GetCliffValidator(ctx) - require.Equal(t, validatorAddr2.Bytes(), cliffVal) -} - -func TestJoiningToCreateFirstCliffValidator(t *testing.T) { - ctx, _, keeper := keep.CreateTestInput(t, false, 1000) - validatorAddr1, validatorAddr2 := sdk.ValAddress(keep.Addrs[0]), sdk.ValAddress(keep.Addrs[1]) - - // make sure that the cliff validator is nil to begin with - cliffVal := keeper.GetCliffValidator(ctx) - require.Equal(t, []byte(nil), cliffVal) - - // set the unbonding time - params := keeper.GetParams(ctx) - params.UnbondingTime = 0 - params.MaxValidators = 2 - keeper.SetParams(ctx, params) - - // add the first validator - msgCreateValidator := newTestMsgCreateValidator(validatorAddr1, keep.PKs[0], 50) - got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") - - // cliff validator should still be nil - cliffVal = keeper.GetCliffValidator(ctx) - require.Equal(t, []byte(nil), cliffVal) - - // Add the second validator - msgCreateValidator = newTestMsgCreateValidator(validatorAddr2, keep.PKs[1], 60) - got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") - - // now that we've reached maximum validators, validator-1 should be added to the cliff (top) - cliffVal = keeper.GetCliffValidator(ctx) - require.Equal(t, validatorAddr1.Bytes(), cliffVal) -} - -func TestCliffValidator(t *testing.T) { - ctx, _, keeper := keep.CreateTestInput(t, false, 1000) - validatorAddr1 := sdk.ValAddress(keep.Addrs[0]) - validatorAddr2 := sdk.ValAddress(keep.Addrs[1]) - validatorAddr3 := sdk.ValAddress(keep.Addrs[2]) - - // make sure that the cliff validator is nil to begin with - cliffVal := keeper.GetCliffValidator(ctx) - require.Equal(t, []byte(nil), cliffVal) - - // set the unbonding time - params := keeper.GetParams(ctx) - params.UnbondingTime = 0 - params.MaxValidators = 2 - keeper.SetParams(ctx, params) - - // add the first validator - msgCreateValidator := newTestMsgCreateValidator(validatorAddr1, keep.PKs[0], 50) - got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") - - // cliff validator should still be nil - cliffVal = keeper.GetCliffValidator(ctx) - require.Equal(t, []byte(nil), cliffVal) - - // Add the second validator - msgCreateValidator = newTestMsgCreateValidator(validatorAddr2, keep.PKs[1], 30) - got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") - - // now that we've reached maximum validators, validator-2 should be added to the cliff (top) - cliffVal = keeper.GetCliffValidator(ctx) - require.Equal(t, validatorAddr2.Bytes(), cliffVal) - - // add the third validator, which should not make it to being bonded, - // so the cliff validator should not change because nobody has been kicked out - msgCreateValidator = newTestMsgCreateValidator(validatorAddr3, keep.PKs[2], 10) - got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") - - cliffVal = keeper.GetCliffValidator(ctx) - require.Equal(t, validatorAddr2.Bytes(), cliffVal) - - // unbond valdator-2 - msgBeginUnbonding := NewMsgBeginUnbonding(sdk.AccAddress(validatorAddr2), validatorAddr2, sdk.NewDec(30)) - got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgBeginUnbonding") - - vals := keeper.GetValidatorsBonded(ctx) - require.Equal(t, 2, len(vals)) - - // now the validator set should be updated, - // where val-3 enters the validator set on the cliff - cliffVal = keeper.GetCliffValidator(ctx) - require.Equal(t, validatorAddr3.Bytes(), cliffVal) - - // unbond valdator-1 - msgBeginUnbonding = NewMsgBeginUnbonding(sdk.AccAddress(validatorAddr1), validatorAddr1, sdk.NewDec(50)) - got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgBeginUnbonding") - - // get bonded validators - should just be one - vals = keeper.GetValidatorsBonded(ctx) - require.Equal(t, 1, len(vals)) - - // cliff now should be empty - cliffVal = keeper.GetCliffValidator(ctx) - require.Equal(t, []byte(nil), cliffVal) -} - func TestBondUnbondRedelegateSlashTwice(t *testing.T) { ctx, _, keeper := keep.CreateTestInput(t, false, 1000) valA, valB, del := sdk.ValAddress(keep.Addrs[0]), sdk.ValAddress(keep.Addrs[1]), keep.Addrs[2] diff --git a/x/stake/keeper/delegation_test.go b/x/stake/keeper/delegation_test.go index ed65f1f404b3..96f0ba383e93 100644 --- a/x/stake/keeper/delegation_test.go +++ b/x/stake/keeper/delegation_test.go @@ -25,9 +25,9 @@ func TestDelegation(t *testing.T) { } keeper.SetPool(ctx, pool) - validators[0] = keeper.UpdateValidator(ctx, validators[0]) - validators[1] = keeper.UpdateValidator(ctx, validators[1]) - validators[2] = keeper.UpdateValidator(ctx, validators[2]) + validators[0] = updateValidator(keeper, ctx, validators[0]) + validators[1] = updateValidator(keeper, ctx, validators[1]) + validators[2] = updateValidator(keeper, ctx, validators[2]) // first add a validators[0] to delegate too @@ -184,7 +184,7 @@ func TestUnbondDelegation(t *testing.T) { validator, pool, issuedShares := validator.AddTokensFromDel(pool, sdk.NewInt(10)) require.Equal(t, int64(10), issuedShares.RoundInt64()) keeper.SetPool(ctx, pool) - validator = keeper.UpdateValidator(ctx, validator) + validator = updateValidator(keeper, ctx, validator) pool = keeper.GetPool(ctx) require.Equal(t, int64(10), pool.BondedTokens.RoundInt64()) @@ -226,7 +226,7 @@ func TestUndelegateSelfDelegation(t *testing.T) { validator, pool, issuedShares := validator.AddTokensFromDel(pool, sdk.NewInt(10)) require.Equal(t, int64(10), issuedShares.RoundInt64()) keeper.SetPool(ctx, pool) - validator = keeper.UpdateValidator(ctx, validator) + validator = updateValidator(keeper, ctx, validator) pool = keeper.GetPool(ctx) selfDelegation := types.Delegation{ DelegatorAddr: sdk.AccAddress(addrVals[0].Bytes()), @@ -239,7 +239,7 @@ func TestUndelegateSelfDelegation(t *testing.T) { validator, pool, issuedShares = validator.AddTokensFromDel(pool, sdk.NewInt(10)) require.Equal(t, int64(10), issuedShares.RoundInt64()) keeper.SetPool(ctx, pool) - validator = keeper.UpdateValidator(ctx, validator) + validator = updateValidator(keeper, ctx, validator) pool = keeper.GetPool(ctx) delegation := types.Delegation{ DelegatorAddr: addrDels[0], @@ -269,7 +269,7 @@ func TestUndelegateFromUnbondingValidator(t *testing.T) { validator, pool, issuedShares := validator.AddTokensFromDel(pool, sdk.NewInt(10)) require.Equal(t, int64(10), issuedShares.RoundInt64()) keeper.SetPool(ctx, pool) - validator = keeper.UpdateValidator(ctx, validator) + validator = updateValidator(keeper, ctx, validator) pool = keeper.GetPool(ctx) selfDelegation := types.Delegation{ DelegatorAddr: sdk.AccAddress(addrVals[0].Bytes()), @@ -282,7 +282,7 @@ func TestUndelegateFromUnbondingValidator(t *testing.T) { validator, pool, issuedShares = validator.AddTokensFromDel(pool, sdk.NewInt(10)) require.Equal(t, int64(10), issuedShares.RoundInt64()) keeper.SetPool(ctx, pool) - validator = keeper.UpdateValidator(ctx, validator) + validator = updateValidator(keeper, ctx, validator) pool = keeper.GetPool(ctx) delegation := types.Delegation{ DelegatorAddr: addrDels[0], @@ -340,7 +340,7 @@ func TestUndelegateFromUnbondedValidator(t *testing.T) { validator, pool, issuedShares := validator.AddTokensFromDel(pool, sdk.NewInt(10)) require.Equal(t, int64(10), issuedShares.RoundInt64()) keeper.SetPool(ctx, pool) - validator = keeper.UpdateValidator(ctx, validator) + validator = updateValidator(keeper, ctx, validator) pool = keeper.GetPool(ctx) val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) selfDelegation := types.Delegation{ @@ -354,7 +354,7 @@ func TestUndelegateFromUnbondedValidator(t *testing.T) { validator, pool, issuedShares = validator.AddTokensFromDel(pool, sdk.NewInt(10)) require.Equal(t, int64(10), issuedShares.RoundInt64()) keeper.SetPool(ctx, pool) - validator = keeper.UpdateValidator(ctx, validator) + validator = updateValidator(keeper, ctx, validator) pool = keeper.GetPool(ctx) delegation := types.Delegation{ DelegatorAddr: addrDels[0], @@ -506,7 +506,7 @@ func TestRedelegateSelfDelegation(t *testing.T) { validator, pool, issuedShares := validator.AddTokensFromDel(pool, sdk.NewInt(10)) require.Equal(t, int64(10), issuedShares.RoundInt64()) keeper.SetPool(ctx, pool) - validator = keeper.UpdateValidator(ctx, validator) + validator = updateValidator(keeper, ctx, validator) pool = keeper.GetPool(ctx) val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) selfDelegation := types.Delegation{ @@ -521,13 +521,13 @@ func TestRedelegateSelfDelegation(t *testing.T) { validator2, pool, issuedShares = validator2.AddTokensFromDel(pool, sdk.NewInt(10)) require.Equal(t, int64(10), issuedShares.RoundInt64()) keeper.SetPool(ctx, pool) - validator2 = keeper.UpdateValidator(ctx, validator2) + validator2 = updateValidator(keeper, ctx, validator2) // create a second delegation to this validator validator, pool, issuedShares = validator.AddTokensFromDel(pool, sdk.NewInt(10)) require.Equal(t, int64(10), issuedShares.RoundInt64()) keeper.SetPool(ctx, pool) - validator = keeper.UpdateValidator(ctx, validator) + validator = updateValidator(keeper, ctx, validator) pool = keeper.GetPool(ctx) delegation := types.Delegation{ DelegatorAddr: addrDels[0], @@ -556,7 +556,7 @@ func TestRedelegateFromUnbondingValidator(t *testing.T) { validator, pool, issuedShares := validator.AddTokensFromDel(pool, sdk.NewInt(10)) require.Equal(t, int64(10), issuedShares.RoundInt64()) keeper.SetPool(ctx, pool) - validator = keeper.UpdateValidator(ctx, validator) + validator = updateValidator(keeper, ctx, validator) pool = keeper.GetPool(ctx) val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) selfDelegation := types.Delegation{ @@ -570,7 +570,7 @@ func TestRedelegateFromUnbondingValidator(t *testing.T) { validator, pool, issuedShares = validator.AddTokensFromDel(pool, sdk.NewInt(10)) require.Equal(t, int64(10), issuedShares.RoundInt64()) keeper.SetPool(ctx, pool) - validator = keeper.UpdateValidator(ctx, validator) + validator = updateValidator(keeper, ctx, validator) pool = keeper.GetPool(ctx) delegation := types.Delegation{ DelegatorAddr: addrDels[0], @@ -584,7 +584,7 @@ func TestRedelegateFromUnbondingValidator(t *testing.T) { validator2, pool, issuedShares = validator2.AddTokensFromDel(pool, sdk.NewInt(10)) require.Equal(t, int64(10), issuedShares.RoundInt64()) keeper.SetPool(ctx, pool) - validator2 = keeper.UpdateValidator(ctx, validator2) + validator2 = updateValidator(keeper, ctx, validator2) header := ctx.BlockHeader() blockHeight := int64(10) @@ -634,7 +634,7 @@ func TestRedelegateFromUnbondedValidator(t *testing.T) { validator, pool, issuedShares := validator.AddTokensFromDel(pool, sdk.NewInt(10)) require.Equal(t, int64(10), issuedShares.RoundInt64()) keeper.SetPool(ctx, pool) - validator = keeper.UpdateValidator(ctx, validator) + validator = updateValidator(keeper, ctx, validator) pool = keeper.GetPool(ctx) val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) selfDelegation := types.Delegation{ @@ -648,7 +648,7 @@ func TestRedelegateFromUnbondedValidator(t *testing.T) { validator, pool, issuedShares = validator.AddTokensFromDel(pool, sdk.NewInt(10)) require.Equal(t, int64(10), issuedShares.RoundInt64()) keeper.SetPool(ctx, pool) - validator = keeper.UpdateValidator(ctx, validator) + validator = updateValidator(keeper, ctx, validator) pool = keeper.GetPool(ctx) delegation := types.Delegation{ DelegatorAddr: addrDels[0], @@ -662,7 +662,7 @@ func TestRedelegateFromUnbondedValidator(t *testing.T) { validator2, pool, issuedShares = validator2.AddTokensFromDel(pool, sdk.NewInt(10)) require.Equal(t, int64(10), issuedShares.RoundInt64()) keeper.SetPool(ctx, pool) - validator2 = keeper.UpdateValidator(ctx, validator2) + validator2 = updateValidator(keeper, ctx, validator2) header := ctx.BlockHeader() blockHeight := int64(10) diff --git a/x/stake/keeper/slash_test.go b/x/stake/keeper/slash_test.go index 0a6cccac2abf..b8c90d4a0a55 100644 --- a/x/stake/keeper/slash_test.go +++ b/x/stake/keeper/slash_test.go @@ -27,7 +27,7 @@ func setupHelper(t *testing.T, amt int64) (sdk.Context, Keeper, types.Params) { validator := types.NewValidator(addrVals[i], PKs[i], types.Description{}) validator, pool, _ = validator.AddTokensFromDel(pool, sdk.NewInt(amt)) keeper.SetPool(ctx, pool) - validator = keeper.UpdateValidator(ctx, validator) + validator = updateValidator(keeper, ctx, validator) keeper.SetValidatorByConsAddr(ctx, validator) } pool = keeper.GetPool(ctx) diff --git a/x/stake/keeper/test_common.go b/x/stake/keeper/test_common.go index 388e7e247045..3b0287e4fe29 100644 --- a/x/stake/keeper/test_common.go +++ b/x/stake/keeper/test_common.go @@ -202,5 +202,20 @@ func createTestPubKeys(numPubKeys int) []crypto.PubKey { // does a certain by-power index record exist func ValidatorByPowerIndexExists(ctx sdk.Context, keeper Keeper, power []byte) bool { store := ctx.KVStore(keeper.storeKey) - return store.Get(power) != nil + return store.Has(power) +} + +func updateValidator(keeper Keeper, ctx sdk.Context, validator types.Validator) types.Validator { + keeper.SetValidator(ctx, validator) + keeper.GetTendermintUpdates(ctx) + validator, found := keeper.GetValidator(ctx, validator.OperatorAddr) + if !found { + panic("validator expected but not found") + } + return validator +} + +func validatorByPowerIndexExists(k Keeper, ctx sdk.Context, power []byte) bool { + store := ctx.KVStore(k.storeKey) + return store.Has(power) } diff --git a/x/stake/keeper/val_state_change.go b/x/stake/keeper/val_state_change.go index eba626af10fa..f463e39c168d 100644 --- a/x/stake/keeper/val_state_change.go +++ b/x/stake/keeper/val_state_change.go @@ -21,8 +21,6 @@ import ( // are returned to Tendermint. func (k Keeper) GetTendermintUpdates(ctx sdk.Context) (updates []abci.ValidatorUpdate) { - fmt.Printf("GetTendermintUpdates\n") - store := ctx.KVStore(k.storeKey) maxValidators := k.GetParams(ctx).MaxValidators diff --git a/x/stake/keeper/validator_test.go b/x/stake/keeper/validator_test.go index cb30ebea1a18..3c7a4875371b 100644 --- a/x/stake/keeper/validator_test.go +++ b/x/stake/keeper/validator_test.go @@ -13,23 +13,6 @@ import ( "github.com/stretchr/testify/require" ) -// for testing, remove all validator update entries after applied to Tendermint -func clearTendermintUpdates(ctx sdk.Context, k Keeper) { - store := ctx.TransientStore(k.storeTKey) - - // delete subspace - iterator := sdk.KVStorePrefixIterator(store, TendermintUpdatesTKey) - for ; iterator.Valid(); iterator.Next() { - store.Delete(iterator.Key()) - } - iterator.Close() -} - -func validatorByPowerIndexExists(k Keeper, ctx sdk.Context, power []byte) bool { - store := ctx.KVStore(k.storeKey) - return store.Has(power) -} - //_______________________________________________________ func TestSetValidator(t *testing.T) { @@ -46,7 +29,7 @@ func TestSetValidator(t *testing.T) { assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.Tokens)) assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.DelegatorShares)) keeper.SetPool(ctx, pool) - keeper.UpdateValidator(ctx, validator) + updateValidator(keeper, ctx, validator) // after the save the validator should be bonded validator, found := keeper.GetValidator(ctx, valAddr) @@ -99,7 +82,7 @@ func TestUpdateValidatorByPowerIndex(t *testing.T) { require.Equal(t, sdk.Unbonded, validator.Status) require.Equal(t, int64(100), validator.Tokens.RoundInt64()) keeper.SetPool(ctx, pool) - keeper.UpdateValidator(ctx, validator) + updateValidator(keeper, ctx, validator) validator, found := keeper.GetValidator(ctx, addrVals[0]) require.True(t, found) require.Equal(t, int64(100), validator.Tokens.RoundInt64(), "\nvalidator %v\npool %v", validator, pool) @@ -111,8 +94,8 @@ func TestUpdateValidatorByPowerIndex(t *testing.T) { // burn half the delegator shares validator, pool, burned := validator.RemoveDelShares(pool, delSharesCreated.Quo(sdk.NewDec(2))) require.Equal(t, int64(50), burned.RoundInt64()) - keeper.SetPool(ctx, pool) // update the pool - keeper.UpdateValidator(ctx, validator) // update the validator, possibly kicking it out + keeper.SetPool(ctx, pool) // update the pool + updateValidator(keeper, ctx, validator) // update the validator, possibly kicking it out require.False(t, validatorByPowerIndexExists(keeper, ctx, power)) pool = keeper.GetPool(ctx) @@ -149,7 +132,7 @@ func TestUpdateBondedValidatorsDecreaseCliff(t *testing.T) { val, pool, _ = val.AddTokensFromDel(pool, sdk.NewInt(int64((i+1)*10))) keeper.SetPool(ctx, pool) - val = keeper.UpdateValidator(ctx, val) + val = updateValidator(keeper, ctx, val) validators[i] = val } @@ -159,15 +142,7 @@ func TestUpdateBondedValidatorsDecreaseCliff(t *testing.T) { // validator and next in line cliff validator nextCliffVal, pool, _ = nextCliffVal.RemoveDelShares(pool, sdk.NewDec(21)) keeper.SetPool(ctx, pool) - nextCliffVal = keeper.UpdateValidator(ctx, nextCliffVal) - - // require the cliff validator has changed - cliffVal := validators[numVals-maxVals-1] - require.Equal(t, cliffVal.OperatorAddr, sdk.ValAddress(keeper.GetCliffValidator(ctx))) - - // require the cliff validator power has changed - cliffPower := keeper.GetCliffValidatorPower(ctx) - require.Equal(t, GetBondedValidatorsByPowerIndexKey(cliffVal, pool), cliffPower) + nextCliffVal = updateValidator(keeper, ctx, nextCliffVal) expectedValStatus := map[int]sdk.BondStatus{ 9: sdk.Bonded, 8: sdk.Bonded, 7: sdk.Bonded, 5: sdk.Bonded, 4: sdk.Bonded, @@ -187,75 +162,6 @@ func TestUpdateBondedValidatorsDecreaseCliff(t *testing.T) { } } -func TestCliffValidatorChange(t *testing.T) { - numVals := 10 - maxVals := 5 - - // create context, keeper, and pool for tests - ctx, _, keeper := CreateTestInput(t, false, 0) - pool := keeper.GetPool(ctx) - - // create keeper parameters - params := keeper.GetParams(ctx) - params.MaxValidators = uint16(maxVals) - keeper.SetParams(ctx, params) - - // create a random pool - pool.LooseTokens = sdk.NewDec(10000) - pool.BondedTokens = sdk.NewDec(1234) - keeper.SetPool(ctx, pool) - - validators := make([]types.Validator, numVals) - for i := 0; i < len(validators); i++ { - moniker := fmt.Sprintf("val#%d", int64(i)) - val := types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{Moniker: moniker}) - val.BondHeight = int64(i) - val.BondIntraTxCounter = int16(i) - val, pool, _ = val.AddTokensFromDel(pool, sdk.NewInt(int64((i+1)*10))) - - keeper.SetPool(ctx, pool) - val = keeper.UpdateValidator(ctx, val) - validators[i] = val - } - - // add a large amount of tokens to current cliff validator - currCliffVal := validators[numVals-maxVals] - currCliffVal, pool, _ = currCliffVal.AddTokensFromDel(pool, sdk.NewInt(200)) - keeper.SetPool(ctx, pool) - currCliffVal = keeper.UpdateValidator(ctx, currCliffVal) - - // assert new cliff validator to be set to the second lowest bonded validator by power - newCliffVal := validators[numVals-maxVals+1] - require.Equal(t, newCliffVal.OperatorAddr, sdk.ValAddress(keeper.GetCliffValidator(ctx))) - - // assert cliff validator power should have been updated - cliffPower := keeper.GetCliffValidatorPower(ctx) - require.Equal(t, GetBondedValidatorsByPowerIndexKey(newCliffVal, pool), cliffPower) - - // add small amount of tokens to new current cliff validator - newCliffVal, pool, _ = newCliffVal.AddTokensFromDel(pool, sdk.NewInt(1)) - keeper.SetPool(ctx, pool) - newCliffVal = keeper.UpdateValidator(ctx, newCliffVal) - - // assert cliff validator has not change but increased in power - cliffPower = keeper.GetCliffValidatorPower(ctx) - require.Equal(t, newCliffVal.OperatorAddr, sdk.ValAddress(keeper.GetCliffValidator(ctx))) - require.Equal(t, GetBondedValidatorsByPowerIndexKey(newCliffVal, pool), cliffPower) - - // add enough power to cliff validator to be equal in rank to next validator - newCliffVal, pool, _ = newCliffVal.AddTokensFromDel(pool, sdk.NewInt(9)) - keeper.SetPool(ctx, pool) - newCliffVal = keeper.UpdateValidator(ctx, newCliffVal) - - // assert new cliff validator due to power rank construction - newCliffVal = validators[numVals-maxVals+2] - require.Equal(t, newCliffVal.OperatorAddr, sdk.ValAddress(keeper.GetCliffValidator(ctx))) - - // assert cliff validator power should have been updated - cliffPower = keeper.GetCliffValidatorPower(ctx) - require.Equal(t, GetBondedValidatorsByPowerIndexKey(newCliffVal, pool), cliffPower) -} - func TestSlashToZeroPowerRemoved(t *testing.T) { // initialize setup ctx, _, keeper := CreateTestInput(t, false, 100) @@ -268,7 +174,7 @@ func TestSlashToZeroPowerRemoved(t *testing.T) { require.Equal(t, int64(100), validator.Tokens.RoundInt64()) keeper.SetPool(ctx, pool) keeper.SetValidatorByConsAddr(ctx, validator) - validator = keeper.UpdateValidator(ctx, validator) + validator = updateValidator(keeper, ctx, validator) require.Equal(t, int64(100), validator.Tokens.RoundInt64(), "\nvalidator %v\npool %v", validator, pool) // slash the validator by 100% @@ -311,7 +217,7 @@ func TestValidatorBasics(t *testing.T) { assert.True(sdk.DecEq(t, sdk.ZeroDec(), pool.BondedTokens)) // set and retrieve a record - validators[0] = keeper.UpdateValidator(ctx, validators[0]) + validators[0] = updateValidator(keeper, ctx, validators[0]) keeper.SetValidatorByConsAddr(ctx, validators[0]) resVal, found := keeper.GetValidator(ctx, addrVals[0]) require.True(t, found) @@ -338,7 +244,7 @@ func TestValidatorBasics(t *testing.T) { validators[0].Status = sdk.Bonded validators[0].Tokens = sdk.NewDec(10) validators[0].DelegatorShares = sdk.NewDec(10) - validators[0] = keeper.UpdateValidator(ctx, validators[0]) + validators[0] = updateValidator(keeper, ctx, validators[0]) resVal, found = keeper.GetValidator(ctx, addrVals[0]) require.True(t, found) assert.True(ValEq(t, validators[0], resVal)) @@ -348,8 +254,8 @@ func TestValidatorBasics(t *testing.T) { assert.True(ValEq(t, validators[0], resVals[0])) // add other validators - validators[1] = keeper.UpdateValidator(ctx, validators[1]) - validators[2] = keeper.UpdateValidator(ctx, validators[2]) + validators[1] = updateValidator(keeper, ctx, validators[1]) + validators[2] = updateValidator(keeper, ctx, validators[2]) resVal, found = keeper.GetValidator(ctx, addrVals[1]) require.True(t, found) assert.True(ValEq(t, validators[1], resVal)) @@ -382,7 +288,7 @@ func GetValidatorSortingUnmixed(t *testing.T) { validators[i].Status = sdk.Bonded validators[i].Tokens = sdk.NewDec(amt) validators[i].DelegatorShares = sdk.NewDec(amt) - keeper.UpdateValidator(ctx, validators[i]) + updateValidator(keeper, ctx, validators[i]) } // first make sure everything made it in to the gotValidator group @@ -401,14 +307,14 @@ func GetValidatorSortingUnmixed(t *testing.T) { // test a basic increase in voting power validators[3].Tokens = sdk.NewDec(500) - keeper.UpdateValidator(ctx, validators[3]) + updateValidator(keeper, ctx, validators[3]) resValidators = keeper.GetBondedValidatorsByPower(ctx) require.Equal(t, len(resValidators), n) assert.True(ValEq(t, validators[3], resValidators[0])) // test a decrease in voting power validators[3].Tokens = sdk.NewDec(300) - keeper.UpdateValidator(ctx, validators[3]) + updateValidator(keeper, ctx, validators[3]) resValidators = keeper.GetBondedValidatorsByPower(ctx) require.Equal(t, len(resValidators), n) assert.True(ValEq(t, validators[3], resValidators[0])) @@ -417,7 +323,7 @@ func GetValidatorSortingUnmixed(t *testing.T) { // test equal voting power, different age validators[3].Tokens = sdk.NewDec(200) ctx = ctx.WithBlockHeight(10) - keeper.UpdateValidator(ctx, validators[3]) + updateValidator(keeper, ctx, validators[3]) resValidators = keeper.GetBondedValidatorsByPower(ctx) require.Equal(t, len(resValidators), n) assert.True(ValEq(t, validators[3], resValidators[0])) @@ -427,7 +333,7 @@ func GetValidatorSortingUnmixed(t *testing.T) { // no change in voting power - no change in sort ctx = ctx.WithBlockHeight(20) - keeper.UpdateValidator(ctx, validators[4]) + updateValidator(keeper, ctx, validators[4]) resValidators = keeper.GetBondedValidatorsByPower(ctx) require.Equal(t, len(resValidators), n) assert.True(ValEq(t, validators[3], resValidators[0])) @@ -436,11 +342,11 @@ func GetValidatorSortingUnmixed(t *testing.T) { // change in voting power of both validators, both still in v-set, no age change validators[3].Tokens = sdk.NewDec(300) validators[4].Tokens = sdk.NewDec(300) - keeper.UpdateValidator(ctx, validators[3]) + updateValidator(keeper, ctx, validators[3]) resValidators = keeper.GetBondedValidatorsByPower(ctx) require.Equal(t, len(resValidators), n) ctx = ctx.WithBlockHeight(30) - keeper.UpdateValidator(ctx, validators[4]) + updateValidator(keeper, ctx, validators[4]) resValidators = keeper.GetBondedValidatorsByPower(ctx) require.Equal(t, len(resValidators), n, "%v", resValidators) assert.True(ValEq(t, validators[3], resValidators[0])) @@ -478,7 +384,7 @@ func GetValidatorSortingMixed(t *testing.T) { validators[4].Tokens = sdk.NewDec(amts[4]) for i := range amts { - keeper.UpdateValidator(ctx, validators[i]) + updateValidator(keeper, ctx, validators[i]) } val0, found := keeper.GetValidator(ctx, sdk.ValAddress(Addrs[0])) require.True(t, found) @@ -531,7 +437,7 @@ func TestGetValidatorsEdgeCases(t *testing.T) { validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{Moniker: moniker}) validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt)) keeper.SetPool(ctx, pool) - validators[i] = keeper.UpdateValidator(ctx, validators[i]) + validators[i] = updateValidator(keeper, ctx, validators[i]) } for i := range amts { @@ -546,7 +452,7 @@ func TestGetValidatorsEdgeCases(t *testing.T) { pool := keeper.GetPool(ctx) validators[0], pool, _ = validators[0].AddTokensFromDel(pool, sdk.NewInt(500)) keeper.SetPool(ctx, pool) - validators[0] = keeper.UpdateValidator(ctx, validators[0]) + validators[0] = updateValidator(keeper, ctx, validators[0]) resValidators = keeper.GetBondedValidatorsByPower(ctx) require.Equal(t, nMax, uint16(len(resValidators))) assert.True(ValEq(t, validators[0], resValidators[0])) @@ -563,7 +469,7 @@ func TestGetValidatorsEdgeCases(t *testing.T) { require.True(t, found) validators[3], pool, _ = validators[3].AddTokensFromDel(pool, sdk.NewInt(1)) keeper.SetPool(ctx, pool) - validators[3] = keeper.UpdateValidator(ctx, validators[3]) + validators[3] = updateValidator(keeper, ctx, validators[3]) resValidators = keeper.GetBondedValidatorsByPower(ctx) require.Equal(t, nMax, uint16(len(resValidators))) assert.True(ValEq(t, validators[0], resValidators[0])) @@ -572,7 +478,7 @@ func TestGetValidatorsEdgeCases(t *testing.T) { // validator 3 kicked out temporarily validators[3], pool, _ = validators[3].RemoveDelShares(pool, sdk.NewDec(201)) keeper.SetPool(ctx, pool) - validators[3] = keeper.UpdateValidator(ctx, validators[3]) + validators[3] = updateValidator(keeper, ctx, validators[3]) resValidators = keeper.GetBondedValidatorsByPower(ctx) require.Equal(t, nMax, uint16(len(resValidators))) assert.True(ValEq(t, validators[0], resValidators[0])) @@ -581,7 +487,7 @@ func TestGetValidatorsEdgeCases(t *testing.T) { // validator 4 does not get spot back validators[3], pool, _ = validators[3].AddTokensFromDel(pool, sdk.NewInt(200)) keeper.SetPool(ctx, pool) - validators[3] = keeper.UpdateValidator(ctx, validators[3]) + validators[3] = updateValidator(keeper, ctx, validators[3]) resValidators = keeper.GetBondedValidatorsByPower(ctx) require.Equal(t, nMax, uint16(len(resValidators))) assert.True(ValEq(t, validators[0], resValidators[0])) @@ -611,13 +517,13 @@ func TestValidatorBondHeight(t *testing.T) { validators[2], pool, _ = validators[2].AddTokensFromDel(pool, sdk.NewInt(100)) keeper.SetPool(ctx, pool) - validators[0] = keeper.UpdateValidator(ctx, validators[0]) + validators[0] = updateValidator(keeper, ctx, validators[0]) //////////////////////////////////////// // If two validators both increase to the same voting power in the same block, // the one with the first transaction should become bonded - validators[1] = keeper.UpdateValidator(ctx, validators[1]) - validators[2] = keeper.UpdateValidator(ctx, validators[2]) + validators[1] = updateValidator(keeper, ctx, validators[1]) + validators[2] = updateValidator(keeper, ctx, validators[2]) pool = keeper.GetPool(ctx) @@ -629,10 +535,10 @@ func TestValidatorBondHeight(t *testing.T) { validators[1], pool, _ = validators[1].AddTokensFromDel(pool, sdk.NewInt(50)) validators[2], pool, _ = validators[2].AddTokensFromDel(pool, sdk.NewInt(50)) keeper.SetPool(ctx, pool) - validators[2] = keeper.UpdateValidator(ctx, validators[2]) + validators[2] = updateValidator(keeper, ctx, validators[2]) resValidators = keeper.GetBondedValidatorsByPower(ctx) require.Equal(t, params.MaxValidators, uint16(len(resValidators))) - validators[1] = keeper.UpdateValidator(ctx, validators[1]) + validators[1] = updateValidator(keeper, ctx, validators[1]) assert.True(ValEq(t, validators[0], resValidators[0])) assert.True(ValEq(t, validators[2], resValidators[1])) } @@ -652,7 +558,7 @@ func TestFullValidatorSetPowerChange(t *testing.T) { validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{}) validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt)) keeper.SetPool(ctx, pool) - keeper.UpdateValidator(ctx, validators[i]) + updateValidator(keeper, ctx, validators[i]) } for i := range amts { var found bool @@ -673,7 +579,7 @@ func TestFullValidatorSetPowerChange(t *testing.T) { pool := keeper.GetPool(ctx) validators[0], pool, _ = validators[0].AddTokensFromDel(pool, sdk.NewInt(600)) keeper.SetPool(ctx, pool) - validators[0] = keeper.UpdateValidator(ctx, validators[0]) + validators[0] = updateValidator(keeper, ctx, validators[0]) resValidators = keeper.GetBondedValidatorsByPower(ctx) assert.Equal(t, max, len(resValidators)) assert.True(ValEq(t, validators[0], resValidators[0])) @@ -699,8 +605,8 @@ func TestGetTendermintUpdatesAllNone(t *testing.T) { // test from nothing to something // tendermintUpdate set: {} -> {c1, c3} require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) - validators[0] = keeper.UpdateValidator(ctx, validators[0]) - validators[1] = keeper.UpdateValidator(ctx, validators[1]) + validators[0] = updateValidator(keeper, ctx, validators[0]) + validators[1] = updateValidator(keeper, ctx, validators[1]) updates := keeper.GetTendermintUpdates(ctx) assert.Equal(t, 2, len(updates)) @@ -719,15 +625,14 @@ func TestGetTendermintUpdatesIdentical(t *testing.T) { validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt)) keeper.SetPool(ctx, pool) } - validators[0] = keeper.UpdateValidator(ctx, validators[0]) - validators[1] = keeper.UpdateValidator(ctx, validators[1]) - clearTendermintUpdates(ctx, keeper) + validators[0] = updateValidator(keeper, ctx, validators[0]) + validators[1] = updateValidator(keeper, ctx, validators[1]) require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) // test identical, // tendermintUpdate set: {} -> {} - validators[0] = keeper.UpdateValidator(ctx, validators[0]) - validators[1] = keeper.UpdateValidator(ctx, validators[1]) + validators[0] = updateValidator(keeper, ctx, validators[0]) + validators[1] = updateValidator(keeper, ctx, validators[1]) require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) } @@ -742,16 +647,15 @@ func TestGetTendermintUpdatesSingleValueChange(t *testing.T) { validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt)) keeper.SetPool(ctx, pool) } - validators[0] = keeper.UpdateValidator(ctx, validators[0]) - validators[1] = keeper.UpdateValidator(ctx, validators[1]) - clearTendermintUpdates(ctx, keeper) + validators[0] = updateValidator(keeper, ctx, validators[0]) + validators[1] = updateValidator(keeper, ctx, validators[1]) require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) // test single value change // tendermintUpdate set: {} -> {c1'} validators[0].Status = sdk.Bonded validators[0].Tokens = sdk.NewDec(600) - validators[0] = keeper.UpdateValidator(ctx, validators[0]) + validators[0] = updateValidator(keeper, ctx, validators[0]) updates := keeper.GetTendermintUpdates(ctx) @@ -770,9 +674,8 @@ func TestGetTendermintUpdatesMultipleValueChange(t *testing.T) { validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt)) keeper.SetPool(ctx, pool) } - validators[0] = keeper.UpdateValidator(ctx, validators[0]) - validators[1] = keeper.UpdateValidator(ctx, validators[1]) - clearTendermintUpdates(ctx, keeper) + validators[0] = updateValidator(keeper, ctx, validators[0]) + validators[1] = updateValidator(keeper, ctx, validators[1]) require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) // test multiple value change @@ -781,8 +684,8 @@ func TestGetTendermintUpdatesMultipleValueChange(t *testing.T) { validators[0], pool, _ = validators[0].AddTokensFromDel(pool, sdk.NewInt(190)) validators[1], pool, _ = validators[1].AddTokensFromDel(pool, sdk.NewInt(80)) keeper.SetPool(ctx, pool) - validators[0] = keeper.UpdateValidator(ctx, validators[0]) - validators[1] = keeper.UpdateValidator(ctx, validators[1]) + validators[0] = updateValidator(keeper, ctx, validators[0]) + validators[1] = updateValidator(keeper, ctx, validators[1]) updates := keeper.GetTendermintUpdates(ctx) require.Equal(t, 2, len(updates)) @@ -801,30 +704,27 @@ func TestGetTendermintUpdatesInserted(t *testing.T) { validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt)) keeper.SetPool(ctx, pool) } - validators[0] = keeper.UpdateValidator(ctx, validators[0]) - validators[1] = keeper.UpdateValidator(ctx, validators[1]) - clearTendermintUpdates(ctx, keeper) + validators[0] = updateValidator(keeper, ctx, validators[0]) + validators[1] = updateValidator(keeper, ctx, validators[1]) require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) // test validtor added at the beginning // tendermintUpdate set: {} -> {c0} - validators[2] = keeper.UpdateValidator(ctx, validators[2]) + validators[2] = updateValidator(keeper, ctx, validators[2]) updates := keeper.GetTendermintUpdates(ctx) require.Equal(t, 1, len(updates)) require.Equal(t, validators[2].ABCIValidatorUpdate(), updates[0]) // test validtor added at the beginning // tendermintUpdate set: {} -> {c0} - clearTendermintUpdates(ctx, keeper) - validators[3] = keeper.UpdateValidator(ctx, validators[3]) + validators[3] = updateValidator(keeper, ctx, validators[3]) updates = keeper.GetTendermintUpdates(ctx) require.Equal(t, 1, len(updates)) require.Equal(t, validators[3].ABCIValidatorUpdate(), updates[0]) // test validtor added at the end // tendermintUpdate set: {} -> {c0} - clearTendermintUpdates(ctx, keeper) - validators[4] = keeper.UpdateValidator(ctx, validators[4]) + validators[4] = updateValidator(keeper, ctx, validators[4]) updates = keeper.GetTendermintUpdates(ctx) require.Equal(t, 1, len(updates)) require.Equal(t, validators[4].ABCIValidatorUpdate(), updates[0]) @@ -844,26 +744,24 @@ func TestGetTendermintUpdatesWithCliffValidator(t *testing.T) { validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt)) keeper.SetPool(ctx, pool) } - validators[0] = keeper.UpdateValidator(ctx, validators[0]) - validators[1] = keeper.UpdateValidator(ctx, validators[1]) - clearTendermintUpdates(ctx, keeper) + validators[0] = updateValidator(keeper, ctx, validators[0]) + validators[1] = updateValidator(keeper, ctx, validators[1]) require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) // test validator added at the end but not inserted in the valset // tendermintUpdate set: {} -> {} - keeper.UpdateValidator(ctx, validators[2]) + updateValidator(keeper, ctx, validators[2]) updates := keeper.GetTendermintUpdates(ctx) require.Equal(t, 0, len(updates)) // test validator change its power and become a gotValidator (pushing out an existing) // tendermintUpdate set: {} -> {c0, c4} - clearTendermintUpdates(ctx, keeper) require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) pool := keeper.GetPool(ctx) validators[2], pool, _ = validators[2].AddTokensFromDel(pool, sdk.NewInt(10)) keeper.SetPool(ctx, pool) - validators[2] = keeper.UpdateValidator(ctx, validators[2]) + validators[2] = updateValidator(keeper, ctx, validators[2]) updates = keeper.GetTendermintUpdates(ctx) require.Equal(t, 2, len(updates), "%v", updates) @@ -882,9 +780,8 @@ func TestGetTendermintUpdatesPowerDecrease(t *testing.T) { validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt)) keeper.SetPool(ctx, pool) } - validators[0] = keeper.UpdateValidator(ctx, validators[0]) - validators[1] = keeper.UpdateValidator(ctx, validators[1]) - clearTendermintUpdates(ctx, keeper) + validators[0] = updateValidator(keeper, ctx, validators[0]) + validators[1] = updateValidator(keeper, ctx, validators[1]) require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) // check initial power @@ -897,8 +794,8 @@ func TestGetTendermintUpdatesPowerDecrease(t *testing.T) { validators[0], pool, _ = validators[0].RemoveDelShares(pool, sdk.NewDec(20)) validators[1], pool, _ = validators[1].RemoveDelShares(pool, sdk.NewDec(30)) keeper.SetPool(ctx, pool) - validators[0] = keeper.UpdateValidator(ctx, validators[0]) - validators[1] = keeper.UpdateValidator(ctx, validators[1]) + validators[0] = updateValidator(keeper, ctx, validators[0]) + validators[1] = updateValidator(keeper, ctx, validators[1]) // power has changed require.Equal(t, sdk.NewDec(80).RoundInt64(), validators[0].GetPower().RoundInt64()) @@ -931,7 +828,7 @@ func TestGetTendermintUpdatesNewValidator(t *testing.T) { validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt)) keeper.SetPool(ctx, pool) - validators[i] = keeper.UpdateValidator(ctx, validators[i]) + validators[i] = updateValidator(keeper, ctx, validators[i]) } // verify initial Tendermint updates are correct @@ -940,7 +837,6 @@ func TestGetTendermintUpdatesNewValidator(t *testing.T) { require.Equal(t, validators[0].ABCIValidatorUpdate(), updates[0]) require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[1]) - clearTendermintUpdates(ctx, keeper) require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) // update initial validator set @@ -949,7 +845,7 @@ func TestGetTendermintUpdatesNewValidator(t *testing.T) { validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt)) keeper.SetPool(ctx, pool) - validators[i] = keeper.UpdateValidator(ctx, validators[i]) + validators[i] = updateValidator(keeper, ctx, validators[i]) } // add a new validator that goes from zero power, to non-zero power, back to @@ -963,10 +859,10 @@ func TestGetTendermintUpdatesNewValidator(t *testing.T) { validator, pool, _ = validator.AddTokensFromDel(pool, amt) keeper.SetPool(ctx, pool) - validator = keeper.UpdateValidator(ctx, validator) + validator = updateValidator(keeper, ctx, validator) validator, pool, _ = validator.RemoveDelShares(pool, sdk.NewDecFromInt(amt)) - validator = keeper.UpdateValidator(ctx, validator) + validator = updateValidator(keeper, ctx, validator) // add a new validator that increases in power valPubKey = PKs[len(validators)+2] @@ -976,7 +872,7 @@ func TestGetTendermintUpdatesNewValidator(t *testing.T) { validator, pool, _ = validator.AddTokensFromDel(pool, sdk.NewInt(500)) keeper.SetPool(ctx, pool) - validator = keeper.UpdateValidator(ctx, validator) + validator = updateValidator(keeper, ctx, validator) // verify initial Tendermint updates are correct updates = keeper.GetTendermintUpdates(ctx) @@ -1007,7 +903,7 @@ func TestGetTendermintUpdatesBondTransition(t *testing.T) { validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt)) keeper.SetPool(ctx, pool) - validators[i] = keeper.UpdateValidator(ctx, validators[i]) + validators[i] = updateValidator(keeper, ctx, validators[i]) } // verify initial Tendermint updates are correct @@ -1016,7 +912,6 @@ func TestGetTendermintUpdatesBondTransition(t *testing.T) { require.Equal(t, validators[2].ABCIValidatorUpdate(), updates[0]) require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[1]) - clearTendermintUpdates(ctx, keeper) require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) // delegate to validator with lowest power but not enough to bond @@ -1029,7 +924,7 @@ func TestGetTendermintUpdatesBondTransition(t *testing.T) { validator, pool, _ = validator.AddTokensFromDel(pool, sdk.NewInt(1)) keeper.SetPool(ctx, pool) - validators[0] = keeper.UpdateValidator(ctx, validator) + validators[0] = updateValidator(keeper, ctx, validator) // verify initial Tendermint updates are correct require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) @@ -1045,19 +940,18 @@ func TestGetTendermintUpdatesBondTransition(t *testing.T) { validator, pool, _ = validator.RemoveDelShares(pool, validator.DelegatorShares) keeper.SetPool(ctx, pool) - validator = keeper.UpdateValidator(ctx, validator) + validator = updateValidator(keeper, ctx, validator) validator, pool, _ = validator.AddTokensFromDel(pool, sdk.NewInt(250)) keeper.SetPool(ctx, pool) - validators[1] = keeper.UpdateValidator(ctx, validator) + validators[1] = updateValidator(keeper, ctx, validator) // verify initial Tendermint updates are correct updates = keeper.GetTendermintUpdates(ctx) require.Equal(t, 1, len(updates)) require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[0]) - clearTendermintUpdates(ctx, keeper) require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) } @@ -1090,7 +984,7 @@ func TestUpdateValidatorCommission(t *testing.T) { } for i, tc := range testCases { - err := keeper.UpdateValidatorCommission(ctx, tc.validator, tc.newRate) + _, err := keeper.UpdateValidatorCommission(ctx, tc.validator, tc.newRate) if tc.expectedErr { require.Error(t, err, "expected error for test case #%d with rate: %s", i, tc.newRate) diff --git a/x/stake/querier/queryable_test.go b/x/stake/querier/queryable_test.go index ee52773c6e4c..cbc947889f55 100644 --- a/x/stake/querier/queryable_test.go +++ b/x/stake/querier/queryable_test.go @@ -71,8 +71,8 @@ func TestQueryValidators(t *testing.T) { validators[i], pool, _ = validators[i].AddTokensFromDel(pool, amt) } keeper.SetPool(ctx, pool) - validators[0] = keeper.UpdateValidator(ctx, validators[0]) - validators[1] = keeper.UpdateValidator(ctx, validators[1]) + keeper.SetValidator(ctx, validators[0]) + keeper.SetValidator(ctx, validators[1]) // Query Validators queriedValidators := keeper.GetValidators(ctx, params.MaxValidators) From 77c2cc8aeeee85a41f674a7c5b642a72465aa8de Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Mon, 1 Oct 2018 13:54:31 +0200 Subject: [PATCH 21/44] Testcase fixes in progress --- x/stake/handler_test.go | 29 +++++++++++++++++++++++++++++ x/stake/keeper/delegation.go | 7 ++++--- x/stake/keeper/delegation_test.go | 3 +++ x/stake/keeper/test_common.go | 2 ++ x/stake/keeper/val_state_change.go | 6 ++++++ 5 files changed, 44 insertions(+), 3 deletions(-) diff --git a/x/stake/handler_test.go b/x/stake/handler_test.go index 7d51aa90ec77..31adb307b7cd 100644 --- a/x/stake/handler_test.go +++ b/x/stake/handler_test.go @@ -63,6 +63,10 @@ func TestValidatorByPowerIndex(t *testing.T) { got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) require.True(t, got.IsOK(), "expected create-validator to be ok, got %v", got) + // must end-block + updates := keeper.GetTendermintUpdates(ctx) + require.Equal(t, 1, len(updates)) + // verify the self-delegation exists bond, found := keeper.GetDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) require.True(t, found) @@ -82,6 +86,9 @@ func TestValidatorByPowerIndex(t *testing.T) { msgCreateValidator = newTestMsgCreateValidator(validatorAddr3, keep.PKs[2], int64(1000000)) got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) require.True(t, got.IsOK(), "expected create-validator to be ok, got %v", got) + // must end-block + updates = keeper.GetTendermintUpdates(ctx) + require.Equal(t, 1, len(updates)) // slash and jail the first validator consAddr0 := sdk.ConsAddress(keep.PKs[0].Address()) @@ -160,6 +167,11 @@ func TestDuplicatesMsgCreateValidator(t *testing.T) { msgCreateValidator4 := newTestMsgCreateValidator(addr2, pk2, 10) got = handleMsgCreateValidator(ctx, msgCreateValidator4, keeper) require.True(t, got.IsOK(), "%v", got) + + // must end-block + updates := keeper.GetTendermintUpdates(ctx) + require.Equal(t, 1, len(updates)) + validator, found = keeper.GetValidator(ctx, addr2) require.True(t, found) @@ -180,6 +192,11 @@ func TestDuplicatesMsgCreateValidatorOnBehalfOf(t *testing.T) { msgCreateValidatorOnBehalfOf := newTestMsgCreateValidatorOnBehalfOf(delegatorAddr, validatorAddr, pk, 10) got := handleMsgCreateValidator(ctx, msgCreateValidatorOnBehalfOf, keeper) require.True(t, got.IsOK(), "%v", got) + + // must end-block + updates := keeper.GetTendermintUpdates(ctx) + require.Equal(t, 1, len(updates)) + validator, found := keeper.GetValidator(ctx, validatorAddr) require.True(t, found) @@ -211,6 +228,10 @@ func TestLegacyValidatorDelegations(t *testing.T) { got := handleMsgCreateValidator(ctx, msgCreateVal, keeper) require.True(t, got.IsOK(), "expected create validator msg to be ok, got %v", got) + // must end-block + updates := keeper.GetTendermintUpdates(ctx) + require.Equal(t, 1, len(updates)) + // verify the validator exists and has the correct attributes validator, found := keeper.GetValidator(ctx, valAddr) require.True(t, found) @@ -795,6 +816,10 @@ func TestBondUnbondRedelegateSlashTwice(t *testing.T) { got = handleMsgDelegate(ctx, msgDelegate, keeper) require.True(t, got.IsOK(), "expected no error on runMsgDelegate") + // apply Tendermint updates + updates := keeper.GetTendermintUpdates(ctx) + require.Equal(t, 1, len(updates)) + // a block passes ctx = ctx.WithBlockHeight(1) @@ -813,6 +838,10 @@ func TestBondUnbondRedelegateSlashTwice(t *testing.T) { require.True(t, found) require.Equal(t, sdk.NewDec(6), delegation.Shares) + // must apply validator updates + updates = keeper.GetTendermintUpdates(ctx) + require.Equal(t, 1, len(updates)) + // slash the validator by half keeper.Slash(ctx, consAddr0, 0, 20, sdk.NewDecWithPrec(5, 1)) diff --git a/x/stake/keeper/delegation.go b/x/stake/keeper/delegation.go index e640b997703d..f245da9e3db1 100644 --- a/x/stake/keeper/delegation.go +++ b/x/stake/keeper/delegation.go @@ -308,8 +308,9 @@ func (k Keeper) unbond(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValA // if the delegation is the operator of the validator then // trigger a jail validator - if bytes.Equal(delegation.DelegatorAddr, validator.OperatorAddr) && validator.Jailed == false { - validator.Jailed = true + if bytes.Equal(delegation.DelegatorAddr, validator.OperatorAddr) && !validator.Jailed { + k.JailValidator(ctx, validator) + validator = k.mustGetValidator(ctx, validator.OperatorAddr) } k.RemoveDelegation(ctx, delegation) @@ -358,7 +359,7 @@ func (k Keeper) getBeginInfo(ctx sdk.Context, params types.Params, valSrcAddr sd } } -// complete unbonding an unbonding record +// begin unbonding an unbonding record func (k Keeper) BeginUnbonding(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress, sharesAmount sdk.Dec) sdk.Error { diff --git a/x/stake/keeper/delegation_test.go b/x/stake/keeper/delegation_test.go index 96f0ba383e93..b9eb18be42e0 100644 --- a/x/stake/keeper/delegation_test.go +++ b/x/stake/keeper/delegation_test.go @@ -520,8 +520,10 @@ func TestRedelegateSelfDelegation(t *testing.T) { validator2 := types.NewValidator(addrVals[1], PKs[1], types.Description{}) validator2, pool, issuedShares = validator2.AddTokensFromDel(pool, sdk.NewInt(10)) require.Equal(t, int64(10), issuedShares.RoundInt64()) + pool.BondedTokens = pool.BondedTokens.Add(sdk.NewDec(10)) keeper.SetPool(ctx, pool) validator2 = updateValidator(keeper, ctx, validator2) + require.Equal(t, sdk.Bonded, validator2.Status) // create a second delegation to this validator validator, pool, issuedShares = validator.AddTokensFromDel(pool, sdk.NewInt(10)) @@ -663,6 +665,7 @@ func TestRedelegateFromUnbondedValidator(t *testing.T) { require.Equal(t, int64(10), issuedShares.RoundInt64()) keeper.SetPool(ctx, pool) validator2 = updateValidator(keeper, ctx, validator2) + require.Equal(t, sdk.Bonded, validator2.Status) header := ctx.BlockHeader() blockHeight := int64(10) diff --git a/x/stake/keeper/test_common.go b/x/stake/keeper/test_common.go index 3b0287e4fe29..cdd13a96b1a3 100644 --- a/x/stake/keeper/test_common.go +++ b/x/stake/keeper/test_common.go @@ -206,7 +206,9 @@ func ValidatorByPowerIndexExists(ctx sdk.Context, keeper Keeper, power []byte) b } func updateValidator(keeper Keeper, ctx sdk.Context, validator types.Validator) types.Validator { + pool := keeper.GetPool(ctx) keeper.SetValidator(ctx, validator) + keeper.SetValidatorByPowerIndex(ctx, validator, pool) keeper.GetTendermintUpdates(ctx) validator, found := keeper.GetValidator(ctx, validator.OperatorAddr) if !found { diff --git a/x/stake/keeper/val_state_change.go b/x/stake/keeper/val_state_change.go index f463e39c168d..c6537455b629 100644 --- a/x/stake/keeper/val_state_change.go +++ b/x/stake/keeper/val_state_change.go @@ -150,6 +150,12 @@ func (k Keeper) JailValidator(ctx sdk.Context, validator types.Validator) { validator.Jailed = true k.SetValidator(ctx, validator) k.SetValidatorByPowerIndex(ctx, validator, pool) + + // if bonded, unbond + if validator.Status == sdk.Bonded { + k.bondedToUnbonding(ctx, validator) + } + // TODO we should be able to just delete the index, and only set it again once unjailed } From 123bc06bd116d046637fa10aaa536e2866318dc8 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Mon, 1 Oct 2018 14:23:48 +0200 Subject: [PATCH 22/44] Minor fixes --- x/stake/keeper/slash_test.go | 14 ++++++++++++ x/stake/keeper/val_state_change.go | 34 +++++++++++++++++------------- x/stake/types/validator.go | 6 ++++++ 3 files changed, 39 insertions(+), 15 deletions(-) diff --git a/x/stake/keeper/slash_test.go b/x/stake/keeper/slash_test.go index b8c90d4a0a55..b4e9e54499a7 100644 --- a/x/stake/keeper/slash_test.go +++ b/x/stake/keeper/slash_test.go @@ -1,6 +1,7 @@ package keeper import ( + "fmt" "testing" "time" @@ -26,6 +27,7 @@ func setupHelper(t *testing.T, amt int64) (sdk.Context, Keeper, types.Params) { for i := 0; i < numVals; i++ { validator := types.NewValidator(addrVals[i], PKs[i], types.Description{}) validator, pool, _ = validator.AddTokensFromDel(pool, sdk.NewInt(amt)) + pool.BondedTokens = pool.BondedTokens.Add(sdk.NewDec(amt)) keeper.SetPool(ctx, pool) validator = updateValidator(keeper, ctx, validator) keeper.SetValidatorByConsAddr(ctx, validator) @@ -161,6 +163,10 @@ func TestSlashRedelegation(t *testing.T) { rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) require.True(t, found) + // end block + updates := keeper.GetTendermintUpdates(ctx) + require.Equal(t, 2, len(updates)) + // initialbalance unchanged require.Equal(t, sdk.NewInt64Coin(params.BondDenom, 10), rd.InitialBalance) @@ -201,6 +207,10 @@ func TestSlashValidatorAtCurrentHeight(t *testing.T) { require.True(t, found) newPool := keeper.GetPool(ctx) + // end block + updates := keeper.GetTendermintUpdates(ctx) + require.Equal(t, 1, len(updates), "cons addr: %v, updates: %v", []byte(consAddr), updates) + // power decreased require.Equal(t, sdk.NewDec(5), validator.GetPower()) // pool bonded shares decreased @@ -232,6 +242,10 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { require.True(t, found) keeper.Slash(ctx, consAddr, 10, 10, fraction) + // end block + updates := keeper.GetTendermintUpdates(ctx) + require.Equal(t, 1, len(updates)) + // read updating unbonding delegation ubd, found = keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) require.True(t, found) diff --git a/x/stake/keeper/val_state_change.go b/x/stake/keeper/val_state_change.go index c6537455b629..0c94c33b4aa2 100644 --- a/x/stake/keeper/val_state_change.go +++ b/x/stake/keeper/val_state_change.go @@ -25,12 +25,12 @@ func (k Keeper) GetTendermintUpdates(ctx sdk.Context) (updates []abci.ValidatorU maxValidators := k.GetParams(ctx).MaxValidators // copy last validator set - last := make(map[[sdk.AddrLen]byte]interface{}) + last := make(map[[sdk.AddrLen]byte][]byte) iterator := sdk.KVStorePrefixIterator(store, BondedValidatorsIndexKey) for ; iterator.Valid(); iterator.Next() { var operator [sdk.AddrLen]byte copy(operator[:], iterator.Key()[1:]) - last[operator] = nil + last[operator] = iterator.Value() } iterator = sdk.KVStoreReversePrefixIterator(store, ValidatorsByPowerIndexKey) @@ -44,7 +44,8 @@ func (k Keeper) GetTendermintUpdates(ctx sdk.Context) (updates []abci.ValidatorU // jailed validators are ranked last, so if we get to a jailed validator // we have no more bonded validators // TODO we can remove this if we remove jailed validators from the power store - if validator.Jailed { + // likewise for zero-power validators, which we never bond + if validator.Jailed || validator.BondedTokens().Equal(sdk.ZeroDec()) { break } @@ -58,17 +59,26 @@ func (k Keeper) GetTendermintUpdates(ctx sdk.Context) (updates []abci.ValidatorU // no state change } - // update the validator (power might have changed) - updates = append(updates, validator.ABCIValidatorUpdate()) - // validator still in the validator set var opbytes [sdk.AddrLen]byte copy(opbytes[:], operator[:]) + + // fetch the old power bytes + powerBytes, ok := last[opbytes] + + // calculate the new power bytes + newPowerBytes := validator.ABCIValidatorPowerBytes(k.cdc) + + // update the validator set if power has changed + if !ok || !bytes.Equal(powerBytes, newPowerBytes) { + updates = append(updates, validator.ABCIValidatorUpdate()) + } + + // validator still in the validator set delete(last, opbytes) // set the bonded validator index - // TODO move me - store.Set(GetBondedValidatorIndexKey(operator), []byte{}) + store.Set(GetBondedValidatorIndexKey(operator), newPowerBytes) // keep count count++ @@ -99,7 +109,6 @@ func (k Keeper) GetTendermintUpdates(ctx sdk.Context) (updates []abci.ValidatorU k.bondedToUnbonding(ctx, validator) // delete from the bonded validator index - // TODO move me store.Delete(GetBondedValidatorIndexKey(operator)) // update the validator @@ -113,7 +122,7 @@ func (k Keeper) GetTendermintUpdates(ctx sdk.Context) (updates []abci.ValidatorU func (k Keeper) bondedToUnbonding(ctx sdk.Context, validator types.Validator) types.Validator { if validator.Status != sdk.Bonded { - panic(fmt.Sprintf("bad state transition bondedToUnbonded, validator: %v\n", validator)) + panic(fmt.Sprintf("bad state transition bondedToUnbonding, validator: %v\n", validator)) } return k.beginUnbondingValidator(ctx, validator) } @@ -151,11 +160,6 @@ func (k Keeper) JailValidator(ctx sdk.Context, validator types.Validator) { k.SetValidator(ctx, validator) k.SetValidatorByPowerIndex(ctx, validator, pool) - // if bonded, unbond - if validator.Status == sdk.Bonded { - k.bondedToUnbonding(ctx, validator) - } - // TODO we should be able to just delete the index, and only set it again once unjailed } diff --git a/x/stake/types/validator.go b/x/stake/types/validator.go index 5d0de4bc7d06..dbd4e2a54000 100644 --- a/x/stake/types/validator.go +++ b/x/stake/types/validator.go @@ -314,6 +314,12 @@ func (v Validator) ABCIValidatorUpdate() abci.ValidatorUpdate { } } +// ABCIValidatorPowerBytes +func (v Validator) ABCIValidatorPowerBytes(cdc *codec.Codec) []byte { + power := v.BondedTokens().RoundInt64() + return cdc.MustMarshalBinary(power) +} + // ABCIValidatorUpdateZero returns an abci.ValidatorUpdate from a staked validator type // with zero power used for validator updates. func (v Validator) ABCIValidatorUpdateZero() abci.ValidatorUpdate { From 6d4af75b3f638e3c5823d5f1c5b9ad66111da307 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Mon, 1 Oct 2018 17:19:34 +0200 Subject: [PATCH 23/44] Testcase fixes contd... --- x/stake/keeper/delegation_test.go | 24 +++++++ x/stake/keeper/slash_test.go | 5 +- x/stake/keeper/val_state_change.go | 13 ++-- x/stake/keeper/validator_test.go | 101 ++++++++++++++++++++--------- 4 files changed, 107 insertions(+), 36 deletions(-) diff --git a/x/stake/keeper/delegation_test.go b/x/stake/keeper/delegation_test.go index b9eb18be42e0..74d9866fd786 100644 --- a/x/stake/keeper/delegation_test.go +++ b/x/stake/keeper/delegation_test.go @@ -252,6 +252,10 @@ func TestUndelegateSelfDelegation(t *testing.T) { err := keeper.BeginUnbonding(ctx, val0AccAddr, addrVals[0], sdk.NewDec(10)) require.NoError(t, err) + // end block + updates := keeper.GetTendermintUpdates(ctx) + require.Equal(t, 1, len(updates)) + validator, found := keeper.GetValidator(ctx, addrVals[0]) require.True(t, found) require.Equal(t, int64(10), validator.Tokens.RoundInt64()) @@ -303,6 +307,10 @@ func TestUndelegateFromUnbondingValidator(t *testing.T) { err := keeper.BeginUnbonding(ctx, val0AccAddr, addrVals[0], sdk.NewDec(10)) require.NoError(t, err) + // end block + updates := keeper.GetTendermintUpdates(ctx) + require.Equal(t, 1, len(updates)) + validator, found := keeper.GetValidator(ctx, addrVals[0]) require.True(t, found) require.Equal(t, blockHeight, validator.UnbondingHeight) @@ -374,6 +382,10 @@ func TestUndelegateFromUnbondedValidator(t *testing.T) { err := keeper.BeginUnbonding(ctx, val0AccAddr, addrVals[0], sdk.NewDec(10)) require.NoError(t, err) + // end block + updates := keeper.GetTendermintUpdates(ctx) + require.Equal(t, 1, len(updates)) + validator, found := keeper.GetValidator(ctx, addrVals[0]) require.True(t, found) require.Equal(t, blockHeight, validator.UnbondingHeight) @@ -541,6 +553,10 @@ func TestRedelegateSelfDelegation(t *testing.T) { err := keeper.BeginRedelegation(ctx, val0AccAddr, addrVals[0], addrVals[1], sdk.NewDec(10)) require.NoError(t, err) + // end block + updates := keeper.GetTendermintUpdates(ctx) + require.Equal(t, 2, len(updates)) + validator, found := keeper.GetValidator(ctx, addrVals[0]) require.True(t, found) require.Equal(t, int64(10), validator.Tokens.RoundInt64()) @@ -599,6 +615,10 @@ func TestRedelegateFromUnbondingValidator(t *testing.T) { err := keeper.BeginUnbonding(ctx, val0AccAddr, addrVals[0], sdk.NewDec(10)) require.NoError(t, err) + // end block + updates := keeper.GetTendermintUpdates(ctx) + require.Equal(t, 1, len(updates)) + validator, found := keeper.GetValidator(ctx, addrVals[0]) require.True(t, found) require.Equal(t, blockHeight, validator.UnbondingHeight) @@ -678,6 +698,10 @@ func TestRedelegateFromUnbondedValidator(t *testing.T) { err := keeper.BeginUnbonding(ctx, val0AccAddr, addrVals[0], sdk.NewDec(10)) require.NoError(t, err) + // end block + updates := keeper.GetTendermintUpdates(ctx) + require.Equal(t, 1, len(updates)) + validator, found := keeper.GetValidator(ctx, addrVals[0]) require.True(t, found) require.Equal(t, blockHeight, validator.UnbondingHeight) diff --git a/x/stake/keeper/slash_test.go b/x/stake/keeper/slash_test.go index b4e9e54499a7..9db459539853 100644 --- a/x/stake/keeper/slash_test.go +++ b/x/stake/keeper/slash_test.go @@ -1,7 +1,6 @@ package keeper import ( - "fmt" "testing" "time" @@ -27,6 +26,7 @@ func setupHelper(t *testing.T, amt int64) (sdk.Context, Keeper, types.Params) { for i := 0; i < numVals; i++ { validator := types.NewValidator(addrVals[i], PKs[i], types.Description{}) validator, pool, _ = validator.AddTokensFromDel(pool, sdk.NewInt(amt)) + validator.BondIntraTxCounter = int16(i) pool.BondedTokens = pool.BondedTokens.Add(sdk.NewDec(amt)) keeper.SetPool(ctx, pool) validator = updateValidator(keeper, ctx, validator) @@ -165,7 +165,7 @@ func TestSlashRedelegation(t *testing.T) { // end block updates := keeper.GetTendermintUpdates(ctx) - require.Equal(t, 2, len(updates)) + require.Equal(t, 1, len(updates)) // initialbalance unchanged require.Equal(t, sdk.NewInt64Coin(params.BondDenom, 10), rd.InitialBalance) @@ -211,6 +211,7 @@ func TestSlashValidatorAtCurrentHeight(t *testing.T) { updates := keeper.GetTendermintUpdates(ctx) require.Equal(t, 1, len(updates), "cons addr: %v, updates: %v", []byte(consAddr), updates) + validator = keeper.mustGetValidator(ctx, validator.OperatorAddr) // power decreased require.Equal(t, sdk.NewDec(5), validator.GetPower()) // pool bonded shares decreased diff --git a/x/stake/keeper/val_state_change.go b/x/stake/keeper/val_state_change.go index 0c94c33b4aa2..545c19379ba5 100644 --- a/x/stake/keeper/val_state_change.go +++ b/x/stake/keeper/val_state_change.go @@ -30,7 +30,9 @@ func (k Keeper) GetTendermintUpdates(ctx sdk.Context) (updates []abci.ValidatorU for ; iterator.Valid(); iterator.Next() { var operator [sdk.AddrLen]byte copy(operator[:], iterator.Key()[1:]) - last[operator] = iterator.Value() + powerBytes := iterator.Value() + last[operator] = make([]byte, len(powerBytes)) + copy(last[operator][:], powerBytes[:]) } iterator = sdk.KVStoreReversePrefixIterator(store, ValidatorsByPowerIndexKey) @@ -45,7 +47,7 @@ func (k Keeper) GetTendermintUpdates(ctx sdk.Context) (updates []abci.ValidatorU // we have no more bonded validators // TODO we can remove this if we remove jailed validators from the power store // likewise for zero-power validators, which we never bond - if validator.Jailed || validator.BondedTokens().Equal(sdk.ZeroDec()) { + if validator.Jailed || validator.Tokens.Equal(sdk.ZeroDec()) { break } @@ -186,10 +188,13 @@ func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) types. k.DeleteValidatorByPowerIndex(ctx, validator, pool) - // XXX WHAT DO WE DO FOR BondIntraTxCounter Height Now?????????????????????????? - validator.BondHeight = ctx.BlockHeight() + // XXX Are we OK with this? In order of power decreasing, but addresses break ties. + counter := k.GetIntraTxCounter(ctx) + validator.BondIntraTxCounter = counter + k.SetIntraTxCounter(ctx, counter+1) + // set the status validator, pool = validator.UpdateStatus(pool, sdk.Bonded) k.SetPool(ctx, pool) diff --git a/x/stake/keeper/validator_test.go b/x/stake/keeper/validator_test.go index 3c7a4875371b..1a0809c98eda 100644 --- a/x/stake/keeper/validator_test.go +++ b/x/stake/keeper/validator_test.go @@ -29,11 +29,17 @@ func TestSetValidator(t *testing.T) { assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.Tokens)) assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.DelegatorShares)) keeper.SetPool(ctx, pool) - updateValidator(keeper, ctx, validator) + keeper.SetValidator(ctx, validator) + keeper.SetValidatorByPowerIndex(ctx, validator, pool) - // after the save the validator should be bonded + // ensure update + updates := keeper.GetTendermintUpdates(ctx) validator, found := keeper.GetValidator(ctx, valAddr) require.True(t, found) + require.Equal(t, 1, len(updates)) + require.Equal(t, validator.ABCIValidatorUpdate(), updates[0]) + + // after the save the validator should be bonded require.Equal(t, sdk.Bonded, validator.Status) assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.Tokens)) assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.DelegatorShares)) @@ -59,10 +65,6 @@ func TestSetValidator(t *testing.T) { require.Equal(t, 1, len(resVals)) require.True(ValEq(t, validator, resVals[0])) - updates := keeper.GetTendermintUpdates(ctx) - require.Equal(t, 1, len(updates)) - require.Equal(t, validator.ABCIValidatorUpdate(), updates[0]) - allVals := keeper.GetAllValidators(ctx) require.Equal(t, 1, len(allVals)) } @@ -92,6 +94,7 @@ func TestUpdateValidatorByPowerIndex(t *testing.T) { require.True(t, validatorByPowerIndexExists(keeper, ctx, power)) // burn half the delegator shares + keeper.DeleteValidatorByPowerIndex(ctx, validator, pool) validator, pool, burned := validator.RemoveDelShares(pool, delSharesCreated.Quo(sdk.NewDec(2))) require.Equal(t, int64(50), burned.RoundInt64()) keeper.SetPool(ctx, pool) // update the pool @@ -140,6 +143,7 @@ func TestUpdateBondedValidatorsDecreaseCliff(t *testing.T) { // remove enough tokens to kick out the validator below the current cliff // validator and next in line cliff validator + keeper.DeleteValidatorByPowerIndex(ctx, nextCliffVal, pool) nextCliffVal, pool, _ = nextCliffVal.RemoveDelShares(pool, sdk.NewDec(21)) keeper.SetPool(ctx, pool) nextCliffVal = updateValidator(keeper, ctx, nextCliffVal) @@ -450,6 +454,7 @@ func TestGetValidatorsEdgeCases(t *testing.T) { assert.True(ValEq(t, validators[3], resValidators[1])) pool := keeper.GetPool(ctx) + keeper.DeleteValidatorByPowerIndex(ctx, validators[0], pool) validators[0], pool, _ = validators[0].AddTokensFromDel(pool, sdk.NewInt(500)) keeper.SetPool(ctx, pool) validators[0] = updateValidator(keeper, ctx, validators[0]) @@ -467,6 +472,7 @@ func TestGetValidatorsEdgeCases(t *testing.T) { validators[3], found = keeper.GetValidator(ctx, validators[3].OperatorAddr) require.True(t, found) + keeper.DeleteValidatorByPowerIndex(ctx, validators[3], pool) validators[3], pool, _ = validators[3].AddTokensFromDel(pool, sdk.NewInt(1)) keeper.SetPool(ctx, pool) validators[3] = updateValidator(keeper, ctx, validators[3]) @@ -476,6 +482,7 @@ func TestGetValidatorsEdgeCases(t *testing.T) { assert.True(ValEq(t, validators[3], resValidators[1])) // validator 3 kicked out temporarily + keeper.DeleteValidatorByPowerIndex(ctx, validators[3], pool) validators[3], pool, _ = validators[3].RemoveDelShares(pool, sdk.NewDec(201)) keeper.SetPool(ctx, pool) validators[3] = updateValidator(keeper, ctx, validators[3]) @@ -485,6 +492,7 @@ func TestGetValidatorsEdgeCases(t *testing.T) { assert.True(ValEq(t, validators[2], resValidators[1])) // validator 4 does not get spot back + keeper.DeleteValidatorByPowerIndex(ctx, validators[3], pool) validators[3], pool, _ = validators[3].AddTokensFromDel(pool, sdk.NewInt(200)) keeper.SetPool(ctx, pool) validators[3] = updateValidator(keeper, ctx, validators[3]) @@ -532,6 +540,8 @@ func TestValidatorBondHeight(t *testing.T) { assert.True(ValEq(t, validators[0], resValidators[0])) assert.True(ValEq(t, validators[1], resValidators[1])) + keeper.DeleteValidatorByPowerIndex(ctx, validators[1], pool) + keeper.DeleteValidatorByPowerIndex(ctx, validators[2], pool) validators[1], pool, _ = validators[1].AddTokensFromDel(pool, sdk.NewInt(50)) validators[2], pool, _ = validators[2].AddTokensFromDel(pool, sdk.NewInt(50)) keeper.SetPool(ctx, pool) @@ -557,6 +567,7 @@ func TestFullValidatorSetPowerChange(t *testing.T) { pool := keeper.GetPool(ctx) validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{}) validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt)) + validators[i].BondIntraTxCounter = int16(i) keeper.SetPool(ctx, pool) updateValidator(keeper, ctx, validators[i]) } @@ -565,7 +576,7 @@ func TestFullValidatorSetPowerChange(t *testing.T) { validators[i], found = keeper.GetValidator(ctx, validators[i].OperatorAddr) require.True(t, found) } - assert.Equal(t, sdk.Unbonding, validators[0].Status) + assert.Equal(t, sdk.Unbonded, validators[0].Status) assert.Equal(t, sdk.Unbonding, validators[1].Status) assert.Equal(t, sdk.Bonded, validators[2].Status) assert.Equal(t, sdk.Bonded, validators[3].Status) @@ -605,13 +616,18 @@ func TestGetTendermintUpdatesAllNone(t *testing.T) { // test from nothing to something // tendermintUpdate set: {} -> {c1, c3} require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) - validators[0] = updateValidator(keeper, ctx, validators[0]) - validators[1] = updateValidator(keeper, ctx, validators[1]) + pool := keeper.GetPool(ctx) + keeper.SetValidator(ctx, validators[0]) + keeper.SetValidatorByPowerIndex(ctx, validators[0], pool) + keeper.SetValidator(ctx, validators[1]) + keeper.SetValidatorByPowerIndex(ctx, validators[1], pool) updates := keeper.GetTendermintUpdates(ctx) assert.Equal(t, 2, len(updates)) - assert.Equal(t, validators[0].ABCIValidatorUpdate(), updates[0]) - assert.Equal(t, validators[1].ABCIValidatorUpdate(), updates[1]) + validators[0], _ = keeper.GetValidator(ctx, validators[0].OperatorAddr) + validators[1], _ = keeper.GetValidator(ctx, validators[1].OperatorAddr) + assert.Equal(t, validators[0].ABCIValidatorUpdate(), updates[1]) + assert.Equal(t, validators[1].ABCIValidatorUpdate(), updates[0]) } func TestGetTendermintUpdatesIdentical(t *testing.T) { @@ -689,8 +705,8 @@ func TestGetTendermintUpdatesMultipleValueChange(t *testing.T) { updates := keeper.GetTendermintUpdates(ctx) require.Equal(t, 2, len(updates)) - require.Equal(t, validators[0].ABCIValidatorUpdate(), updates[0]) - require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[1]) + require.Equal(t, validators[0].ABCIValidatorUpdate(), updates[1]) + require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[0]) } func TestGetTendermintUpdatesInserted(t *testing.T) { @@ -710,22 +726,31 @@ func TestGetTendermintUpdatesInserted(t *testing.T) { // test validtor added at the beginning // tendermintUpdate set: {} -> {c0} - validators[2] = updateValidator(keeper, ctx, validators[2]) + pool := keeper.GetPool(ctx) + keeper.SetValidator(ctx, validators[2]) + keeper.SetValidatorByPowerIndex(ctx, validators[2], pool) updates := keeper.GetTendermintUpdates(ctx) + validators[2], _ = keeper.GetValidator(ctx, validators[2].OperatorAddr) require.Equal(t, 1, len(updates)) require.Equal(t, validators[2].ABCIValidatorUpdate(), updates[0]) // test validtor added at the beginning // tendermintUpdate set: {} -> {c0} - validators[3] = updateValidator(keeper, ctx, validators[3]) + pool = keeper.GetPool(ctx) + keeper.SetValidator(ctx, validators[3]) + keeper.SetValidatorByPowerIndex(ctx, validators[3], pool) updates = keeper.GetTendermintUpdates(ctx) + validators[3], _ = keeper.GetValidator(ctx, validators[3].OperatorAddr) require.Equal(t, 1, len(updates)) require.Equal(t, validators[3].ABCIValidatorUpdate(), updates[0]) // test validtor added at the end // tendermintUpdate set: {} -> {c0} - validators[4] = updateValidator(keeper, ctx, validators[4]) + pool = keeper.GetPool(ctx) + keeper.SetValidator(ctx, validators[4]) + keeper.SetValidatorByPowerIndex(ctx, validators[4], pool) updates = keeper.GetTendermintUpdates(ctx) + validators[4], _ = keeper.GetValidator(ctx, validators[4].OperatorAddr) require.Equal(t, 1, len(updates)) require.Equal(t, validators[4].ABCIValidatorUpdate(), updates[0]) } @@ -761,12 +786,13 @@ func TestGetTendermintUpdatesWithCliffValidator(t *testing.T) { pool := keeper.GetPool(ctx) validators[2], pool, _ = validators[2].AddTokensFromDel(pool, sdk.NewInt(10)) keeper.SetPool(ctx, pool) - validators[2] = updateValidator(keeper, ctx, validators[2]) - + keeper.SetValidator(ctx, validators[2]) + keeper.SetValidatorByPowerIndex(ctx, validators[2], pool) updates = keeper.GetTendermintUpdates(ctx) + validators[2], _ = keeper.GetValidator(ctx, validators[2].OperatorAddr) require.Equal(t, 2, len(updates), "%v", updates) - require.Equal(t, validators[0].ABCIValidatorUpdateZero(), updates[0]) - require.Equal(t, validators[2].ABCIValidatorUpdate(), updates[1]) + require.Equal(t, validators[0].ABCIValidatorUpdateZero(), updates[1]) + require.Equal(t, validators[2].ABCIValidatorUpdate(), updates[0]) } func TestGetTendermintUpdatesPowerDecrease(t *testing.T) { @@ -778,6 +804,7 @@ func TestGetTendermintUpdatesPowerDecrease(t *testing.T) { pool := keeper.GetPool(ctx) validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{}) validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt)) + validators[i].BondIntraTxCounter = int16(i) keeper.SetPool(ctx, pool) } validators[0] = updateValidator(keeper, ctx, validators[0]) @@ -825,15 +852,19 @@ func TestGetTendermintUpdatesNewValidator(t *testing.T) { valAddr := sdk.ValAddress(valPubKey.Address().Bytes()) validators[i] = types.NewValidator(valAddr, valPubKey, types.Description{}) + validators[i].BondIntraTxCounter = int16(i) validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt)) keeper.SetPool(ctx, pool) - validators[i] = updateValidator(keeper, ctx, validators[i]) + keeper.SetValidator(ctx, validators[i]) + keeper.SetValidatorByPowerIndex(ctx, validators[i], pool) } // verify initial Tendermint updates are correct updates := keeper.GetTendermintUpdates(ctx) require.Equal(t, len(validators), len(updates)) + validators[0], _ = keeper.GetValidator(ctx, validators[0].OperatorAddr) + validators[1], _ = keeper.GetValidator(ctx, validators[1].OperatorAddr) require.Equal(t, validators[0].ABCIValidatorUpdate(), updates[0]) require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[1]) @@ -842,10 +873,12 @@ func TestGetTendermintUpdatesNewValidator(t *testing.T) { // update initial validator set for i, amt := range amts { pool := keeper.GetPool(ctx) + keeper.DeleteValidatorByPowerIndex(ctx, validators[i], pool) validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt)) keeper.SetPool(ctx, pool) - validators[i] = updateValidator(keeper, ctx, validators[i]) + keeper.SetValidator(ctx, validators[i]) + keeper.SetValidatorByPowerIndex(ctx, validators[i], pool) } // add a new validator that goes from zero power, to non-zero power, back to @@ -859,10 +892,11 @@ func TestGetTendermintUpdatesNewValidator(t *testing.T) { validator, pool, _ = validator.AddTokensFromDel(pool, amt) keeper.SetPool(ctx, pool) - validator = updateValidator(keeper, ctx, validator) + keeper.SetValidator(ctx, validator) validator, pool, _ = validator.RemoveDelShares(pool, sdk.NewDecFromInt(amt)) - validator = updateValidator(keeper, ctx, validator) + keeper.SetValidator(ctx, validator) + keeper.SetValidatorByPowerIndex(ctx, validator, pool) // add a new validator that increases in power valPubKey = PKs[len(validators)+2] @@ -870,12 +904,15 @@ func TestGetTendermintUpdatesNewValidator(t *testing.T) { validator = types.NewValidator(valAddr, valPubKey, types.Description{}) validator, pool, _ = validator.AddTokensFromDel(pool, sdk.NewInt(500)) - + keeper.SetValidator(ctx, validator) + keeper.SetValidatorByPowerIndex(ctx, validator, pool) keeper.SetPool(ctx, pool) - validator = updateValidator(keeper, ctx, validator) // verify initial Tendermint updates are correct updates = keeper.GetTendermintUpdates(ctx) + validator, _ = keeper.GetValidator(ctx, validator.OperatorAddr) + validators[0], _ = keeper.GetValidator(ctx, validators[0].OperatorAddr) + validators[1], _ = keeper.GetValidator(ctx, validators[1].OperatorAddr) require.Equal(t, len(validators)+1, len(updates)) require.Equal(t, validator.ABCIValidatorUpdate(), updates[0]) require.Equal(t, validators[0].ABCIValidatorUpdate(), updates[1]) @@ -901,14 +938,17 @@ func TestGetTendermintUpdatesBondTransition(t *testing.T) { validators[i] = types.NewValidator(valAddr, valPubKey, types.Description{Moniker: moniker}) validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt)) - + validators[i].BondIntraTxCounter = int16(i) keeper.SetPool(ctx, pool) - validators[i] = updateValidator(keeper, ctx, validators[i]) + keeper.SetValidator(ctx, validators[i]) + keeper.SetValidatorByPowerIndex(ctx, validators[i], pool) } // verify initial Tendermint updates are correct updates := keeper.GetTendermintUpdates(ctx) require.Equal(t, 2, len(updates)) + validators[2], _ = keeper.GetValidator(ctx, validators[2].OperatorAddr) + validators[1], _ = keeper.GetValidator(ctx, validators[1].OperatorAddr) require.Equal(t, validators[2].ABCIValidatorUpdate(), updates[0]) require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[1]) @@ -942,10 +982,11 @@ func TestGetTendermintUpdatesBondTransition(t *testing.T) { keeper.SetPool(ctx, pool) validator = updateValidator(keeper, ctx, validator) + keeper.DeleteValidatorByPowerIndex(ctx, validators[1], pool) validator, pool, _ = validator.AddTokensFromDel(pool, sdk.NewInt(250)) - keeper.SetPool(ctx, pool) - validators[1] = updateValidator(keeper, ctx, validator) + keeper.SetValidator(ctx, validators[1]) + keeper.SetValidatorByPowerIndex(ctx, validators[1], pool) // verify initial Tendermint updates are correct updates = keeper.GetTendermintUpdates(ctx) From d8f2656818bed05ef16446254bdf0a4c116b4933 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Mon, 1 Oct 2018 17:45:22 +0200 Subject: [PATCH 24/44] Fix slashing tests (just adding stake.EndBlocker calls) --- x/slashing/handler_test.go | 3 +++ x/slashing/keeper_test.go | 27 ++++++++++++++++++++++++++- x/slashing/tick_test.go | 3 +++ x/stake/keeper/slash.go | 6 ++---- 4 files changed, 34 insertions(+), 5 deletions(-) diff --git a/x/slashing/handler_test.go b/x/slashing/handler_test.go index 9cdcd05334f0..7aebf0d0bf11 100644 --- a/x/slashing/handler_test.go +++ b/x/slashing/handler_test.go @@ -45,6 +45,9 @@ func TestJailedValidatorDelegations(t *testing.T) { got := stake.NewHandler(stakeKeeper)(ctx, msgCreateVal) require.True(t, got.IsOK(), "expected create validator msg to be ok, got: %v", got) + // end block + stake.EndBlocker(ctx, stakeKeeper) + // set dummy signing info newInfo := ValidatorSigningInfo{ StartHeight: int64(0), diff --git a/x/slashing/keeper_test.go b/x/slashing/keeper_test.go index 6845f35ce2c2..e32e7af5b314 100644 --- a/x/slashing/keeper_test.go +++ b/x/slashing/keeper_test.go @@ -85,13 +85,16 @@ func TestSlashingPeriodCap(t *testing.T) { // double sign less than max age keeper.handleDoubleSign(ctx, valConsPubKey.Address(), 0, time.Unix(0, 0), amtInt) - // should be jailed require.True(t, sk.Validator(ctx, addr).GetJailed()) + // end block + stake.EndBlocker(ctx, sk) // update block height ctx = ctx.WithBlockHeight(int64(1)) // unjail to measure power sk.Unjail(ctx, valConsAddr) + // end block + stake.EndBlocker(ctx, sk) // power should be reduced expectedPower := sdk.NewDecFromInt(amt).Mul(sdk.NewDec(19).Quo(sdk.NewDec(20))) require.Equal(t, expectedPower, sk.Validator(ctx, addr).GetPower()) @@ -100,10 +103,14 @@ func TestSlashingPeriodCap(t *testing.T) { keeper.handleDoubleSign(ctx, valConsPubKey.Address(), 0, time.Unix(0, 0), amtInt) // should be jailed require.True(t, sk.Validator(ctx, addr).GetJailed()) + // end block + stake.EndBlocker(ctx, sk) // update block height ctx = ctx.WithBlockHeight(int64(2)) // unjail to measure power sk.Unjail(ctx, valConsAddr) + // end block + stake.EndBlocker(ctx, sk) // power should be equal, no more should have been slashed expectedPower = sdk.NewDecFromInt(amt).Mul(sdk.NewDec(19).Quo(sdk.NewDec(20))) require.Equal(t, expectedPower, sk.Validator(ctx, addr).GetPower()) @@ -114,6 +121,8 @@ func TestSlashingPeriodCap(t *testing.T) { require.True(t, sk.Validator(ctx, addr).GetJailed()) // unjail to measure power sk.Unjail(ctx, valConsAddr) + // end block + stake.EndBlocker(ctx, sk) // power should be reduced expectedPower = sdk.NewDecFromInt(amt).Mul(sdk.NewDec(18).Quo(sdk.NewDec(20))) require.Equal(t, expectedPower, sk.Validator(ctx, addr).GetPower()) @@ -180,6 +189,9 @@ func TestHandleAbsentValidator(t *testing.T) { require.Equal(t, int64(0), info.StartHeight) require.Equal(t, keeper.SignedBlocksWindow(ctx)-keeper.MinSignedPerWindow(ctx)-1, info.SignedBlocksCounter) + // end block + stake.EndBlocker(ctx, sk) + // validator should have been jailed validator, _ = sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) require.Equal(t, sdk.Unbonding, validator.GetStatus()) @@ -193,6 +205,9 @@ func TestHandleAbsentValidator(t *testing.T) { got = slh(ctx, NewMsgUnjail(addr)) require.True(t, got.IsOK()) + // end block + stake.EndBlocker(ctx, sk) + // validator should be rebonded now validator, _ = sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) require.Equal(t, sdk.Bonded, validator.GetStatus()) @@ -222,12 +237,19 @@ func TestHandleAbsentValidator(t *testing.T) { keeper.handleValidatorSignature(ctx, val.Address(), amtInt, false) } + // end block + stake.EndBlocker(ctx, sk) + // validator should be jailed again after 500 unsigned blocks nextHeight = height + keeper.MinSignedPerWindow(ctx) + 1 for ; height <= nextHeight; height++ { ctx = ctx.WithBlockHeight(height) keeper.handleValidatorSignature(ctx, val.Address(), amtInt, false) } + + // end block + stake.EndBlocker(ctx, sk) + validator, _ = sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) require.Equal(t, sdk.Unbonding, validator.GetStatus()) } @@ -296,6 +318,9 @@ func TestHandleAlreadyJailed(t *testing.T) { keeper.handleValidatorSignature(ctx, val.Address(), amtInt, false) } + // end block + stake.EndBlocker(ctx, sk) + // validator should have been jailed and slashed validator, _ := sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val)) require.Equal(t, sdk.Unbonding, validator.GetStatus()) diff --git a/x/slashing/tick_test.go b/x/slashing/tick_test.go index 5f0ccf8ed54e..a98d97c54ce7 100644 --- a/x/slashing/tick_test.go +++ b/x/slashing/tick_test.go @@ -77,6 +77,9 @@ func TestBeginBlocker(t *testing.T) { BeginBlocker(ctx, req, keeper) } + // end block + stake.EndBlocker(ctx, sk) + // validator should be jailed validator, found := sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(pk)) require.True(t, found) diff --git a/x/stake/keeper/slash.go b/x/stake/keeper/slash.go index 60bff51ff108..9c8a0dac4b78 100644 --- a/x/stake/keeper/slash.go +++ b/x/stake/keeper/slash.go @@ -95,17 +95,15 @@ func (k Keeper) Slash(ctx sdk.Context, consAddr sdk.ConsAddress, infractionHeigh } } - // Cannot decrease balance below zero + // cannot decrease balance below zero tokensToBurn := sdk.MinDec(remainingSlashAmount, validator.Tokens) - // burn validator's tokens + // burn validator's tokens and update the validator validator = k.RemoveValidatorTokens(ctx, validator, tokensToBurn) pool := k.GetPool(ctx) pool.LooseTokens = pool.LooseTokens.Sub(tokensToBurn) k.SetPool(ctx, pool) - // update the validator, possibly kicking it out - // remove validator if it has no more tokens if validator.Tokens.IsZero() { k.RemoveValidator(ctx, validator.OperatorAddr) From a12cda181ebf8fe846730072842ef0f6db83ccf0 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Mon, 1 Oct 2018 18:16:57 +0200 Subject: [PATCH 25/44] Fix more testcases --- x/stake/handler_test.go | 24 ++++- x/stake/keeper/delegation_test.go | 4 +- x/stake/keeper/key.go | 5 +- x/stake/keeper/val_state_change.go | 1 - x/stake/keeper/validator_test.go | 141 ++++++++++++++++------------- 5 files changed, 105 insertions(+), 70 deletions(-) diff --git a/x/stake/handler_test.go b/x/stake/handler_test.go index 31adb307b7cd..085e11503050 100644 --- a/x/stake/handler_test.go +++ b/x/stake/handler_test.go @@ -86,6 +86,7 @@ func TestValidatorByPowerIndex(t *testing.T) { msgCreateValidator = newTestMsgCreateValidator(validatorAddr3, keep.PKs[2], int64(1000000)) got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) require.True(t, got.IsOK(), "expected create-validator to be ok, got %v", got) + // must end-block updates = keeper.GetTendermintUpdates(ctx) require.Equal(t, 1, len(updates)) @@ -94,6 +95,7 @@ func TestValidatorByPowerIndex(t *testing.T) { consAddr0 := sdk.ConsAddress(keep.PKs[0].Address()) keeper.Slash(ctx, consAddr0, 0, initBond, sdk.NewDecWithPrec(5, 1)) keeper.Jail(ctx, consAddr0) + keeper.GetTendermintUpdates(ctx) validator, found = keeper.GetValidator(ctx, validatorAddr) require.True(t, found) require.Equal(t, sdk.Unbonding, validator.Status) // ensure is unbonding @@ -143,8 +145,10 @@ func TestDuplicatesMsgCreateValidator(t *testing.T) { msgCreateValidator1 := newTestMsgCreateValidator(addr1, pk1, 10) got := handleMsgCreateValidator(ctx, msgCreateValidator1, keeper) require.True(t, got.IsOK(), "%v", got) - validator, found := keeper.GetValidator(ctx, addr1) + keeper.GetTendermintUpdates(ctx) + + validator, found := keeper.GetValidator(ctx, addr1) require.True(t, found) assert.Equal(t, sdk.Bonded, validator.Status) assert.Equal(t, addr1, validator.OperatorAddr) @@ -323,6 +327,9 @@ func TestIncrementsMsgDelegate(t *testing.T) { got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) require.True(t, got.IsOK(), "expected create validator msg to be ok, got %v", got) + // apply TM updates + keeper.GetTendermintUpdates(ctx) + validator, found := keeper.GetValidator(ctx, validatorAddr) require.True(t, found) require.Equal(t, sdk.Bonded, validator.Status) @@ -405,6 +412,9 @@ func TestIncrementsMsgUnbond(t *testing.T) { amt2 := accMapper.GetAccount(ctx, delegatorAddr).GetCoins().AmountOf(denom) require.Equal(t, amt1.Sub(sdk.NewInt(initBond)).Int64(), amt2.Int64(), "expected coins to be subtracted") + // apply TM updates + keeper.GetTendermintUpdates(ctx) + validator, found := keeper.GetValidator(ctx, validatorAddr) require.True(t, found) require.Equal(t, initBond*2, validator.DelegatorShares.RoundInt64()) @@ -587,9 +597,9 @@ func TestJailValidator(t *testing.T) { msgBeginUnbondingValidator := NewMsgBeginUnbonding(sdk.AccAddress(validatorAddr), validatorAddr, sdk.NewDec(10)) msgCompleteUnbondingValidator := NewMsgCompleteUnbonding(sdk.AccAddress(validatorAddr), validatorAddr) got = handleMsgBeginUnbonding(ctx, msgBeginUnbondingValidator, keeper) - require.True(t, got.IsOK(), "expected no error") + require.True(t, got.IsOK(), "expected no error: %v", got) got = handleMsgCompleteUnbonding(ctx, msgCompleteUnbondingValidator, keeper) - require.True(t, got.IsOK(), "expected no error") + require.True(t, got.IsOK(), "expected no error: %v", got) validator, found := keeper.GetValidator(ctx, validatorAddr) require.True(t, found) @@ -771,22 +781,30 @@ func TestUnbondingWhenExcessValidators(t *testing.T) { msgCreateValidator := newTestMsgCreateValidator(validatorAddr1, keep.PKs[0], 50) got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") + // apply TM updates + keeper.GetTendermintUpdates(ctx) require.Equal(t, 1, len(keeper.GetValidatorsBonded(ctx))) msgCreateValidator = newTestMsgCreateValidator(validatorAddr2, keep.PKs[1], 30) got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") + // apply TM updates + keeper.GetTendermintUpdates(ctx) require.Equal(t, 2, len(keeper.GetValidatorsBonded(ctx))) msgCreateValidator = newTestMsgCreateValidator(validatorAddr3, keep.PKs[2], 10) got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") + // apply TM updates + keeper.GetTendermintUpdates(ctx) require.Equal(t, 2, len(keeper.GetValidatorsBonded(ctx))) // unbond the valdator-2 msgBeginUnbonding := NewMsgBeginUnbonding(sdk.AccAddress(validatorAddr2), validatorAddr2, sdk.NewDec(30)) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), "expected no error on runMsgBeginUnbonding") + // apply TM updates + keeper.GetTendermintUpdates(ctx) // because there are extra validators waiting to get in, the queued // validator (aka. validator-1) should make it into the bonded group, thus diff --git a/x/stake/keeper/delegation_test.go b/x/stake/keeper/delegation_test.go index 74d9866fd786..c101bec1c466 100644 --- a/x/stake/keeper/delegation_test.go +++ b/x/stake/keeper/delegation_test.go @@ -617,7 +617,7 @@ func TestRedelegateFromUnbondingValidator(t *testing.T) { // end block updates := keeper.GetTendermintUpdates(ctx) - require.Equal(t, 1, len(updates)) + require.Equal(t, 2, len(updates)) validator, found := keeper.GetValidator(ctx, addrVals[0]) require.True(t, found) @@ -700,7 +700,7 @@ func TestRedelegateFromUnbondedValidator(t *testing.T) { // end block updates := keeper.GetTendermintUpdates(ctx) - require.Equal(t, 1, len(updates)) + require.Equal(t, 2, len(updates)) validator, found := keeper.GetValidator(ctx, addrVals[0]) require.True(t, found) diff --git a/x/stake/keeper/key.go b/x/stake/keeper/key.go index 2de4ac37c794..a93af0c120e5 100644 --- a/x/stake/keeper/key.go +++ b/x/stake/keeper/key.go @@ -88,12 +88,13 @@ func getValidatorPowerRank(validator types.Validator, pool types.Pool) []byte { counterBytes := make([]byte, 2) binary.BigEndian.PutUint16(counterBytes, ^uint16(validator.BondIntraTxCounter)) // invert counter (first txns have priority) - return append(append(append(append( + return append(append(append(append(append( ValidatorsByPowerIndexKey, jailedBytes...), powerBytes...), heightBytes...), - counterBytes...) + counterBytes...), + validator.OperatorAddr...) } //______________________________________________________________________________ diff --git a/x/stake/keeper/val_state_change.go b/x/stake/keeper/val_state_change.go index 545c19379ba5..bc0c9eec5510 100644 --- a/x/stake/keeper/val_state_change.go +++ b/x/stake/keeper/val_state_change.go @@ -104,7 +104,6 @@ func (k Keeper) GetTendermintUpdates(ctx sdk.Context) (updates []abci.ValidatorU // any validators left in `last` are no longer bonded for _, operator := range noLongerBonded { // fetch the validator - // TODO might it have been deleted in RemoveValidator? validator := k.mustGetValidator(ctx, sdk.ValAddress(operator)) // bonded to unbonding diff --git a/x/stake/keeper/validator_test.go b/x/stake/keeper/validator_test.go index 1a0809c98eda..773bc0d4d6d6 100644 --- a/x/stake/keeper/validator_test.go +++ b/x/stake/keeper/validator_test.go @@ -463,46 +463,52 @@ func TestGetValidatorsEdgeCases(t *testing.T) { assert.True(ValEq(t, validators[0], resValidators[0])) assert.True(ValEq(t, validators[2], resValidators[1])) - // A validator which leaves the gotValidator set due to a decrease in voting power, - // then increases to the original voting power, does not get its spot back in the - // case of a tie. - - // validator 3 enters bonded validator set - ctx = ctx.WithBlockHeight(40) - - validators[3], found = keeper.GetValidator(ctx, validators[3].OperatorAddr) - require.True(t, found) - keeper.DeleteValidatorByPowerIndex(ctx, validators[3], pool) - validators[3], pool, _ = validators[3].AddTokensFromDel(pool, sdk.NewInt(1)) - keeper.SetPool(ctx, pool) - validators[3] = updateValidator(keeper, ctx, validators[3]) - resValidators = keeper.GetBondedValidatorsByPower(ctx) - require.Equal(t, nMax, uint16(len(resValidators))) - assert.True(ValEq(t, validators[0], resValidators[0])) - assert.True(ValEq(t, validators[3], resValidators[1])) - - // validator 3 kicked out temporarily - keeper.DeleteValidatorByPowerIndex(ctx, validators[3], pool) - validators[3], pool, _ = validators[3].RemoveDelShares(pool, sdk.NewDec(201)) - keeper.SetPool(ctx, pool) - validators[3] = updateValidator(keeper, ctx, validators[3]) - resValidators = keeper.GetBondedValidatorsByPower(ctx) - require.Equal(t, nMax, uint16(len(resValidators))) - assert.True(ValEq(t, validators[0], resValidators[0])) - assert.True(ValEq(t, validators[2], resValidators[1])) - - // validator 4 does not get spot back - keeper.DeleteValidatorByPowerIndex(ctx, validators[3], pool) - validators[3], pool, _ = validators[3].AddTokensFromDel(pool, sdk.NewInt(200)) - keeper.SetPool(ctx, pool) - validators[3] = updateValidator(keeper, ctx, validators[3]) - resValidators = keeper.GetBondedValidatorsByPower(ctx) - require.Equal(t, nMax, uint16(len(resValidators))) - assert.True(ValEq(t, validators[0], resValidators[0])) - assert.True(ValEq(t, validators[2], resValidators[1])) - validator, exists := keeper.GetValidator(ctx, validators[3].OperatorAddr) - require.Equal(t, exists, true) - require.Equal(t, int64(40), validator.BondHeight) + /* + + TODO: This is no longer true, due to the BondIntraTxCounter changes. + + // A validator which leaves the gotValidator set due to a decrease in voting power, + // then increases to the original voting power, does not get its spot back in the + // case of a tie. + + // validator 3 enters bonded validator set + ctx = ctx.WithBlockHeight(40) + + validators[3], found = keeper.GetValidator(ctx, validators[3].OperatorAddr) + require.True(t, found) + keeper.DeleteValidatorByPowerIndex(ctx, validators[3], pool) + validators[3], pool, _ = validators[3].AddTokensFromDel(pool, sdk.NewInt(1)) + keeper.SetPool(ctx, pool) + validators[3] = updateValidator(keeper, ctx, validators[3]) + resValidators = keeper.GetBondedValidatorsByPower(ctx) + require.Equal(t, nMax, uint16(len(resValidators))) + assert.True(ValEq(t, validators[0], resValidators[0])) + assert.True(ValEq(t, validators[3], resValidators[1])) + + // validator 3 kicked out temporarily + keeper.DeleteValidatorByPowerIndex(ctx, validators[3], pool) + validators[3], pool, _ = validators[3].RemoveDelShares(pool, sdk.NewDec(201)) + keeper.SetPool(ctx, pool) + validators[3] = updateValidator(keeper, ctx, validators[3]) + resValidators = keeper.GetBondedValidatorsByPower(ctx) + require.Equal(t, nMax, uint16(len(resValidators))) + assert.True(ValEq(t, validators[0], resValidators[0])) + assert.True(ValEq(t, validators[2], resValidators[1])) + + // validator 4 does not get spot back + keeper.DeleteValidatorByPowerIndex(ctx, validators[3], pool) + validators[3], pool, _ = validators[3].AddTokensFromDel(pool, sdk.NewInt(200)) + keeper.SetPool(ctx, pool) + validators[3] = updateValidator(keeper, ctx, validators[3]) + resValidators = keeper.GetBondedValidatorsByPower(ctx) + require.Equal(t, nMax, uint16(len(resValidators))) + assert.True(ValEq(t, validators[0], resValidators[0])) + assert.True(ValEq(t, validators[2], resValidators[1])) + validator, exists := keeper.GetValidator(ctx, validators[3].OperatorAddr) + require.Equal(t, exists, true) + require.Equal(t, int64(40), validator.BondHeight) + + */ } func TestValidatorBondHeight(t *testing.T) { @@ -527,30 +533,36 @@ func TestValidatorBondHeight(t *testing.T) { validators[0] = updateValidator(keeper, ctx, validators[0]) - //////////////////////////////////////// - // If two validators both increase to the same voting power in the same block, - // the one with the first transaction should become bonded - validators[1] = updateValidator(keeper, ctx, validators[1]) - validators[2] = updateValidator(keeper, ctx, validators[2]) + /* - pool = keeper.GetPool(ctx) + TODO: This is no longer true, due to the BondIntraTxCounter changes. - resValidators := keeper.GetBondedValidatorsByPower(ctx) - require.Equal(t, uint16(len(resValidators)), params.MaxValidators) + //////////////////////////////////////// + // If two validators both increase to the same voting power in the same block, + // the one with the first transaction should become bonded + validators[1] = updateValidator(keeper, ctx, validators[1]) + validators[2] = updateValidator(keeper, ctx, validators[2]) - assert.True(ValEq(t, validators[0], resValidators[0])) - assert.True(ValEq(t, validators[1], resValidators[1])) - keeper.DeleteValidatorByPowerIndex(ctx, validators[1], pool) - keeper.DeleteValidatorByPowerIndex(ctx, validators[2], pool) - validators[1], pool, _ = validators[1].AddTokensFromDel(pool, sdk.NewInt(50)) - validators[2], pool, _ = validators[2].AddTokensFromDel(pool, sdk.NewInt(50)) - keeper.SetPool(ctx, pool) - validators[2] = updateValidator(keeper, ctx, validators[2]) - resValidators = keeper.GetBondedValidatorsByPower(ctx) - require.Equal(t, params.MaxValidators, uint16(len(resValidators))) - validators[1] = updateValidator(keeper, ctx, validators[1]) - assert.True(ValEq(t, validators[0], resValidators[0])) - assert.True(ValEq(t, validators[2], resValidators[1])) + pool = keeper.GetPool(ctx) + + resValidators := keeper.GetBondedValidatorsByPower(ctx) + require.Equal(t, uint16(len(resValidators)), params.MaxValidators) + + assert.True(ValEq(t, validators[0], resValidators[0])) + assert.True(ValEq(t, validators[1], resValidators[1])) + keeper.DeleteValidatorByPowerIndex(ctx, validators[1], pool) + keeper.DeleteValidatorByPowerIndex(ctx, validators[2], pool) + validators[1], pool, _ = validators[1].AddTokensFromDel(pool, sdk.NewInt(50)) + validators[2], pool, _ = validators[2].AddTokensFromDel(pool, sdk.NewInt(50)) + keeper.SetPool(ctx, pool) + validators[2] = updateValidator(keeper, ctx, validators[2]) + resValidators = keeper.GetBondedValidatorsByPower(ctx) + require.Equal(t, params.MaxValidators, uint16(len(resValidators))) + validators[1] = updateValidator(keeper, ctx, validators[1]) + assert.True(ValEq(t, validators[0], resValidators[0])) + assert.True(ValEq(t, validators[2], resValidators[1])) + + */ } func TestFullValidatorSetPowerChange(t *testing.T) { @@ -1012,6 +1024,9 @@ func TestUpdateValidatorCommission(t *testing.T) { val1, _ = val1.SetInitialCommission(commission1) val2, _ = val2.SetInitialCommission(commission2) + keeper.SetValidator(ctx, val1) + keeper.SetValidator(ctx, val2) + testCases := []struct { validator types.Validator newRate sdk.Dec @@ -1025,11 +1040,13 @@ func TestUpdateValidatorCommission(t *testing.T) { } for i, tc := range testCases { - _, err := keeper.UpdateValidatorCommission(ctx, tc.validator, tc.newRate) + commission, err := keeper.UpdateValidatorCommission(ctx, tc.validator, tc.newRate) if tc.expectedErr { require.Error(t, err, "expected error for test case #%d with rate: %s", i, tc.newRate) } else { + tc.validator.Commission = commission + keeper.SetValidator(ctx, tc.validator) val, found := keeper.GetValidator(ctx, tc.validator.OperatorAddr) require.True(t, found, From 0c1ddec314b06295c1f14a0b2ebf03169801c8be Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Mon, 1 Oct 2018 18:48:40 +0200 Subject: [PATCH 26/44] Unit tests as far as the eye can see --- x/gov/tally_test.go | 16 ++++++++++++++++ x/stake/handler_test.go | 16 ++++++++-------- x/stake/keeper/delegation.go | 3 ++- x/stake/keeper/slash.go | 3 ++- x/stake/keeper/slash_test.go | 4 ++++ x/stake/keeper/val_state_change.go | 5 +++++ x/stake/keeper/validator_test.go | 25 ++++++++++++++++--------- x/stake/querier/queryable_test.go | 7 ++++++- 8 files changed, 59 insertions(+), 20 deletions(-) diff --git a/x/gov/tally_test.go b/x/gov/tally_test.go index 28fe0cb5990e..26b32cc93a72 100644 --- a/x/gov/tally_test.go +++ b/x/gov/tally_test.go @@ -45,6 +45,7 @@ func TestTallyNoOneVotes(t *testing.T) { } createValidators(t, stakeHandler, ctx, valAddrs, []int64{5, 5}) + stake.EndBlocker(ctx, sk) proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) proposalID := proposal.GetProposalID() @@ -69,6 +70,7 @@ func TestTallyOnlyValidatorsAllYes(t *testing.T) { } createValidators(t, stakeHandler, ctx, valAddrs, []int64{5, 5}) + stake.EndBlocker(ctx, sk) proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) proposalID := proposal.GetProposalID() @@ -98,6 +100,7 @@ func TestTallyOnlyValidators51No(t *testing.T) { } createValidators(t, stakeHandler, ctx, valAddrs, []int64{5, 6}) + stake.EndBlocker(ctx, sk) proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) proposalID := proposal.GetProposalID() @@ -126,6 +129,7 @@ func TestTallyOnlyValidators51Yes(t *testing.T) { } createValidators(t, stakeHandler, ctx, valAddrs, []int64{6, 6, 7}) + stake.EndBlocker(ctx, sk) proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) proposalID := proposal.GetProposalID() @@ -157,6 +161,7 @@ func TestTallyOnlyValidatorsVetoed(t *testing.T) { } createValidators(t, stakeHandler, ctx, valAddrs, []int64{6, 6, 7}) + stake.EndBlocker(ctx, sk) proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) proposalID := proposal.GetProposalID() @@ -188,6 +193,7 @@ func TestTallyOnlyValidatorsAbstainPasses(t *testing.T) { } createValidators(t, stakeHandler, ctx, valAddrs, []int64{6, 6, 7}) + stake.EndBlocker(ctx, sk) proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) proposalID := proposal.GetProposalID() @@ -219,6 +225,7 @@ func TestTallyOnlyValidatorsAbstainFails(t *testing.T) { } createValidators(t, stakeHandler, ctx, valAddrs, []int64{6, 6, 7}) + stake.EndBlocker(ctx, sk) proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) proposalID := proposal.GetProposalID() @@ -250,6 +257,7 @@ func TestTallyOnlyValidatorsNonVoter(t *testing.T) { } createValidators(t, stakeHandler, ctx, valAddrs, []int64{6, 6, 7}) + stake.EndBlocker(ctx, sk) proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) proposalID := proposal.GetProposalID() @@ -279,6 +287,7 @@ func TestTallyDelgatorOverride(t *testing.T) { } createValidators(t, stakeHandler, ctx, valAddrs, []int64{5, 6, 7}) + stake.EndBlocker(ctx, sk) delegator1Msg := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[2]), sdk.NewInt64Coin("steak", 30)) stakeHandler(ctx, delegator1Msg) @@ -315,6 +324,7 @@ func TestTallyDelgatorInherit(t *testing.T) { } createValidators(t, stakeHandler, ctx, valAddrs, []int64{5, 6, 7}) + stake.EndBlocker(ctx, sk) delegator1Msg := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[2]), sdk.NewInt64Coin("steak", 30)) stakeHandler(ctx, delegator1Msg) @@ -349,6 +359,7 @@ func TestTallyDelgatorMultipleOverride(t *testing.T) { } createValidators(t, stakeHandler, ctx, valAddrs, []int64{5, 6, 7}) + stake.EndBlocker(ctx, sk) delegator1Msg := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[2]), sdk.NewInt64Coin("steak", 10)) stakeHandler(ctx, delegator1Msg) @@ -402,6 +413,8 @@ func TestTallyDelgatorMultipleInherit(t *testing.T) { delegator1Msg2 := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[1]), sdk.NewInt64Coin("steak", 10)) stakeHandler(ctx, delegator1Msg2) + stake.EndBlocker(ctx, sk) + proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) proposalID := proposal.GetProposalID() proposal.SetStatus(StatusVotingPeriod) @@ -432,6 +445,7 @@ func TestTallyJailedValidator(t *testing.T) { } createValidators(t, stakeHandler, ctx, valAddrs, []int64{25, 6, 7}) + stake.EndBlocker(ctx, sk) delegator1Msg := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[2]), sdk.NewInt64Coin("steak", 10)) stakeHandler(ctx, delegator1Msg) @@ -443,6 +457,8 @@ func TestTallyJailedValidator(t *testing.T) { require.True(t, found) sk.Jail(ctx, sdk.ConsAddress(val2.ConsPubKey.Address())) + stake.EndBlocker(ctx, sk) + proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) proposalID := proposal.GetProposalID() proposal.SetStatus(StatusVotingPeriod) diff --git a/x/stake/handler_test.go b/x/stake/handler_test.go index 085e11503050..8c3893cd0dde 100644 --- a/x/stake/handler_test.go +++ b/x/stake/handler_test.go @@ -130,6 +130,8 @@ func TestValidatorByPowerIndex(t *testing.T) { got = handleMsgCompleteUnbonding(ctx, msgCompleteUnbonding, keeper) require.True(t, got.IsOK(), "expected msg to be ok, got %v", got) + EndBlocker(ctx, keeper) + // verify that by power key nolonger exists _, found = keeper.GetValidator(ctx, validatorAddr) require.False(t, found) @@ -564,11 +566,8 @@ func TestMultipleMsgDelegate(t *testing.T) { // unbond them all for i, delegatorAddr := range delegatorAddrs { msgBeginUnbonding := NewMsgBeginUnbonding(delegatorAddr, validatorAddr, sdk.NewDec(10)) - msgCompleteUnbonding := NewMsgCompleteUnbonding(delegatorAddr, validatorAddr) got := handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), "expected msg %d to be ok, got %v", i, got) - got = handleMsgCompleteUnbonding(ctx, msgCompleteUnbonding, keeper) - require.True(t, got.IsOK(), "expected msg %d to be ok, got %v", i, got) //Check that the account is unbonded _, found := keeper.GetDelegation(ctx, delegatorAddr, validatorAddr) @@ -595,11 +594,8 @@ func TestJailValidator(t *testing.T) { // unbond the validators bond portion msgBeginUnbondingValidator := NewMsgBeginUnbonding(sdk.AccAddress(validatorAddr), validatorAddr, sdk.NewDec(10)) - msgCompleteUnbondingValidator := NewMsgCompleteUnbonding(sdk.AccAddress(validatorAddr), validatorAddr) got = handleMsgBeginUnbonding(ctx, msgBeginUnbondingValidator, keeper) require.True(t, got.IsOK(), "expected no error: %v", got) - got = handleMsgCompleteUnbonding(ctx, msgCompleteUnbondingValidator, keeper) - require.True(t, got.IsOK(), "expected no error: %v", got) validator, found := keeper.GetValidator(ctx, validatorAddr) require.True(t, found) @@ -803,6 +799,7 @@ func TestUnbondingWhenExcessValidators(t *testing.T) { msgBeginUnbonding := NewMsgBeginUnbonding(sdk.AccAddress(validatorAddr2), validatorAddr2, sdk.NewDec(30)) got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), "expected no error on runMsgBeginUnbonding") + // apply TM updates keeper.GetTendermintUpdates(ctx) @@ -836,7 +833,7 @@ func TestBondUnbondRedelegateSlashTwice(t *testing.T) { // apply Tendermint updates updates := keeper.GetTendermintUpdates(ctx) - require.Equal(t, 1, len(updates)) + require.Equal(t, 2, len(updates)) // a block passes ctx = ctx.WithBlockHeight(1) @@ -858,7 +855,7 @@ func TestBondUnbondRedelegateSlashTwice(t *testing.T) { // must apply validator updates updates = keeper.GetTendermintUpdates(ctx) - require.Equal(t, 1, len(updates)) + require.Equal(t, 2, len(updates)) // slash the validator by half keeper.Slash(ctx, consAddr0, 0, 20, sdk.NewDecWithPrec(5, 1)) @@ -902,6 +899,9 @@ func TestBondUnbondRedelegateSlashTwice(t *testing.T) { require.True(t, found) require.Equal(t, sdk.NewDec(3), delegation.Shares) + // end blocker + EndBlocker(ctx, keeper) + // validator power should have been reduced to zero // ergo validator should have been removed from the store _, found = keeper.GetValidator(ctx, valA) diff --git a/x/stake/keeper/delegation.go b/x/stake/keeper/delegation.go index f245da9e3db1..7631be8efb0f 100644 --- a/x/stake/keeper/delegation.go +++ b/x/stake/keeper/delegation.go @@ -323,7 +323,8 @@ func (k Keeper) unbond(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValA // remove the coins from the validator validator, amount = k.RemoveValidatorTokensAndShares(ctx, validator, shares) - if validator.DelegatorShares.IsZero() { + if validator.DelegatorShares.IsZero() && validator.Status != sdk.Bonded { + // if bonded, we must remove in EndBlocker instead k.RemoveValidator(ctx, validator.OperatorAddr) } diff --git a/x/stake/keeper/slash.go b/x/stake/keeper/slash.go index 9c8a0dac4b78..9275689fe648 100644 --- a/x/stake/keeper/slash.go +++ b/x/stake/keeper/slash.go @@ -105,7 +105,8 @@ func (k Keeper) Slash(ctx sdk.Context, consAddr sdk.ConsAddress, infractionHeigh k.SetPool(ctx, pool) // remove validator if it has no more tokens - if validator.Tokens.IsZero() { + if validator.Tokens.IsZero() && validator.Status != sdk.Bonded { + // if bonded, we must remove in GetTendermintUpdates instead k.RemoveValidator(ctx, validator.OperatorAddr) } diff --git a/x/stake/keeper/slash_test.go b/x/stake/keeper/slash_test.go index 9db459539853..275e39cdac79 100644 --- a/x/stake/keeper/slash_test.go +++ b/x/stake/keeper/slash_test.go @@ -316,6 +316,8 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { newPool = keeper.GetPool(ctx) // just 1 bonded token burned again since that's all the validator now has require.Equal(t, int64(10), oldPool.BondedTokens.Sub(newPool.BondedTokens).RoundInt64()) + // apply TM updates + keeper.GetTendermintUpdates(ctx) // read updated validator // power decreased by 1 again, validator is out of stake // ergo validator should have been removed from the store @@ -417,6 +419,8 @@ func TestSlashWithRedelegation(t *testing.T) { newPool = keeper.GetPool(ctx) // four more bonded tokens burned require.Equal(t, int64(16), oldPool.BondedTokens.Sub(newPool.BondedTokens).RoundInt64()) + // apply TM updates + keeper.GetTendermintUpdates(ctx) // read updated validator // validator decreased to zero power, should have been removed from the store _, found = keeper.GetValidatorByConsAddr(ctx, consAddr) diff --git a/x/stake/keeper/val_state_change.go b/x/stake/keeper/val_state_change.go index bc0c9eec5510..528a53deadac 100644 --- a/x/stake/keeper/val_state_change.go +++ b/x/stake/keeper/val_state_change.go @@ -109,6 +109,11 @@ func (k Keeper) GetTendermintUpdates(ctx sdk.Context) (updates []abci.ValidatorU // bonded to unbonding k.bondedToUnbonding(ctx, validator) + // remove validator if it has no more tokens + if validator.Tokens.IsZero() { + k.RemoveValidator(ctx, validator.OperatorAddr) + } + // delete from the bonded validator index store.Delete(GetBondedValidatorIndexKey(operator)) diff --git a/x/stake/keeper/validator_test.go b/x/stake/keeper/validator_test.go index 773bc0d4d6d6..e717b42956d1 100644 --- a/x/stake/keeper/validator_test.go +++ b/x/stake/keeper/validator_test.go @@ -184,6 +184,8 @@ func TestSlashToZeroPowerRemoved(t *testing.T) { // slash the validator by 100% consAddr0 := sdk.ConsAddress(PKs[0].Address()) keeper.Slash(ctx, consAddr0, 0, 100, sdk.OneDec()) + // apply TM updates + keeper.GetTendermintUpdates(ctx) // validator should have been deleted _, found := keeper.GetValidator(ctx, addrVals[0]) require.False(t, found) @@ -970,13 +972,15 @@ func TestGetTendermintUpdatesBondTransition(t *testing.T) { ctx = ctx.WithBlockHeight(1) pool := keeper.GetPool(ctx) - validator, found := keeper.GetValidator(ctx, validators[0].OperatorAddr) + var found bool + validators[0], found = keeper.GetValidator(ctx, validators[0].OperatorAddr) require.True(t, found) - validator, pool, _ = validator.AddTokensFromDel(pool, sdk.NewInt(1)) - + keeper.DeleteValidatorByPowerIndex(ctx, validators[0], pool) + validators[0], pool, _ = validators[0].AddTokensFromDel(pool, sdk.NewInt(1)) keeper.SetPool(ctx, pool) - validators[0] = updateValidator(keeper, ctx, validator) + keeper.SetValidator(ctx, validators[0]) + keeper.SetValidatorByPowerIndex(ctx, validators[0], pool) // verify initial Tendermint updates are correct require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) @@ -986,16 +990,19 @@ func TestGetTendermintUpdatesBondTransition(t *testing.T) { ctx = ctx.WithBlockHeight(2) pool = keeper.GetPool(ctx) - validator, found = keeper.GetValidator(ctx, validators[1].OperatorAddr) + validators[1], found = keeper.GetValidator(ctx, validators[1].OperatorAddr) require.True(t, found) - validator, pool, _ = validator.RemoveDelShares(pool, validator.DelegatorShares) - + keeper.DeleteValidatorByPowerIndex(ctx, validators[0], pool) + validators[0], pool, _ = validators[0].RemoveDelShares(pool, validators[0].DelegatorShares) keeper.SetPool(ctx, pool) - validator = updateValidator(keeper, ctx, validator) + keeper.SetValidator(ctx, validators[0]) + keeper.SetValidatorByPowerIndex(ctx, validators[0], pool) + updates = keeper.GetTendermintUpdates(ctx) + require.Equal(t, 0, len(updates)) keeper.DeleteValidatorByPowerIndex(ctx, validators[1], pool) - validator, pool, _ = validator.AddTokensFromDel(pool, sdk.NewInt(250)) + validators[1], pool, _ = validators[1].AddTokensFromDel(pool, sdk.NewInt(250)) keeper.SetPool(ctx, pool) keeper.SetValidator(ctx, validators[1]) keeper.SetValidatorByPowerIndex(ctx, validators[1], pool) diff --git a/x/stake/querier/queryable_test.go b/x/stake/querier/queryable_test.go index cbc947889f55..6b403aebadab 100644 --- a/x/stake/querier/queryable_test.go +++ b/x/stake/querier/queryable_test.go @@ -114,9 +114,14 @@ func TestQueryDelegation(t *testing.T) { // Create Validators and Delegation val1 := types.NewValidator(addrVal1, pk1, types.Description{}) keeper.SetValidator(ctx, val1) + pool := keeper.GetPool(ctx) + keeper.SetValidatorByPowerIndex(ctx, val1, pool) keeper.Delegate(ctx, addrAcc2, sdk.NewCoin("steak", sdk.NewInt(20)), val1, true) + // apply TM updates + keeper.GetTendermintUpdates(ctx) + // Query Delegator bonded validators queryParams := newTestDelegatorQuery(addrAcc2) bz, errRes := cdc.MarshalJSON(queryParams) @@ -177,7 +182,7 @@ func TestQueryDelegation(t *testing.T) { require.Equal(t, delegation, delegationRes) - // Query unbonging delegation + // Query unbonding delegation keeper.BeginUnbonding(ctx, addrAcc2, val1.OperatorAddr, sdk.NewDec(10)) query = abci.RequestQuery{ From c7cac2d5f60c62839c76df4e97af59a74fb21395 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Mon, 1 Oct 2018 18:53:17 +0200 Subject: [PATCH 27/44] Update PENDING.md --- PENDING.md | 1 + 1 file changed, 1 insertion(+) diff --git a/PENDING.md b/PENDING.md index 4956fbc2c6cb..fd16669aaf70 100644 --- a/PENDING.md +++ b/PENDING.md @@ -64,6 +64,7 @@ BREAKING CHANGES * [x/auth] \#2377 auth.StdSignMsg -> txbuilder.StdSignMsg * [x/staking] \#2244 staking now holds a consensus-address-index instead of a consensus-pubkey-index * [x/staking] \#2236 more distribution hooks for distribution + * [x/stake] \#2394 Split up UpdateValidator into distinct state transitions applied only in EndBlock * Tendermint From 7d82281715e9c1c87ed880e415421f548d4e7605 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Tue, 2 Oct 2018 09:43:18 +0200 Subject: [PATCH 28/44] Address review comments, round one --- x/stake/keeper/delegation_test.go | 4 + x/stake/keeper/key.go | 5 +- x/stake/keeper/val_state_change.go | 37 +------- x/stake/keeper/validator.go | 5 ++ x/stake/keeper/validator_test.go | 138 ++++++++++++++--------------- 5 files changed, 80 insertions(+), 109 deletions(-) diff --git a/x/stake/keeper/delegation_test.go b/x/stake/keeper/delegation_test.go index c101bec1c466..104d5d27635a 100644 --- a/x/stake/keeper/delegation_test.go +++ b/x/stake/keeper/delegation_test.go @@ -570,6 +570,7 @@ func TestRedelegateFromUnbondingValidator(t *testing.T) { //create a validator with a self-delegation validator := types.NewValidator(addrVals[0], PKs[0], types.Description{}) + validator.BondIntraTxCounter = 1 validator, pool, issuedShares := validator.AddTokensFromDel(pool, sdk.NewInt(10)) require.Equal(t, int64(10), issuedShares.RoundInt64()) @@ -599,6 +600,7 @@ func TestRedelegateFromUnbondingValidator(t *testing.T) { // create a second validator validator2 := types.NewValidator(addrVals[1], PKs[1], types.Description{}) + validator2.BondIntraTxCounter = 2 validator2, pool, issuedShares = validator2.AddTokensFromDel(pool, sdk.NewInt(10)) require.Equal(t, int64(10), issuedShares.RoundInt64()) keeper.SetPool(ctx, pool) @@ -668,6 +670,7 @@ func TestRedelegateFromUnbondedValidator(t *testing.T) { // create a second delegation to this validator validator, pool, issuedShares = validator.AddTokensFromDel(pool, sdk.NewInt(10)) + validator.BondIntraTxCounter = 1 require.Equal(t, int64(10), issuedShares.RoundInt64()) keeper.SetPool(ctx, pool) validator = updateValidator(keeper, ctx, validator) @@ -681,6 +684,7 @@ func TestRedelegateFromUnbondedValidator(t *testing.T) { // create a second validator validator2 := types.NewValidator(addrVals[1], PKs[1], types.Description{}) + validator2.BondIntraTxCounter = 2 validator2, pool, issuedShares = validator2.AddTokensFromDel(pool, sdk.NewInt(10)) require.Equal(t, int64(10), issuedShares.RoundInt64()) keeper.SetPool(ctx, pool) diff --git a/x/stake/keeper/key.go b/x/stake/keeper/key.go index a93af0c120e5..2de4ac37c794 100644 --- a/x/stake/keeper/key.go +++ b/x/stake/keeper/key.go @@ -88,13 +88,12 @@ func getValidatorPowerRank(validator types.Validator, pool types.Pool) []byte { counterBytes := make([]byte, 2) binary.BigEndian.PutUint16(counterBytes, ^uint16(validator.BondIntraTxCounter)) // invert counter (first txns have priority) - return append(append(append(append(append( + return append(append(append(append( ValidatorsByPowerIndexKey, jailedBytes...), powerBytes...), heightBytes...), - counterBytes...), - validator.OperatorAddr...) + counterBytes...) } //______________________________________________________________________________ diff --git a/x/stake/keeper/val_state_change.go b/x/stake/keeper/val_state_change.go index 528a53deadac..afb600a713b3 100644 --- a/x/stake/keeper/val_state_change.go +++ b/x/stake/keeper/val_state_change.go @@ -61,18 +61,16 @@ func (k Keeper) GetTendermintUpdates(ctx sdk.Context) (updates []abci.ValidatorU // no state change } - // validator still in the validator set + // fetch the old power bytes var opbytes [sdk.AddrLen]byte copy(opbytes[:], operator[:]) - - // fetch the old power bytes - powerBytes, ok := last[opbytes] + oldPowerBytes, ok := last[opbytes] // calculate the new power bytes newPowerBytes := validator.ABCIValidatorPowerBytes(k.cdc) // update the validator set if power has changed - if !ok || !bytes.Equal(powerBytes, newPowerBytes) { + if !ok || !bytes.Equal(oldPowerBytes, newPowerBytes) { updates = append(updates, validator.ABCIValidatorUpdate()) } @@ -88,6 +86,7 @@ func (k Keeper) GetTendermintUpdates(ctx sdk.Context) (updates []abci.ValidatorU } // sort the map keys for determinism + // sorted by address - order doesn't matter noLongerBonded := make([][]byte, len(last)) index := 0 for oper := range last { @@ -194,11 +193,6 @@ func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) types. validator.BondHeight = ctx.BlockHeight() - // XXX Are we OK with this? In order of power decreasing, but addresses break ties. - counter := k.GetIntraTxCounter(ctx) - validator.BondIntraTxCounter = counter - k.SetIntraTxCounter(ctx, counter+1) - // set the status validator, pool = validator.UpdateStatus(pool, sdk.Bonded) k.SetPool(ctx, pool) @@ -262,26 +256,3 @@ func (k Keeper) completeUnbondingValidator(ctx sdk.Context, validator types.Vali k.SetValidator(ctx, validator) return validator } - -// XXX need to figure out how to set a validator's BondIntraTxCounter - probably during delegation bonding? -// or keep track of tx for final bonding and set during endblock??? wish we could reduce this complexity - -// get the bond height and incremented intra-tx counter -// nolint: unparam -func (k Keeper) bondIncrement(ctx sdk.Context, isNewValidator bool, validator types.Validator) ( - height int64, intraTxCounter int16) { - - // if already a validator, copy the old block height and counter - if !isNewValidator && validator.Status == sdk.Bonded { - height = validator.BondHeight - intraTxCounter = validator.BondIntraTxCounter - return - } - - height = ctx.BlockHeight() - counter := k.GetIntraTxCounter(ctx) - intraTxCounter = counter - - k.SetIntraTxCounter(ctx, counter+1) - return -} diff --git a/x/stake/keeper/validator.go b/x/stake/keeper/validator.go index 5024ba17e4e6..568b24a0d527 100644 --- a/x/stake/keeper/validator.go +++ b/x/stake/keeper/validator.go @@ -130,6 +130,11 @@ func (k Keeper) AddValidatorTokensAndShares(ctx sdk.Context, validator types.Val pool := k.GetPool(ctx) k.DeleteValidatorByPowerIndex(ctx, validator, pool) validator, pool, addedShares = validator.AddTokensFromDel(pool, tokensToAdd) + // increment the intra-tx counter + // in case of a conflict, the validator which least recently changed power takes precedence + counter := k.GetIntraTxCounter(ctx) + validator.BondIntraTxCounter = counter + k.SetIntraTxCounter(ctx, counter+1) k.SetValidator(ctx, validator) k.SetPool(ctx, pool) k.SetValidatorByPowerIndex(ctx, validator, pool) diff --git a/x/stake/keeper/validator_test.go b/x/stake/keeper/validator_test.go index e717b42956d1..301f19a17f4e 100644 --- a/x/stake/keeper/validator_test.go +++ b/x/stake/keeper/validator_test.go @@ -442,6 +442,7 @@ func TestGetValidatorsEdgeCases(t *testing.T) { moniker := fmt.Sprintf("val#%d", int64(i)) validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{Moniker: moniker}) validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt)) + validators[i].BondIntraTxCounter = int16(i) keeper.SetPool(ctx, pool) validators[i] = updateValidator(keeper, ctx, validators[i]) } @@ -465,52 +466,46 @@ func TestGetValidatorsEdgeCases(t *testing.T) { assert.True(ValEq(t, validators[0], resValidators[0])) assert.True(ValEq(t, validators[2], resValidators[1])) - /* - - TODO: This is no longer true, due to the BondIntraTxCounter changes. - - // A validator which leaves the gotValidator set due to a decrease in voting power, - // then increases to the original voting power, does not get its spot back in the - // case of a tie. - - // validator 3 enters bonded validator set - ctx = ctx.WithBlockHeight(40) - - validators[3], found = keeper.GetValidator(ctx, validators[3].OperatorAddr) - require.True(t, found) - keeper.DeleteValidatorByPowerIndex(ctx, validators[3], pool) - validators[3], pool, _ = validators[3].AddTokensFromDel(pool, sdk.NewInt(1)) - keeper.SetPool(ctx, pool) - validators[3] = updateValidator(keeper, ctx, validators[3]) - resValidators = keeper.GetBondedValidatorsByPower(ctx) - require.Equal(t, nMax, uint16(len(resValidators))) - assert.True(ValEq(t, validators[0], resValidators[0])) - assert.True(ValEq(t, validators[3], resValidators[1])) - - // validator 3 kicked out temporarily - keeper.DeleteValidatorByPowerIndex(ctx, validators[3], pool) - validators[3], pool, _ = validators[3].RemoveDelShares(pool, sdk.NewDec(201)) - keeper.SetPool(ctx, pool) - validators[3] = updateValidator(keeper, ctx, validators[3]) - resValidators = keeper.GetBondedValidatorsByPower(ctx) - require.Equal(t, nMax, uint16(len(resValidators))) - assert.True(ValEq(t, validators[0], resValidators[0])) - assert.True(ValEq(t, validators[2], resValidators[1])) - - // validator 4 does not get spot back - keeper.DeleteValidatorByPowerIndex(ctx, validators[3], pool) - validators[3], pool, _ = validators[3].AddTokensFromDel(pool, sdk.NewInt(200)) - keeper.SetPool(ctx, pool) - validators[3] = updateValidator(keeper, ctx, validators[3]) - resValidators = keeper.GetBondedValidatorsByPower(ctx) - require.Equal(t, nMax, uint16(len(resValidators))) - assert.True(ValEq(t, validators[0], resValidators[0])) - assert.True(ValEq(t, validators[2], resValidators[1])) - validator, exists := keeper.GetValidator(ctx, validators[3].OperatorAddr) - require.Equal(t, exists, true) - require.Equal(t, int64(40), validator.BondHeight) - - */ + // A validator which leaves the gotValidator set due to a decrease in voting power, + // then increases to the original voting power, does not get its spot back in the + // case of a tie. + + // validator 3 enters bonded validator set + ctx = ctx.WithBlockHeight(40) + + validators[3], found = keeper.GetValidator(ctx, validators[3].OperatorAddr) + require.True(t, found) + keeper.DeleteValidatorByPowerIndex(ctx, validators[3], pool) + validators[3], pool, _ = validators[3].AddTokensFromDel(pool, sdk.NewInt(1)) + keeper.SetPool(ctx, pool) + validators[3] = updateValidator(keeper, ctx, validators[3]) + resValidators = keeper.GetBondedValidatorsByPower(ctx) + require.Equal(t, nMax, uint16(len(resValidators))) + assert.True(ValEq(t, validators[0], resValidators[0])) + assert.True(ValEq(t, validators[3], resValidators[1])) + + // validator 3 kicked out temporarily + keeper.DeleteValidatorByPowerIndex(ctx, validators[3], pool) + validators[3], pool, _ = validators[3].RemoveDelShares(pool, sdk.NewDec(201)) + keeper.SetPool(ctx, pool) + validators[3] = updateValidator(keeper, ctx, validators[3]) + resValidators = keeper.GetBondedValidatorsByPower(ctx) + require.Equal(t, nMax, uint16(len(resValidators))) + assert.True(ValEq(t, validators[0], resValidators[0])) + assert.True(ValEq(t, validators[2], resValidators[1])) + + // validator 4 does not get spot back + keeper.DeleteValidatorByPowerIndex(ctx, validators[3], pool) + validators[3], pool, _ = validators[3].AddTokensFromDel(pool, sdk.NewInt(200)) + keeper.SetPool(ctx, pool) + validators[3] = updateValidator(keeper, ctx, validators[3]) + resValidators = keeper.GetBondedValidatorsByPower(ctx) + require.Equal(t, nMax, uint16(len(resValidators))) + assert.True(ValEq(t, validators[0], resValidators[0])) + assert.True(ValEq(t, validators[2], resValidators[1])) + validator, exists := keeper.GetValidator(ctx, validators[3].OperatorAddr) + require.Equal(t, exists, true) + require.Equal(t, int64(40), validator.BondHeight) } func TestValidatorBondHeight(t *testing.T) { @@ -527,6 +522,9 @@ func TestValidatorBondHeight(t *testing.T) { validators[0] = types.NewValidator(sdk.ValAddress(Addrs[0]), PKs[0], types.Description{}) validators[1] = types.NewValidator(sdk.ValAddress(Addrs[1]), PKs[1], types.Description{}) validators[2] = types.NewValidator(sdk.ValAddress(Addrs[2]), PKs[2], types.Description{}) + validators[0].BondIntraTxCounter = 0 + validators[1].BondIntraTxCounter = 1 + validators[2].BondIntraTxCounter = 2 validators[0], pool, _ = validators[0].AddTokensFromDel(pool, sdk.NewInt(200)) validators[1], pool, _ = validators[1].AddTokensFromDel(pool, sdk.NewInt(100)) @@ -535,36 +533,30 @@ func TestValidatorBondHeight(t *testing.T) { validators[0] = updateValidator(keeper, ctx, validators[0]) - /* - - TODO: This is no longer true, due to the BondIntraTxCounter changes. - - //////////////////////////////////////// - // If two validators both increase to the same voting power in the same block, - // the one with the first transaction should become bonded - validators[1] = updateValidator(keeper, ctx, validators[1]) - validators[2] = updateValidator(keeper, ctx, validators[2]) - - pool = keeper.GetPool(ctx) + //////////////////////////////////////// + // If two validators both increase to the same voting power in the same block, + // the one with the first transaction should become bonded + validators[1] = updateValidator(keeper, ctx, validators[1]) + validators[2] = updateValidator(keeper, ctx, validators[2]) - resValidators := keeper.GetBondedValidatorsByPower(ctx) - require.Equal(t, uint16(len(resValidators)), params.MaxValidators) + pool = keeper.GetPool(ctx) - assert.True(ValEq(t, validators[0], resValidators[0])) - assert.True(ValEq(t, validators[1], resValidators[1])) - keeper.DeleteValidatorByPowerIndex(ctx, validators[1], pool) - keeper.DeleteValidatorByPowerIndex(ctx, validators[2], pool) - validators[1], pool, _ = validators[1].AddTokensFromDel(pool, sdk.NewInt(50)) - validators[2], pool, _ = validators[2].AddTokensFromDel(pool, sdk.NewInt(50)) - keeper.SetPool(ctx, pool) - validators[2] = updateValidator(keeper, ctx, validators[2]) - resValidators = keeper.GetBondedValidatorsByPower(ctx) - require.Equal(t, params.MaxValidators, uint16(len(resValidators))) - validators[1] = updateValidator(keeper, ctx, validators[1]) - assert.True(ValEq(t, validators[0], resValidators[0])) - assert.True(ValEq(t, validators[2], resValidators[1])) + resValidators := keeper.GetBondedValidatorsByPower(ctx) + require.Equal(t, uint16(len(resValidators)), params.MaxValidators) - */ + assert.True(ValEq(t, validators[0], resValidators[0])) + assert.True(ValEq(t, validators[1], resValidators[1])) + keeper.DeleteValidatorByPowerIndex(ctx, validators[1], pool) + keeper.DeleteValidatorByPowerIndex(ctx, validators[2], pool) + validators[1], pool, _ = validators[1].AddTokensFromDel(pool, sdk.NewInt(50)) + validators[2], pool, _ = validators[2].AddTokensFromDel(pool, sdk.NewInt(50)) + keeper.SetPool(ctx, pool) + validators[2] = updateValidator(keeper, ctx, validators[2]) + resValidators = keeper.GetBondedValidatorsByPower(ctx) + require.Equal(t, params.MaxValidators, uint16(len(resValidators))) + validators[1] = updateValidator(keeper, ctx, validators[1]) + assert.True(ValEq(t, validators[0], resValidators[0])) + assert.True(ValEq(t, validators[2], resValidators[1])) } func TestFullValidatorSetPowerChange(t *testing.T) { From b96faf6dbb5990f9eb673f58692b5d6c44e39e6b Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Tue, 2 Oct 2018 09:52:58 +0200 Subject: [PATCH 29/44] dep update, rename to clarify that function applies state changes --- Gopkg.lock | 16 +++---- x/stake/genesis.go | 2 +- x/stake/handler.go | 2 +- x/stake/handler_test.go | 30 ++++++------ x/stake/keeper/delegation_test.go | 12 ++--- x/stake/keeper/slash.go | 2 +- x/stake/keeper/slash_test.go | 10 ++-- x/stake/keeper/test_common.go | 2 +- x/stake/keeper/val_state_change.go | 2 +- x/stake/keeper/validator_test.go | 76 +++++++++++++++--------------- x/stake/querier/queryable_test.go | 2 +- x/stake/simulation/invariants.go | 1 - 12 files changed, 78 insertions(+), 79 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 5160d752e904..62f1f7e5b2f2 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -239,12 +239,12 @@ version = "v1.0.0" [[projects]] - digest = "1:645110e089152bd0f4a011a2648fbb0e4df5977be73ca605781157ac297f50c4" + digest = "1:e32dfc6abff6a3633ef4d9a1022fd707c8ef26f1e1e8f855dc58dc415ce7c8f3" name = "github.com/mitchellh/mapstructure" packages = ["."] pruneopts = "UT" - revision = "fa473d140ef3c6adf42d6b391fe76707f1f243c8" - version = "v1.0.0" + revision = "fe40af7a9c397fa3ddba203c38a5042c5d0475ad" + version = "v1.1.1" [[projects]] digest = "1:95741de3af260a92cc5c7f3f3061e85273f5a81b5db20d4bd68da74bd521675e" @@ -536,7 +536,7 @@ "salsa20/salsa", ] pruneopts = "UT" - revision = "0e37d006457bf46f9e6692014ba72ef82c33022c" + revision = "e3636079e1a4c1f337f212cc5cd2aca108f6c900" [[projects]] digest = "1:d36f55a999540d29b6ea3c2ea29d71c76b1d9853fdcd3e5c5cb4836f2ba118f1" @@ -556,14 +556,14 @@ [[projects]] branch = "master" - digest = "1:68023dc297a659d5eb2dafd62eda811456b338c5b3ec3c27da79e8a47d3f456a" + digest = "1:8bc8ecef1d63576cfab4d08b44a1f255dd67e5b019b7a44837d62380f266a91c" name = "golang.org/x/sys" packages = [ "cpu", "unix", ] pruneopts = "UT" - revision = "2f1df4e56cdeb503a08d8577e6f1a7eb12efab82" + revision = "e4b3c5e9061176387e7cea65e4dc5853801f3fb7" [[projects]] digest = "1:a2ab62866c75542dd18d2b069fec854577a20211d7c0ea6ae746072a1dccdd18" @@ -590,11 +590,11 @@ [[projects]] branch = "master" - digest = "1:56b0bca90b7e5d1facf5fbdacba23e4e0ce069d25381b8e2f70ef1e7ebfb9c1a" + digest = "1:1e6b0176e8c5dd8ff551af65c76f8b73a99bcf4d812cedff1b91711b7df4804c" name = "google.golang.org/genproto" packages = ["googleapis/rpc/status"] pruneopts = "UT" - revision = "0e822944c569bf5c9afd034adaa56208bd2906ac" + revision = "c7e5094acea1ca1b899e2259d80a6b0f882f81f8" [[projects]] digest = "1:2dab32a43451e320e49608ff4542fdfc653c95dcc35d0065ec9c6c3dd540ed74" diff --git a/x/stake/genesis.go b/x/stake/genesis.go index 5bc76d562e7a..45754f34309d 100644 --- a/x/stake/genesis.go +++ b/x/stake/genesis.go @@ -44,7 +44,7 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) (res [ keeper.SetDelegation(ctx, bond) } - res = keeper.GetTendermintUpdates(ctx) + res = keeper.ApplyAndReturnValidatorSetUpdates(ctx) return } diff --git a/x/stake/handler.go b/x/stake/handler.go index 89b6406de26d..f3a007fd51d9 100644 --- a/x/stake/handler.go +++ b/x/stake/handler.go @@ -52,7 +52,7 @@ func EndBlocker(ctx sdk.Context, k keeper.Keeper) (ValidatorUpdates []abci.Valid k.SetIntraTxCounter(ctx, 0) // calculate validator set changes - ValidatorUpdates = k.GetTendermintUpdates(ctx) + ValidatorUpdates = k.ApplyAndReturnValidatorSetUpdates(ctx) return } diff --git a/x/stake/handler_test.go b/x/stake/handler_test.go index 8c3893cd0dde..7c97b8190af7 100644 --- a/x/stake/handler_test.go +++ b/x/stake/handler_test.go @@ -64,7 +64,7 @@ func TestValidatorByPowerIndex(t *testing.T) { require.True(t, got.IsOK(), "expected create-validator to be ok, got %v", got) // must end-block - updates := keeper.GetTendermintUpdates(ctx) + updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) require.Equal(t, 1, len(updates)) // verify the self-delegation exists @@ -88,14 +88,14 @@ func TestValidatorByPowerIndex(t *testing.T) { require.True(t, got.IsOK(), "expected create-validator to be ok, got %v", got) // must end-block - updates = keeper.GetTendermintUpdates(ctx) + updates = keeper.ApplyAndReturnValidatorSetUpdates(ctx) require.Equal(t, 1, len(updates)) // slash and jail the first validator consAddr0 := sdk.ConsAddress(keep.PKs[0].Address()) keeper.Slash(ctx, consAddr0, 0, initBond, sdk.NewDecWithPrec(5, 1)) keeper.Jail(ctx, consAddr0) - keeper.GetTendermintUpdates(ctx) + keeper.ApplyAndReturnValidatorSetUpdates(ctx) validator, found = keeper.GetValidator(ctx, validatorAddr) require.True(t, found) require.Equal(t, sdk.Unbonding, validator.Status) // ensure is unbonding @@ -148,7 +148,7 @@ func TestDuplicatesMsgCreateValidator(t *testing.T) { got := handleMsgCreateValidator(ctx, msgCreateValidator1, keeper) require.True(t, got.IsOK(), "%v", got) - keeper.GetTendermintUpdates(ctx) + keeper.ApplyAndReturnValidatorSetUpdates(ctx) validator, found := keeper.GetValidator(ctx, addr1) require.True(t, found) @@ -175,7 +175,7 @@ func TestDuplicatesMsgCreateValidator(t *testing.T) { require.True(t, got.IsOK(), "%v", got) // must end-block - updates := keeper.GetTendermintUpdates(ctx) + updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) require.Equal(t, 1, len(updates)) validator, found = keeper.GetValidator(ctx, addr2) @@ -200,7 +200,7 @@ func TestDuplicatesMsgCreateValidatorOnBehalfOf(t *testing.T) { require.True(t, got.IsOK(), "%v", got) // must end-block - updates := keeper.GetTendermintUpdates(ctx) + updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) require.Equal(t, 1, len(updates)) validator, found := keeper.GetValidator(ctx, validatorAddr) @@ -235,7 +235,7 @@ func TestLegacyValidatorDelegations(t *testing.T) { require.True(t, got.IsOK(), "expected create validator msg to be ok, got %v", got) // must end-block - updates := keeper.GetTendermintUpdates(ctx) + updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) require.Equal(t, 1, len(updates)) // verify the validator exists and has the correct attributes @@ -330,7 +330,7 @@ func TestIncrementsMsgDelegate(t *testing.T) { require.True(t, got.IsOK(), "expected create validator msg to be ok, got %v", got) // apply TM updates - keeper.GetTendermintUpdates(ctx) + keeper.ApplyAndReturnValidatorSetUpdates(ctx) validator, found := keeper.GetValidator(ctx, validatorAddr) require.True(t, found) @@ -415,7 +415,7 @@ func TestIncrementsMsgUnbond(t *testing.T) { require.Equal(t, amt1.Sub(sdk.NewInt(initBond)).Int64(), amt2.Int64(), "expected coins to be subtracted") // apply TM updates - keeper.GetTendermintUpdates(ctx) + keeper.ApplyAndReturnValidatorSetUpdates(ctx) validator, found := keeper.GetValidator(ctx, validatorAddr) require.True(t, found) @@ -778,21 +778,21 @@ func TestUnbondingWhenExcessValidators(t *testing.T) { got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") // apply TM updates - keeper.GetTendermintUpdates(ctx) + keeper.ApplyAndReturnValidatorSetUpdates(ctx) require.Equal(t, 1, len(keeper.GetValidatorsBonded(ctx))) msgCreateValidator = newTestMsgCreateValidator(validatorAddr2, keep.PKs[1], 30) got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") // apply TM updates - keeper.GetTendermintUpdates(ctx) + keeper.ApplyAndReturnValidatorSetUpdates(ctx) require.Equal(t, 2, len(keeper.GetValidatorsBonded(ctx))) msgCreateValidator = newTestMsgCreateValidator(validatorAddr3, keep.PKs[2], 10) got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") // apply TM updates - keeper.GetTendermintUpdates(ctx) + keeper.ApplyAndReturnValidatorSetUpdates(ctx) require.Equal(t, 2, len(keeper.GetValidatorsBonded(ctx))) // unbond the valdator-2 @@ -801,7 +801,7 @@ func TestUnbondingWhenExcessValidators(t *testing.T) { require.True(t, got.IsOK(), "expected no error on runMsgBeginUnbonding") // apply TM updates - keeper.GetTendermintUpdates(ctx) + keeper.ApplyAndReturnValidatorSetUpdates(ctx) // because there are extra validators waiting to get in, the queued // validator (aka. validator-1) should make it into the bonded group, thus @@ -832,7 +832,7 @@ func TestBondUnbondRedelegateSlashTwice(t *testing.T) { require.True(t, got.IsOK(), "expected no error on runMsgDelegate") // apply Tendermint updates - updates := keeper.GetTendermintUpdates(ctx) + updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) require.Equal(t, 2, len(updates)) // a block passes @@ -854,7 +854,7 @@ func TestBondUnbondRedelegateSlashTwice(t *testing.T) { require.Equal(t, sdk.NewDec(6), delegation.Shares) // must apply validator updates - updates = keeper.GetTendermintUpdates(ctx) + updates = keeper.ApplyAndReturnValidatorSetUpdates(ctx) require.Equal(t, 2, len(updates)) // slash the validator by half diff --git a/x/stake/keeper/delegation_test.go b/x/stake/keeper/delegation_test.go index 104d5d27635a..6197935746a2 100644 --- a/x/stake/keeper/delegation_test.go +++ b/x/stake/keeper/delegation_test.go @@ -253,7 +253,7 @@ func TestUndelegateSelfDelegation(t *testing.T) { require.NoError(t, err) // end block - updates := keeper.GetTendermintUpdates(ctx) + updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) require.Equal(t, 1, len(updates)) validator, found := keeper.GetValidator(ctx, addrVals[0]) @@ -308,7 +308,7 @@ func TestUndelegateFromUnbondingValidator(t *testing.T) { require.NoError(t, err) // end block - updates := keeper.GetTendermintUpdates(ctx) + updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) require.Equal(t, 1, len(updates)) validator, found := keeper.GetValidator(ctx, addrVals[0]) @@ -383,7 +383,7 @@ func TestUndelegateFromUnbondedValidator(t *testing.T) { require.NoError(t, err) // end block - updates := keeper.GetTendermintUpdates(ctx) + updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) require.Equal(t, 1, len(updates)) validator, found := keeper.GetValidator(ctx, addrVals[0]) @@ -554,7 +554,7 @@ func TestRedelegateSelfDelegation(t *testing.T) { require.NoError(t, err) // end block - updates := keeper.GetTendermintUpdates(ctx) + updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) require.Equal(t, 2, len(updates)) validator, found := keeper.GetValidator(ctx, addrVals[0]) @@ -618,7 +618,7 @@ func TestRedelegateFromUnbondingValidator(t *testing.T) { require.NoError(t, err) // end block - updates := keeper.GetTendermintUpdates(ctx) + updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) require.Equal(t, 2, len(updates)) validator, found := keeper.GetValidator(ctx, addrVals[0]) @@ -703,7 +703,7 @@ func TestRedelegateFromUnbondedValidator(t *testing.T) { require.NoError(t, err) // end block - updates := keeper.GetTendermintUpdates(ctx) + updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) require.Equal(t, 2, len(updates)) validator, found := keeper.GetValidator(ctx, addrVals[0]) diff --git a/x/stake/keeper/slash.go b/x/stake/keeper/slash.go index 9275689fe648..dd678858c483 100644 --- a/x/stake/keeper/slash.go +++ b/x/stake/keeper/slash.go @@ -106,7 +106,7 @@ func (k Keeper) Slash(ctx sdk.Context, consAddr sdk.ConsAddress, infractionHeigh // remove validator if it has no more tokens if validator.Tokens.IsZero() && validator.Status != sdk.Bonded { - // if bonded, we must remove in GetTendermintUpdates instead + // if bonded, we must remove in ApplyAndReturnValidatorSetUpdates instead k.RemoveValidator(ctx, validator.OperatorAddr) } diff --git a/x/stake/keeper/slash_test.go b/x/stake/keeper/slash_test.go index 275e39cdac79..70c456a02994 100644 --- a/x/stake/keeper/slash_test.go +++ b/x/stake/keeper/slash_test.go @@ -164,7 +164,7 @@ func TestSlashRedelegation(t *testing.T) { require.True(t, found) // end block - updates := keeper.GetTendermintUpdates(ctx) + updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) require.Equal(t, 1, len(updates)) // initialbalance unchanged @@ -208,7 +208,7 @@ func TestSlashValidatorAtCurrentHeight(t *testing.T) { newPool := keeper.GetPool(ctx) // end block - updates := keeper.GetTendermintUpdates(ctx) + updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) require.Equal(t, 1, len(updates), "cons addr: %v, updates: %v", []byte(consAddr), updates) validator = keeper.mustGetValidator(ctx, validator.OperatorAddr) @@ -244,7 +244,7 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { keeper.Slash(ctx, consAddr, 10, 10, fraction) // end block - updates := keeper.GetTendermintUpdates(ctx) + updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) require.Equal(t, 1, len(updates)) // read updating unbonding delegation @@ -317,7 +317,7 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { // just 1 bonded token burned again since that's all the validator now has require.Equal(t, int64(10), oldPool.BondedTokens.Sub(newPool.BondedTokens).RoundInt64()) // apply TM updates - keeper.GetTendermintUpdates(ctx) + keeper.ApplyAndReturnValidatorSetUpdates(ctx) // read updated validator // power decreased by 1 again, validator is out of stake // ergo validator should have been removed from the store @@ -420,7 +420,7 @@ func TestSlashWithRedelegation(t *testing.T) { // four more bonded tokens burned require.Equal(t, int64(16), oldPool.BondedTokens.Sub(newPool.BondedTokens).RoundInt64()) // apply TM updates - keeper.GetTendermintUpdates(ctx) + keeper.ApplyAndReturnValidatorSetUpdates(ctx) // read updated validator // validator decreased to zero power, should have been removed from the store _, found = keeper.GetValidatorByConsAddr(ctx, consAddr) diff --git a/x/stake/keeper/test_common.go b/x/stake/keeper/test_common.go index cdd13a96b1a3..5cfbf603118c 100644 --- a/x/stake/keeper/test_common.go +++ b/x/stake/keeper/test_common.go @@ -209,7 +209,7 @@ func updateValidator(keeper Keeper, ctx sdk.Context, validator types.Validator) pool := keeper.GetPool(ctx) keeper.SetValidator(ctx, validator) keeper.SetValidatorByPowerIndex(ctx, validator, pool) - keeper.GetTendermintUpdates(ctx) + keeper.ApplyAndReturnValidatorSetUpdates(ctx) validator, found := keeper.GetValidator(ctx, validator.OperatorAddr) if !found { panic("validator expected but not found") diff --git a/x/stake/keeper/val_state_change.go b/x/stake/keeper/val_state_change.go index afb600a713b3..d3c804efa745 100644 --- a/x/stake/keeper/val_state_change.go +++ b/x/stake/keeper/val_state_change.go @@ -19,7 +19,7 @@ import ( // CONTRACT: Only validators with non-zero power or zero-power that were bonded // at the previous block height or were removed from the validator set entirely // are returned to Tendermint. -func (k Keeper) GetTendermintUpdates(ctx sdk.Context) (updates []abci.ValidatorUpdate) { +func (k Keeper) ApplyAndReturnValidatorSetUpdates(ctx sdk.Context) (updates []abci.ValidatorUpdate) { store := ctx.KVStore(k.storeKey) maxValidators := k.GetParams(ctx).MaxValidators diff --git a/x/stake/keeper/validator_test.go b/x/stake/keeper/validator_test.go index 301f19a17f4e..b948fb87e517 100644 --- a/x/stake/keeper/validator_test.go +++ b/x/stake/keeper/validator_test.go @@ -33,7 +33,7 @@ func TestSetValidator(t *testing.T) { keeper.SetValidatorByPowerIndex(ctx, validator, pool) // ensure update - updates := keeper.GetTendermintUpdates(ctx) + updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) validator, found := keeper.GetValidator(ctx, valAddr) require.True(t, found) require.Equal(t, 1, len(updates)) @@ -185,7 +185,7 @@ func TestSlashToZeroPowerRemoved(t *testing.T) { consAddr0 := sdk.ConsAddress(PKs[0].Address()) keeper.Slash(ctx, consAddr0, 0, 100, sdk.OneDec()) // apply TM updates - keeper.GetTendermintUpdates(ctx) + keeper.ApplyAndReturnValidatorSetUpdates(ctx) // validator should have been deleted _, found := keeper.GetValidator(ctx, addrVals[0]) require.False(t, found) @@ -603,7 +603,7 @@ func TestFullValidatorSetPowerChange(t *testing.T) { assert.True(ValEq(t, validators[2], resValidators[1])) } -func TestGetTendermintUpdatesAllNone(t *testing.T) { +func TestApplyAndReturnValidatorSetUpdatesAllNone(t *testing.T) { ctx, _, keeper := CreateTestInput(t, false, 1000) amts := []int64{10, 20} @@ -621,14 +621,14 @@ func TestGetTendermintUpdatesAllNone(t *testing.T) { // test from nothing to something // tendermintUpdate set: {} -> {c1, c3} - require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) + require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) pool := keeper.GetPool(ctx) keeper.SetValidator(ctx, validators[0]) keeper.SetValidatorByPowerIndex(ctx, validators[0], pool) keeper.SetValidator(ctx, validators[1]) keeper.SetValidatorByPowerIndex(ctx, validators[1], pool) - updates := keeper.GetTendermintUpdates(ctx) + updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) assert.Equal(t, 2, len(updates)) validators[0], _ = keeper.GetValidator(ctx, validators[0].OperatorAddr) validators[1], _ = keeper.GetValidator(ctx, validators[1].OperatorAddr) @@ -636,7 +636,7 @@ func TestGetTendermintUpdatesAllNone(t *testing.T) { assert.Equal(t, validators[1].ABCIValidatorUpdate(), updates[0]) } -func TestGetTendermintUpdatesIdentical(t *testing.T) { +func TestApplyAndReturnValidatorSetUpdatesIdentical(t *testing.T) { ctx, _, keeper := CreateTestInput(t, false, 1000) amts := []int64{10, 20} @@ -649,16 +649,16 @@ func TestGetTendermintUpdatesIdentical(t *testing.T) { } validators[0] = updateValidator(keeper, ctx, validators[0]) validators[1] = updateValidator(keeper, ctx, validators[1]) - require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) + require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) // test identical, // tendermintUpdate set: {} -> {} validators[0] = updateValidator(keeper, ctx, validators[0]) validators[1] = updateValidator(keeper, ctx, validators[1]) - require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) + require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) } -func TestGetTendermintUpdatesSingleValueChange(t *testing.T) { +func TestApplyAndReturnValidatorSetUpdatesSingleValueChange(t *testing.T) { ctx, _, keeper := CreateTestInput(t, false, 1000) amts := []int64{10, 20} @@ -671,7 +671,7 @@ func TestGetTendermintUpdatesSingleValueChange(t *testing.T) { } validators[0] = updateValidator(keeper, ctx, validators[0]) validators[1] = updateValidator(keeper, ctx, validators[1]) - require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) + require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) // test single value change // tendermintUpdate set: {} -> {c1'} @@ -679,13 +679,13 @@ func TestGetTendermintUpdatesSingleValueChange(t *testing.T) { validators[0].Tokens = sdk.NewDec(600) validators[0] = updateValidator(keeper, ctx, validators[0]) - updates := keeper.GetTendermintUpdates(ctx) + updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) require.Equal(t, 1, len(updates)) require.Equal(t, validators[0].ABCIValidatorUpdate(), updates[0]) } -func TestGetTendermintUpdatesMultipleValueChange(t *testing.T) { +func TestApplyAndReturnValidatorSetUpdatesMultipleValueChange(t *testing.T) { ctx, _, keeper := CreateTestInput(t, false, 1000) amts := []int64{10, 20} @@ -698,7 +698,7 @@ func TestGetTendermintUpdatesMultipleValueChange(t *testing.T) { } validators[0] = updateValidator(keeper, ctx, validators[0]) validators[1] = updateValidator(keeper, ctx, validators[1]) - require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) + require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) // test multiple value change // tendermintUpdate set: {c1, c3} -> {c1', c3'} @@ -709,13 +709,13 @@ func TestGetTendermintUpdatesMultipleValueChange(t *testing.T) { validators[0] = updateValidator(keeper, ctx, validators[0]) validators[1] = updateValidator(keeper, ctx, validators[1]) - updates := keeper.GetTendermintUpdates(ctx) + updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) require.Equal(t, 2, len(updates)) require.Equal(t, validators[0].ABCIValidatorUpdate(), updates[1]) require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[0]) } -func TestGetTendermintUpdatesInserted(t *testing.T) { +func TestApplyAndReturnValidatorSetUpdatesInserted(t *testing.T) { ctx, _, keeper := CreateTestInput(t, false, 1000) amts := []int64{10, 20, 5, 15, 25} @@ -728,14 +728,14 @@ func TestGetTendermintUpdatesInserted(t *testing.T) { } validators[0] = updateValidator(keeper, ctx, validators[0]) validators[1] = updateValidator(keeper, ctx, validators[1]) - require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) + require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) // test validtor added at the beginning // tendermintUpdate set: {} -> {c0} pool := keeper.GetPool(ctx) keeper.SetValidator(ctx, validators[2]) keeper.SetValidatorByPowerIndex(ctx, validators[2], pool) - updates := keeper.GetTendermintUpdates(ctx) + updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) validators[2], _ = keeper.GetValidator(ctx, validators[2].OperatorAddr) require.Equal(t, 1, len(updates)) require.Equal(t, validators[2].ABCIValidatorUpdate(), updates[0]) @@ -745,7 +745,7 @@ func TestGetTendermintUpdatesInserted(t *testing.T) { pool = keeper.GetPool(ctx) keeper.SetValidator(ctx, validators[3]) keeper.SetValidatorByPowerIndex(ctx, validators[3], pool) - updates = keeper.GetTendermintUpdates(ctx) + updates = keeper.ApplyAndReturnValidatorSetUpdates(ctx) validators[3], _ = keeper.GetValidator(ctx, validators[3].OperatorAddr) require.Equal(t, 1, len(updates)) require.Equal(t, validators[3].ABCIValidatorUpdate(), updates[0]) @@ -755,13 +755,13 @@ func TestGetTendermintUpdatesInserted(t *testing.T) { pool = keeper.GetPool(ctx) keeper.SetValidator(ctx, validators[4]) keeper.SetValidatorByPowerIndex(ctx, validators[4], pool) - updates = keeper.GetTendermintUpdates(ctx) + updates = keeper.ApplyAndReturnValidatorSetUpdates(ctx) validators[4], _ = keeper.GetValidator(ctx, validators[4].OperatorAddr) require.Equal(t, 1, len(updates)) require.Equal(t, validators[4].ABCIValidatorUpdate(), updates[0]) } -func TestGetTendermintUpdatesWithCliffValidator(t *testing.T) { +func TestApplyAndReturnValidatorSetUpdatesWithCliffValidator(t *testing.T) { ctx, _, keeper := CreateTestInput(t, false, 1000) params := types.DefaultParams() params.MaxValidators = 2 @@ -777,31 +777,31 @@ func TestGetTendermintUpdatesWithCliffValidator(t *testing.T) { } validators[0] = updateValidator(keeper, ctx, validators[0]) validators[1] = updateValidator(keeper, ctx, validators[1]) - require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) + require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) // test validator added at the end but not inserted in the valset // tendermintUpdate set: {} -> {} updateValidator(keeper, ctx, validators[2]) - updates := keeper.GetTendermintUpdates(ctx) + updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) require.Equal(t, 0, len(updates)) // test validator change its power and become a gotValidator (pushing out an existing) // tendermintUpdate set: {} -> {c0, c4} - require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) + require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) pool := keeper.GetPool(ctx) validators[2], pool, _ = validators[2].AddTokensFromDel(pool, sdk.NewInt(10)) keeper.SetPool(ctx, pool) keeper.SetValidator(ctx, validators[2]) keeper.SetValidatorByPowerIndex(ctx, validators[2], pool) - updates = keeper.GetTendermintUpdates(ctx) + updates = keeper.ApplyAndReturnValidatorSetUpdates(ctx) validators[2], _ = keeper.GetValidator(ctx, validators[2].OperatorAddr) require.Equal(t, 2, len(updates), "%v", updates) require.Equal(t, validators[0].ABCIValidatorUpdateZero(), updates[1]) require.Equal(t, validators[2].ABCIValidatorUpdate(), updates[0]) } -func TestGetTendermintUpdatesPowerDecrease(t *testing.T) { +func TestApplyAndReturnValidatorSetUpdatesPowerDecrease(t *testing.T) { ctx, _, keeper := CreateTestInput(t, false, 1000) amts := []int64{100, 100} @@ -815,7 +815,7 @@ func TestGetTendermintUpdatesPowerDecrease(t *testing.T) { } validators[0] = updateValidator(keeper, ctx, validators[0]) validators[1] = updateValidator(keeper, ctx, validators[1]) - require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) + require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) // check initial power require.Equal(t, sdk.NewDec(100).RoundInt64(), validators[0].GetPower().RoundInt64()) @@ -835,13 +835,13 @@ func TestGetTendermintUpdatesPowerDecrease(t *testing.T) { require.Equal(t, sdk.NewDec(70).RoundInt64(), validators[1].GetPower().RoundInt64()) // Tendermint updates should reflect power change - updates := keeper.GetTendermintUpdates(ctx) + updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) require.Equal(t, 2, len(updates)) require.Equal(t, validators[0].ABCIValidatorUpdate(), updates[0]) require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[1]) } -func TestGetTendermintUpdatesNewValidator(t *testing.T) { +func TestApplyAndReturnValidatorSetUpdatesNewValidator(t *testing.T) { ctx, _, keeper := CreateTestInput(t, false, 1000) params := keeper.GetParams(ctx) params.MaxValidators = uint16(3) @@ -867,14 +867,14 @@ func TestGetTendermintUpdatesNewValidator(t *testing.T) { } // verify initial Tendermint updates are correct - updates := keeper.GetTendermintUpdates(ctx) + updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) require.Equal(t, len(validators), len(updates)) validators[0], _ = keeper.GetValidator(ctx, validators[0].OperatorAddr) validators[1], _ = keeper.GetValidator(ctx, validators[1].OperatorAddr) require.Equal(t, validators[0].ABCIValidatorUpdate(), updates[0]) require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[1]) - require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) + require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) // update initial validator set for i, amt := range amts { @@ -915,7 +915,7 @@ func TestGetTendermintUpdatesNewValidator(t *testing.T) { keeper.SetPool(ctx, pool) // verify initial Tendermint updates are correct - updates = keeper.GetTendermintUpdates(ctx) + updates = keeper.ApplyAndReturnValidatorSetUpdates(ctx) validator, _ = keeper.GetValidator(ctx, validator.OperatorAddr) validators[0], _ = keeper.GetValidator(ctx, validators[0].OperatorAddr) validators[1], _ = keeper.GetValidator(ctx, validators[1].OperatorAddr) @@ -925,7 +925,7 @@ func TestGetTendermintUpdatesNewValidator(t *testing.T) { require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[2]) } -func TestGetTendermintUpdatesBondTransition(t *testing.T) { +func TestApplyAndReturnValidatorSetUpdatesBondTransition(t *testing.T) { ctx, _, keeper := CreateTestInput(t, false, 1000) params := keeper.GetParams(ctx) params.MaxValidators = uint16(2) @@ -951,14 +951,14 @@ func TestGetTendermintUpdatesBondTransition(t *testing.T) { } // verify initial Tendermint updates are correct - updates := keeper.GetTendermintUpdates(ctx) + updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) require.Equal(t, 2, len(updates)) validators[2], _ = keeper.GetValidator(ctx, validators[2].OperatorAddr) validators[1], _ = keeper.GetValidator(ctx, validators[1].OperatorAddr) require.Equal(t, validators[2].ABCIValidatorUpdate(), updates[0]) require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[1]) - require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) + require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) // delegate to validator with lowest power but not enough to bond ctx = ctx.WithBlockHeight(1) @@ -975,7 +975,7 @@ func TestGetTendermintUpdatesBondTransition(t *testing.T) { keeper.SetValidatorByPowerIndex(ctx, validators[0], pool) // verify initial Tendermint updates are correct - require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) + require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) // create a series of events that will bond and unbond the validator with // lowest power in a single block context (height) @@ -990,7 +990,7 @@ func TestGetTendermintUpdatesBondTransition(t *testing.T) { keeper.SetPool(ctx, pool) keeper.SetValidator(ctx, validators[0]) keeper.SetValidatorByPowerIndex(ctx, validators[0], pool) - updates = keeper.GetTendermintUpdates(ctx) + updates = keeper.ApplyAndReturnValidatorSetUpdates(ctx) require.Equal(t, 0, len(updates)) keeper.DeleteValidatorByPowerIndex(ctx, validators[1], pool) @@ -1000,11 +1000,11 @@ func TestGetTendermintUpdatesBondTransition(t *testing.T) { keeper.SetValidatorByPowerIndex(ctx, validators[1], pool) // verify initial Tendermint updates are correct - updates = keeper.GetTendermintUpdates(ctx) + updates = keeper.ApplyAndReturnValidatorSetUpdates(ctx) require.Equal(t, 1, len(updates)) require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[0]) - require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx))) + require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) } func TestUpdateValidatorCommission(t *testing.T) { diff --git a/x/stake/querier/queryable_test.go b/x/stake/querier/queryable_test.go index 6b403aebadab..00a524b5b43d 100644 --- a/x/stake/querier/queryable_test.go +++ b/x/stake/querier/queryable_test.go @@ -120,7 +120,7 @@ func TestQueryDelegation(t *testing.T) { keeper.Delegate(ctx, addrAcc2, sdk.NewCoin("steak", sdk.NewInt(20)), val1, true) // apply TM updates - keeper.GetTendermintUpdates(ctx) + keeper.ApplyAndReturnValidatorSetUpdates(ctx) // Query Delegator bonded validators queryParams := newTestDelegatorQuery(addrAcc2) diff --git a/x/stake/simulation/invariants.go b/x/stake/simulation/invariants.go index b06c7bb7cce3..2866f6292fef 100644 --- a/x/stake/simulation/invariants.go +++ b/x/stake/simulation/invariants.go @@ -76,7 +76,6 @@ func SupplyInvariants(ck bank.Keeper, k stake.Keeper, am auth.AccountMapper) sim // PositivePowerInvariant checks that all stored validators have > 0 power func PositivePowerInvariant(k stake.Keeper) simulation.Invariant { return func(app *baseapp.BaseApp) error { - // TODO Reenable but only check after EndBlock, is this accurate now? ctx := app.NewContext(false, abci.Header{}) var err error k.IterateValidatorsBonded(ctx, func(_ int64, validator sdk.Validator) bool { From dbd2c0ae2eca1969990927e56d02f7d734c2271a Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Tue, 2 Oct 2018 10:01:18 +0200 Subject: [PATCH 30/44] Split up function for clarity --- x/stake/keeper/val_state_change.go | 75 ++++++++++++++++++------------ 1 file changed, 44 insertions(+), 31 deletions(-) diff --git a/x/stake/keeper/val_state_change.go b/x/stake/keeper/val_state_change.go index d3c804efa745..ae76caf21e65 100644 --- a/x/stake/keeper/val_state_change.go +++ b/x/stake/keeper/val_state_change.go @@ -11,10 +11,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/stake/types" ) -//_________________________________________________________________________ -// Accumulated updates to the active/bonded validator set for tendermint - -// get the most recently updated validators +// Apply and return accumulated updates to the bonded validator set // // CONTRACT: Only validators with non-zero power or zero-power that were bonded // at the previous block height or were removed from the validator set entirely @@ -24,18 +21,11 @@ func (k Keeper) ApplyAndReturnValidatorSetUpdates(ctx sdk.Context) (updates []ab store := ctx.KVStore(k.storeKey) maxValidators := k.GetParams(ctx).MaxValidators - // copy last validator set - last := make(map[[sdk.AddrLen]byte][]byte) - iterator := sdk.KVStorePrefixIterator(store, BondedValidatorsIndexKey) - for ; iterator.Valid(); iterator.Next() { - var operator [sdk.AddrLen]byte - copy(operator[:], iterator.Key()[1:]) - powerBytes := iterator.Value() - last[operator] = make([]byte, len(powerBytes)) - copy(last[operator][:], powerBytes[:]) - } + // retrieve last validator set + last := k.retrieveLastValidatorSet(ctx) - iterator = sdk.KVStoreReversePrefixIterator(store, ValidatorsByPowerIndexKey) + // iterate over validators, highest power to lowest + iterator := sdk.KVStoreReversePrefixIterator(store, ValidatorsByPowerIndexKey) count := 0 for ; iterator.Valid() && count < int(maxValidators); iterator.Next() { @@ -74,7 +64,7 @@ func (k Keeper) ApplyAndReturnValidatorSetUpdates(ctx sdk.Context) (updates []ab updates = append(updates, validator.ABCIValidatorUpdate()) } - // validator still in the validator set + // validator still in the validator set, so delete from the copy delete(last, opbytes) // set the bonded validator index @@ -85,23 +75,12 @@ func (k Keeper) ApplyAndReturnValidatorSetUpdates(ctx sdk.Context) (updates []ab } - // sort the map keys for determinism - // sorted by address - order doesn't matter - noLongerBonded := make([][]byte, len(last)) - index := 0 - for oper := range last { - operator := make([]byte, sdk.AddrLen) - copy(operator[:], oper[:]) - noLongerBonded[index] = operator - index++ - } - sort.SliceStable(noLongerBonded, func(i, j int) bool { - return bytes.Compare(noLongerBonded[i], noLongerBonded[j]) == -1 - }) + // sort the no-longer-bonded validators + noLongerBonded := k.sortNoLongerBonded(last) // iterate through the sorted no-longer-bonded validators - // any validators left in `last` are no longer bonded for _, operator := range noLongerBonded { + // fetch the validator validator := k.mustGetValidator(ctx, sdk.ValAddress(operator)) @@ -116,8 +95,9 @@ func (k Keeper) ApplyAndReturnValidatorSetUpdates(ctx sdk.Context) (updates []ab // delete from the bonded validator index store.Delete(GetBondedValidatorIndexKey(operator)) - // update the validator + // update the validator set updates = append(updates, validator.ABCIValidatorUpdateZero()) + } return updates @@ -256,3 +236,36 @@ func (k Keeper) completeUnbondingValidator(ctx sdk.Context, validator types.Vali k.SetValidator(ctx, validator) return validator } + +// retrieve the last validator set +func (k Keeper) retrieveLastValidatorSet(ctx sdk.Context) map[[sdk.AddrLen]byte][]byte { + last := make(map[[sdk.AddrLen]byte][]byte) + store := ctx.KVStore(k.storeKey) + iterator := sdk.KVStorePrefixIterator(store, BondedValidatorsIndexKey) + for ; iterator.Valid(); iterator.Next() { + var operator [sdk.AddrLen]byte + copy(operator[:], iterator.Key()[1:]) + powerBytes := iterator.Value() + last[operator] = make([]byte, len(powerBytes)) + copy(last[operator][:], powerBytes[:]) + } + return last +} + +// sort the validators to be unbonded +func (k Keeper) sortNoLongerBonded(last map[[sdk.AddrLen]byte][]byte) [][]byte { + // sort the map keys for determinism + noLongerBonded := make([][]byte, len(last)) + index := 0 + for oper := range last { + operator := make([]byte, sdk.AddrLen) + copy(operator[:], oper[:]) + noLongerBonded[index] = operator + index++ + } + // sorted by address - order doesn't matter + sort.SliceStable(noLongerBonded, func(i, j int) bool { + return bytes.Compare(noLongerBonded[i], noLongerBonded[j]) == -1 + }) + return noLongerBonded +} From 54d5ce80a6fc073d566ecb874af806f38a0a5019 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Tue, 2 Oct 2018 10:37:56 +0200 Subject: [PATCH 31/44] Remove jailed validators from the power store entirely --- x/stake/handler_test.go | 1 + x/stake/keeper/delegation_test.go | 9 +++++++-- x/stake/keeper/key.go | 10 +--------- x/stake/keeper/val_state_change.go | 20 ++++++++------------ x/stake/keeper/validator.go | 4 ++++ 5 files changed, 21 insertions(+), 23 deletions(-) diff --git a/x/stake/handler_test.go b/x/stake/handler_test.go index 7c97b8190af7..7513b0881e2e 100644 --- a/x/stake/handler_test.go +++ b/x/stake/handler_test.go @@ -100,6 +100,7 @@ func TestValidatorByPowerIndex(t *testing.T) { require.True(t, found) require.Equal(t, sdk.Unbonding, validator.Status) // ensure is unbonding require.Equal(t, int64(500000), validator.Tokens.RoundInt64()) // ensure tokens slashed + keeper.Unjail(ctx, consAddr0) // the old power record should have been deleted as the power changed require.False(t, keep.ValidatorByPowerIndexExists(ctx, keeper, power)) diff --git a/x/stake/keeper/delegation_test.go b/x/stake/keeper/delegation_test.go index 6197935746a2..ab79022d8c4a 100644 --- a/x/stake/keeper/delegation_test.go +++ b/x/stake/keeper/delegation_test.go @@ -236,6 +236,7 @@ func TestUndelegateSelfDelegation(t *testing.T) { keeper.SetDelegation(ctx, selfDelegation) // create a second delegation to this validator + keeper.DeleteValidatorByPowerIndex(ctx, validator, pool) validator, pool, issuedShares = validator.AddTokensFromDel(pool, sdk.NewInt(10)) require.Equal(t, int64(10), issuedShares.RoundInt64()) keeper.SetPool(ctx, pool) @@ -283,6 +284,7 @@ func TestUndelegateFromUnbondingValidator(t *testing.T) { keeper.SetDelegation(ctx, selfDelegation) // create a second delegation to this validator + keeper.DeleteValidatorByPowerIndex(ctx, validator, pool) validator, pool, issuedShares = validator.AddTokensFromDel(pool, sdk.NewInt(10)) require.Equal(t, int64(10), issuedShares.RoundInt64()) keeper.SetPool(ctx, pool) @@ -359,6 +361,7 @@ func TestUndelegateFromUnbondedValidator(t *testing.T) { keeper.SetDelegation(ctx, selfDelegation) // create a second delegation to this validator + keeper.DeleteValidatorByPowerIndex(ctx, validator, pool) validator, pool, issuedShares = validator.AddTokensFromDel(pool, sdk.NewInt(10)) require.Equal(t, int64(10), issuedShares.RoundInt64()) keeper.SetPool(ctx, pool) @@ -586,6 +589,7 @@ func TestRedelegateFromUnbondingValidator(t *testing.T) { keeper.SetDelegation(ctx, selfDelegation) // create a second delegation to this validator + keeper.DeleteValidatorByPowerIndex(ctx, validator, pool) validator, pool, issuedShares = validator.AddTokensFromDel(pool, sdk.NewInt(10)) require.Equal(t, int64(10), issuedShares.RoundInt64()) keeper.SetPool(ctx, pool) @@ -619,7 +623,7 @@ func TestRedelegateFromUnbondingValidator(t *testing.T) { // end block updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 2, len(updates)) + require.Equal(t, 1, len(updates)) validator, found := keeper.GetValidator(ctx, addrVals[0]) require.True(t, found) @@ -669,6 +673,7 @@ func TestRedelegateFromUnbondedValidator(t *testing.T) { keeper.SetDelegation(ctx, selfDelegation) // create a second delegation to this validator + keeper.DeleteValidatorByPowerIndex(ctx, validator, pool) validator, pool, issuedShares = validator.AddTokensFromDel(pool, sdk.NewInt(10)) validator.BondIntraTxCounter = 1 require.Equal(t, int64(10), issuedShares.RoundInt64()) @@ -704,7 +709,7 @@ func TestRedelegateFromUnbondedValidator(t *testing.T) { // end block updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 2, len(updates)) + require.Equal(t, 1, len(updates)) validator, found := keeper.GetValidator(ctx, addrVals[0]) require.True(t, found) diff --git a/x/stake/keeper/key.go b/x/stake/keeper/key.go index 2de4ac37c794..f6e38a23071a 100644 --- a/x/stake/keeper/key.go +++ b/x/stake/keeper/key.go @@ -75,22 +75,14 @@ func getValidatorPowerRank(validator types.Validator, pool types.Pool) []byte { potentialPower := validator.Tokens powerBytes := []byte(potentialPower.ToLeftPadded(maxDigitsForAccount)) // power big-endian (more powerful validators first) - jailedBytes := make([]byte, 1) - if validator.Jailed { - jailedBytes[0] = byte(0x00) - } else { - jailedBytes[0] = byte(0x01) - } - // heightBytes and counterBytes represent strings like powerBytes does heightBytes := make([]byte, binary.MaxVarintLen64) binary.BigEndian.PutUint64(heightBytes, ^uint64(validator.BondHeight)) // invert height (older validators first) counterBytes := make([]byte, 2) binary.BigEndian.PutUint16(counterBytes, ^uint16(validator.BondIntraTxCounter)) // invert counter (first txns have priority) - return append(append(append(append( + return append(append(append( ValidatorsByPowerIndexKey, - jailedBytes...), powerBytes...), heightBytes...), counterBytes...) diff --git a/x/stake/keeper/val_state_change.go b/x/stake/keeper/val_state_change.go index ae76caf21e65..06782634f062 100644 --- a/x/stake/keeper/val_state_change.go +++ b/x/stake/keeper/val_state_change.go @@ -33,11 +33,13 @@ func (k Keeper) ApplyAndReturnValidatorSetUpdates(ctx sdk.Context) (updates []ab operator := sdk.ValAddress(iterator.Value()) validator := k.mustGetValidator(ctx, operator) - // jailed validators are ranked last, so if we get to a jailed validator - // we have no more bonded validators - // TODO we can remove this if we remove jailed validators from the power store - // likewise for zero-power validators, which we never bond - if validator.Jailed || validator.Tokens.Equal(sdk.ZeroDec()) { + if validator.Jailed { + panic("should never retrieve a jailed validator from the power store") + } + + // if we get to a zero-power validator (which we don't bond), + // there are no more possible bonded validators + if validator.Tokens.Equal(sdk.ZeroDec()) { break } @@ -140,12 +142,9 @@ func (k Keeper) JailValidator(ctx sdk.Context, validator types.Validator) { } pool := k.GetPool(ctx) - k.DeleteValidatorByPowerIndex(ctx, validator, pool) validator.Jailed = true k.SetValidator(ctx, validator) - k.SetValidatorByPowerIndex(ctx, validator, pool) - - // TODO we should be able to just delete the index, and only set it again once unjailed + k.DeleteValidatorByPowerIndex(ctx, validator, pool) } // remove a validator from jail @@ -155,14 +154,11 @@ func (k Keeper) UnjailValidator(ctx sdk.Context, validator types.Validator) { } pool := k.GetPool(ctx) - k.DeleteValidatorByPowerIndex(ctx, validator, pool) validator.Jailed = false k.SetValidator(ctx, validator) k.SetValidatorByPowerIndex(ctx, validator, pool) } -//________________________________________________________________________________________________ - // perform all the store operations for when a validator status becomes bonded func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) types.Validator { diff --git a/x/stake/keeper/validator.go b/x/stake/keeper/validator.go index 568b24a0d527..0b78f2cbf2ec 100644 --- a/x/stake/keeper/validator.go +++ b/x/stake/keeper/validator.go @@ -98,6 +98,10 @@ func (k Keeper) SetValidatorByConsAddr(ctx sdk.Context, validator types.Validato // validator index func (k Keeper) SetValidatorByPowerIndex(ctx sdk.Context, validator types.Validator, pool types.Pool) { + // jailed validators are not kept in the power index + if validator.Jailed { + return + } store := ctx.KVStore(k.storeKey) store.Set(GetBondedValidatorsByPowerIndexKey(validator, pool), validator.OperatorAddr) } From 413fa42c97a27f1149738aa3767946309d2c3a3e Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Tue, 2 Oct 2018 11:40:21 +0200 Subject: [PATCH 32/44] Remove redundant bonded validator store --- x/stake/genesis.go | 4 ---- x/stake/keeper/key.go | 9 +-------- x/stake/keeper/val_state_change.go | 8 +------- x/stake/keeper/validator.go | 12 ------------ x/stake/stake.go | 1 - 5 files changed, 2 insertions(+), 32 deletions(-) diff --git a/x/stake/genesis.go b/x/stake/genesis.go index 45754f34309d..fa81cc03bc6f 100644 --- a/x/stake/genesis.go +++ b/x/stake/genesis.go @@ -34,10 +34,6 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) (res [ // Manually set indexes for the first time keeper.SetValidatorByConsAddr(ctx, validator) keeper.SetValidatorByPowerIndex(ctx, validator, data.Pool) - - if validator.Status == sdk.Bonded { - keeper.SetValidatorBondedIndex(ctx, validator) - } } for _, bond := range data.Bonds { diff --git a/x/stake/keeper/key.go b/x/stake/keeper/key.go index f6e38a23071a..c6b3b6b55082 100644 --- a/x/stake/keeper/key.go +++ b/x/stake/keeper/key.go @@ -25,7 +25,6 @@ var ( RedelegationKey = []byte{0x0A} // key for a redelegation RedelegationByValSrcIndexKey = []byte{0x0B} // prefix for each key for an redelegation, by source validator operator RedelegationByValDstIndexKey = []byte{0x0C} // prefix for each key for an redelegation, by destination validator operator - BondedValidatorsIndexKey = []byte{0x0D} // prefix for each key to the bonded validator set ) const maxDigitsForAccount = 12 // ~220,000,000 atoms created at launch @@ -42,12 +41,6 @@ func GetValidatorByConsAddrKey(addr sdk.ConsAddress) []byte { return append(ValidatorsByConsAddrKey, addr.Bytes()...) } -// gets the key for the current validator group -// VALUE: none (key rearrangement with GetValKeyFromValBondedIndexKey) -func GetValidatorsBondedIndexKey(operatorAddr sdk.ValAddress) []byte { - return append(ValidatorsBondedIndexKey, operatorAddr.Bytes()...) -} - // Get the validator operator address from ValBondedIndexKey func GetAddressFromValBondedIndexKey(IndexKey []byte) []byte { return IndexKey[1:] // remove prefix bytes @@ -64,7 +57,7 @@ func GetBondedValidatorsByPowerIndexKey(validator types.Validator, pool types.Po // get the bonded validator index key for an operator address func GetBondedValidatorIndexKey(operator sdk.ValAddress) []byte { - return append(BondedValidatorsIndexKey, operator...) + return append(ValidatorsBondedIndexKey, operator...) } // get the power ranking of a validator diff --git a/x/stake/keeper/val_state_change.go b/x/stake/keeper/val_state_change.go index 06782634f062..0fbc729787de 100644 --- a/x/stake/keeper/val_state_change.go +++ b/x/stake/keeper/val_state_change.go @@ -162,7 +162,6 @@ func (k Keeper) UnjailValidator(ctx sdk.Context, validator types.Validator) { // perform all the store operations for when a validator status becomes bonded func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) types.Validator { - store := ctx.KVStore(k.storeKey) pool := k.GetPool(ctx) k.DeleteValidatorByPowerIndex(ctx, validator, pool) @@ -175,7 +174,6 @@ func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) types. // save the now bonded validator record to the three referenced stores k.SetValidator(ctx, validator) - store.Set(GetValidatorsBondedIndexKey(validator.OperatorAddr), []byte{}) k.SetValidatorByPowerIndex(ctx, validator, pool) @@ -190,7 +188,6 @@ func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) types. // perform all the store operations for when a validator status begins unbonding func (k Keeper) beginUnbondingValidator(ctx sdk.Context, validator types.Validator) types.Validator { - store := ctx.KVStore(k.storeKey) pool := k.GetPool(ctx) params := k.GetParams(ctx) @@ -211,9 +208,6 @@ func (k Keeper) beginUnbondingValidator(ctx sdk.Context, validator types.Validat // save the now unbonded validator record k.SetValidator(ctx, validator) - // also remove from the Bonded types.Validators Store - store.Delete(GetValidatorsBondedIndexKey(validator.OperatorAddr)) - k.SetValidatorByPowerIndex(ctx, validator, pool) // call the unbond hook if present @@ -237,7 +231,7 @@ func (k Keeper) completeUnbondingValidator(ctx sdk.Context, validator types.Vali func (k Keeper) retrieveLastValidatorSet(ctx sdk.Context) map[[sdk.AddrLen]byte][]byte { last := make(map[[sdk.AddrLen]byte][]byte) store := ctx.KVStore(k.storeKey) - iterator := sdk.KVStorePrefixIterator(store, BondedValidatorsIndexKey) + iterator := sdk.KVStorePrefixIterator(store, ValidatorsBondedIndexKey) for ; iterator.Valid(); iterator.Next() { var operator [sdk.AddrLen]byte copy(operator[:], iterator.Key()[1:]) diff --git a/x/stake/keeper/validator.go b/x/stake/keeper/validator.go index 0b78f2cbf2ec..705c33b7ed7e 100644 --- a/x/stake/keeper/validator.go +++ b/x/stake/keeper/validator.go @@ -119,12 +119,6 @@ func (k Keeper) SetNewValidatorByPowerIndex(ctx sdk.Context, validator types.Val store.Set(GetBondedValidatorsByPowerIndexKey(validator, pool), validator.OperatorAddr) } -// validator index -func (k Keeper) SetValidatorBondedIndex(ctx sdk.Context, validator types.Validator) { - store := ctx.KVStore(k.storeKey) - store.Set(GetValidatorsBondedIndexKey(validator.OperatorAddr), []byte{}) -} - //___________________________________________________________________________ // Update the tokens of an existing validator, update the validators power index key @@ -201,12 +195,6 @@ func (k Keeper) RemoveValidator(ctx sdk.Context, address sdk.ValAddress) { store.Delete(GetValidatorByConsAddrKey(sdk.ConsAddress(validator.ConsPubKey.Address()))) store.Delete(GetBondedValidatorsByPowerIndexKey(validator, pool)) - // delete from the current and power weighted validator groups if the validator - // is bonded - and add validator with zero power to the validator updates - if store.Get(GetValidatorsBondedIndexKey(validator.OperatorAddr)) == nil { - return - } - store.Delete(GetValidatorsBondedIndexKey(validator.OperatorAddr)) } //___________________________________________________________________________ diff --git a/x/stake/stake.go b/x/stake/stake.go index 817f73ca311d..b7ed8be4d027 100644 --- a/x/stake/stake.go +++ b/x/stake/stake.go @@ -37,7 +37,6 @@ var ( GetValidatorKey = keeper.GetValidatorKey GetValidatorByConsAddrKey = keeper.GetValidatorByConsAddrKey - GetValidatorsBondedIndexKey = keeper.GetValidatorsBondedIndexKey GetBondedValidatorsByPowerIndexKey = keeper.GetBondedValidatorsByPowerIndexKey GetDelegationKey = keeper.GetDelegationKey GetDelegationsKey = keeper.GetDelegationsKey From 1c1183a86ec65a052925a42c9f0f3a7b835d0a34 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Tue, 2 Oct 2018 12:05:43 +0200 Subject: [PATCH 33/44] Fix simulator bug --- x/mock/simulation/random_simulate_blocks.go | 17 +++++++---------- x/stake/genesis.go | 2 +- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/x/mock/simulation/random_simulate_blocks.go b/x/mock/simulation/random_simulate_blocks.go index ee93cfea393a..51705cbef098 100644 --- a/x/mock/simulation/random_simulate_blocks.go +++ b/x/mock/simulation/random_simulate_blocks.go @@ -36,12 +36,8 @@ func initChain(r *rand.Rand, accounts []Account, setups []RandSetup, app *baseap res := app.InitChain(abci.RequestInitChain{AppStateBytes: appStateFn(r, accounts)}) validators = make(map[string]mockValidator) for _, validator := range res.Validators { - pubkey, err := tmtypes.PB2TM.PubKey(validator.PubKey) - if err != nil { - panic(err) - } - address := pubkey.Address() - validators[string(address)] = mockValidator{validator, GetMemberOfInitialState(r, initialLivenessWeightings)} + str := fmt.Sprintf("%v", validator.PubKey) + validators[str] = mockValidator{validator, GetMemberOfInitialState(r, initialLivenessWeightings)} } for i := 0; i < len(setups); i++ { @@ -400,22 +396,23 @@ func RandomRequestBeginBlock(r *rand.Rand, validators map[string]mockValidator, func updateValidators(tb testing.TB, r *rand.Rand, current map[string]mockValidator, updates []abci.ValidatorUpdate, event func(string)) map[string]mockValidator { for _, update := range updates { + str := fmt.Sprintf("%v", update.PubKey) switch { case update.Power == 0: - if _, ok := current[string(update.PubKey.Data)]; !ok { + if _, ok := current[str]; !ok { tb.Fatalf("tried to delete a nonexistent validator") } event("endblock/validatorupdates/kicked") - delete(current, string(update.PubKey.Data)) + delete(current, str) default: // Does validator already exist? - if mVal, ok := current[string(update.PubKey.Data)]; ok { + if mVal, ok := current[str]; ok { mVal.val = update event("endblock/validatorupdates/updated") } else { // Set this new validator - current[string(update.PubKey.Data)] = mockValidator{update, GetMemberOfInitialState(r, initialLivenessWeightings)} + current[str] = mockValidator{update, GetMemberOfInitialState(r, initialLivenessWeightings)} event("endblock/validatorupdates/added") } } diff --git a/x/stake/genesis.go b/x/stake/genesis.go index fa81cc03bc6f..e1f33d94cdff 100644 --- a/x/stake/genesis.go +++ b/x/stake/genesis.go @@ -31,7 +31,7 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) (res [ return res, errors.Errorf("genesis validator cannot have zero delegator shares, validator: %v", validator) } - // Manually set indexes for the first time + // Manually set indices for the first time keeper.SetValidatorByConsAddr(ctx, validator) keeper.SetValidatorByPowerIndex(ctx, validator, data.Pool) } From 951cacc46b4cc1c9ca7cb963cac4005430ee4f5e Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Tue, 2 Oct 2018 12:16:34 +0200 Subject: [PATCH 34/44] Change key name to reflect usage --- x/stake/handler_test.go | 6 ++-- x/stake/keeper/key.go | 2 +- x/stake/keeper/val_state_change.go | 3 +- x/stake/keeper/validator.go | 8 ++--- x/stake/keeper/validator_test.go | 4 +-- x/stake/stake.go | 48 +++++++++++++++--------------- 6 files changed, 36 insertions(+), 35 deletions(-) diff --git a/x/stake/handler_test.go b/x/stake/handler_test.go index 7513b0881e2e..0e4a2bf65481 100644 --- a/x/stake/handler_test.go +++ b/x/stake/handler_test.go @@ -79,7 +79,7 @@ func TestValidatorByPowerIndex(t *testing.T) { validator, found := keeper.GetValidator(ctx, validatorAddr) require.True(t, found) pool := keeper.GetPool(ctx) - power := keep.GetBondedValidatorsByPowerIndexKey(validator, pool) + power := keep.GetValidatorsByPowerIndexKey(validator, pool) require.True(t, keep.ValidatorByPowerIndexExists(ctx, keeper, power)) // create a second validator keep it bonded @@ -109,7 +109,7 @@ func TestValidatorByPowerIndex(t *testing.T) { validator, found = keeper.GetValidator(ctx, validatorAddr) require.True(t, found) pool = keeper.GetPool(ctx) - power2 := GetBondedValidatorsByPowerIndexKey(validator, pool) + power2 := GetValidatorsByPowerIndexKey(validator, pool) require.True(t, keep.ValidatorByPowerIndexExists(ctx, keeper, power2)) // inflate a bunch @@ -120,7 +120,7 @@ func TestValidatorByPowerIndex(t *testing.T) { } // now the new record power index should be the same as the original record - power3 := GetBondedValidatorsByPowerIndexKey(validator, pool) + power3 := GetValidatorsByPowerIndexKey(validator, pool) require.Equal(t, power2, power3) // unbond self-delegation diff --git a/x/stake/keeper/key.go b/x/stake/keeper/key.go index c6b3b6b55082..02d54e2b71ae 100644 --- a/x/stake/keeper/key.go +++ b/x/stake/keeper/key.go @@ -50,7 +50,7 @@ func GetAddressFromValBondedIndexKey(IndexKey []byte) []byte { // Power index is the key used in the power-store, and represents the relative // power ranking of the validator. // VALUE: validator operator address ([]byte) -func GetBondedValidatorsByPowerIndexKey(validator types.Validator, pool types.Pool) []byte { +func GetValidatorsByPowerIndexKey(validator types.Validator, pool types.Pool) []byte { // NOTE the address doesn't need to be stored because counter bytes must always be different return getValidatorPowerRank(validator, pool) } diff --git a/x/stake/keeper/val_state_change.go b/x/stake/keeper/val_state_change.go index 0fbc729787de..63b66e8d71d6 100644 --- a/x/stake/keeper/val_state_change.go +++ b/x/stake/keeper/val_state_change.go @@ -39,7 +39,8 @@ func (k Keeper) ApplyAndReturnValidatorSetUpdates(ctx sdk.Context) (updates []ab // if we get to a zero-power validator (which we don't bond), // there are no more possible bonded validators - if validator.Tokens.Equal(sdk.ZeroDec()) { + // note: we must check the ABCI power, since we round before sending to Tendermint + if validator.Tokens.RoundInt64() == int64(0) { break } diff --git a/x/stake/keeper/validator.go b/x/stake/keeper/validator.go index 705c33b7ed7e..927a361a2dd7 100644 --- a/x/stake/keeper/validator.go +++ b/x/stake/keeper/validator.go @@ -103,20 +103,20 @@ func (k Keeper) SetValidatorByPowerIndex(ctx sdk.Context, validator types.Valida return } store := ctx.KVStore(k.storeKey) - store.Set(GetBondedValidatorsByPowerIndexKey(validator, pool), validator.OperatorAddr) + store.Set(GetValidatorsByPowerIndexKey(validator, pool), validator.OperatorAddr) } // validator index func (k Keeper) DeleteValidatorByPowerIndex(ctx sdk.Context, validator types.Validator, pool types.Pool) { store := ctx.KVStore(k.storeKey) - store.Delete(GetBondedValidatorsByPowerIndexKey(validator, pool)) + store.Delete(GetValidatorsByPowerIndexKey(validator, pool)) } // validator index func (k Keeper) SetNewValidatorByPowerIndex(ctx sdk.Context, validator types.Validator) { store := ctx.KVStore(k.storeKey) pool := k.GetPool(ctx) - store.Set(GetBondedValidatorsByPowerIndexKey(validator, pool), validator.OperatorAddr) + store.Set(GetValidatorsByPowerIndexKey(validator, pool), validator.OperatorAddr) } //___________________________________________________________________________ @@ -193,7 +193,7 @@ func (k Keeper) RemoveValidator(ctx sdk.Context, address sdk.ValAddress) { pool := k.GetPool(ctx) store.Delete(GetValidatorKey(address)) store.Delete(GetValidatorByConsAddrKey(sdk.ConsAddress(validator.ConsPubKey.Address()))) - store.Delete(GetBondedValidatorsByPowerIndexKey(validator, pool)) + store.Delete(GetValidatorsByPowerIndexKey(validator, pool)) } diff --git a/x/stake/keeper/validator_test.go b/x/stake/keeper/validator_test.go index b948fb87e517..c422cf803223 100644 --- a/x/stake/keeper/validator_test.go +++ b/x/stake/keeper/validator_test.go @@ -90,7 +90,7 @@ func TestUpdateValidatorByPowerIndex(t *testing.T) { require.Equal(t, int64(100), validator.Tokens.RoundInt64(), "\nvalidator %v\npool %v", validator, pool) pool = keeper.GetPool(ctx) - power := GetBondedValidatorsByPowerIndexKey(validator, pool) + power := GetValidatorsByPowerIndexKey(validator, pool) require.True(t, validatorByPowerIndexExists(keeper, ctx, power)) // burn half the delegator shares @@ -104,7 +104,7 @@ func TestUpdateValidatorByPowerIndex(t *testing.T) { pool = keeper.GetPool(ctx) validator, found = keeper.GetValidator(ctx, addrVals[0]) require.True(t, found) - power = GetBondedValidatorsByPowerIndexKey(validator, pool) + power = GetValidatorsByPowerIndexKey(validator, pool) require.True(t, validatorByPowerIndexExists(keeper, ctx, power)) } diff --git a/x/stake/stake.go b/x/stake/stake.go index b7ed8be4d027..a9a3ca3cd544 100644 --- a/x/stake/stake.go +++ b/x/stake/stake.go @@ -35,30 +35,30 @@ type ( var ( NewKeeper = keeper.NewKeeper - GetValidatorKey = keeper.GetValidatorKey - GetValidatorByConsAddrKey = keeper.GetValidatorByConsAddrKey - GetBondedValidatorsByPowerIndexKey = keeper.GetBondedValidatorsByPowerIndexKey - GetDelegationKey = keeper.GetDelegationKey - GetDelegationsKey = keeper.GetDelegationsKey - ParamKey = keeper.ParamKey - PoolKey = keeper.PoolKey - ValidatorsKey = keeper.ValidatorsKey - ValidatorsByConsAddrKey = keeper.ValidatorsByConsAddrKey - ValidatorsBondedIndexKey = keeper.ValidatorsBondedIndexKey - ValidatorsByPowerIndexKey = keeper.ValidatorsByPowerIndexKey - DelegationKey = keeper.DelegationKey - IntraTxCounterKey = keeper.IntraTxCounterKey - GetUBDKey = keeper.GetUBDKey - GetUBDByValIndexKey = keeper.GetUBDByValIndexKey - GetUBDsKey = keeper.GetUBDsKey - GetUBDsByValIndexKey = keeper.GetUBDsByValIndexKey - GetREDKey = keeper.GetREDKey - GetREDByValSrcIndexKey = keeper.GetREDByValSrcIndexKey - GetREDByValDstIndexKey = keeper.GetREDByValDstIndexKey - GetREDsKey = keeper.GetREDsKey - GetREDsFromValSrcIndexKey = keeper.GetREDsFromValSrcIndexKey - GetREDsToValDstIndexKey = keeper.GetREDsToValDstIndexKey - GetREDsByDelToValDstIndexKey = keeper.GetREDsByDelToValDstIndexKey + GetValidatorKey = keeper.GetValidatorKey + GetValidatorByConsAddrKey = keeper.GetValidatorByConsAddrKey + GetValidatorsByPowerIndexKey = keeper.GetValidatorsByPowerIndexKey + GetDelegationKey = keeper.GetDelegationKey + GetDelegationsKey = keeper.GetDelegationsKey + ParamKey = keeper.ParamKey + PoolKey = keeper.PoolKey + ValidatorsKey = keeper.ValidatorsKey + ValidatorsByConsAddrKey = keeper.ValidatorsByConsAddrKey + ValidatorsBondedIndexKey = keeper.ValidatorsBondedIndexKey + ValidatorsByPowerIndexKey = keeper.ValidatorsByPowerIndexKey + DelegationKey = keeper.DelegationKey + IntraTxCounterKey = keeper.IntraTxCounterKey + GetUBDKey = keeper.GetUBDKey + GetUBDByValIndexKey = keeper.GetUBDByValIndexKey + GetUBDsKey = keeper.GetUBDsKey + GetUBDsByValIndexKey = keeper.GetUBDsByValIndexKey + GetREDKey = keeper.GetREDKey + GetREDByValSrcIndexKey = keeper.GetREDByValSrcIndexKey + GetREDByValDstIndexKey = keeper.GetREDByValDstIndexKey + GetREDsKey = keeper.GetREDsKey + GetREDsFromValSrcIndexKey = keeper.GetREDsFromValSrcIndexKey + GetREDsToValDstIndexKey = keeper.GetREDsToValDstIndexKey + GetREDsByDelToValDstIndexKey = keeper.GetREDsByDelToValDstIndexKey DefaultParams = types.DefaultParams InitialPool = types.InitialPool From 8e67f6d1b67f972b3e43cfc17889ee665efe2be3 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Wed, 3 Oct 2018 02:27:51 +0200 Subject: [PATCH 35/44] updateValidator -> testingUpdateValidator --- x/stake/keeper/delegation_test.go | 38 ++++++------ x/stake/keeper/slash_test.go | 2 +- x/stake/keeper/test_common.go | 2 +- x/stake/keeper/validator_test.go | 98 +++++++++++++++---------------- 4 files changed, 70 insertions(+), 70 deletions(-) diff --git a/x/stake/keeper/delegation_test.go b/x/stake/keeper/delegation_test.go index ab79022d8c4a..863c08a9674c 100644 --- a/x/stake/keeper/delegation_test.go +++ b/x/stake/keeper/delegation_test.go @@ -25,9 +25,9 @@ func TestDelegation(t *testing.T) { } keeper.SetPool(ctx, pool) - validators[0] = updateValidator(keeper, ctx, validators[0]) - validators[1] = updateValidator(keeper, ctx, validators[1]) - validators[2] = updateValidator(keeper, ctx, validators[2]) + validators[0] = testingUpdateValidator(keeper, ctx, validators[0]) + validators[1] = testingUpdateValidator(keeper, ctx, validators[1]) + validators[2] = testingUpdateValidator(keeper, ctx, validators[2]) // first add a validators[0] to delegate too @@ -184,7 +184,7 @@ func TestUnbondDelegation(t *testing.T) { validator, pool, issuedShares := validator.AddTokensFromDel(pool, sdk.NewInt(10)) require.Equal(t, int64(10), issuedShares.RoundInt64()) keeper.SetPool(ctx, pool) - validator = updateValidator(keeper, ctx, validator) + validator = testingUpdateValidator(keeper, ctx, validator) pool = keeper.GetPool(ctx) require.Equal(t, int64(10), pool.BondedTokens.RoundInt64()) @@ -226,7 +226,7 @@ func TestUndelegateSelfDelegation(t *testing.T) { validator, pool, issuedShares := validator.AddTokensFromDel(pool, sdk.NewInt(10)) require.Equal(t, int64(10), issuedShares.RoundInt64()) keeper.SetPool(ctx, pool) - validator = updateValidator(keeper, ctx, validator) + validator = testingUpdateValidator(keeper, ctx, validator) pool = keeper.GetPool(ctx) selfDelegation := types.Delegation{ DelegatorAddr: sdk.AccAddress(addrVals[0].Bytes()), @@ -240,7 +240,7 @@ func TestUndelegateSelfDelegation(t *testing.T) { validator, pool, issuedShares = validator.AddTokensFromDel(pool, sdk.NewInt(10)) require.Equal(t, int64(10), issuedShares.RoundInt64()) keeper.SetPool(ctx, pool) - validator = updateValidator(keeper, ctx, validator) + validator = testingUpdateValidator(keeper, ctx, validator) pool = keeper.GetPool(ctx) delegation := types.Delegation{ DelegatorAddr: addrDels[0], @@ -274,7 +274,7 @@ func TestUndelegateFromUnbondingValidator(t *testing.T) { validator, pool, issuedShares := validator.AddTokensFromDel(pool, sdk.NewInt(10)) require.Equal(t, int64(10), issuedShares.RoundInt64()) keeper.SetPool(ctx, pool) - validator = updateValidator(keeper, ctx, validator) + validator = testingUpdateValidator(keeper, ctx, validator) pool = keeper.GetPool(ctx) selfDelegation := types.Delegation{ DelegatorAddr: sdk.AccAddress(addrVals[0].Bytes()), @@ -288,7 +288,7 @@ func TestUndelegateFromUnbondingValidator(t *testing.T) { validator, pool, issuedShares = validator.AddTokensFromDel(pool, sdk.NewInt(10)) require.Equal(t, int64(10), issuedShares.RoundInt64()) keeper.SetPool(ctx, pool) - validator = updateValidator(keeper, ctx, validator) + validator = testingUpdateValidator(keeper, ctx, validator) pool = keeper.GetPool(ctx) delegation := types.Delegation{ DelegatorAddr: addrDels[0], @@ -350,7 +350,7 @@ func TestUndelegateFromUnbondedValidator(t *testing.T) { validator, pool, issuedShares := validator.AddTokensFromDel(pool, sdk.NewInt(10)) require.Equal(t, int64(10), issuedShares.RoundInt64()) keeper.SetPool(ctx, pool) - validator = updateValidator(keeper, ctx, validator) + validator = testingUpdateValidator(keeper, ctx, validator) pool = keeper.GetPool(ctx) val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) selfDelegation := types.Delegation{ @@ -365,7 +365,7 @@ func TestUndelegateFromUnbondedValidator(t *testing.T) { validator, pool, issuedShares = validator.AddTokensFromDel(pool, sdk.NewInt(10)) require.Equal(t, int64(10), issuedShares.RoundInt64()) keeper.SetPool(ctx, pool) - validator = updateValidator(keeper, ctx, validator) + validator = testingUpdateValidator(keeper, ctx, validator) pool = keeper.GetPool(ctx) delegation := types.Delegation{ DelegatorAddr: addrDels[0], @@ -521,7 +521,7 @@ func TestRedelegateSelfDelegation(t *testing.T) { validator, pool, issuedShares := validator.AddTokensFromDel(pool, sdk.NewInt(10)) require.Equal(t, int64(10), issuedShares.RoundInt64()) keeper.SetPool(ctx, pool) - validator = updateValidator(keeper, ctx, validator) + validator = testingUpdateValidator(keeper, ctx, validator) pool = keeper.GetPool(ctx) val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) selfDelegation := types.Delegation{ @@ -537,14 +537,14 @@ func TestRedelegateSelfDelegation(t *testing.T) { require.Equal(t, int64(10), issuedShares.RoundInt64()) pool.BondedTokens = pool.BondedTokens.Add(sdk.NewDec(10)) keeper.SetPool(ctx, pool) - validator2 = updateValidator(keeper, ctx, validator2) + validator2 = testingUpdateValidator(keeper, ctx, validator2) require.Equal(t, sdk.Bonded, validator2.Status) // create a second delegation to this validator validator, pool, issuedShares = validator.AddTokensFromDel(pool, sdk.NewInt(10)) require.Equal(t, int64(10), issuedShares.RoundInt64()) keeper.SetPool(ctx, pool) - validator = updateValidator(keeper, ctx, validator) + validator = testingUpdateValidator(keeper, ctx, validator) pool = keeper.GetPool(ctx) delegation := types.Delegation{ DelegatorAddr: addrDels[0], @@ -578,7 +578,7 @@ func TestRedelegateFromUnbondingValidator(t *testing.T) { validator, pool, issuedShares := validator.AddTokensFromDel(pool, sdk.NewInt(10)) require.Equal(t, int64(10), issuedShares.RoundInt64()) keeper.SetPool(ctx, pool) - validator = updateValidator(keeper, ctx, validator) + validator = testingUpdateValidator(keeper, ctx, validator) pool = keeper.GetPool(ctx) val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) selfDelegation := types.Delegation{ @@ -593,7 +593,7 @@ func TestRedelegateFromUnbondingValidator(t *testing.T) { validator, pool, issuedShares = validator.AddTokensFromDel(pool, sdk.NewInt(10)) require.Equal(t, int64(10), issuedShares.RoundInt64()) keeper.SetPool(ctx, pool) - validator = updateValidator(keeper, ctx, validator) + validator = testingUpdateValidator(keeper, ctx, validator) pool = keeper.GetPool(ctx) delegation := types.Delegation{ DelegatorAddr: addrDels[0], @@ -608,7 +608,7 @@ func TestRedelegateFromUnbondingValidator(t *testing.T) { validator2, pool, issuedShares = validator2.AddTokensFromDel(pool, sdk.NewInt(10)) require.Equal(t, int64(10), issuedShares.RoundInt64()) keeper.SetPool(ctx, pool) - validator2 = updateValidator(keeper, ctx, validator2) + validator2 = testingUpdateValidator(keeper, ctx, validator2) header := ctx.BlockHeader() blockHeight := int64(10) @@ -662,7 +662,7 @@ func TestRedelegateFromUnbondedValidator(t *testing.T) { validator, pool, issuedShares := validator.AddTokensFromDel(pool, sdk.NewInt(10)) require.Equal(t, int64(10), issuedShares.RoundInt64()) keeper.SetPool(ctx, pool) - validator = updateValidator(keeper, ctx, validator) + validator = testingUpdateValidator(keeper, ctx, validator) pool = keeper.GetPool(ctx) val0AccAddr := sdk.AccAddress(addrVals[0].Bytes()) selfDelegation := types.Delegation{ @@ -678,7 +678,7 @@ func TestRedelegateFromUnbondedValidator(t *testing.T) { validator.BondIntraTxCounter = 1 require.Equal(t, int64(10), issuedShares.RoundInt64()) keeper.SetPool(ctx, pool) - validator = updateValidator(keeper, ctx, validator) + validator = testingUpdateValidator(keeper, ctx, validator) pool = keeper.GetPool(ctx) delegation := types.Delegation{ DelegatorAddr: addrDels[0], @@ -693,7 +693,7 @@ func TestRedelegateFromUnbondedValidator(t *testing.T) { validator2, pool, issuedShares = validator2.AddTokensFromDel(pool, sdk.NewInt(10)) require.Equal(t, int64(10), issuedShares.RoundInt64()) keeper.SetPool(ctx, pool) - validator2 = updateValidator(keeper, ctx, validator2) + validator2 = testingUpdateValidator(keeper, ctx, validator2) require.Equal(t, sdk.Bonded, validator2.Status) header := ctx.BlockHeader() diff --git a/x/stake/keeper/slash_test.go b/x/stake/keeper/slash_test.go index 70c456a02994..7959679c6fbf 100644 --- a/x/stake/keeper/slash_test.go +++ b/x/stake/keeper/slash_test.go @@ -29,7 +29,7 @@ func setupHelper(t *testing.T, amt int64) (sdk.Context, Keeper, types.Params) { validator.BondIntraTxCounter = int16(i) pool.BondedTokens = pool.BondedTokens.Add(sdk.NewDec(amt)) keeper.SetPool(ctx, pool) - validator = updateValidator(keeper, ctx, validator) + validator = testingUpdateValidator(keeper, ctx, validator) keeper.SetValidatorByConsAddr(ctx, validator) } pool = keeper.GetPool(ctx) diff --git a/x/stake/keeper/test_common.go b/x/stake/keeper/test_common.go index 5cfbf603118c..8f5b2fa3967f 100644 --- a/x/stake/keeper/test_common.go +++ b/x/stake/keeper/test_common.go @@ -205,7 +205,7 @@ func ValidatorByPowerIndexExists(ctx sdk.Context, keeper Keeper, power []byte) b return store.Has(power) } -func updateValidator(keeper Keeper, ctx sdk.Context, validator types.Validator) types.Validator { +func testingUpdateValidator(keeper Keeper, ctx sdk.Context, validator types.Validator) types.Validator { pool := keeper.GetPool(ctx) keeper.SetValidator(ctx, validator) keeper.SetValidatorByPowerIndex(ctx, validator, pool) diff --git a/x/stake/keeper/validator_test.go b/x/stake/keeper/validator_test.go index c422cf803223..0b18178fc81f 100644 --- a/x/stake/keeper/validator_test.go +++ b/x/stake/keeper/validator_test.go @@ -84,7 +84,7 @@ func TestUpdateValidatorByPowerIndex(t *testing.T) { require.Equal(t, sdk.Unbonded, validator.Status) require.Equal(t, int64(100), validator.Tokens.RoundInt64()) keeper.SetPool(ctx, pool) - updateValidator(keeper, ctx, validator) + testingUpdateValidator(keeper, ctx, validator) validator, found := keeper.GetValidator(ctx, addrVals[0]) require.True(t, found) require.Equal(t, int64(100), validator.Tokens.RoundInt64(), "\nvalidator %v\npool %v", validator, pool) @@ -98,7 +98,7 @@ func TestUpdateValidatorByPowerIndex(t *testing.T) { validator, pool, burned := validator.RemoveDelShares(pool, delSharesCreated.Quo(sdk.NewDec(2))) require.Equal(t, int64(50), burned.RoundInt64()) keeper.SetPool(ctx, pool) // update the pool - updateValidator(keeper, ctx, validator) // update the validator, possibly kicking it out + testingUpdateValidator(keeper, ctx, validator) // update the validator, possibly kicking it out require.False(t, validatorByPowerIndexExists(keeper, ctx, power)) pool = keeper.GetPool(ctx) @@ -135,7 +135,7 @@ func TestUpdateBondedValidatorsDecreaseCliff(t *testing.T) { val, pool, _ = val.AddTokensFromDel(pool, sdk.NewInt(int64((i+1)*10))) keeper.SetPool(ctx, pool) - val = updateValidator(keeper, ctx, val) + val = testingUpdateValidator(keeper, ctx, val) validators[i] = val } @@ -146,7 +146,7 @@ func TestUpdateBondedValidatorsDecreaseCliff(t *testing.T) { keeper.DeleteValidatorByPowerIndex(ctx, nextCliffVal, pool) nextCliffVal, pool, _ = nextCliffVal.RemoveDelShares(pool, sdk.NewDec(21)) keeper.SetPool(ctx, pool) - nextCliffVal = updateValidator(keeper, ctx, nextCliffVal) + nextCliffVal = testingUpdateValidator(keeper, ctx, nextCliffVal) expectedValStatus := map[int]sdk.BondStatus{ 9: sdk.Bonded, 8: sdk.Bonded, 7: sdk.Bonded, 5: sdk.Bonded, 4: sdk.Bonded, @@ -178,7 +178,7 @@ func TestSlashToZeroPowerRemoved(t *testing.T) { require.Equal(t, int64(100), validator.Tokens.RoundInt64()) keeper.SetPool(ctx, pool) keeper.SetValidatorByConsAddr(ctx, validator) - validator = updateValidator(keeper, ctx, validator) + validator = testingUpdateValidator(keeper, ctx, validator) require.Equal(t, int64(100), validator.Tokens.RoundInt64(), "\nvalidator %v\npool %v", validator, pool) // slash the validator by 100% @@ -223,7 +223,7 @@ func TestValidatorBasics(t *testing.T) { assert.True(sdk.DecEq(t, sdk.ZeroDec(), pool.BondedTokens)) // set and retrieve a record - validators[0] = updateValidator(keeper, ctx, validators[0]) + validators[0] = testingUpdateValidator(keeper, ctx, validators[0]) keeper.SetValidatorByConsAddr(ctx, validators[0]) resVal, found := keeper.GetValidator(ctx, addrVals[0]) require.True(t, found) @@ -250,7 +250,7 @@ func TestValidatorBasics(t *testing.T) { validators[0].Status = sdk.Bonded validators[0].Tokens = sdk.NewDec(10) validators[0].DelegatorShares = sdk.NewDec(10) - validators[0] = updateValidator(keeper, ctx, validators[0]) + validators[0] = testingUpdateValidator(keeper, ctx, validators[0]) resVal, found = keeper.GetValidator(ctx, addrVals[0]) require.True(t, found) assert.True(ValEq(t, validators[0], resVal)) @@ -260,8 +260,8 @@ func TestValidatorBasics(t *testing.T) { assert.True(ValEq(t, validators[0], resVals[0])) // add other validators - validators[1] = updateValidator(keeper, ctx, validators[1]) - validators[2] = updateValidator(keeper, ctx, validators[2]) + validators[1] = testingUpdateValidator(keeper, ctx, validators[1]) + validators[2] = testingUpdateValidator(keeper, ctx, validators[2]) resVal, found = keeper.GetValidator(ctx, addrVals[1]) require.True(t, found) assert.True(ValEq(t, validators[1], resVal)) @@ -294,7 +294,7 @@ func GetValidatorSortingUnmixed(t *testing.T) { validators[i].Status = sdk.Bonded validators[i].Tokens = sdk.NewDec(amt) validators[i].DelegatorShares = sdk.NewDec(amt) - updateValidator(keeper, ctx, validators[i]) + testingUpdateValidator(keeper, ctx, validators[i]) } // first make sure everything made it in to the gotValidator group @@ -313,14 +313,14 @@ func GetValidatorSortingUnmixed(t *testing.T) { // test a basic increase in voting power validators[3].Tokens = sdk.NewDec(500) - updateValidator(keeper, ctx, validators[3]) + testingUpdateValidator(keeper, ctx, validators[3]) resValidators = keeper.GetBondedValidatorsByPower(ctx) require.Equal(t, len(resValidators), n) assert.True(ValEq(t, validators[3], resValidators[0])) // test a decrease in voting power validators[3].Tokens = sdk.NewDec(300) - updateValidator(keeper, ctx, validators[3]) + testingUpdateValidator(keeper, ctx, validators[3]) resValidators = keeper.GetBondedValidatorsByPower(ctx) require.Equal(t, len(resValidators), n) assert.True(ValEq(t, validators[3], resValidators[0])) @@ -329,7 +329,7 @@ func GetValidatorSortingUnmixed(t *testing.T) { // test equal voting power, different age validators[3].Tokens = sdk.NewDec(200) ctx = ctx.WithBlockHeight(10) - updateValidator(keeper, ctx, validators[3]) + testingUpdateValidator(keeper, ctx, validators[3]) resValidators = keeper.GetBondedValidatorsByPower(ctx) require.Equal(t, len(resValidators), n) assert.True(ValEq(t, validators[3], resValidators[0])) @@ -339,7 +339,7 @@ func GetValidatorSortingUnmixed(t *testing.T) { // no change in voting power - no change in sort ctx = ctx.WithBlockHeight(20) - updateValidator(keeper, ctx, validators[4]) + testingUpdateValidator(keeper, ctx, validators[4]) resValidators = keeper.GetBondedValidatorsByPower(ctx) require.Equal(t, len(resValidators), n) assert.True(ValEq(t, validators[3], resValidators[0])) @@ -348,11 +348,11 @@ func GetValidatorSortingUnmixed(t *testing.T) { // change in voting power of both validators, both still in v-set, no age change validators[3].Tokens = sdk.NewDec(300) validators[4].Tokens = sdk.NewDec(300) - updateValidator(keeper, ctx, validators[3]) + testingUpdateValidator(keeper, ctx, validators[3]) resValidators = keeper.GetBondedValidatorsByPower(ctx) require.Equal(t, len(resValidators), n) ctx = ctx.WithBlockHeight(30) - updateValidator(keeper, ctx, validators[4]) + testingUpdateValidator(keeper, ctx, validators[4]) resValidators = keeper.GetBondedValidatorsByPower(ctx) require.Equal(t, len(resValidators), n, "%v", resValidators) assert.True(ValEq(t, validators[3], resValidators[0])) @@ -390,7 +390,7 @@ func GetValidatorSortingMixed(t *testing.T) { validators[4].Tokens = sdk.NewDec(amts[4]) for i := range amts { - updateValidator(keeper, ctx, validators[i]) + testingUpdateValidator(keeper, ctx, validators[i]) } val0, found := keeper.GetValidator(ctx, sdk.ValAddress(Addrs[0])) require.True(t, found) @@ -444,7 +444,7 @@ func TestGetValidatorsEdgeCases(t *testing.T) { validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt)) validators[i].BondIntraTxCounter = int16(i) keeper.SetPool(ctx, pool) - validators[i] = updateValidator(keeper, ctx, validators[i]) + validators[i] = testingUpdateValidator(keeper, ctx, validators[i]) } for i := range amts { @@ -460,7 +460,7 @@ func TestGetValidatorsEdgeCases(t *testing.T) { keeper.DeleteValidatorByPowerIndex(ctx, validators[0], pool) validators[0], pool, _ = validators[0].AddTokensFromDel(pool, sdk.NewInt(500)) keeper.SetPool(ctx, pool) - validators[0] = updateValidator(keeper, ctx, validators[0]) + validators[0] = testingUpdateValidator(keeper, ctx, validators[0]) resValidators = keeper.GetBondedValidatorsByPower(ctx) require.Equal(t, nMax, uint16(len(resValidators))) assert.True(ValEq(t, validators[0], resValidators[0])) @@ -478,7 +478,7 @@ func TestGetValidatorsEdgeCases(t *testing.T) { keeper.DeleteValidatorByPowerIndex(ctx, validators[3], pool) validators[3], pool, _ = validators[3].AddTokensFromDel(pool, sdk.NewInt(1)) keeper.SetPool(ctx, pool) - validators[3] = updateValidator(keeper, ctx, validators[3]) + validators[3] = testingUpdateValidator(keeper, ctx, validators[3]) resValidators = keeper.GetBondedValidatorsByPower(ctx) require.Equal(t, nMax, uint16(len(resValidators))) assert.True(ValEq(t, validators[0], resValidators[0])) @@ -488,7 +488,7 @@ func TestGetValidatorsEdgeCases(t *testing.T) { keeper.DeleteValidatorByPowerIndex(ctx, validators[3], pool) validators[3], pool, _ = validators[3].RemoveDelShares(pool, sdk.NewDec(201)) keeper.SetPool(ctx, pool) - validators[3] = updateValidator(keeper, ctx, validators[3]) + validators[3] = testingUpdateValidator(keeper, ctx, validators[3]) resValidators = keeper.GetBondedValidatorsByPower(ctx) require.Equal(t, nMax, uint16(len(resValidators))) assert.True(ValEq(t, validators[0], resValidators[0])) @@ -498,7 +498,7 @@ func TestGetValidatorsEdgeCases(t *testing.T) { keeper.DeleteValidatorByPowerIndex(ctx, validators[3], pool) validators[3], pool, _ = validators[3].AddTokensFromDel(pool, sdk.NewInt(200)) keeper.SetPool(ctx, pool) - validators[3] = updateValidator(keeper, ctx, validators[3]) + validators[3] = testingUpdateValidator(keeper, ctx, validators[3]) resValidators = keeper.GetBondedValidatorsByPower(ctx) require.Equal(t, nMax, uint16(len(resValidators))) assert.True(ValEq(t, validators[0], resValidators[0])) @@ -531,13 +531,13 @@ func TestValidatorBondHeight(t *testing.T) { validators[2], pool, _ = validators[2].AddTokensFromDel(pool, sdk.NewInt(100)) keeper.SetPool(ctx, pool) - validators[0] = updateValidator(keeper, ctx, validators[0]) + validators[0] = testingUpdateValidator(keeper, ctx, validators[0]) //////////////////////////////////////// // If two validators both increase to the same voting power in the same block, // the one with the first transaction should become bonded - validators[1] = updateValidator(keeper, ctx, validators[1]) - validators[2] = updateValidator(keeper, ctx, validators[2]) + validators[1] = testingUpdateValidator(keeper, ctx, validators[1]) + validators[2] = testingUpdateValidator(keeper, ctx, validators[2]) pool = keeper.GetPool(ctx) @@ -551,10 +551,10 @@ func TestValidatorBondHeight(t *testing.T) { validators[1], pool, _ = validators[1].AddTokensFromDel(pool, sdk.NewInt(50)) validators[2], pool, _ = validators[2].AddTokensFromDel(pool, sdk.NewInt(50)) keeper.SetPool(ctx, pool) - validators[2] = updateValidator(keeper, ctx, validators[2]) + validators[2] = testingUpdateValidator(keeper, ctx, validators[2]) resValidators = keeper.GetBondedValidatorsByPower(ctx) require.Equal(t, params.MaxValidators, uint16(len(resValidators))) - validators[1] = updateValidator(keeper, ctx, validators[1]) + validators[1] = testingUpdateValidator(keeper, ctx, validators[1]) assert.True(ValEq(t, validators[0], resValidators[0])) assert.True(ValEq(t, validators[2], resValidators[1])) } @@ -575,7 +575,7 @@ func TestFullValidatorSetPowerChange(t *testing.T) { validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt)) validators[i].BondIntraTxCounter = int16(i) keeper.SetPool(ctx, pool) - updateValidator(keeper, ctx, validators[i]) + testingUpdateValidator(keeper, ctx, validators[i]) } for i := range amts { var found bool @@ -596,7 +596,7 @@ func TestFullValidatorSetPowerChange(t *testing.T) { pool := keeper.GetPool(ctx) validators[0], pool, _ = validators[0].AddTokensFromDel(pool, sdk.NewInt(600)) keeper.SetPool(ctx, pool) - validators[0] = updateValidator(keeper, ctx, validators[0]) + validators[0] = testingUpdateValidator(keeper, ctx, validators[0]) resValidators = keeper.GetBondedValidatorsByPower(ctx) assert.Equal(t, max, len(resValidators)) assert.True(ValEq(t, validators[0], resValidators[0])) @@ -647,14 +647,14 @@ func TestApplyAndReturnValidatorSetUpdatesIdentical(t *testing.T) { validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt)) keeper.SetPool(ctx, pool) } - validators[0] = updateValidator(keeper, ctx, validators[0]) - validators[1] = updateValidator(keeper, ctx, validators[1]) + validators[0] = testingUpdateValidator(keeper, ctx, validators[0]) + validators[1] = testingUpdateValidator(keeper, ctx, validators[1]) require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) // test identical, // tendermintUpdate set: {} -> {} - validators[0] = updateValidator(keeper, ctx, validators[0]) - validators[1] = updateValidator(keeper, ctx, validators[1]) + validators[0] = testingUpdateValidator(keeper, ctx, validators[0]) + validators[1] = testingUpdateValidator(keeper, ctx, validators[1]) require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) } @@ -669,15 +669,15 @@ func TestApplyAndReturnValidatorSetUpdatesSingleValueChange(t *testing.T) { validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt)) keeper.SetPool(ctx, pool) } - validators[0] = updateValidator(keeper, ctx, validators[0]) - validators[1] = updateValidator(keeper, ctx, validators[1]) + validators[0] = testingUpdateValidator(keeper, ctx, validators[0]) + validators[1] = testingUpdateValidator(keeper, ctx, validators[1]) require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) // test single value change // tendermintUpdate set: {} -> {c1'} validators[0].Status = sdk.Bonded validators[0].Tokens = sdk.NewDec(600) - validators[0] = updateValidator(keeper, ctx, validators[0]) + validators[0] = testingUpdateValidator(keeper, ctx, validators[0]) updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) @@ -696,8 +696,8 @@ func TestApplyAndReturnValidatorSetUpdatesMultipleValueChange(t *testing.T) { validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt)) keeper.SetPool(ctx, pool) } - validators[0] = updateValidator(keeper, ctx, validators[0]) - validators[1] = updateValidator(keeper, ctx, validators[1]) + validators[0] = testingUpdateValidator(keeper, ctx, validators[0]) + validators[1] = testingUpdateValidator(keeper, ctx, validators[1]) require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) // test multiple value change @@ -706,8 +706,8 @@ func TestApplyAndReturnValidatorSetUpdatesMultipleValueChange(t *testing.T) { validators[0], pool, _ = validators[0].AddTokensFromDel(pool, sdk.NewInt(190)) validators[1], pool, _ = validators[1].AddTokensFromDel(pool, sdk.NewInt(80)) keeper.SetPool(ctx, pool) - validators[0] = updateValidator(keeper, ctx, validators[0]) - validators[1] = updateValidator(keeper, ctx, validators[1]) + validators[0] = testingUpdateValidator(keeper, ctx, validators[0]) + validators[1] = testingUpdateValidator(keeper, ctx, validators[1]) updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) require.Equal(t, 2, len(updates)) @@ -726,8 +726,8 @@ func TestApplyAndReturnValidatorSetUpdatesInserted(t *testing.T) { validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt)) keeper.SetPool(ctx, pool) } - validators[0] = updateValidator(keeper, ctx, validators[0]) - validators[1] = updateValidator(keeper, ctx, validators[1]) + validators[0] = testingUpdateValidator(keeper, ctx, validators[0]) + validators[1] = testingUpdateValidator(keeper, ctx, validators[1]) require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) // test validtor added at the beginning @@ -775,13 +775,13 @@ func TestApplyAndReturnValidatorSetUpdatesWithCliffValidator(t *testing.T) { validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt)) keeper.SetPool(ctx, pool) } - validators[0] = updateValidator(keeper, ctx, validators[0]) - validators[1] = updateValidator(keeper, ctx, validators[1]) + validators[0] = testingUpdateValidator(keeper, ctx, validators[0]) + validators[1] = testingUpdateValidator(keeper, ctx, validators[1]) require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) // test validator added at the end but not inserted in the valset // tendermintUpdate set: {} -> {} - updateValidator(keeper, ctx, validators[2]) + testingUpdateValidator(keeper, ctx, validators[2]) updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) require.Equal(t, 0, len(updates)) @@ -813,8 +813,8 @@ func TestApplyAndReturnValidatorSetUpdatesPowerDecrease(t *testing.T) { validators[i].BondIntraTxCounter = int16(i) keeper.SetPool(ctx, pool) } - validators[0] = updateValidator(keeper, ctx, validators[0]) - validators[1] = updateValidator(keeper, ctx, validators[1]) + validators[0] = testingUpdateValidator(keeper, ctx, validators[0]) + validators[1] = testingUpdateValidator(keeper, ctx, validators[1]) require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) // check initial power @@ -827,8 +827,8 @@ func TestApplyAndReturnValidatorSetUpdatesPowerDecrease(t *testing.T) { validators[0], pool, _ = validators[0].RemoveDelShares(pool, sdk.NewDec(20)) validators[1], pool, _ = validators[1].RemoveDelShares(pool, sdk.NewDec(30)) keeper.SetPool(ctx, pool) - validators[0] = updateValidator(keeper, ctx, validators[0]) - validators[1] = updateValidator(keeper, ctx, validators[1]) + validators[0] = testingUpdateValidator(keeper, ctx, validators[0]) + validators[1] = testingUpdateValidator(keeper, ctx, validators[1]) // power has changed require.Equal(t, sdk.NewDec(80).RoundInt64(), validators[0].GetPower().RoundInt64()) From 94b0ca99fdc1ca64892fbcee48b81a3bf80adc76 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Wed, 3 Oct 2018 02:28:15 +0200 Subject: [PATCH 36/44] 'make format' --- x/stake/keeper/validator_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/stake/keeper/validator_test.go b/x/stake/keeper/validator_test.go index 0b18178fc81f..9b4dc3c55ef1 100644 --- a/x/stake/keeper/validator_test.go +++ b/x/stake/keeper/validator_test.go @@ -97,7 +97,7 @@ func TestUpdateValidatorByPowerIndex(t *testing.T) { keeper.DeleteValidatorByPowerIndex(ctx, validator, pool) validator, pool, burned := validator.RemoveDelShares(pool, delSharesCreated.Quo(sdk.NewDec(2))) require.Equal(t, int64(50), burned.RoundInt64()) - keeper.SetPool(ctx, pool) // update the pool + keeper.SetPool(ctx, pool) // update the pool testingUpdateValidator(keeper, ctx, validator) // update the validator, possibly kicking it out require.False(t, validatorByPowerIndexExists(keeper, ctx, power)) From 5893e2337cb3df951442d8f9a427dc694a723b62 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Wed, 3 Oct 2018 14:43:12 +0200 Subject: [PATCH 37/44] Address @rigelrozanski comments --- x/stake/keeper/delegation.go | 2 +- x/stake/keeper/slash.go | 4 ++-- x/stake/keeper/val_state_change.go | 32 ++++++++++++++++++------------ x/stake/querier/queryable_test.go | 2 +- 4 files changed, 23 insertions(+), 17 deletions(-) diff --git a/x/stake/keeper/delegation.go b/x/stake/keeper/delegation.go index 7631be8efb0f..d7e9c57952d6 100644 --- a/x/stake/keeper/delegation.go +++ b/x/stake/keeper/delegation.go @@ -309,7 +309,7 @@ func (k Keeper) unbond(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValA // if the delegation is the operator of the validator then // trigger a jail validator if bytes.Equal(delegation.DelegatorAddr, validator.OperatorAddr) && !validator.Jailed { - k.JailValidator(ctx, validator) + k.jailValidator(ctx, validator) validator = k.mustGetValidator(ctx, validator.OperatorAddr) } diff --git a/x/stake/keeper/slash.go b/x/stake/keeper/slash.go index dd678858c483..dc57dc5dd47b 100644 --- a/x/stake/keeper/slash.go +++ b/x/stake/keeper/slash.go @@ -122,7 +122,7 @@ func (k Keeper) Slash(ctx sdk.Context, consAddr sdk.ConsAddress, infractionHeigh // jail a validator func (k Keeper) Jail(ctx sdk.Context, consAddr sdk.ConsAddress) { validator := k.mustGetValidatorByConsAddr(ctx, consAddr) - k.JailValidator(ctx, validator) + k.jailValidator(ctx, validator) logger := ctx.Logger().With("module", "x/stake") logger.Info(fmt.Sprintf("validator %s jailed", consAddr)) // TODO Return event(s), blocked on https://github.com/tendermint/tendermint/pull/1803 @@ -132,7 +132,7 @@ func (k Keeper) Jail(ctx sdk.Context, consAddr sdk.ConsAddress) { // unjail a validator func (k Keeper) Unjail(ctx sdk.Context, consAddr sdk.ConsAddress) { validator := k.mustGetValidatorByConsAddr(ctx, consAddr) - k.UnjailValidator(ctx, validator) + k.unjailValidator(ctx, validator) logger := ctx.Logger().With("module", "x/stake") logger.Info(fmt.Sprintf("validator %s unjailed", consAddr)) // TODO Return event(s), blocked on https://github.com/tendermint/tendermint/pull/1803 diff --git a/x/stake/keeper/val_state_change.go b/x/stake/keeper/val_state_change.go index 63b66e8d71d6..f9cf6e463fb6 100644 --- a/x/stake/keeper/val_state_change.go +++ b/x/stake/keeper/val_state_change.go @@ -52,23 +52,25 @@ func (k Keeper) ApplyAndReturnValidatorSetUpdates(ctx sdk.Context) (updates []ab validator = k.unbondingToBonded(ctx, validator) case sdk.Bonded: // no state change + default: + panic("unexpected validator status") } // fetch the old power bytes - var opbytes [sdk.AddrLen]byte - copy(opbytes[:], operator[:]) - oldPowerBytes, ok := last[opbytes] + var operatorBytes [sdk.AddrLen]byte + copy(operatorBytes[:], operator[:]) + oldPowerBytes, found := last[operatorBytes] // calculate the new power bytes newPowerBytes := validator.ABCIValidatorPowerBytes(k.cdc) // update the validator set if power has changed - if !ok || !bytes.Equal(oldPowerBytes, newPowerBytes) { + if !found || !bytes.Equal(oldPowerBytes, newPowerBytes) { updates = append(updates, validator.ABCIValidatorUpdate()) } // validator still in the validator set, so delete from the copy - delete(last, opbytes) + delete(last, operatorBytes) // set the bonded validator index store.Set(GetBondedValidatorIndexKey(operator), newPowerBytes) @@ -137,7 +139,7 @@ func (k Keeper) unbondingToUnbonded(ctx sdk.Context, validator types.Validator) } // send a validator to jail -func (k Keeper) JailValidator(ctx sdk.Context, validator types.Validator) { +func (k Keeper) jailValidator(ctx sdk.Context, validator types.Validator) { if validator.Jailed { panic(fmt.Sprintf("cannot jail already jailed validator, validator: %v\n", validator)) } @@ -149,7 +151,7 @@ func (k Keeper) JailValidator(ctx sdk.Context, validator types.Validator) { } // remove a validator from jail -func (k Keeper) UnjailValidator(ctx sdk.Context, validator types.Validator) { +func (k Keeper) unjailValidator(ctx sdk.Context, validator types.Validator) { if !validator.Jailed { panic(fmt.Sprintf("cannot unjail already unjailed validator, validator: %v\n", validator)) } @@ -228,9 +230,12 @@ func (k Keeper) completeUnbondingValidator(ctx sdk.Context, validator types.Vali return validator } +// map of operator addresses to serialized power +type validatorsByAddr map[[sdk.AddrLen]byte][]byte + // retrieve the last validator set -func (k Keeper) retrieveLastValidatorSet(ctx sdk.Context) map[[sdk.AddrLen]byte][]byte { - last := make(map[[sdk.AddrLen]byte][]byte) +func (k Keeper) retrieveLastValidatorSet(ctx sdk.Context) validatorsByAddr { + last := make(validatorsByAddr) store := ctx.KVStore(k.storeKey) iterator := sdk.KVStorePrefixIterator(store, ValidatorsBondedIndexKey) for ; iterator.Valid(); iterator.Next() { @@ -243,14 +248,15 @@ func (k Keeper) retrieveLastValidatorSet(ctx sdk.Context) map[[sdk.AddrLen]byte] return last } -// sort the validators to be unbonded -func (k Keeper) sortNoLongerBonded(last map[[sdk.AddrLen]byte][]byte) [][]byte { +// given a map of remaining validators to previous bonded power +// returns the list of validators to be unbonded, sorted by operator address +func (k Keeper) sortNoLongerBonded(last validatorsByAddr) [][]byte { // sort the map keys for determinism noLongerBonded := make([][]byte, len(last)) index := 0 - for oper := range last { + for operatorBytes := range last { operator := make([]byte, sdk.AddrLen) - copy(operator[:], oper[:]) + copy(operator[:], operatorBytes[:]) noLongerBonded[index] = operator index++ } diff --git a/x/stake/querier/queryable_test.go b/x/stake/querier/queryable_test.go index 00a524b5b43d..d950f90bf91c 100644 --- a/x/stake/querier/queryable_test.go +++ b/x/stake/querier/queryable_test.go @@ -182,7 +182,7 @@ func TestQueryDelegation(t *testing.T) { require.Equal(t, delegation, delegationRes) - // Query unbonding delegation + // Query unbonging delegation keeper.BeginUnbonding(ctx, addrAcc2, val1.OperatorAddr, sdk.NewDec(10)) query = abci.RequestQuery{ From 4102f7630941eb4020d231ccc2599eefba8e3b5c Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Wed, 3 Oct 2018 16:32:04 +0200 Subject: [PATCH 38/44] Validator might already be jailed --- scripts/multisim.sh | 11 +++++++---- x/mock/simulation/constants.go | 2 +- x/slashing/keeper.go | 9 ++++++--- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/scripts/multisim.sh b/scripts/multisim.sh index be59b0f1a8ff..ebd6cadae6ae 100755 --- a/scripts/multisim.sh +++ b/scripts/multisim.sh @@ -1,6 +1,6 @@ #!/bin/bash -seeds=(1 2 4 7 9 20 32 123 4728 37827 981928 87821 891823782 989182 89182391) +seeds=(1 2 4 7 9 20 32 123 124 582 1893 2989 3012 4728 37827 981928 87821 891823782 989182 89182391) echo "Running multi-seed simulation with seeds: ${seeds[@]}" echo "Edit scripts/multisim.sh to add new seeds. Keeping parameters in the file makes failures easy to reproduce." @@ -16,7 +16,7 @@ sim() { echo "Running full Gaia simulation with seed $seed. This may take awhile!" file="$tmpdir/gaia-simulation-seed-$seed-date-$(date -Iseconds -u).stdout" echo "Writing stdout to $file..." - go test ./cmd/gaia/app -run TestFullGaiaSimulation -SimulationEnabled=true -SimulationNumBlocks=1000 \ + go test ./cmd/gaia/app -run TestFullGaiaSimulation -SimulationEnabled=true -SimulationNumBlocks=200 \ -SimulationVerbose=true -SimulationCommit=true -SimulationSeed=$seed -v -timeout 24h > $file } @@ -37,10 +37,13 @@ i=0 for pid in ${pids[*]}; do wait $pid last=$? - if [ $last -ne 0 ]; then - seed=${seeds[${i}]} + seed=${seeds[${i}]} + if [ $last -ne 0 ] + then echo "Simulation with seed $seed failed!" code=1 + else + echo "Simulation with seed $seed OK" fi i=$(($i+1)) done diff --git a/x/mock/simulation/constants.go b/x/mock/simulation/constants.go index 544da50e3e3e..a96d4541f186 100644 --- a/x/mock/simulation/constants.go +++ b/x/mock/simulation/constants.go @@ -14,7 +14,7 @@ const ( numKeys int = 250 // Chance that double-signing evidence is found on a given block - evidenceFraction float64 = 0.01 + evidenceFraction float64 = 0.5 // TODO Remove in favor of binary search for invariant violation onOperation bool = false diff --git a/x/slashing/keeper.go b/x/slashing/keeper.go index 0c1c70b362a1..dcade8b14efc 100644 --- a/x/slashing/keeper.go +++ b/x/slashing/keeper.go @@ -65,10 +65,13 @@ func (k Keeper) handleDoubleSign(ctx sdk.Context, addr crypto.Address, infractio // Slash validator k.validatorSet.Slash(ctx, consAddr, infractionHeight, power, revisedFraction) - // Jail validator - k.validatorSet.Jail(ctx, consAddr) + // Jail validator if not already in jail + validator := k.validatorSet.ValidatorByConsAddr(ctx, consAddr) + if !validator.GetJailed() { + k.validatorSet.Jail(ctx, consAddr) + } - // Set validator jail duration + // Set or updated validator jail duration signInfo, found := k.getValidatorSigningInfo(ctx, consAddr) if !found { panic(fmt.Sprintf("Expected signing info for validator %s but not found", consAddr)) From a1c9cd8b53707cf5bf11d9f2a50753fb69966169 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Wed, 3 Oct 2018 16:35:20 +0200 Subject: [PATCH 39/44] Update PENDING.md --- PENDING.md | 1 + 1 file changed, 1 insertion(+) diff --git a/PENDING.md b/PENDING.md index fd16669aaf70..a63d23df70e3 100644 --- a/PENDING.md +++ b/PENDING.md @@ -40,6 +40,7 @@ BREAKING CHANGES * [x/gov] [#2195] Governance uses BFT Time * [x/gov] \#2256 Removed slashing for governance non-voting validators * [simulation] \#2162 Added back correct supply invariants + * [x/slashing] \#2430 Simulate more slashes, check if validator is jailed before jailing * SDK * [core] \#2219 Update to Tendermint 0.24.0 From b119a54f79751e36002528a9f070f839ac1d8e0f Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Wed, 3 Oct 2018 17:29:44 +0200 Subject: [PATCH 40/44] Use a KVStoreReversePrefixIterator instead --- x/slashing/slashing_period.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/x/slashing/slashing_period.go b/x/slashing/slashing_period.go index 44e5a6242d41..668f96536422 100644 --- a/x/slashing/slashing_period.go +++ b/x/slashing/slashing_period.go @@ -52,11 +52,14 @@ func (k Keeper) getValidatorSlashingPeriodForHeight(ctx sdk.Context, address sdk itr.Next() } // END TODO - iterator := store.ReverseIterator(start, end) + iterator := sdk.KVStoreReversePrefixIterator(store, GetValidatorSlashingPeriodPrefix(address)) if !iterator.Valid() { panic(fmt.Sprintf("expected to find slashing period for validator %s before height %d, but none was found", address, height)) } slashingPeriod = k.unmarshalSlashingPeriodKeyValue(iterator.Key(), iterator.Value()) + if slashingPeriod.StartHeight > height { + panic(fmt.Sprintf("expected to find slashing period for validator %s before height %d, but instead was from height %d", address, height, slashingPeriod.StartHeight)) + } return } @@ -71,7 +74,7 @@ func (k Keeper) addOrUpdateValidatorSlashingPeriod(ctx sdk.Context, slashingPeri } store := ctx.KVStore(k.storeKey) bz := k.cdc.MustMarshalBinary(slashingPeriodValue) - fmt.Printf("Set slashing period for validator: %X => %s\n", GetValidatorSlashingPeriodKey(slashingPeriod.ValidatorAddr, slashingPeriod.StartHeight), slashingPeriod.ValidatorAddr) + fmt.Printf("Set slashing period for validator at height %d: %X => %s\n", slashingPeriod.StartHeight, GetValidatorSlashingPeriodKey(slashingPeriod.ValidatorAddr, slashingPeriod.StartHeight), slashingPeriod.ValidatorAddr) store.Set(GetValidatorSlashingPeriodKey(slashingPeriod.ValidatorAddr, slashingPeriod.StartHeight), bz) } From 9a4249ec5edb789a7579fc056a959d2c908d0b72 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Wed, 3 Oct 2018 18:38:41 +0200 Subject: [PATCH 41/44] Undo accidental merge changes --- README.md | 7 +++---- docs/README.md | 4 ++-- docs/getting-started/installation.md | 2 +- docs/getting-started/networks.md | 2 +- docs/introduction/tendermint.md | 2 +- docs/sdk/clients.md | 2 +- x/stake/keeper/validator.go | 1 + 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 75761f5f4dca..94b2b19da848 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ breaking changes. ## Gaia Testnet To join the latest testnet, follow -[the guide](https://cosmos.network/docs/getting-started/full-node.html#setting-up-a-new-node). +[the guide](./docs/getting-started/join-testnet.md). For status updates and genesis files, see the [testnets repo](https://github.com/cosmos/testnets). @@ -30,15 +30,14 @@ For status updates and genesis files, see the ## Install See the -[install instructions](https://cosmos.network/docs/getting-started/installation.html). +[install instructions](./docs/getting-started/installation.md). ## Quick Start See the [Cosmos Docs](https://cosmos.network/docs/) -- [Getting started with the SDK](https://cosmos.network/docs/sdk/core/intro.html) +- [Getting started with the SDK](./docs/sdk/core/intro.md) - [SDK Examples](/examples) -- [Join the testnet](https://cosmos.network/docs/getting-started/full-node.html#run-a-full-node) ## Disambiguation diff --git a/docs/README.md b/docs/README.md index 2edcebe8dbd4..13b831f39318 100644 --- a/docs/README.md +++ b/docs/README.md @@ -10,9 +10,9 @@ Cosmos can interoperate with multiple other applications and cryptocurrencies. B ## Quick Start -- [Getting started with the SDK](./sdk/core/intro.html) +- [Getting started with the SDK](./sdk/core/intro.md) - [SDK Examples](../examples) -- [Join the testnet](./getting-started/full-node.html#run-a-full-node) +- [Join the testnet](./getting-started/join-testnet.md#run-a-full-node) ## Edit the Documentation diff --git a/docs/getting-started/installation.md b/docs/getting-started/installation.md index c23f3b02cdf6..66ccae4b85e8 100644 --- a/docs/getting-started/installation.md +++ b/docs/getting-started/installation.md @@ -1,6 +1,6 @@ # Install the SDK -This guide will explain how to install the [Cosmos SDK](/sdk/overview.md) onto your system. With the SDK installed on a server, you can participate in the latest testnet as either a [Full Node](full-node.md) or a [Validator](/validators/validator-setup.md). +This guide will explain how to install the [Cosmos SDK](/sdk/overview.md) onto your system. With the SDK installed on a server, you can participate in the latest testnet as either a [Full Node](./join-testnet.md#run-a-full-node) or a [Validator](/validators/validator-setup.md). ## Install Go diff --git a/docs/getting-started/networks.md b/docs/getting-started/networks.md index abd2999baab3..67f0dab5aa45 100644 --- a/docs/getting-started/networks.md +++ b/docs/getting-started/networks.md @@ -9,7 +9,7 @@ From the [networks/local directory](https://github.com/cosmos/cosmos-sdk/tree/de ### Requirements -- [Install gaia](https://cosmos.network/docs/getting-started/installation.html) +- [Install gaia](./installation.md) - [Install docker](https://docs.docker.com/engine/installation/) - [Install docker-compose](https://docs.docker.com/compose/install/) diff --git a/docs/introduction/tendermint.md b/docs/introduction/tendermint.md index 62db8cdbc609..4192a03ea6e7 100644 --- a/docs/introduction/tendermint.md +++ b/docs/introduction/tendermint.md @@ -10,7 +10,7 @@ The ability to tolerate machines failing in arbitrary ways, including becoming m ## Application Blockchain Interface -Tendermint consists of two chief technical components: a blockchain consensus engine and a generic application interface. The consensus engine, called Tendermint Core, ensures that the same transactions are recorded on every machine in the same order. The application interface, called the Application Blockchain Interface (ABCI), enables the transactions to be processed in any programming language. Unlike other blockchain and consensus solutions developers can use Tendermint for BFT state machine replication in any programming language or development environment. Visit the [Tendermint docs](https://tendermint.readthedocs.io/projects/tools/en/master/introduction.html#abci-overview) for a deep dive into the ABCI. +Tendermint consists of two chief technical components: a blockchain consensus engine and a generic application interface. The consensus engine, called Tendermint Core, ensures that the same transactions are recorded on every machine in the same order. The application interface, called the Application Blockchain Interface (ABCI), enables the transactions to be processed in any programming language. Unlike other blockchain and consensus solutions developers can use Tendermint for BFT state machine replication in any programming language or development environment. Visit the [Tendermint docs](https://tendermint.com/docs/introduction/introduction.html#abci-overview) for a deep dive into the ABCI. ## Understanding the roles of the different layers diff --git a/docs/sdk/clients.md b/docs/sdk/clients.md index 5e5a9c7ac3c2..9637b3b4beb8 100644 --- a/docs/sdk/clients.md +++ b/docs/sdk/clients.md @@ -169,7 +169,7 @@ gaiacli tx broadcast --node= signedSendTx.json #### Set up a Validator -Please refer to the [Validator Setup](https://cosmos.network/docs/validators/validator-setup.html) section for a more complete guide on how to set up a validator-candidate. +Please refer to the [Validator Setup](../validators/validator-setup.md) section for a more complete guide on how to set up a validator-candidate. #### Delegate to a Validator diff --git a/x/stake/keeper/validator.go b/x/stake/keeper/validator.go index 927a361a2dd7..b405312a1b2d 100644 --- a/x/stake/keeper/validator.go +++ b/x/stake/keeper/validator.go @@ -180,6 +180,7 @@ func (k Keeper) UpdateValidatorCommission(ctx sdk.Context, validator types.Valid } // remove the validator record and associated indexes +// except for the bonded validator index which is only handled in ApplyAndReturnTendermintUpdates func (k Keeper) RemoveValidator(ctx sdk.Context, address sdk.ValAddress) { // first retrieve the old validator record From c50a29b664609f4ee9228fc830aa78833cb308d1 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Fri, 5 Oct 2018 17:27:46 +0200 Subject: [PATCH 42/44] Height must be stored big-endian (duh) --- x/slashing/keys.go | 2 +- x/slashing/slashing_period.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x/slashing/keys.go b/x/slashing/keys.go index 183dfde60d18..4303f4635e4c 100644 --- a/x/slashing/keys.go +++ b/x/slashing/keys.go @@ -35,7 +35,7 @@ func GetValidatorSlashingPeriodPrefix(v sdk.ConsAddress) []byte { func GetValidatorSlashingPeriodKey(v sdk.ConsAddress, startHeight int64) []byte { b := make([]byte, 8) // this needs to be height + 1 because the slashing period for genesis validators starts at height -1 - binary.LittleEndian.PutUint64(b, uint64(startHeight+1)) + binary.BigEndian.PutUint64(b, uint64(startHeight+1)) return append(GetValidatorSlashingPeriodPrefix(v), b...) } diff --git a/x/slashing/slashing_period.go b/x/slashing/slashing_period.go index 4bd27d5cb743..c5314002ff89 100644 --- a/x/slashing/slashing_period.go +++ b/x/slashing/slashing_period.go @@ -83,7 +83,7 @@ func (k Keeper) unmarshalSlashingPeriodKeyValue(key []byte, value []byte) Valida var slashingPeriodValue ValidatorSlashingPeriodValue k.cdc.MustUnmarshalBinary(value, &slashingPeriodValue) address := sdk.ConsAddress(key[1 : 1+sdk.AddrLen]) - startHeight := int64(binary.LittleEndian.Uint64(key[1+sdk.AddrLen:1+sdk.AddrLen+8]) - 1) + startHeight := int64(binary.BigEndian.Uint64(key[1+sdk.AddrLen:1+sdk.AddrLen+8]) - 1) return ValidatorSlashingPeriod{ ValidatorAddr: address, StartHeight: startHeight, From c629be9f648e193d40bcd600a17756a026eea202 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Fri, 5 Oct 2018 17:36:29 +0200 Subject: [PATCH 43/44] Big endian, more simulation seeds --- types/store.go | 24 ------------------------ x/slashing/keeper.go | 1 + x/slashing/slashing_period.go | 17 +---------------- 3 files changed, 2 insertions(+), 40 deletions(-) diff --git a/types/store.go b/types/store.go index 4aa195d9851f..e895b24c94d8 100644 --- a/types/store.go +++ b/types/store.go @@ -306,30 +306,6 @@ func PrefixEndBytes(prefix []byte) []byte { return end } -// PrefixStartBytes returns the []byte that would start a -// range query for all []byte with a certain prefix -func PrefixStartBytes(prefix []byte) []byte { - if prefix == nil { - return nil - } - - end := make([]byte, len(prefix)) - copy(end, prefix) - - for { - if end[len(end)-1] != byte(0) { - end[len(end)-1]-- - break - } else { - end = end[:len(end)-1] - if len(end) == 0 { - panic("could not subtract") - } - } - } - return end -} - // TransientStoreKey is used for indexing transient stores in a MultiStore type TransientStoreKey struct { name string diff --git a/x/slashing/keeper.go b/x/slashing/keeper.go index c3f4a8804276..dc316b2b6f78 100644 --- a/x/slashing/keeper.go +++ b/x/slashing/keeper.go @@ -71,6 +71,7 @@ func (k Keeper) handleDoubleSign(ctx sdk.Context, addr crypto.Address, infractio // Slash validator k.validatorSet.Slash(ctx, consAddr, distributionHeight, power, revisedFraction) + // Jail validator if not already jailed validator := k.validatorSet.ValidatorByConsAddr(ctx, consAddr) if !validator.GetJailed() { k.validatorSet.Jail(ctx, consAddr) diff --git a/x/slashing/slashing_period.go b/x/slashing/slashing_period.go index c5314002ff89..1d94aa55993e 100644 --- a/x/slashing/slashing_period.go +++ b/x/slashing/slashing_period.go @@ -1,7 +1,6 @@ package slashing import ( - "bytes" "encoding/binary" "fmt" @@ -42,24 +41,11 @@ func (k Keeper) getValidatorSlashingPeriodForHeight(ctx sdk.Context, address sdk // Get the most recent slashing period at or before the infraction height start := GetValidatorSlashingPeriodPrefix(address) end := sdk.PrefixEndBytes(GetValidatorSlashingPeriodKey(address, height)) - fmt.Printf("start: %X, end: %X, diff: %v\n", start, end, bytes.Compare(start, end)) - // TODO - itr := sdk.KVStorePrefixIterator(store, GetValidatorSlashingPeriodPrefix(address)) - for itr.Valid() { - fmt.Printf("Key: %X\n", itr.Key()) - period := k.unmarshalSlashingPeriodKeyValue(itr.Key(), itr.Value()) - fmt.Printf("Found %X => %v\n", address, period) - itr.Next() - } - // END TODO - iterator := sdk.KVStoreReversePrefixIterator(store, GetValidatorSlashingPeriodPrefix(address)) + iterator := store.ReverseIterator(start, end) if !iterator.Valid() { panic(fmt.Sprintf("expected to find slashing period for validator %s before height %d, but none was found", address, height)) } slashingPeriod = k.unmarshalSlashingPeriodKeyValue(iterator.Key(), iterator.Value()) - if slashingPeriod.StartHeight > height { - panic(fmt.Sprintf("expected to find slashing period for validator %s before height %d, but instead was from height %d", address, height, slashingPeriod.StartHeight)) - } return } @@ -74,7 +60,6 @@ func (k Keeper) addOrUpdateValidatorSlashingPeriod(ctx sdk.Context, slashingPeri } store := ctx.KVStore(k.storeKey) bz := k.cdc.MustMarshalBinary(slashingPeriodValue) - fmt.Printf("Set slashing period for validator at height %d: %X => %s\n", slashingPeriod.StartHeight, GetValidatorSlashingPeriodKey(slashingPeriod.ValidatorAddr, slashingPeriod.StartHeight), slashingPeriod.ValidatorAddr) store.Set(GetValidatorSlashingPeriodKey(slashingPeriod.ValidatorAddr, slashingPeriod.StartHeight), bz) } From 7e5945494b9f92be3df2af1e26bcfccd0b99d2f7 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Fri, 5 Oct 2018 17:40:32 +0200 Subject: [PATCH 44/44] More sleep on the multi-sim --- scripts/multisim.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/multisim.sh b/scripts/multisim.sh index b0c74a9ff751..8ffa338b84e5 100755 --- a/scripts/multisim.sh +++ b/scripts/multisim.sh @@ -28,7 +28,7 @@ for seed in ${seeds[@]}; do sim $seed & pids[${i}]=$! i=$(($i+1)) - sleep 5 # start in order, nicer logs + sleep 10 # start in order, nicer logs done echo "Simulation processes spawned, waiting for completion..."