From dff668120286ccf75cc80c0a96b082ec85e9eac9 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Fri, 4 Jan 2019 22:16:01 -0500 Subject: [PATCH 01/26] remove kv seperation for marshalling --- x/stake/client/cli/query.go | 18 +++--- x/stake/client/cli/utils.go | 2 +- x/stake/keeper/delegation.go | 24 +++---- x/stake/keeper/query_utils.go | 9 ++- x/stake/keeper/sdk_types.go | 5 +- x/stake/keeper/validator.go | 10 ++- x/stake/types/delegation.go | 116 ++++++---------------------------- x/stake/types/validator.go | 59 ++--------------- 8 files changed, 55 insertions(+), 188 deletions(-) diff --git a/x/stake/client/cli/query.go b/x/stake/client/cli/query.go index 40598fcf800..488ea5b0433 100644 --- a/x/stake/client/cli/query.go +++ b/x/stake/client/cli/query.go @@ -36,7 +36,7 @@ func GetCmdQueryValidator(storeName string, cdc *codec.Codec) *cobra.Command { return fmt.Errorf("No validator found with address %s", args[0]) } - validator := types.MustUnmarshalValidator(cdc, addr, res) + validator := types.MustUnmarshalValidator(cdc, res) switch viper.Get(cli.OutputFlag) { case "text": @@ -81,8 +81,7 @@ func GetCmdQueryValidators(storeName string, cdc *codec.Codec) *cobra.Command { // parse out the validators var validators []stake.Validator for _, kv := range resKVs { - addr := kv.Key[1:] - validator := types.MustUnmarshalValidator(cdc, addr, kv.Value) + validator := types.MustUnmarshalValidator(cdc, kv.Value) validators = append(validators, validator) } @@ -209,8 +208,7 @@ func GetCmdQueryDelegation(storeName string, cdc *codec.Codec) *cobra.Command { } // parse out the delegation - - delegation, err := types.UnmarshalDelegation(cdc, key, res) + delegation, err := types.UnmarshalDelegation(cdc, res) if err != nil { return err } @@ -267,7 +265,7 @@ func GetCmdQueryDelegations(storeName string, cdc *codec.Codec) *cobra.Command { // parse out the validators var delegations []stake.Delegation for _, kv := range resKVs { - delegation := types.MustUnmarshalDelegation(cdc, kv.Key, kv.Value) + delegation := types.MustUnmarshalDelegation(cdc, kv.Value) delegations = append(delegations, delegation) } @@ -347,7 +345,7 @@ func GetCmdQueryUnbondingDelegation(storeName string, cdc *codec.Codec) *cobra.C } // parse out the unbonding delegation - ubd := types.MustUnmarshalUBD(cdc, key, res) + ubd := types.MustUnmarshalUBD(cdc, res) switch viper.Get(cli.OutputFlag) { case "text": @@ -401,7 +399,7 @@ func GetCmdQueryUnbondingDelegations(storeName string, cdc *codec.Codec) *cobra. // parse out the unbonding delegations var ubds []stake.UnbondingDelegation for _, kv := range resKVs { - ubd := types.MustUnmarshalUBD(cdc, kv.Key, kv.Value) + ubd := types.MustUnmarshalUBD(cdc, kv.Value) ubds = append(ubds, ubd) } @@ -451,7 +449,7 @@ func GetCmdQueryRedelegation(storeName string, cdc *codec.Codec) *cobra.Command } // parse out the unbonding delegation - red := types.MustUnmarshalRED(cdc, key, res) + red := types.MustUnmarshalRED(cdc, res) switch viper.Get(cli.OutputFlag) { case "text": @@ -505,7 +503,7 @@ func GetCmdQueryRedelegations(storeName string, cdc *codec.Codec) *cobra.Command // parse out the validators var reds []stake.Redelegation for _, kv := range resKVs { - red := types.MustUnmarshalRED(cdc, kv.Key, kv.Value) + red := types.MustUnmarshalRED(cdc, kv.Value) reds = append(reds, red) } diff --git a/x/stake/client/cli/utils.go b/x/stake/client/cli/utils.go index 848e1725d05..8a83e531447 100644 --- a/x/stake/client/cli/utils.go +++ b/x/stake/client/cli/utils.go @@ -52,7 +52,7 @@ func getShares( return sharesAmount, errors.Errorf("cannot find delegation to determine percent Error: %v", err) } - delegation, err := types.UnmarshalDelegation(cdc, key, resQuery) + delegation, err := types.UnmarshalDelegation(cdc, resQuery) if err != nil { return sdk.ZeroDec(), err } diff --git a/x/stake/keeper/delegation.go b/x/stake/keeper/delegation.go index 926d5274af3..a1f26e3078f 100644 --- a/x/stake/keeper/delegation.go +++ b/x/stake/keeper/delegation.go @@ -20,7 +20,7 @@ func (k Keeper) GetDelegation(ctx sdk.Context, return delegation, false } - delegation = types.MustUnmarshalDelegation(k.cdc, key, value) + delegation = types.MustUnmarshalDelegation(k.cdc, value) return delegation, true } @@ -31,7 +31,7 @@ func (k Keeper) GetAllDelegations(ctx sdk.Context) (delegations []types.Delegati defer iterator.Close() for ; iterator.Valid(); iterator.Next() { - delegation := types.MustUnmarshalDelegation(k.cdc, iterator.Key(), iterator.Value()) + delegation := types.MustUnmarshalDelegation(k.cdc, iterator.Value()) delegations = append(delegations, delegation) } return delegations @@ -44,7 +44,7 @@ func (k Keeper) GetValidatorDelegations(ctx sdk.Context, valAddr sdk.ValAddress) defer iterator.Close() for ; iterator.Valid(); iterator.Next() { - delegation := types.MustUnmarshalDelegation(k.cdc, iterator.Key(), iterator.Value()) + delegation := types.MustUnmarshalDelegation(k.cdc, iterator.Value()) if delegation.GetValidatorAddr().Equals(valAddr) { delegations = append(delegations, delegation) } @@ -65,7 +65,7 @@ func (k Keeper) GetDelegatorDelegations(ctx sdk.Context, delegator sdk.AccAddres i := 0 for ; iterator.Valid() && i < int(maxRetrieve); iterator.Next() { - delegation := types.MustUnmarshalDelegation(k.cdc, iterator.Key(), iterator.Value()) + delegation := types.MustUnmarshalDelegation(k.cdc, iterator.Value()) delegations[i] = delegation i++ } @@ -101,7 +101,7 @@ func (k Keeper) GetUnbondingDelegations(ctx sdk.Context, delegator sdk.AccAddres i := 0 for ; iterator.Valid() && i < int(maxRetrieve); iterator.Next() { - unbondingDelegation := types.MustUnmarshalUBD(k.cdc, iterator.Key(), iterator.Value()) + unbondingDelegation := types.MustUnmarshalUBD(k.cdc, iterator.Value()) unbondingDelegations[i] = unbondingDelegation i++ } @@ -119,7 +119,7 @@ func (k Keeper) GetUnbondingDelegation(ctx sdk.Context, return ubd, false } - ubd = types.MustUnmarshalUBD(k.cdc, key, value) + ubd = types.MustUnmarshalUBD(k.cdc, value) return ubd, true } @@ -132,7 +132,7 @@ func (k Keeper) GetUnbondingDelegationsFromValidator(ctx sdk.Context, valAddr sd for ; iterator.Valid(); iterator.Next() { key := GetUBDKeyFromValIndexKey(iterator.Key()) value := store.Get(key) - ubd := types.MustUnmarshalUBD(k.cdc, key, value) + ubd := types.MustUnmarshalUBD(k.cdc, value) ubds = append(ubds, ubd) } return ubds @@ -145,7 +145,7 @@ func (k Keeper) IterateUnbondingDelegations(ctx sdk.Context, fn func(index int64 defer iterator.Close() for i := int64(0); iterator.Valid(); iterator.Next() { - ubd := types.MustUnmarshalUBD(k.cdc, iterator.Key(), iterator.Value()) + ubd := types.MustUnmarshalUBD(k.cdc, iterator.Value()) if stop := fn(i, ubd); stop { break } @@ -235,7 +235,7 @@ func (k Keeper) GetRedelegations(ctx sdk.Context, delegator sdk.AccAddress, i := 0 for ; iterator.Valid() && i < int(maxRetrieve); iterator.Next() { - redelegation := types.MustUnmarshalRED(k.cdc, iterator.Key(), iterator.Value()) + redelegation := types.MustUnmarshalRED(k.cdc, iterator.Value()) redelegations[i] = redelegation i++ } @@ -253,7 +253,7 @@ func (k Keeper) GetRedelegation(ctx sdk.Context, return red, false } - red = types.MustUnmarshalRED(k.cdc, key, value) + red = types.MustUnmarshalRED(k.cdc, value) return red, true } @@ -266,7 +266,7 @@ func (k Keeper) GetRedelegationsFromValidator(ctx sdk.Context, valAddr sdk.ValAd for ; iterator.Valid(); iterator.Next() { key := GetREDKeyFromValSrcIndexKey(iterator.Key()) value := store.Get(key) - red := types.MustUnmarshalRED(k.cdc, key, value) + red := types.MustUnmarshalRED(k.cdc, value) reds = append(reds, red) } return reds @@ -305,7 +305,7 @@ func (k Keeper) IterateRedelegations(ctx sdk.Context, fn func(index int64, red t defer iterator.Close() for i := int64(0); iterator.Valid(); iterator.Next() { - red := types.MustUnmarshalRED(k.cdc, iterator.Key(), iterator.Value()) + red := types.MustUnmarshalRED(k.cdc, iterator.Value()) if stop := fn(i, red); stop { break } diff --git a/x/stake/keeper/query_utils.go b/x/stake/keeper/query_utils.go index 699ae8ccff9..aef7bad47dd 100644 --- a/x/stake/keeper/query_utils.go +++ b/x/stake/keeper/query_utils.go @@ -17,8 +17,7 @@ func (k Keeper) GetDelegatorValidators(ctx sdk.Context, delegatorAddr sdk.AccAdd i := 0 for ; iterator.Valid() && i < int(maxRetrieve); iterator.Next() { - addr := iterator.Key() - delegation := types.MustUnmarshalDelegation(k.cdc, addr, iterator.Value()) + delegation := types.MustUnmarshalDelegation(k.cdc, iterator.Value()) validator, found := k.GetValidator(ctx, delegation.ValidatorAddr) if !found { @@ -59,7 +58,7 @@ func (k Keeper) GetAllDelegatorDelegations(ctx sdk.Context, delegator sdk.AccAdd i := 0 for ; iterator.Valid(); iterator.Next() { - delegation := types.MustUnmarshalDelegation(k.cdc, iterator.Key(), iterator.Value()) + delegation := types.MustUnmarshalDelegation(k.cdc, iterator.Value()) delegations = append(delegations, delegation) i++ } @@ -77,7 +76,7 @@ func (k Keeper) GetAllUnbondingDelegations(ctx sdk.Context, delegator sdk.AccAdd i := 0 for ; iterator.Valid(); iterator.Next() { - unbondingDelegation := types.MustUnmarshalUBD(k.cdc, iterator.Key(), iterator.Value()) + unbondingDelegation := types.MustUnmarshalUBD(k.cdc, iterator.Value()) unbondingDelegations = append(unbondingDelegations, unbondingDelegation) i++ } @@ -95,7 +94,7 @@ func (k Keeper) GetAllRedelegations(ctx sdk.Context, delegator sdk.AccAddress, s dstValFilter := !(dstValAddress.Empty() || dstValAddress == nil) for ; iterator.Valid(); iterator.Next() { - redelegation := types.MustUnmarshalRED(k.cdc, iterator.Key(), iterator.Value()) + redelegation := types.MustUnmarshalRED(k.cdc, iterator.Value()) if srcValFilter && !(srcValAddress.Equals(redelegation.ValidatorSrcAddr)) { continue } diff --git a/x/stake/keeper/sdk_types.go b/x/stake/keeper/sdk_types.go index dcef5c6d656..316ca79ff72 100644 --- a/x/stake/keeper/sdk_types.go +++ b/x/stake/keeper/sdk_types.go @@ -16,8 +16,7 @@ func (k Keeper) IterateValidators(ctx sdk.Context, fn func(index int64, validato iterator := sdk.KVStorePrefixIterator(store, ValidatorsKey) i := int64(0) for ; iterator.Valid(); iterator.Next() { - addr := iterator.Key()[1:] - validator := types.MustUnmarshalValidator(k.cdc, addr, iterator.Value()) + validator := types.MustUnmarshalValidator(k.cdc, iterator.Value()) stop := fn(i, validator) // XXX is this safe will the validator unexposed fields be able to get written to? if stop { break @@ -136,7 +135,7 @@ func (k Keeper) IterateDelegations(ctx sdk.Context, delAddr sdk.AccAddress, delegatorPrefixKey := GetDelegationsKey(delAddr) iterator := sdk.KVStorePrefixIterator(store, delegatorPrefixKey) //smallest to largest for i := int64(0); iterator.Valid(); iterator.Next() { - del := types.MustUnmarshalDelegation(k.cdc, iterator.Key(), iterator.Value()) + del := types.MustUnmarshalDelegation(k.cdc, iterator.Value()) stop := fn(i, del) if stop { break diff --git a/x/stake/keeper/validator.go b/x/stake/keeper/validator.go index c69a7e63cdd..f5795bd4a18 100644 --- a/x/stake/keeper/validator.go +++ b/x/stake/keeper/validator.go @@ -36,7 +36,7 @@ func (k Keeper) GetValidator(ctx sdk.Context, addr sdk.ValAddress) (validator ty } // amino bytes weren't found in cache, so amino unmarshal and add it to the cache - validator = types.MustUnmarshalValidator(k.cdc, addr, value) + validator = types.MustUnmarshalValidator(k.cdc, value) cachedVal := cachedValidator{validator, strValue} k.validatorCache[strValue] = cachedValidator{validator, strValue} k.validatorCacheList.PushBack(cachedVal) @@ -47,7 +47,7 @@ func (k Keeper) GetValidator(ctx sdk.Context, addr sdk.ValAddress) (validator ty delete(k.validatorCache, valToRemove.marshalled) } - validator = types.MustUnmarshalValidator(k.cdc, addr, value) + validator = types.MustUnmarshalValidator(k.cdc, value) return validator, true } @@ -217,8 +217,7 @@ func (k Keeper) GetAllValidators(ctx sdk.Context) (validators []types.Validator) defer iterator.Close() for ; iterator.Valid(); iterator.Next() { - addr := iterator.Key()[1:] - validator := types.MustUnmarshalValidator(k.cdc, addr, iterator.Value()) + validator := types.MustUnmarshalValidator(k.cdc, iterator.Value()) validators = append(validators, validator) } return validators @@ -234,8 +233,7 @@ func (k Keeper) GetValidators(ctx sdk.Context, maxRetrieve uint16) (validators [ i := 0 for ; iterator.Valid() && i < int(maxRetrieve); iterator.Next() { - addr := iterator.Key()[1:] - validator := types.MustUnmarshalValidator(k.cdc, addr, iterator.Value()) + validator := types.MustUnmarshalValidator(k.cdc, iterator.Value()) validators[i] = validator i++ } diff --git a/x/stake/types/delegation.go b/x/stake/types/delegation.go index 0d49b1db58a..cb840ceb17a 100644 --- a/x/stake/types/delegation.go +++ b/x/stake/types/delegation.go @@ -41,15 +41,12 @@ type delegationValue struct { // return the delegation without fields contained within the key for the store func MustMarshalDelegation(cdc *codec.Codec, delegation Delegation) []byte { - val := delegationValue{ - delegation.Shares, - } - return cdc.MustMarshalBinaryLengthPrefixed(val) + return cdc.MustMarshalBinaryLengthPrefixed(delegation) } // return the delegation without fields contained within the key for the store -func MustUnmarshalDelegation(cdc *codec.Codec, key, value []byte) Delegation { - delegation, err := UnmarshalDelegation(cdc, key, value) +func MustUnmarshalDelegation(cdc *codec.Codec, value []byte) Delegation { + delegation, err := UnmarshalDelegation(cdc, value) if err != nil { panic(err) } @@ -57,28 +54,9 @@ func MustUnmarshalDelegation(cdc *codec.Codec, key, value []byte) Delegation { } // return the delegation without fields contained within the key for the store -func UnmarshalDelegation(cdc *codec.Codec, key, value []byte) (delegation Delegation, err error) { - var storeValue delegationValue - err = cdc.UnmarshalBinaryLengthPrefixed(value, &storeValue) - if err != nil { - err = fmt.Errorf("%v: %v", ErrNoDelegation(DefaultCodespace).Data(), err) - return - } - - addrs := key[1:] // remove prefix bytes - if len(addrs) != 2*sdk.AddrLen { - err = fmt.Errorf("%v", ErrBadDelegationAddr(DefaultCodespace).Data()) - return - } - - delAddr := sdk.AccAddress(addrs[:sdk.AddrLen]) - valAddr := sdk.ValAddress(addrs[sdk.AddrLen:]) - - return Delegation{ - DelegatorAddr: delAddr, - ValidatorAddr: valAddr, - Shares: storeValue.Shares, - }, nil +func UnmarshalDelegation(cdc *codec.Codec, value []byte) (delegation Delegation, err error) { + err = cdc.UnmarshalBinaryLengthPrefixed(value, &delegation) + return delegation, err } // nolint @@ -127,18 +105,12 @@ type ubdValue struct { // return the unbonding delegation without fields contained within the key for the store func MustMarshalUBD(cdc *codec.Codec, ubd UnbondingDelegation) []byte { - val := ubdValue{ - ubd.CreationHeight, - ubd.MinTime, - ubd.InitialBalance, - ubd.Balance, - } - return cdc.MustMarshalBinaryLengthPrefixed(val) + return cdc.MustMarshalBinaryLengthPrefixed(ubd) } // unmarshal a unbonding delegation from a store key and value -func MustUnmarshalUBD(cdc *codec.Codec, key, value []byte) UnbondingDelegation { - ubd, err := UnmarshalUBD(cdc, key, value) +func MustUnmarshalUBD(cdc *codec.Codec, value []byte) UnbondingDelegation { + ubd, err := UnmarshalUBD(cdc, value) if err != nil { panic(err) } @@ -146,29 +118,9 @@ func MustUnmarshalUBD(cdc *codec.Codec, key, value []byte) UnbondingDelegation { } // unmarshal a unbonding delegation from a store key and value -func UnmarshalUBD(cdc *codec.Codec, key, value []byte) (ubd UnbondingDelegation, err error) { - var storeValue ubdValue - err = cdc.UnmarshalBinaryLengthPrefixed(value, &storeValue) - if err != nil { - return - } - - addrs := key[1:] // remove prefix bytes - if len(addrs) != 2*sdk.AddrLen { - err = fmt.Errorf("%v", ErrBadDelegationAddr(DefaultCodespace).Data()) - return - } - delAddr := sdk.AccAddress(addrs[:sdk.AddrLen]) - valAddr := sdk.ValAddress(addrs[sdk.AddrLen:]) - - return UnbondingDelegation{ - DelegatorAddr: delAddr, - ValidatorAddr: valAddr, - CreationHeight: storeValue.CreationHeight, - MinTime: storeValue.MinTime, - InitialBalance: storeValue.InitialBalance, - Balance: storeValue.Balance, - }, nil +func UnmarshalUBD(cdc *codec.Codec, value []byte) (ubd UnbondingDelegation, err error) { + err = cdc.UnmarshalBinaryLengthPrefixed(value, &ubd) + return ubd, err } // nolint @@ -217,20 +169,12 @@ type redValue struct { // return the redelegation without fields contained within the key for the store func MustMarshalRED(cdc *codec.Codec, red Redelegation) []byte { - val := redValue{ - red.CreationHeight, - red.MinTime, - red.InitialBalance, - red.Balance, - red.SharesSrc, - red.SharesDst, - } - return cdc.MustMarshalBinaryLengthPrefixed(val) + return cdc.MustMarshalBinaryLengthPrefixed(red) } // unmarshal a redelegation from a store key and value -func MustUnmarshalRED(cdc *codec.Codec, key, value []byte) Redelegation { - red, err := UnmarshalRED(cdc, key, value) +func MustUnmarshalRED(cdc *codec.Codec, value []byte) Redelegation { + red, err := UnmarshalRED(cdc, value) if err != nil { panic(err) } @@ -238,33 +182,9 @@ func MustUnmarshalRED(cdc *codec.Codec, key, value []byte) Redelegation { } // unmarshal a redelegation from a store key and value -func UnmarshalRED(cdc *codec.Codec, key, value []byte) (red Redelegation, err error) { - var storeValue redValue - err = cdc.UnmarshalBinaryLengthPrefixed(value, &storeValue) - if err != nil { - return - } - - addrs := key[1:] // remove prefix bytes - if len(addrs) != 3*sdk.AddrLen { - err = fmt.Errorf("%v", ErrBadRedelegationAddr(DefaultCodespace).Data()) - return - } - delAddr := sdk.AccAddress(addrs[:sdk.AddrLen]) - valSrcAddr := sdk.ValAddress(addrs[sdk.AddrLen : 2*sdk.AddrLen]) - valDstAddr := sdk.ValAddress(addrs[2*sdk.AddrLen:]) - - return Redelegation{ - DelegatorAddr: delAddr, - ValidatorSrcAddr: valSrcAddr, - ValidatorDstAddr: valDstAddr, - CreationHeight: storeValue.CreationHeight, - MinTime: storeValue.MinTime, - InitialBalance: storeValue.InitialBalance, - Balance: storeValue.Balance, - SharesSrc: storeValue.SharesSrc, - SharesDst: storeValue.SharesDst, - }, nil +func UnmarshalRED(cdc *codec.Codec, value []byte) (red Redelegation, err error) { + err = cdc.UnmarshalBinaryLengthPrefixed(value, &red) + return red, err } // nolint diff --git a/x/stake/types/validator.go b/x/stake/types/validator.go index 065e4d42bd8..7ac148a85f9 100644 --- a/x/stake/types/validator.go +++ b/x/stake/types/validator.go @@ -55,40 +55,14 @@ func NewValidator(operator sdk.ValAddress, pubKey crypto.PubKey, description Des } } -// what's kept in the store value -type validatorValue struct { - ConsPubKey crypto.PubKey - Jailed bool - Status sdk.BondStatus - Tokens sdk.Int - DelegatorShares sdk.Dec - Description Description - BondHeight int64 - UnbondingHeight int64 - UnbondingMinTime time.Time - Commission Commission -} - // return the redelegation without fields contained within the key for the store func MustMarshalValidator(cdc *codec.Codec, validator Validator) []byte { - val := validatorValue{ - ConsPubKey: validator.ConsPubKey, - Jailed: validator.Jailed, - Status: validator.Status, - Tokens: validator.Tokens, - DelegatorShares: validator.DelegatorShares, - Description: validator.Description, - BondHeight: validator.BondHeight, - UnbondingHeight: validator.UnbondingHeight, - UnbondingMinTime: validator.UnbondingMinTime, - Commission: validator.Commission, - } - return cdc.MustMarshalBinaryLengthPrefixed(val) + return cdc.MustMarshalBinaryLengthPrefixed(validator) } // unmarshal a redelegation from a store key and value -func MustUnmarshalValidator(cdc *codec.Codec, operatorAddr, value []byte) Validator { - validator, err := UnmarshalValidator(cdc, operatorAddr, value) +func MustUnmarshalValidator(cdc *codec.Codec, value []byte) Validator { + validator, err := UnmarshalValidator(cdc, value) if err != nil { panic(err) } @@ -96,30 +70,9 @@ func MustUnmarshalValidator(cdc *codec.Codec, operatorAddr, value []byte) Valida } // unmarshal a redelegation from a store key and value -func UnmarshalValidator(cdc *codec.Codec, operatorAddr, value []byte) (validator Validator, err error) { - if len(operatorAddr) != sdk.AddrLen { - err = fmt.Errorf("%v", ErrBadValidatorAddr(DefaultCodespace).Data()) - return - } - var storeValue validatorValue - err = cdc.UnmarshalBinaryLengthPrefixed(value, &storeValue) - if err != nil { - return - } - - return Validator{ - OperatorAddr: operatorAddr, - ConsPubKey: storeValue.ConsPubKey, - Jailed: storeValue.Jailed, - Tokens: storeValue.Tokens, - Status: storeValue.Status, - DelegatorShares: storeValue.DelegatorShares, - Description: storeValue.Description, - BondHeight: storeValue.BondHeight, - UnbondingHeight: storeValue.UnbondingHeight, - UnbondingMinTime: storeValue.UnbondingMinTime, - Commission: storeValue.Commission, - }, nil +func UnmarshalValidator(cdc *codec.Codec, value []byte) (validator Validator, err error) { + err = cdc.UnmarshalBinaryLengthPrefixed(value, &validator) + return validator, err } // HumanReadableString returns a human readable string representation of a From 1170ee3dba61905de7f94c1e897ca035cd29d30d Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Fri, 4 Jan 2019 22:36:55 -0500 Subject: [PATCH 02/26] pending --- PENDING.md | 1 + 1 file changed, 1 insertion(+) diff --git a/PENDING.md b/PENDING.md index d2c9b4bddf0..ce2efe01eeb 100644 --- a/PENDING.md +++ b/PENDING.md @@ -22,6 +22,7 @@ BREAKING CHANGES * SDK * [stake] \#2513 Validator power type from Dec -> Int + * [stake] \#3233 key and value now contain duplicate fields to simplify code * [\#3064](https://github.com/cosmos/cosmos-sdk/issues/3064) Sanitize `sdk.Coin` denom. Coins denoms are now case insensitive, i.e. 100fooToken equals to 100FOOTOKEN. * Tendermint From 4b90e7fe6676374b6c2e6fd70abcec521881741a Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Sat, 5 Jan 2019 23:11:37 -0500 Subject: [PATCH 03/26] cleanup --- x/stake/types/delegation.go | 24 ++++-------------------- x/stake/types/validator.go | 4 ++-- 2 files changed, 6 insertions(+), 22 deletions(-) diff --git a/x/stake/types/delegation.go b/x/stake/types/delegation.go index cb840ceb17a..80e90e0c5c8 100644 --- a/x/stake/types/delegation.go +++ b/x/stake/types/delegation.go @@ -96,19 +96,12 @@ type UnbondingDelegation struct { Balance sdk.Coin `json:"balance"` // atoms to receive at completion } -type ubdValue struct { - CreationHeight int64 - MinTime time.Time - InitialBalance sdk.Coin - Balance sdk.Coin -} - // return the unbonding delegation without fields contained within the key for the store func MustMarshalUBD(cdc *codec.Codec, ubd UnbondingDelegation) []byte { return cdc.MustMarshalBinaryLengthPrefixed(ubd) } -// unmarshal a unbonding delegation from a store key and value +// unmarshal a unbonding delegation from a store value func MustUnmarshalUBD(cdc *codec.Codec, value []byte) UnbondingDelegation { ubd, err := UnmarshalUBD(cdc, value) if err != nil { @@ -117,7 +110,7 @@ func MustUnmarshalUBD(cdc *codec.Codec, value []byte) UnbondingDelegation { return ubd } -// unmarshal a unbonding delegation from a store key and value +// unmarshal a unbonding delegation from a store value func UnmarshalUBD(cdc *codec.Codec, value []byte) (ubd UnbondingDelegation, err error) { err = cdc.UnmarshalBinaryLengthPrefixed(value, &ubd) return ubd, err @@ -158,21 +151,12 @@ type Redelegation struct { SharesDst sdk.Dec `json:"shares_dst"` // amount of destination shares redelegating } -type redValue struct { - CreationHeight int64 - MinTime time.Time - InitialBalance sdk.Coin - Balance sdk.Coin - SharesSrc sdk.Dec - SharesDst sdk.Dec -} - // return the redelegation without fields contained within the key for the store func MustMarshalRED(cdc *codec.Codec, red Redelegation) []byte { return cdc.MustMarshalBinaryLengthPrefixed(red) } -// unmarshal a redelegation from a store key and value +// unmarshal a redelegation from a store value func MustUnmarshalRED(cdc *codec.Codec, value []byte) Redelegation { red, err := UnmarshalRED(cdc, value) if err != nil { @@ -181,7 +165,7 @@ func MustUnmarshalRED(cdc *codec.Codec, value []byte) Redelegation { return red } -// unmarshal a redelegation from a store key and value +// unmarshal a redelegation from a store value func UnmarshalRED(cdc *codec.Codec, value []byte) (red Redelegation, err error) { err = cdc.UnmarshalBinaryLengthPrefixed(value, &red) return red, err diff --git a/x/stake/types/validator.go b/x/stake/types/validator.go index 7ac148a85f9..6402769edc0 100644 --- a/x/stake/types/validator.go +++ b/x/stake/types/validator.go @@ -60,7 +60,7 @@ func MustMarshalValidator(cdc *codec.Codec, validator Validator) []byte { return cdc.MustMarshalBinaryLengthPrefixed(validator) } -// unmarshal a redelegation from a store key and value +// unmarshal a redelegation from a store value func MustUnmarshalValidator(cdc *codec.Codec, value []byte) Validator { validator, err := UnmarshalValidator(cdc, value) if err != nil { @@ -69,7 +69,7 @@ func MustUnmarshalValidator(cdc *codec.Codec, value []byte) Validator { return validator } -// unmarshal a redelegation from a store key and value +// unmarshal a redelegation from a store value func UnmarshalValidator(cdc *codec.Codec, value []byte) (validator Validator, err error) { err = cdc.UnmarshalBinaryLengthPrefixed(value, &validator) return validator, err From 017dab167e001eade82d86ed7a14100137a4780f Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Sun, 6 Jan 2019 00:12:28 -0500 Subject: [PATCH 04/26] cleanup x2 --- x/stake/types/delegation.go | 14 +++++--------- x/stake/types/validator.go | 2 +- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/x/stake/types/delegation.go b/x/stake/types/delegation.go index 80e90e0c5c8..46fb74e1dc2 100644 --- a/x/stake/types/delegation.go +++ b/x/stake/types/delegation.go @@ -35,16 +35,12 @@ type Delegation struct { Shares sdk.Dec `json:"shares"` } -type delegationValue struct { - Shares sdk.Dec -} - -// return the delegation without fields contained within the key for the store +// return the delegation func MustMarshalDelegation(cdc *codec.Codec, delegation Delegation) []byte { return cdc.MustMarshalBinaryLengthPrefixed(delegation) } -// return the delegation without fields contained within the key for the store +// return the delegation func MustUnmarshalDelegation(cdc *codec.Codec, value []byte) Delegation { delegation, err := UnmarshalDelegation(cdc, value) if err != nil { @@ -53,7 +49,7 @@ func MustUnmarshalDelegation(cdc *codec.Codec, value []byte) Delegation { return delegation } -// return the delegation without fields contained within the key for the store +// return the delegation func UnmarshalDelegation(cdc *codec.Codec, value []byte) (delegation Delegation, err error) { err = cdc.UnmarshalBinaryLengthPrefixed(value, &delegation) return delegation, err @@ -96,7 +92,7 @@ type UnbondingDelegation struct { Balance sdk.Coin `json:"balance"` // atoms to receive at completion } -// return the unbonding delegation without fields contained within the key for the store +// return the unbonding delegation func MustMarshalUBD(cdc *codec.Codec, ubd UnbondingDelegation) []byte { return cdc.MustMarshalBinaryLengthPrefixed(ubd) } @@ -151,7 +147,7 @@ type Redelegation struct { SharesDst sdk.Dec `json:"shares_dst"` // amount of destination shares redelegating } -// return the redelegation without fields contained within the key for the store +// return the redelegation func MustMarshalRED(cdc *codec.Codec, red Redelegation) []byte { return cdc.MustMarshalBinaryLengthPrefixed(red) } diff --git a/x/stake/types/validator.go b/x/stake/types/validator.go index 6402769edc0..eddce185ea0 100644 --- a/x/stake/types/validator.go +++ b/x/stake/types/validator.go @@ -55,7 +55,7 @@ func NewValidator(operator sdk.ValAddress, pubKey crypto.PubKey, description Des } } -// return the redelegation without fields contained within the key for the store +// return the redelegation func MustMarshalValidator(cdc *codec.Codec, validator Validator) []byte { return cdc.MustMarshalBinaryLengthPrefixed(validator) } From 270fe043d02f9618e028262ceb1a056386f95636 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Sat, 5 Jan 2019 23:05:08 -0500 Subject: [PATCH 05/26] pending --- PENDING.md | 1 + 1 file changed, 1 insertion(+) diff --git a/PENDING.md b/PENDING.md index ce2efe01eeb..a649307038a 100644 --- a/PENDING.md +++ b/PENDING.md @@ -71,6 +71,7 @@ IMPROVEMENTS slashing, and staking modules. * [\#3093](https://github.com/cosmos/cosmos-sdk/issues/3093) Ante handler does no longer read all accounts in one go when processing signatures as signature verification may fail before last signature is checked. + * [x/stake] \#1402 Add global redelegation-unbonding index * Tendermint From 9436a19378ed2983206a12ba38e08720512ea3bd Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Sat, 5 Jan 2019 23:09:27 -0500 Subject: [PATCH 06/26] working --- x/stake/types/delegation.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/x/stake/types/delegation.go b/x/stake/types/delegation.go index 46fb74e1dc2..bf2ded86029 100644 --- a/x/stake/types/delegation.go +++ b/x/stake/types/delegation.go @@ -82,6 +82,8 @@ func (d Delegation) HumanReadableString() (string, error) { return resp, nil } +type UnbondingDelegations []UnbondingDelegation + // UnbondingDelegation reflects a delegation's passive unbonding queue. type UnbondingDelegation struct { DelegatorAddr sdk.AccAddress `json:"delegator_addr"` // delegator @@ -134,6 +136,8 @@ func (d UnbondingDelegation) HumanReadableString() (string, error) { } +type Redelegations []Redelegation + // Redelegation reflects a delegation's passive re-delegation queue. type Redelegation struct { DelegatorAddr sdk.AccAddress `json:"delegator_addr"` // delegator From 3a656a292cfba93959e0ee87a000197790db4e0e Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Sun, 6 Jan 2019 00:08:35 -0500 Subject: [PATCH 07/26] minor refactors --- x/stake/handler.go | 5 +-- x/stake/keeper/delegation.go | 63 +++++++++++++++++------------------- x/stake/types/delegation.go | 36 +++++++++++++++++++++ 3 files changed, 68 insertions(+), 36 deletions(-) diff --git a/x/stake/handler.go b/x/stake/handler.go index 408ca52a338..a984118266a 100644 --- a/x/stake/handler.go +++ b/x/stake/handler.go @@ -53,7 +53,7 @@ func EndBlocker(ctx sdk.Context, k keeper.Keeper) ([]abci.ValidatorUpdate, sdk.T k.UnbondAllMatureValidatorQueue(ctx) // Remove all mature unbonding delegations from the ubd queue. - matureUnbonds := k.DequeueAllMatureUnbondingQueue(ctx, ctx.BlockHeader().Time) + matureUnbonds := k.DequeueAllMatureUBDQueue(ctx, ctx.BlockHeader().Time) for _, dvPair := range matureUnbonds { err := k.CompleteUnbonding(ctx, dvPair.DelegatorAddr, dvPair.ValidatorAddr) if err != nil { @@ -70,7 +70,8 @@ func EndBlocker(ctx sdk.Context, k keeper.Keeper) ([]abci.ValidatorUpdate, sdk.T // Remove all mature redelegations from the red queue. matureRedelegations := k.DequeueAllMatureRedelegationQueue(ctx, ctx.BlockHeader().Time) for _, dvvTriplet := range matureRedelegations { - err := k.CompleteRedelegation(ctx, dvvTriplet.DelegatorAddr, dvvTriplet.ValidatorSrcAddr, dvvTriplet.ValidatorDstAddr) + err := k.CompleteRedelegation(ctx, dvvTriplet.DelegatorAddr, + dvvTriplet.ValidatorSrcAddr, dvvTriplet.ValidatorDstAddr) if err != nil { continue } diff --git a/x/stake/keeper/delegation.go b/x/stake/keeper/delegation.go index a1f26e3078f..e4974a0b2f9 100644 --- a/x/stake/keeper/delegation.go +++ b/x/stake/keeper/delegation.go @@ -170,9 +170,12 @@ func (k Keeper) RemoveUnbondingDelegation(ctx sdk.Context, ubd types.UnbondingDe store.Delete(GetUBDByValIndexKey(ubd.DelegatorAddr, ubd.ValidatorAddr)) } -// gets a specific unbonding queue timeslice. A timeslice is a slice of DVPairs corresponding to unbonding delegations -// that expire at a certain time. -func (k Keeper) GetUnbondingQueueTimeSlice(ctx sdk.Context, timestamp time.Time) (dvPairs []types.DVPair) { +//________________________________________________ +// unbonding delegation queue timeslice operations + +// gets a specific unbonding queue timeslice. A timeslice is a slice of DVPairs +// corresponding to unbonding delegations that expire at a certain time. +func (k Keeper) GetUBDQueueTimeSlice(ctx sdk.Context, timestamp time.Time) (dvPairs []types.DVPair) { store := ctx.KVStore(k.storeKey) bz := store.Get(GetUnbondingDelegationTimeKey(timestamp)) if bz == nil { @@ -183,38 +186,42 @@ func (k Keeper) GetUnbondingQueueTimeSlice(ctx sdk.Context, timestamp time.Time) } // Sets a specific unbonding queue timeslice. -func (k Keeper) SetUnbondingQueueTimeSlice(ctx sdk.Context, timestamp time.Time, keys []types.DVPair) { +func (k Keeper) SetUBDQueueTimeSlice(ctx sdk.Context, timestamp time.Time, keys []types.DVPair) { store := ctx.KVStore(k.storeKey) bz := k.cdc.MustMarshalBinaryLengthPrefixed(keys) store.Set(GetUnbondingDelegationTimeKey(timestamp), bz) } // Insert an unbonding delegation to the appropriate timeslice in the unbonding queue -func (k Keeper) InsertUnbondingQueue(ctx sdk.Context, ubd types.UnbondingDelegation) { - timeSlice := k.GetUnbondingQueueTimeSlice(ctx, ubd.MinTime) +func (k Keeper) InsertUBDQueue(ctx sdk.Context, ubd types.UnbondingDelegation) { + timeSlice := k.GetUBDQueueTimeSlice(ctx, ubd.MinTime) dvPair := types.DVPair{ubd.DelegatorAddr, ubd.ValidatorAddr} if len(timeSlice) == 0 { - k.SetUnbondingQueueTimeSlice(ctx, ubd.MinTime, []types.DVPair{dvPair}) + k.SetUBDQueueTimeSlice(ctx, ubd.MinTime, []types.DVPair{dvPair}) } else { timeSlice = append(timeSlice, dvPair) - k.SetUnbondingQueueTimeSlice(ctx, ubd.MinTime, timeSlice) + k.SetUBDQueueTimeSlice(ctx, ubd.MinTime, timeSlice) } } // Returns all the unbonding queue timeslices from time 0 until endTime -func (k Keeper) UnbondingQueueIterator(ctx sdk.Context, endTime time.Time) sdk.Iterator { +func (k Keeper) UBDQueueIterator(ctx sdk.Context, endTime time.Time) sdk.Iterator { store := ctx.KVStore(k.storeKey) - return store.Iterator(UnbondingQueueKey, sdk.InclusiveEndBytes(GetUnbondingDelegationTimeKey(endTime))) + return store.Iterator(UnbondingQueueKey, + sdk.InclusiveEndBytes(GetUnbondingDelegationTimeKey(endTime))) } // Returns a concatenated list of all the timeslices before currTime, and deletes the timeslices from the queue -func (k Keeper) DequeueAllMatureUnbondingQueue(ctx sdk.Context, currTime time.Time) (matureUnbonds []types.DVPair) { +func (k Keeper) DequeueAllMatureUBDQueue(ctx sdk.Context, + currTime time.Time) (matureUnbonds []types.DVPair) { + store := ctx.KVStore(k.storeKey) // gets an iterator for all timeslices from time 0 until the current Blockheader time - unbondingTimesliceIterator := k.UnbondingQueueIterator(ctx, ctx.BlockHeader().Time) + unbondingTimesliceIterator := k.UBDQueueIterator(ctx, ctx.BlockHeader().Time) for ; unbondingTimesliceIterator.Valid(); unbondingTimesliceIterator.Next() { timeslice := []types.DVPair{} - k.cdc.MustUnmarshalBinaryLengthPrefixed(unbondingTimesliceIterator.Value(), ×lice) + value := unbondingTimesliceIterator.Value() + k.cdc.MustUnmarshalBinaryLengthPrefixed(value, ×lice) matureUnbonds = append(matureUnbonds, timeslice...) store.Delete(unbondingTimesliceIterator.Key()) } @@ -322,6 +329,9 @@ func (k Keeper) RemoveRedelegation(ctx sdk.Context, red types.Redelegation) { store.Delete(GetREDByValDstIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr)) } +//________________________________________________ +// redelegation queue timeslice operations + // Gets a specific redelegation queue timeslice. A timeslice is a slice of DVVTriplets corresponding to redelegations // that expire at a certain time. func (k Keeper) GetRedelegationQueueTimeSlice(ctx sdk.Context, timestamp time.Time) (dvvTriplets []types.DVVTriplet) { @@ -366,7 +376,8 @@ func (k Keeper) DequeueAllMatureRedelegationQueue(ctx sdk.Context, currTime time redelegationTimesliceIterator := k.RedelegationQueueIterator(ctx, ctx.BlockHeader().Time) for ; redelegationTimesliceIterator.Valid(); redelegationTimesliceIterator.Next() { timeslice := []types.DVVTriplet{} - k.cdc.MustUnmarshalBinaryLengthPrefixed(redelegationTimesliceIterator.Value(), ×lice) + value := redelegationTimesliceIterator.Value() + k.cdc.MustUnmarshalBinaryLengthPrefixed(value, ×lice) matureRedelegations = append(matureRedelegations, timeslice...) store.Delete(redelegationTimesliceIterator.Key()) } @@ -530,16 +541,9 @@ func (k Keeper) BeginUnbonding(ctx sdk.Context, return types.UnbondingDelegation{MinTime: minTime}, nil } - ubd := types.UnbondingDelegation{ - DelegatorAddr: delAddr, - ValidatorAddr: valAddr, - CreationHeight: height, - MinTime: minTime, - Balance: balance, - InitialBalance: balance, - } + ubd := NewUnbondingDelegation(delAddr, valAddr, height, minTime, balance) k.SetUnbondingDelegation(ctx, ubd) - k.InsertUnbondingQueue(ctx, ubd) + k.InsertUBDQueue(ctx, ubd) return ubd, nil } @@ -608,17 +612,8 @@ func (k Keeper) BeginRedelegation(ctx sdk.Context, delAddr sdk.AccAddress, return types.Redelegation{MinTime: minTime}, nil } - red := types.Redelegation{ - DelegatorAddr: delAddr, - ValidatorSrcAddr: valSrcAddr, - ValidatorDstAddr: valDstAddr, - CreationHeight: height, - MinTime: minTime, - SharesDst: sharesCreated, - SharesSrc: sharesAmount, - Balance: returnCoin, - InitialBalance: returnCoin, - } + red := NewRedelegation(delAddr, valSrcAddr, valDstAddr, height, minTime, + returnCoin, sharesAmount, sharesCreated) k.SetRedelegation(ctx, red) k.InsertRedelegationQueue(ctx, red) return red, nil diff --git a/x/stake/types/delegation.go b/x/stake/types/delegation.go index bf2ded86029..4f25a9e5619 100644 --- a/x/stake/types/delegation.go +++ b/x/stake/types/delegation.go @@ -82,6 +82,7 @@ func (d Delegation) HumanReadableString() (string, error) { return resp, nil } +// UnbondingDelegations - all UnbondingDelegation from a delegation to a validator type UnbondingDelegations []UnbondingDelegation // UnbondingDelegation reflects a delegation's passive unbonding queue. @@ -94,6 +95,21 @@ type UnbondingDelegation struct { Balance sdk.Coin `json:"balance"` // atoms to receive at completion } +// NewUnbondingDelegation - create a new unbonding delegation object +func NewUnbondingDelegation(delegatorAddr sdk.AccAddress, + validatorAddr sdk.ValAddress, creationHeight int64, minTime time.Time, + balance sdk.Coin) UnbondingDelegation { + + return UnbondingDelegation{ + DelegatorAddr: delegatorAddr, + ValidatorAddr: validatorAddr, + CreationHeight: creationHeight, + MinTime: minTime, + InitialBalance: balance, + Balance: balance, + } +} + // return the unbonding delegation func MustMarshalUBD(cdc *codec.Codec, ubd UnbondingDelegation) []byte { return cdc.MustMarshalBinaryLengthPrefixed(ubd) @@ -136,6 +152,7 @@ func (d UnbondingDelegation) HumanReadableString() (string, error) { } +// Redelegations - all Redelegation from a delegation to a validator src/dst type Redelegations []Redelegation // Redelegation reflects a delegation's passive re-delegation queue. @@ -151,6 +168,25 @@ type Redelegation struct { SharesDst sdk.Dec `json:"shares_dst"` // amount of destination shares redelegating } +// NewRedelegation - create a new redelegation object +func NewRedelegation(delegatorAddr sdk.AccAddress, validatorSrcAddr, + validatorDstAddr sdk.ValAddress, creationHeight int64, + minTime time.time, balance sdk.Coin, + sharesSrc, sharesDst sdk.Dec) Redelegation { + + return Redelegation{ + DelegatorAddr: delegatorAddr, + ValidatorSrcAddr: validatorSrcAddr, + ValidatorDstAddr: validatorDstAddr, + CreationHeight: creationHeight, + MinTime: minTime, + InitialBalance: balance, + Balance: balance, + SharesSrc: sharesSrc, + SharesDst: sharesDst, + } +} + // return the redelegation func MustMarshalRED(cdc *codec.Codec, red Redelegation) []byte { return cdc.MustMarshalBinaryLengthPrefixed(red) From e1e24698ee2f4d78252ee361e6b84696261ef91a Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Sun, 6 Jan 2019 00:29:53 -0500 Subject: [PATCH 08/26] entry structs defined --- x/stake/keeper/delegation.go | 8 ++-- x/stake/types/delegation.go | 85 +++++++++++++++++++++++++----------- 2 files changed, 65 insertions(+), 28 deletions(-) diff --git a/x/stake/keeper/delegation.go b/x/stake/keeper/delegation.go index e4974a0b2f9..f3ef56252a3 100644 --- a/x/stake/keeper/delegation.go +++ b/x/stake/keeper/delegation.go @@ -514,9 +514,10 @@ func (k Keeper) getBeginInfo(ctx sdk.Context, valSrcAddr sdk.ValAddress) ( } // begin unbonding an unbonding record -func (k Keeper) BeginUnbonding(ctx sdk.Context, - delAddr sdk.AccAddress, valAddr sdk.ValAddress, sharesAmount sdk.Dec) (types.UnbondingDelegation, sdk.Error) { +func (k Keeper) BeginUnbonding(ctx sdk.Context, delAddr sdk.AccAddress, + valAddr sdk.ValAddress, sharesAmount sdk.Dec) (types.UnbondingDelegation, sdk.Error) { + // XXX remove this quickfix before merge // TODO quick fix, instead we should use an index, see https://github.com/cosmos/cosmos-sdk/issues/1402 _, found := k.GetUnbondingDelegation(ctx, delAddr, valAddr) if found { @@ -550,7 +551,8 @@ func (k Keeper) BeginUnbonding(ctx sdk.Context, // complete unbonding an unbonding record // CONTRACT: Expects unbonding passed in has finished the unbonding period -func (k Keeper) CompleteUnbonding(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) sdk.Error { +func (k Keeper) CompleteUnbonding(ctx sdk.Context, delAddr sdk.AccAddress, + valAddr sdk.ValAddress, currentTime time.Time) sdk.Error { ubd, found := k.GetUnbondingDelegation(ctx, delAddr, valAddr) if !found { diff --git a/x/stake/types/delegation.go b/x/stake/types/delegation.go index 4f25a9e5619..7ce9e6a87db 100644 --- a/x/stake/types/delegation.go +++ b/x/stake/types/delegation.go @@ -26,6 +26,8 @@ type DVVTriplet struct { ValidatorDstAddr sdk.ValAddress } +//_______________________________________________________________________ + // Delegation represents the bond with tokens held by an account. It is // owned by one delegator, and is associated with the voting power of one // pubKey. @@ -82,17 +84,14 @@ func (d Delegation) HumanReadableString() (string, error) { return resp, nil } -// UnbondingDelegations - all UnbondingDelegation from a delegation to a validator -type UnbondingDelegations []UnbondingDelegation +//________________________________________________________________________ // UnbondingDelegation reflects a delegation's passive unbonding queue. +// it may hold multiple entries between the same delegator/validator type UnbondingDelegation struct { - DelegatorAddr sdk.AccAddress `json:"delegator_addr"` // delegator - ValidatorAddr sdk.ValAddress `json:"validator_addr"` // validator unbonding from operator addr - CreationHeight int64 `json:"creation_height"` // height which the unbonding took place - MinTime time.Time `json:"min_time"` // unix time for unbonding completion - InitialBalance sdk.Coin `json:"initial_balance"` // atoms initially scheduled to receive at completion - Balance sdk.Coin `json:"balance"` // atoms to receive at completion + DelegatorAddr sdk.AccAddress `json:"delegator_addr"` // delegator + ValidatorAddr sdk.ValAddress `json:"validator_addr"` // validator unbonding from operator addr + Entries []UnbondingDelegationEntry `json:"entries"` // unbonding delegation entries } // NewUnbondingDelegation - create a new unbonding delegation object @@ -100,9 +99,27 @@ func NewUnbondingDelegation(delegatorAddr sdk.AccAddress, validatorAddr sdk.ValAddress, creationHeight int64, minTime time.Time, balance sdk.Coin) UnbondingDelegation { + entry := NewUnbondingDelegationEntry(creationHeight, minTime, balance) return UnbondingDelegation{ - DelegatorAddr: delegatorAddr, - ValidatorAddr: validatorAddr, + DelegatorAddr: delegatorAddr, + ValidatorAddr: validatorAddr, + Entries: []UnbondingDelegationEntry{entry}, + } +} + +// UnbondingDelegationEntry - entry to an UnbondingDelegation +type UnbondingDelegationEntry struct { + CreationHeight int64 `json:"creation_height"` // height which the unbonding took place + MinTime time.Time `json:"min_time"` // unix time for unbonding completion + InitialBalance sdk.Coin `json:"initial_balance"` // atoms initially scheduled to receive at completion + Balance sdk.Coin `json:"balance"` // atoms to receive at completion +} + +// NewUnbondingDelegation - create a new unbonding delegation object +func NewUnbondingDelegationEntry(creationHeight int64, minTime time.Time, + balance sdk.Coin) UnbondingDelegation { + + return UnbondingDelegationEntry{ CreationHeight: creationHeight, MinTime: minTime, InitialBalance: balance, @@ -157,15 +174,10 @@ type Redelegations []Redelegation // Redelegation reflects a delegation's passive re-delegation queue. type Redelegation struct { - DelegatorAddr sdk.AccAddress `json:"delegator_addr"` // delegator - ValidatorSrcAddr sdk.ValAddress `json:"validator_src_addr"` // validator redelegation source operator addr - ValidatorDstAddr sdk.ValAddress `json:"validator_dst_addr"` // validator redelegation destination operator addr - CreationHeight int64 `json:"creation_height"` // height which the redelegation took place - MinTime time.Time `json:"min_time"` // unix time for redelegation completion - InitialBalance sdk.Coin `json:"initial_balance"` // initial balance when redelegation started - Balance sdk.Coin `json:"balance"` // current balance - SharesSrc sdk.Dec `json:"shares_src"` // amount of source shares redelegating - SharesDst sdk.Dec `json:"shares_dst"` // amount of destination shares redelegating + DelegatorAddr sdk.AccAddress `json:"delegator_addr"` // delegator + ValidatorSrcAddr sdk.ValAddress `json:"validator_src_addr"` // validator redelegation source operator addr + ValidatorDstAddr sdk.ValAddress `json:"validator_dst_addr"` // validator redelegation destination operator addr + Entries []RedelegationEntry `json:"entries"` // redelegation entries } // NewRedelegation - create a new redelegation object @@ -174,16 +186,39 @@ func NewRedelegation(delegatorAddr sdk.AccAddress, validatorSrcAddr, minTime time.time, balance sdk.Coin, sharesSrc, sharesDst sdk.Dec) Redelegation { + entry := NewRedelegationEntry(creationHeight, + minTime, balance, sharesSrc, sharesDst) + return Redelegation{ DelegatorAddr: delegatorAddr, ValidatorSrcAddr: validatorSrcAddr, ValidatorDstAddr: validatorDstAddr, - CreationHeight: creationHeight, - MinTime: minTime, - InitialBalance: balance, - Balance: balance, - SharesSrc: sharesSrc, - SharesDst: sharesDst, + Entries: []EntriesRedelegationEntry{entries}, + } +} + +// RedelegationEntry - entry to a Redelegation +type RedelegationEntry struct { + CreationHeight int64 `json:"creation_height"` // height which the redelegation took place + MinTime time.Time `json:"min_time"` // unix time for redelegation completion + InitialBalance sdk.Coin `json:"initial_balance"` // initial balance when redelegation started + Balance sdk.Coin `json:"balance"` // current balance + SharesSrc sdk.Dec `json:"shares_src"` // amount of source shares redelegating + SharesDst sdk.Dec `json:"shares_dst"` // amount of destination shares redelegating +} + +// NewRedelegation - create a new redelegation object +func NewRedelegationEntry(creationHeight int64, + minTime time.time, balance sdk.Coin, + sharesSrc, sharesDst sdk.Dec) Redelegation { + + return RedelegationEntry{ + CreationHeight: creationHeight, + MinTime: minTime, + InitialBalance: balance, + Balance: balance, + SharesSrc: sharesSrc, + SharesDst: sharesDst, } } From 7ad6dd7c8833268b3c4acaeb2142b8af570796d5 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Mon, 7 Jan 2019 00:25:39 -0500 Subject: [PATCH 09/26] uncompiled mechanism written --- x/stake/keeper/delegation.go | 104 ++++++++++++++++++++++++----------- x/stake/types/delegation.go | 94 +++++++++++++++++++++---------- 2 files changed, 136 insertions(+), 62 deletions(-) diff --git a/x/stake/keeper/delegation.go b/x/stake/keeper/delegation.go index f3ef56252a3..541fff6baa3 100644 --- a/x/stake/keeper/delegation.go +++ b/x/stake/keeper/delegation.go @@ -170,6 +170,22 @@ func (k Keeper) RemoveUnbondingDelegation(ctx sdk.Context, ubd types.UnbondingDe store.Delete(GetUBDByValIndexKey(ubd.DelegatorAddr, ubd.ValidatorAddr)) } +// SetUnbondingDelegationEntry adds an entry to the unbonding delegation at +// the given addresses. It creates the unbonding delegation if it does not exist +func (k Keeper) SetUnbondingDelegationEntry(ctx sdk.Context, + delegatorAddr sdk.AccAddress, validatorAddr sdk.ValAddress, + creationHeight int64, minTime time.Time, balance sdk.Coin) types.UnbondingDelegation { + + ubd, found := k.GetUnbondingDelegation(ctx, delegatorAddr, validatorAddr) + if found { + ubd.AddEntry(creationHeight, minTime, balance) + } else { + ubd = NewUnbondingDelegation(delegationAddr, validatorAddr, creationHeight, minTime, balance) + } + k.SetUnbondingDelegation(ctx, ubd) + return ubd +} + //________________________________________________ // unbonding delegation queue timeslice operations @@ -305,6 +321,26 @@ func (k Keeper) SetRedelegation(ctx sdk.Context, red types.Redelegation) { store.Set(GetREDByValDstIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr), []byte{}) } +// SetUnbondingDelegationEntry adds an entry to the unbonding delegation at +// the given addresses. It creates the unbonding delegation if it does not exist +func (k Keeper) SetRedelegationEntry(ctx sdk.Context, + delegatorAddr sdk.AccAddress, validatorSrcAddr, + validatorDstAddr sdk.ValAddress, creationHeight int64, + minTime time.time, balance sdk.Coin, + sharesSrc, sharesDst sdk.Dec) Redelegation { + + red, found := k.GetRedelegation(ctx, delegatorAddr, validatorSrcAddr, validatorDstAddr) + if found { + red.AddEntry(creationHeight, minTime, balance, sharesSrc, sharesDst) + } else { + red = NewRedelegation(delegatorAddr, validatorSrcAddr, + validatorDstAddr, creationHeight, minTime, balance, sharesSrc, + sharesDst) + } + k.SetRedelegation(ctx, red) + return red +} + // iterate through all redelegations func (k Keeper) IterateRedelegations(ctx sdk.Context, fn func(index int64, red types.Redelegation) (stop bool)) { store := ctx.KVStore(k.storeKey) @@ -517,13 +553,6 @@ func (k Keeper) getBeginInfo(ctx sdk.Context, valSrcAddr sdk.ValAddress) ( func (k Keeper) BeginUnbonding(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress, sharesAmount sdk.Dec) (types.UnbondingDelegation, sdk.Error) { - // XXX remove this quickfix before merge - // TODO quick fix, instead we should use an index, see https://github.com/cosmos/cosmos-sdk/issues/1402 - _, found := k.GetUnbondingDelegation(ctx, delAddr, valAddr) - if found { - return types.UnbondingDelegation{}, types.ErrExistingUnbondingDelegation(k.Codespace()) - } - // create the unbonding delegation minTime, height, completeNow := k.getBeginInfo(ctx, valAddr) @@ -542,28 +571,39 @@ func (k Keeper) BeginUnbonding(ctx sdk.Context, delAddr sdk.AccAddress, return types.UnbondingDelegation{MinTime: minTime}, nil } - ubd := NewUnbondingDelegation(delAddr, valAddr, height, minTime, balance) - k.SetUnbondingDelegation(ctx, ubd) + ubd := k.SetUnbondingDelegationEntry(ctx, delAddr, valAddr, height, minTime, balance) k.InsertUBDQueue(ctx, ubd) - return ubd, nil } -// complete unbonding an unbonding record -// CONTRACT: Expects unbonding passed in has finished the unbonding period +// CompleteUnbonding completes the unbonding of all mature entries in the +// retrieved unbonding delegation object. func (k Keeper) CompleteUnbonding(ctx sdk.Context, delAddr sdk.AccAddress, - valAddr sdk.ValAddress, currentTime time.Time) sdk.Error { + valAddr sdk.ValAddress) sdk.Error { ubd, found := k.GetUnbondingDelegation(ctx, delAddr, valAddr) if !found { return types.ErrNoUnbondingDelegation(k.Codespace()) } - _, _, err := k.bankKeeper.AddCoins(ctx, ubd.DelegatorAddr, sdk.Coins{ubd.Balance}) - if err != nil { - return err + ctxTime := ctx.BlockHeader().Time + + // loop through all the entries and complete unbonding mature entries + for i, entry := range ubd.Entries { + if entry.IsMature(ctxTime) { + _, _, err := k.bankKeeper.AddCoins(ctx, ubd.DelegatorAddr, sdk.Coins{ubd.Balance}) + if err != nil { + return err + } + ubd.RemoveEntry(i) + + // remove the ubd if there are no more entries + if len(Entries) == 0 { + k.RemoveUnbondingDelegation(ctx, ubd) + } + } } - k.RemoveUnbondingDelegation(ctx, ubd) + return nil } @@ -575,13 +615,6 @@ func (k Keeper) BeginRedelegation(ctx sdk.Context, delAddr sdk.AccAddress, return types.Redelegation{}, types.ErrSelfRedelegation(k.Codespace()) } - // check if there is already a redelgation in progress from src to dst - // TODO quick fix, instead we should use an index, see https://github.com/cosmos/cosmos-sdk/issues/1402 - _, found := k.GetRedelegation(ctx, delAddr, valSrcAddr, valDstAddr) - if found { - return types.Redelegation{}, types.ErrConflictingRedelegation(k.Codespace()) - } - // check if this is a transitive redelegation if k.HasReceivingRedelegation(ctx, delAddr, valSrcAddr) { return types.Redelegation{}, types.ErrTransitiveRedelegation(k.Codespace()) @@ -614,14 +647,14 @@ func (k Keeper) BeginRedelegation(ctx sdk.Context, delAddr sdk.AccAddress, return types.Redelegation{MinTime: minTime}, nil } - red := NewRedelegation(delAddr, valSrcAddr, valDstAddr, height, minTime, - returnCoin, sharesAmount, sharesCreated) - k.SetRedelegation(ctx, red) + red := k.SetUnbondingDelegationEntry(ctx, delAddr, valSrcAddr, valDstAddr, + height, minTime, returnCoin, sharesAmount, sharesCreated) k.InsertRedelegationQueue(ctx, red) return red, nil } -// complete unbonding an ongoing redelegation +// CompleteRedelegation completes the unbonding of all mature entries in the +// retrieved unbonding delegation object. func (k Keeper) CompleteRedelegation(ctx sdk.Context, delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress) sdk.Error { @@ -630,12 +663,19 @@ func (k Keeper) CompleteRedelegation(ctx sdk.Context, delAddr sdk.AccAddress, return types.ErrNoRedelegation(k.Codespace()) } - // ensure that enough time has passed ctxTime := ctx.BlockHeader().Time - if red.MinTime.After(ctxTime) { - return types.ErrNotMature(k.Codespace(), "redelegation", "unit-time", red.MinTime, ctxTime) + + // loop through all the entries and complete mature redelegation entries + for i, entry := range red.Entries { + if entry.IsMature(ctxTime) { + red.RemoveEntry(i) + + // remove the redelegation if there are no more entries + if len(red.Entries) == 0 { + k.RemoveRedelegation(ctx, red) + } + } } - k.RemoveRedelegation(ctx, red) return nil } diff --git a/x/stake/types/delegation.go b/x/stake/types/delegation.go index 7ce9e6a87db..05972c5321d 100644 --- a/x/stake/types/delegation.go +++ b/x/stake/types/delegation.go @@ -94,6 +94,19 @@ type UnbondingDelegation struct { Entries []UnbondingDelegationEntry `json:"entries"` // unbonding delegation entries } +// UnbondingDelegationEntry - entry to an UnbondingDelegation +type UnbondingDelegationEntry struct { + CreationHeight int64 `json:"creation_height"` // height which the unbonding took place + CompletionTime time.Time `json:"completion_time"` // unix time for unbonding completion + InitialBalance sdk.Coin `json:"initial_balance"` // atoms initially scheduled to receive at completion + Balance sdk.Coin `json:"balance"` // atoms to receive at completion +} + +// IsMature - is the current entry mature +func (e UnbondingDelegationEntry) IsMature(currentTime time.Time) bool { + return !e.CompletionTime.After(currentTime) +} + // NewUnbondingDelegation - create a new unbonding delegation object func NewUnbondingDelegation(delegatorAddr sdk.AccAddress, validatorAddr sdk.ValAddress, creationHeight int64, minTime time.Time, @@ -107,26 +120,31 @@ func NewUnbondingDelegation(delegatorAddr sdk.AccAddress, } } -// UnbondingDelegationEntry - entry to an UnbondingDelegation -type UnbondingDelegationEntry struct { - CreationHeight int64 `json:"creation_height"` // height which the unbonding took place - MinTime time.Time `json:"min_time"` // unix time for unbonding completion - InitialBalance sdk.Coin `json:"initial_balance"` // atoms initially scheduled to receive at completion - Balance sdk.Coin `json:"balance"` // atoms to receive at completion -} - // NewUnbondingDelegation - create a new unbonding delegation object -func NewUnbondingDelegationEntry(creationHeight int64, minTime time.Time, +func NewUnbondingDelegationEntry(creationHeight int64, completionTime time.Time, balance sdk.Coin) UnbondingDelegation { return UnbondingDelegationEntry{ CreationHeight: creationHeight, - MinTime: minTime, + CompletionTime: completionTime, InitialBalance: balance, Balance: balance, } } +// AddEntry - append entry to the unbonding delegation +func (d *UnbondingDelegation) AddEntry(creationHeight int64, + minTime time.Time, balance sdk.Coin) { + + entry := NewUnbondingDelegationEntry(height, minTime, balance) + d.Entries = append(d.Entries, entry) +} + +// RemoveEntry - remove entry at index i to the unbonding delegation +func (d *UnbondingDelegation) RemoveEntry(i int64) { + d.Entries = append(d.Entries[:i], d.Entries[i+1:]...) +} + // return the unbonding delegation func MustMarshalUBD(cdc *codec.Codec, ubd UnbondingDelegation) []byte { return cdc.MustMarshalBinaryLengthPrefixed(ubd) @@ -169,9 +187,6 @@ func (d UnbondingDelegation) HumanReadableString() (string, error) { } -// Redelegations - all Redelegation from a delegation to a validator src/dst -type Redelegations []Redelegation - // Redelegation reflects a delegation's passive re-delegation queue. type Redelegation struct { DelegatorAddr sdk.AccAddress `json:"delegator_addr"` // delegator @@ -180,6 +195,16 @@ type Redelegation struct { Entries []RedelegationEntry `json:"entries"` // redelegation entries } +// RedelegationEntry - entry to a Redelegation +type RedelegationEntry struct { + CreationHeight int64 `json:"creation_height"` // height which the redelegation took place + CompletetionTime time.Time `json:"completion_time"` // unix time for redelegation completion + InitialBalance sdk.Coin `json:"initial_balance"` // initial balance when redelegation started + Balance sdk.Coin `json:"balance"` // current balance + SharesSrc sdk.Dec `json:"shares_src"` // amount of source shares redelegating + SharesDst sdk.Dec `json:"shares_dst"` // amount of destination shares redelegating +} + // NewRedelegation - create a new redelegation object func NewRedelegation(delegatorAddr sdk.AccAddress, validatorSrcAddr, validatorDstAddr sdk.ValAddress, creationHeight int64, @@ -197,31 +222,40 @@ func NewRedelegation(delegatorAddr sdk.AccAddress, validatorSrcAddr, } } -// RedelegationEntry - entry to a Redelegation -type RedelegationEntry struct { - CreationHeight int64 `json:"creation_height"` // height which the redelegation took place - MinTime time.Time `json:"min_time"` // unix time for redelegation completion - InitialBalance sdk.Coin `json:"initial_balance"` // initial balance when redelegation started - Balance sdk.Coin `json:"balance"` // current balance - SharesSrc sdk.Dec `json:"shares_src"` // amount of source shares redelegating - SharesDst sdk.Dec `json:"shares_dst"` // amount of destination shares redelegating -} - // NewRedelegation - create a new redelegation object func NewRedelegationEntry(creationHeight int64, - minTime time.time, balance sdk.Coin, + completionTime time.time, balance sdk.Coin, sharesSrc, sharesDst sdk.Dec) Redelegation { return RedelegationEntry{ - CreationHeight: creationHeight, - MinTime: minTime, - InitialBalance: balance, - Balance: balance, - SharesSrc: sharesSrc, - SharesDst: sharesDst, + CreationHeight: creationHeight, + CompletetionTime: completionTime, + InitialBalance: balance, + Balance: balance, + SharesSrc: sharesSrc, + SharesDst: sharesDst, } } +// IsMature - is the current entry mature +func (e RedelegationEntry) IsMature(currentTime time.Time) bool { + return !e.CompletionTime.After(currentTime) +} + +// AddEntry - append entry to the unbonding delegation +func (d *Redelegation) AddEntry(creationHeight int64, + minTime time.time, balance sdk.Coin, + sharesSrc, sharesDst sdk.Dec) { + + entry := NewUnbondingDelegationEntry(height, minTime, balance) + d.Entries = append(d.Entries, entry) +} + +// RemoveEntry - remove entry at index i to the unbonding delegation +func (d *Redelegation) RemoveEntry(i int64) { + d.Entries = append(d.Entries[:i], d.Entries[i+1:]...) +} + // return the redelegation func MustMarshalRED(cdc *codec.Codec, red Redelegation) []byte { return cdc.MustMarshalBinaryLengthPrefixed(red) From cae553e52d9257d5c6d6f3e50333030c06f879bf Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Mon, 7 Jan 2019 01:10:02 -0500 Subject: [PATCH 10/26] add many compile fixes --- x/stake/handler.go | 12 +-- x/stake/keeper/delegation.go | 95 ++++++++++---------- x/stake/keeper/slash.go | 150 +++++++++++++++++--------------- x/stake/querier/querier_test.go | 10 ++- x/stake/types/delegation.go | 62 ++++++------- 5 files changed, 176 insertions(+), 153 deletions(-) diff --git a/x/stake/handler.go b/x/stake/handler.go index a984118266a..e5b78329ce5 100644 --- a/x/stake/handler.go +++ b/x/stake/handler.go @@ -216,34 +216,34 @@ func handleMsgDelegate(ctx sdk.Context, msg types.MsgDelegate, k keeper.Keeper) } func handleMsgBeginUnbonding(ctx sdk.Context, msg types.MsgBeginUnbonding, k keeper.Keeper) sdk.Result { - ubd, err := k.BeginUnbonding(ctx, msg.DelegatorAddr, msg.ValidatorAddr, msg.SharesAmount) + completionTime, err := k.BeginUnbonding(ctx, msg.DelegatorAddr, msg.ValidatorAddr, msg.SharesAmount) if err != nil { return err.Result() } - finishTime := types.MsgCdc.MustMarshalBinaryLengthPrefixed(ubd.MinTime) + finishTime := types.MsgCdc.MustMarshalBinaryLengthPrefixed(completionTime) tags := sdk.NewTags( tags.Delegator, []byte(msg.DelegatorAddr.String()), tags.SrcValidator, []byte(msg.ValidatorAddr.String()), - tags.EndTime, []byte(ubd.MinTime.Format(time.RFC3339)), + tags.EndTime, []byte(completionTime.Format(time.RFC3339)), ) return sdk.Result{Data: finishTime, Tags: tags} } func handleMsgBeginRedelegate(ctx sdk.Context, msg types.MsgBeginRedelegate, k keeper.Keeper) sdk.Result { - red, err := k.BeginRedelegation(ctx, msg.DelegatorAddr, msg.ValidatorSrcAddr, + completionTime, err := k.BeginRedelegation(ctx, msg.DelegatorAddr, msg.ValidatorSrcAddr, msg.ValidatorDstAddr, msg.SharesAmount) if err != nil { return err.Result() } - finishTime := types.MsgCdc.MustMarshalBinaryLengthPrefixed(red.MinTime) + finishTime := types.MsgCdc.MustMarshalBinaryLengthPrefixed(completionTime) resTags := sdk.NewTags( tags.Delegator, []byte(msg.DelegatorAddr.String()), tags.SrcValidator, []byte(msg.ValidatorSrcAddr.String()), tags.DstValidator, []byte(msg.ValidatorDstAddr.String()), - tags.EndTime, []byte(red.MinTime.Format(time.RFC3339)), + tags.EndTime, []byte(completionTime.Format(time.RFC3339)), ) return sdk.Result{Data: finishTime, Tags: resTags} diff --git a/x/stake/keeper/delegation.go b/x/stake/keeper/delegation.go index 541fff6baa3..254bcf1a01f 100644 --- a/x/stake/keeper/delegation.go +++ b/x/stake/keeper/delegation.go @@ -180,7 +180,7 @@ func (k Keeper) SetUnbondingDelegationEntry(ctx sdk.Context, if found { ubd.AddEntry(creationHeight, minTime, balance) } else { - ubd = NewUnbondingDelegation(delegationAddr, validatorAddr, creationHeight, minTime, balance) + ubd = types.NewUnbondingDelegation(delegatorAddr, validatorAddr, creationHeight, minTime, balance) } k.SetUnbondingDelegation(ctx, ubd) return ubd @@ -209,14 +209,16 @@ func (k Keeper) SetUBDQueueTimeSlice(ctx sdk.Context, timestamp time.Time, keys } // Insert an unbonding delegation to the appropriate timeslice in the unbonding queue -func (k Keeper) InsertUBDQueue(ctx sdk.Context, ubd types.UnbondingDelegation) { - timeSlice := k.GetUBDQueueTimeSlice(ctx, ubd.MinTime) +func (k Keeper) InsertUBDQueue(ctx sdk.Context, ubd types.UnbondingDelegation, + completionTime time.Time) { + + timeSlice := k.GetUBDQueueTimeSlice(ctx, completionTime) dvPair := types.DVPair{ubd.DelegatorAddr, ubd.ValidatorAddr} if len(timeSlice) == 0 { - k.SetUBDQueueTimeSlice(ctx, ubd.MinTime, []types.DVPair{dvPair}) + k.SetUBDQueueTimeSlice(ctx, completionTime, []types.DVPair{dvPair}) } else { timeSlice = append(timeSlice, dvPair) - k.SetUBDQueueTimeSlice(ctx, ubd.MinTime, timeSlice) + k.SetUBDQueueTimeSlice(ctx, completionTime, timeSlice) } } @@ -326,14 +328,14 @@ func (k Keeper) SetRedelegation(ctx sdk.Context, red types.Redelegation) { func (k Keeper) SetRedelegationEntry(ctx sdk.Context, delegatorAddr sdk.AccAddress, validatorSrcAddr, validatorDstAddr sdk.ValAddress, creationHeight int64, - minTime time.time, balance sdk.Coin, - sharesSrc, sharesDst sdk.Dec) Redelegation { + minTime time.Time, balance sdk.Coin, + sharesSrc, sharesDst sdk.Dec) types.Redelegation { red, found := k.GetRedelegation(ctx, delegatorAddr, validatorSrcAddr, validatorDstAddr) if found { red.AddEntry(creationHeight, minTime, balance, sharesSrc, sharesDst) } else { - red = NewRedelegation(delegatorAddr, validatorSrcAddr, + red = types.NewRedelegation(delegatorAddr, validatorSrcAddr, validatorDstAddr, creationHeight, minTime, balance, sharesSrc, sharesDst) } @@ -388,14 +390,16 @@ func (k Keeper) SetRedelegationQueueTimeSlice(ctx sdk.Context, timestamp time.Ti } // Insert an redelegation delegation to the appropriate timeslice in the redelegation queue -func (k Keeper) InsertRedelegationQueue(ctx sdk.Context, red types.Redelegation) { - timeSlice := k.GetRedelegationQueueTimeSlice(ctx, red.MinTime) +func (k Keeper) InsertRedelegationQueue(ctx sdk.Context, red types.Redelegation, + completionTime time.Time) { + + timeSlice := k.GetRedelegationQueueTimeSlice(ctx, completionTime) dvvTriplet := types.DVVTriplet{red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr} if len(timeSlice) == 0 { - k.SetRedelegationQueueTimeSlice(ctx, red.MinTime, []types.DVVTriplet{dvvTriplet}) + k.SetRedelegationQueueTimeSlice(ctx, completionTime, []types.DVVTriplet{dvvTriplet}) } else { timeSlice = append(timeSlice, dvvTriplet) - k.SetRedelegationQueueTimeSlice(ctx, red.MinTime, timeSlice) + k.SetRedelegationQueueTimeSlice(ctx, completionTime, timeSlice) } } @@ -522,9 +526,9 @@ func (k Keeper) unbond(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValA //______________________________________________________________________________________________________ -// get info for begin functions: MinTime and CreationHeight +// get info for begin functions: completionTime and CreationHeight func (k Keeper) getBeginInfo(ctx sdk.Context, valSrcAddr sdk.ValAddress) ( - minTime time.Time, height int64, completeNow bool) { + completionTime time.Time, height int64, completeNow bool) { validator, found := k.GetValidator(ctx, valSrcAddr) @@ -532,17 +536,17 @@ func (k Keeper) getBeginInfo(ctx sdk.Context, valSrcAddr sdk.ValAddress) ( case !found || validator.Status == sdk.Bonded: // the longest wait - just unbonding period from now - minTime = ctx.BlockHeader().Time.Add(k.UnbondingTime(ctx)) + completionTime = ctx.BlockHeader().Time.Add(k.UnbondingTime(ctx)) height = ctx.BlockHeight() - return minTime, height, false + return completionTime, height, false case validator.Status == sdk.Unbonded: - return minTime, height, true + return completionTime, height, true case validator.Status == sdk.Unbonding: - minTime = validator.UnbondingMinTime + completionTime = validator.UnbondingMinTime height = validator.UnbondingHeight - return minTime, height, false + return completionTime, height, false default: panic("unknown validator status") @@ -551,14 +555,14 @@ func (k Keeper) getBeginInfo(ctx sdk.Context, valSrcAddr sdk.ValAddress) ( // begin unbonding an unbonding record func (k Keeper) BeginUnbonding(ctx sdk.Context, delAddr sdk.AccAddress, - valAddr sdk.ValAddress, sharesAmount sdk.Dec) (types.UnbondingDelegation, sdk.Error) { + valAddr sdk.ValAddress, sharesAmount sdk.Dec) (completionTime time.Time, sdkErr sdk.Error) { // create the unbonding delegation - minTime, height, completeNow := k.getBeginInfo(ctx, valAddr) + completionTime, height, completeNow := k.getBeginInfo(ctx, valAddr) returnAmount, err := k.unbond(ctx, delAddr, valAddr, sharesAmount) if err != nil { - return types.UnbondingDelegation{}, err + return completionTime, err } balance := sdk.NewCoin(k.BondDenom(ctx), returnAmount) @@ -566,14 +570,16 @@ func (k Keeper) BeginUnbonding(ctx sdk.Context, delAddr sdk.AccAddress, if completeNow { _, _, err := k.bankKeeper.AddCoins(ctx, delAddr, sdk.Coins{balance}) if err != nil { - return types.UnbondingDelegation{}, err + return completionTime, err } - return types.UnbondingDelegation{MinTime: minTime}, nil + return completionTime, nil } - ubd := k.SetUnbondingDelegationEntry(ctx, delAddr, valAddr, height, minTime, balance) - k.InsertUBDQueue(ctx, ubd) - return ubd, nil + ubd := k.SetUnbondingDelegationEntry(ctx, delAddr, + valAddr, height, completionTime, balance) + + k.InsertUBDQueue(ctx, ubd, completionTime) + return completionTime, nil } // CompleteUnbonding completes the unbonding of all mature entries in the @@ -591,14 +597,14 @@ func (k Keeper) CompleteUnbonding(ctx sdk.Context, delAddr sdk.AccAddress, // loop through all the entries and complete unbonding mature entries for i, entry := range ubd.Entries { if entry.IsMature(ctxTime) { - _, _, err := k.bankKeeper.AddCoins(ctx, ubd.DelegatorAddr, sdk.Coins{ubd.Balance}) + _, _, err := k.bankKeeper.AddCoins(ctx, ubd.DelegatorAddr, sdk.Coins{entry.Balance}) if err != nil { return err } - ubd.RemoveEntry(i) + ubd.RemoveEntry(int64(i)) // remove the ubd if there are no more entries - if len(Entries) == 0 { + if len(ubd.Entries) == 0 { k.RemoveUnbondingDelegation(ctx, ubd) } } @@ -609,48 +615,49 @@ func (k Keeper) CompleteUnbonding(ctx sdk.Context, delAddr sdk.AccAddress, // begin unbonding / redelegation; create a redelegation record func (k Keeper) BeginRedelegation(ctx sdk.Context, delAddr sdk.AccAddress, - valSrcAddr, valDstAddr sdk.ValAddress, sharesAmount sdk.Dec) (types.Redelegation, sdk.Error) { + valSrcAddr, valDstAddr sdk.ValAddress, sharesAmount sdk.Dec) ( + completionTime time.Time, errSdk sdk.Error) { if bytes.Equal(valSrcAddr, valDstAddr) { - return types.Redelegation{}, types.ErrSelfRedelegation(k.Codespace()) + return time.Time{}, types.ErrSelfRedelegation(k.Codespace()) } // check if this is a transitive redelegation if k.HasReceivingRedelegation(ctx, delAddr, valSrcAddr) { - return types.Redelegation{}, types.ErrTransitiveRedelegation(k.Codespace()) + return time.Time{}, types.ErrTransitiveRedelegation(k.Codespace()) } returnAmount, err := k.unbond(ctx, delAddr, valSrcAddr, sharesAmount) if err != nil { - return types.Redelegation{}, err + return time.Time{}, err } if returnAmount.IsZero() { - return types.Redelegation{}, types.ErrVerySmallRedelegation(k.Codespace()) + return time.Time{}, types.ErrVerySmallRedelegation(k.Codespace()) } returnCoin := sdk.NewCoin(k.BondDenom(ctx), returnAmount) dstValidator, found := k.GetValidator(ctx, valDstAddr) if !found { - return types.Redelegation{}, types.ErrBadRedelegationDst(k.Codespace()) + return time.Time{}, types.ErrBadRedelegationDst(k.Codespace()) } sharesCreated, err := k.Delegate(ctx, delAddr, returnCoin, dstValidator, false) if err != nil { - return types.Redelegation{}, err + return time.Time{}, err } // create the unbonding delegation - minTime, height, completeNow := k.getBeginInfo(ctx, valSrcAddr) + completionTime, height, completeNow := k.getBeginInfo(ctx, valSrcAddr) if completeNow { // no need to create the redelegation object - return types.Redelegation{MinTime: minTime}, nil + return completionTime, nil } - red := k.SetUnbondingDelegationEntry(ctx, delAddr, valSrcAddr, valDstAddr, - height, minTime, returnCoin, sharesAmount, sharesCreated) - k.InsertRedelegationQueue(ctx, red) - return red, nil + red := k.SetRedelegationEntry(ctx, delAddr, valSrcAddr, valDstAddr, + height, completionTime, returnCoin, sharesAmount, sharesCreated) + k.InsertRedelegationQueue(ctx, red, completionTime) + return completionTime, nil } // CompleteRedelegation completes the unbonding of all mature entries in the @@ -668,7 +675,7 @@ func (k Keeper) CompleteRedelegation(ctx sdk.Context, delAddr sdk.AccAddress, // loop through all the entries and complete mature redelegation entries for i, entry := range red.Entries { if entry.IsMature(ctxTime) { - red.RemoveEntry(i) + red.RemoveEntry(int64(i)) // remove the redelegation if there are no more entries if len(red.Entries) == 0 { diff --git a/x/stake/keeper/slash.go b/x/stake/keeper/slash.go index 6d22c82fc98..411908f48a6 100644 --- a/x/stake/keeper/slash.go +++ b/x/stake/keeper/slash.go @@ -149,37 +149,42 @@ func (k Keeper) slashUnbondingDelegation(ctx sdk.Context, unbondingDelegation ty now := ctx.BlockHeader().Time - // If unbonding started before this height, stake didn't contribute to infraction - if unbondingDelegation.CreationHeight < infractionHeight { - return sdk.ZeroInt() - } + // perform slashing on all entries within the unbonding delegation + for i, entry := range unbondingDelegation.Entries { - if unbondingDelegation.MinTime.Before(now) { - // Unbonding delegation no longer eligible for slashing, skip it - // TODO Settle and delete it automatically? - return sdk.ZeroInt() - } + // If unbonding started before this height, stake didn't contribute to infraction + if entry.CreationHeight < infractionHeight { + return sdk.ZeroInt() + } + + if entry.IsMature(now) { + // Unbonding delegation no longer eligible for slashing, skip it + // TODO Settle and delete it automatically? + return sdk.ZeroInt() + } - // Calculate slash amount proportional to stake contributing to infraction - slashAmountDec := slashFactor.MulInt(unbondingDelegation.InitialBalance.Amount) - slashAmount = slashAmountDec.TruncateInt() - - // Don't slash more tokens than held - // Possible since the unbonding delegation may already - // have been slashed, and slash amounts are calculated - // according to stake held at time of infraction - unbondingSlashAmount := sdk.MinInt(slashAmount, unbondingDelegation.Balance.Amount) - - // Update unbonding delegation if necessary - if !unbondingSlashAmount.IsZero() { - unbondingDelegation.Balance.Amount = unbondingDelegation.Balance.Amount.Sub(unbondingSlashAmount) - k.SetUnbondingDelegation(ctx, unbondingDelegation) - pool := k.GetPool(ctx) - - // Burn loose tokens - // Ref https://github.com/cosmos/cosmos-sdk/pull/1278#discussion_r198657760 - pool.LooseTokens = pool.LooseTokens.Sub(unbondingSlashAmount) - k.SetPool(ctx, pool) + // Calculate slash amount proportional to stake contributing to infraction + slashAmountDec := slashFactor.MulInt(entry.InitialBalance.Amount) + slashAmount = slashAmountDec.TruncateInt() + + // Don't slash more tokens than held + // Possible since the unbonding delegation may already + // have been slashed, and slash amounts are calculated + // according to stake held at time of infraction + unbondingSlashAmount := sdk.MinInt(slashAmount, entry.Balance.Amount) + + // Update unbonding delegation if necessary + if !unbondingSlashAmount.IsZero() { + entry.Balance.Amount = entry.Balance.Amount.Sub(unbondingSlashAmount) + unbondingDelegation.Entries[i] = entry + k.SetUnbondingDelegation(ctx, unbondingDelegation) + pool := k.GetPool(ctx) + + // Burn loose tokens + // Ref https://github.com/cosmos/cosmos-sdk/pull/1278#discussion_r198657760 + pool.LooseTokens = pool.LooseTokens.Sub(unbondingSlashAmount) + k.SetPool(ctx, pool) + } } return slashAmount @@ -196,54 +201,59 @@ func (k Keeper) slashRedelegation(ctx sdk.Context, validator types.Validator, re now := ctx.BlockHeader().Time - // If redelegation started before this height, stake didn't contribute to infraction - if redelegation.CreationHeight < infractionHeight { - return sdk.ZeroInt() - } + // perform slashing on all entries within the redelegation + for i, entry := range redelegation.Entries { - if redelegation.MinTime.Before(now) { - // Redelegation no longer eligible for slashing, skip it - // TODO Delete it automatically? - return sdk.ZeroInt() - } + // If redelegation started before this height, stake didn't contribute to infraction + if entry.CreationHeight < infractionHeight { + return sdk.ZeroInt() + } - // Calculate slash amount proportional to stake contributing to infraction - slashAmountDec := slashFactor.MulInt(redelegation.InitialBalance.Amount) - slashAmount = slashAmountDec.TruncateInt() + if entry.IsMature(now) { + // Redelegation no longer eligible for slashing, skip it + // TODO Delete it automatically? + return sdk.ZeroInt() + } - // Don't slash more tokens than held - // Possible since the redelegation may already - // have been slashed, and slash amounts are calculated - // according to stake held at time of infraction - redelegationSlashAmount := sdk.MinInt(slashAmount, redelegation.Balance.Amount) + // Calculate slash amount proportional to stake contributing to infraction + slashAmountDec := slashFactor.MulInt(entry.InitialBalance.Amount) + slashAmount = slashAmountDec.TruncateInt() + + // Don't slash more tokens than held + // Possible since the redelegation may already + // have been slashed, and slash amounts are calculated + // according to stake held at time of infraction + redelegationSlashAmount := sdk.MinInt(slashAmount, entry.Balance.Amount) + + // Update entry if necessary + if !redelegationSlashAmount.IsZero() { + entry.Balance.Amount = entry.Balance.Amount.Sub(redelegationSlashAmount) + redelegation.Entries[i] = entry + k.SetRedelegation(ctx, redelegation) + } - // Update redelegation if necessary - if !redelegationSlashAmount.IsZero() { - redelegation.Balance.Amount = redelegation.Balance.Amount.Sub(redelegationSlashAmount) - k.SetRedelegation(ctx, redelegation) - } + // Unbond from target validator + sharesToUnbond := slashFactor.Mul(entry.SharesDst) + if !sharesToUnbond.IsZero() { + delegation, found := k.GetDelegation(ctx, redelegation.DelegatorAddr, redelegation.ValidatorDstAddr) + if !found { + // If deleted, delegation has zero shares, and we can't unbond any more + return slashAmount + } + if sharesToUnbond.GT(delegation.Shares) { + sharesToUnbond = delegation.Shares + } - // Unbond from target validator - sharesToUnbond := slashFactor.Mul(redelegation.SharesDst) - if !sharesToUnbond.IsZero() { - delegation, found := k.GetDelegation(ctx, redelegation.DelegatorAddr, redelegation.ValidatorDstAddr) - if !found { - // If deleted, delegation has zero shares, and we can't unbond any more - return slashAmount - } - if sharesToUnbond.GT(delegation.Shares) { - sharesToUnbond = delegation.Shares - } + tokensToBurn, err := k.unbond(ctx, redelegation.DelegatorAddr, redelegation.ValidatorDstAddr, sharesToUnbond) + if err != nil { + panic(fmt.Errorf("error unbonding delegator: %v", err)) + } - tokensToBurn, err := k.unbond(ctx, redelegation.DelegatorAddr, redelegation.ValidatorDstAddr, sharesToUnbond) - if err != nil { - panic(fmt.Errorf("error unbonding delegator: %v", err)) + // Burn loose tokens + pool := k.GetPool(ctx) + pool.LooseTokens = pool.LooseTokens.Sub(tokensToBurn) + k.SetPool(ctx, pool) } - - // Burn loose tokens - pool := k.GetPool(ctx) - pool.LooseTokens = pool.LooseTokens.Sub(tokensToBurn) - k.SetPool(ctx, pool) } return slashAmount diff --git a/x/stake/querier/querier_test.go b/x/stake/querier/querier_test.go index 5541cb81c6e..e332fe2351c 100644 --- a/x/stake/querier/querier_test.go +++ b/x/stake/querier/querier_test.go @@ -296,7 +296,8 @@ func TestQueryDelegation(t *testing.T) { require.Equal(t, delegationsRes[0], delegation) // Query unbonging delegation - keeper.BeginUnbonding(ctx, addrAcc2, val1.OperatorAddr, sdk.NewDec(10)) + _, err = keeper.BeginUnbonding(ctx, addrAcc2, val1.OperatorAddr, sdk.NewDec(10)) + require.Nil(t, err) queryBondParams = NewQueryBondsParams(addrAcc2, addrVal1) bz, errRes = cdc.MarshalJSON(queryBondParams) @@ -347,8 +348,10 @@ func TestQueryDelegation(t *testing.T) { require.NotNil(t, err) // Query redelegation - redel, err := keeper.BeginRedelegation(ctx, addrAcc2, val1.OperatorAddr, val2.OperatorAddr, sdk.NewDec(10)) + _, err = keeper.BeginRedelegation(ctx, addrAcc2, val1.OperatorAddr, val2.OperatorAddr, sdk.NewDec(10)) require.Nil(t, err) + redel, found := keeper.GetRedelegation(ctx, addrAcc2, val1.OperatorAddr, val2.OperatorAddr) + require.True(t, found) bz, errRes = cdc.MarshalJSON(NewQueryRedelegationParams(addrAcc2, val1.OperatorAddr, val2.OperatorAddr)) require.Nil(t, errRes) @@ -379,7 +382,8 @@ func TestQueryRedelegations(t *testing.T) { keeper.SetValidator(ctx, val2) keeper.Delegate(ctx, addrAcc2, sdk.NewCoin(types.DefaultBondDenom, sdk.NewInt(100)), val1, true) - keeper.ApplyAndReturnValidatorSetUpdates(ctx) + _, err := keeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.NoError(t, err) keeper.BeginRedelegation(ctx, addrAcc2, val1.GetOperator(), val2.GetOperator(), sdk.NewDec(20)) keeper.ApplyAndReturnValidatorSetUpdates(ctx) diff --git a/x/stake/types/delegation.go b/x/stake/types/delegation.go index 05972c5321d..fb72a8a511b 100644 --- a/x/stake/types/delegation.go +++ b/x/stake/types/delegation.go @@ -122,7 +122,7 @@ func NewUnbondingDelegation(delegatorAddr sdk.AccAddress, // NewUnbondingDelegation - create a new unbonding delegation object func NewUnbondingDelegationEntry(creationHeight int64, completionTime time.Time, - balance sdk.Coin) UnbondingDelegation { + balance sdk.Coin) UnbondingDelegationEntry { return UnbondingDelegationEntry{ CreationHeight: creationHeight, @@ -136,7 +136,7 @@ func NewUnbondingDelegationEntry(creationHeight int64, completionTime time.Time, func (d *UnbondingDelegation) AddEntry(creationHeight int64, minTime time.Time, balance sdk.Coin) { - entry := NewUnbondingDelegationEntry(height, minTime, balance) + entry := NewUnbondingDelegationEntry(creationHeight, minTime, balance) d.Entries = append(d.Entries, entry) } @@ -179,12 +179,14 @@ func (d UnbondingDelegation) HumanReadableString() (string, error) { resp := "Unbonding Delegation \n" resp += fmt.Sprintf("Delegator: %s\n", d.DelegatorAddr) resp += fmt.Sprintf("Validator: %s\n", d.ValidatorAddr) - resp += fmt.Sprintf("Creation height: %v\n", d.CreationHeight) - resp += fmt.Sprintf("Min time to unbond (unix): %v\n", d.MinTime) - resp += fmt.Sprintf("Expected balance: %s", d.Balance.String()) + for _, entry := range d.Entries { + resp += "Unbonding Delegation Entry\n" + resp += fmt.Sprintf("Creation height: %v\n", entry.CreationHeight) + resp += fmt.Sprintf("Min time to unbond (unix): %v\n", entry.CompletionTime) + resp += fmt.Sprintf("Expected balance: %s", entry.Balance.String()) + } return resp, nil - } // Redelegation reflects a delegation's passive re-delegation queue. @@ -197,18 +199,18 @@ type Redelegation struct { // RedelegationEntry - entry to a Redelegation type RedelegationEntry struct { - CreationHeight int64 `json:"creation_height"` // height which the redelegation took place - CompletetionTime time.Time `json:"completion_time"` // unix time for redelegation completion - InitialBalance sdk.Coin `json:"initial_balance"` // initial balance when redelegation started - Balance sdk.Coin `json:"balance"` // current balance - SharesSrc sdk.Dec `json:"shares_src"` // amount of source shares redelegating - SharesDst sdk.Dec `json:"shares_dst"` // amount of destination shares redelegating + CreationHeight int64 `json:"creation_height"` // height which the redelegation took place + CompletionTime time.Time `json:"completion_time"` // unix time for redelegation completion + InitialBalance sdk.Coin `json:"initial_balance"` // initial balance when redelegation started + Balance sdk.Coin `json:"balance"` // current balance + SharesSrc sdk.Dec `json:"shares_src"` // amount of source shares redelegating + SharesDst sdk.Dec `json:"shares_dst"` // amount of destination shares redelegating } // NewRedelegation - create a new redelegation object func NewRedelegation(delegatorAddr sdk.AccAddress, validatorSrcAddr, validatorDstAddr sdk.ValAddress, creationHeight int64, - minTime time.time, balance sdk.Coin, + minTime time.Time, balance sdk.Coin, sharesSrc, sharesDst sdk.Dec) Redelegation { entry := NewRedelegationEntry(creationHeight, @@ -218,22 +220,22 @@ func NewRedelegation(delegatorAddr sdk.AccAddress, validatorSrcAddr, DelegatorAddr: delegatorAddr, ValidatorSrcAddr: validatorSrcAddr, ValidatorDstAddr: validatorDstAddr, - Entries: []EntriesRedelegationEntry{entries}, + Entries: []RedelegationEntry{entry}, } } // NewRedelegation - create a new redelegation object func NewRedelegationEntry(creationHeight int64, - completionTime time.time, balance sdk.Coin, - sharesSrc, sharesDst sdk.Dec) Redelegation { + completionTime time.Time, balance sdk.Coin, + sharesSrc, sharesDst sdk.Dec) RedelegationEntry { return RedelegationEntry{ - CreationHeight: creationHeight, - CompletetionTime: completionTime, - InitialBalance: balance, - Balance: balance, - SharesSrc: sharesSrc, - SharesDst: sharesDst, + CreationHeight: creationHeight, + CompletionTime: completionTime, + InitialBalance: balance, + Balance: balance, + SharesSrc: sharesSrc, + SharesDst: sharesDst, } } @@ -244,10 +246,10 @@ func (e RedelegationEntry) IsMature(currentTime time.Time) bool { // AddEntry - append entry to the unbonding delegation func (d *Redelegation) AddEntry(creationHeight int64, - minTime time.time, balance sdk.Coin, + minTime time.Time, balance sdk.Coin, sharesSrc, sharesDst sdk.Dec) { - entry := NewUnbondingDelegationEntry(height, minTime, balance) + entry := NewRedelegationEntry(creationHeight, minTime, balance, sharesSrc, sharesDst) d.Entries = append(d.Entries, entry) } @@ -291,11 +293,11 @@ func (d Redelegation) HumanReadableString() (string, error) { resp += fmt.Sprintf("Delegator: %s\n", d.DelegatorAddr) resp += fmt.Sprintf("Source Validator: %s\n", d.ValidatorSrcAddr) resp += fmt.Sprintf("Destination Validator: %s\n", d.ValidatorDstAddr) - resp += fmt.Sprintf("Creation height: %v\n", d.CreationHeight) - resp += fmt.Sprintf("Min time to unbond (unix): %v\n", d.MinTime) - resp += fmt.Sprintf("Source shares: %s\n", d.SharesSrc.String()) - resp += fmt.Sprintf("Destination shares: %s", d.SharesDst.String()) - + for _, entry := range d.Entries { + resp += fmt.Sprintf("Creation height: %v\n", entry.CreationHeight) + resp += fmt.Sprintf("Min time to unbond (unix): %v\n", entry.CompletionTime) + resp += fmt.Sprintf("Source shares: %s\n", entry.SharesSrc.String()) + resp += fmt.Sprintf("Destination shares: %s", entry.SharesDst.String()) + } return resp, nil - } From e48fb9549cfadce1a599d1bd2a56ce527a306ab4 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Mon, 7 Jan 2019 19:51:37 -0500 Subject: [PATCH 11/26] code compiles --- cmd/gaia/app/export.go | 8 ++++++-- x/stake/genesis.go | 31 +++++++++++++++++++------------ x/stake/simulation/invariants.go | 4 +++- x/stake/types/delegation.go | 26 -------------------------- 4 files changed, 28 insertions(+), 41 deletions(-) diff --git a/cmd/gaia/app/export.go b/cmd/gaia/app/export.go index ec2e83b2e72..076d693f732 100644 --- a/cmd/gaia/app/export.go +++ b/cmd/gaia/app/export.go @@ -116,14 +116,18 @@ func (app *GaiaApp) prepForZeroHeightGenesis(ctx sdk.Context) { // iterate through redelegations, reset creation height app.stakeKeeper.IterateRedelegations(ctx, func(_ int64, red stake.Redelegation) (stop bool) { - red.CreationHeight = 0 + for i := range red.Entries { + red.Entries[i].CreationHeight = 0 + } app.stakeKeeper.SetRedelegation(ctx, red) return false }) // iterate through unbonding delegations, reset creation height app.stakeKeeper.IterateUnbondingDelegations(ctx, func(_ int64, ubd stake.UnbondingDelegation) (stop bool) { - ubd.CreationHeight = 0 + for i := range ubd.Entries { + ubd.Entries[i].CreationHeight = 0 + } app.stakeKeeper.SetUnbondingDelegation(ctx, ubd) return false }) diff --git a/x/stake/genesis.go b/x/stake/genesis.go index 744226c2c5d..5dd0bb609c7 100644 --- a/x/stake/genesis.go +++ b/x/stake/genesis.go @@ -2,7 +2,6 @@ package stake import ( "fmt" - "sort" abci "github.com/tendermint/tendermint/abci/types" tmtypes "github.com/tendermint/tendermint/types" @@ -18,9 +17,11 @@ import ( // Returns final validator set after applying all declaration and delegations func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) (res []abci.ValidatorUpdate, err error) { - // We need to pretend to be "n blocks before genesis", where "n" is the validator update delay, - // so that e.g. slashing periods are correctly initialized for the validator set - // e.g. with a one-block offset - the first TM block is at height 1, so state updates applied from genesis.json are in block 0. + // We need to pretend to be "n blocks before genesis", where "n" is the + // validator update delay, so that e.g. slashing periods are correctly + // initialized for the validator set e.g. with a one-block offset - the + // first TM block is at height 1, so state updates applied from + // genesis.json are in block 0. ctx = ctx.WithBlockHeight(1 - types.ValidatorUpdateDelay) keeper.SetPool(ctx, data.Pool) @@ -46,20 +47,26 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) (res [ keeper.OnDelegationCreated(ctx, delegation.DelegatorAddr, delegation.ValidatorAddr) } - sort.SliceStable(data.UnbondingDelegations[:], func(i, j int) bool { - return data.UnbondingDelegations[i].CreationHeight < data.UnbondingDelegations[j].CreationHeight - }) + // XXX fix or delete this section + //sort.SliceStable(data.UnbondingDelegations[:], func(i, j int) bool { + //return data.UnbondingDelegations[i].CreationHeight < data.UnbondingDelegations[j].CreationHeight + //}) for _, ubd := range data.UnbondingDelegations { keeper.SetUnbondingDelegation(ctx, ubd) - keeper.InsertUnbondingQueue(ctx, ubd) + for _, entry := range ubd.Entries { + keeper.InsertUBDQueue(ctx, ubd, entry.CompletionTime) + } } - sort.SliceStable(data.Redelegations[:], func(i, j int) bool { - return data.Redelegations[i].CreationHeight < data.Redelegations[j].CreationHeight - }) + // XXX fix or delete this section + //sort.SliceStable(data.Redelegations[:], func(i, j int) bool { + //return data.Redelegations[i].CreationHeight < data.Redelegations[j].CreationHeight + //}) for _, red := range data.Redelegations { keeper.SetRedelegation(ctx, red) - keeper.InsertRedelegationQueue(ctx, red) + for _, entry := range red.Entries { + keeper.InsertRedelegationQueue(ctx, red, entry.CompletionTime) + } } // don't need to run Tendermint updates if we exported diff --git a/x/stake/simulation/invariants.go b/x/stake/simulation/invariants.go index 52775d268cc..c76cf500691 100644 --- a/x/stake/simulation/invariants.go +++ b/x/stake/simulation/invariants.go @@ -59,7 +59,9 @@ func SupplyInvariants(ck bank.Keeper, k stake.Keeper, return false }) k.IterateUnbondingDelegations(ctx, func(_ int64, ubd stake.UnbondingDelegation) bool { - loose = loose.Add(sdk.NewDecFromInt(ubd.Balance.Amount)) + for _, entry := range ubd.Entries { + loose = loose.Add(sdk.NewDecFromInt(entry.Balance.Amount)) + } return false }) k.IterateValidators(ctx, func(_ int64, validator sdk.Validator) bool { diff --git a/x/stake/types/delegation.go b/x/stake/types/delegation.go index 1060881998d..fb72a8a511b 100644 --- a/x/stake/types/delegation.go +++ b/x/stake/types/delegation.go @@ -120,19 +120,6 @@ func NewUnbondingDelegation(delegatorAddr sdk.AccAddress, } } -// return the unbonding delegation -func MustMarshalUBD(cdc *codec.Codec, ubd UnbondingDelegation) []byte { - return cdc.MustMarshalBinaryLengthPrefixed(ubd) -} - -// unmarshal a unbonding delegation from a store value -func MustUnmarshalUBD(cdc *codec.Codec, value []byte) UnbondingDelegation { - ubd, err := UnmarshalUBD(cdc, value) - if err != nil { - panic(err) - } -} - // NewUnbondingDelegation - create a new unbonding delegation object func NewUnbondingDelegationEntry(creationHeight int64, completionTime time.Time, balance sdk.Coin) UnbondingDelegationEntry { @@ -237,19 +224,6 @@ func NewRedelegation(delegatorAddr sdk.AccAddress, validatorSrcAddr, } } -// return the redelegation -func MustMarshalRED(cdc *codec.Codec, red Redelegation) []byte { - return cdc.MustMarshalBinaryLengthPrefixed(red) -} - -// unmarshal a redelegation from a store value -func MustUnmarshalRED(cdc *codec.Codec, value []byte) Redelegation { - red, err := UnmarshalRED(cdc, value) - if err != nil { - panic(err) - } -} - // NewRedelegation - create a new redelegation object func NewRedelegationEntry(creationHeight int64, completionTime time.Time, balance sdk.Coin, From e490924ea4faf55d3dda48cc105b8cb4bae22b58 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Mon, 7 Jan 2019 21:07:55 -0500 Subject: [PATCH 12/26] fix test compile errors --- client/lcd/lcd_test.go | 20 +++-- client/lcd/test_helpers.go | 9 +- cmd/gaia/cli_test/cli_test.go | 3 +- x/stake/handler_test.go | 16 ++-- x/stake/keeper/delegation_test.go | 53 +++++------- x/stake/keeper/slash_test.go | 133 ++++++++++++------------------ x/stake/querier/querier_test.go | 3 +- x/stake/types/delegation.go | 11 +++ x/stake/types/delegation_test.go | 77 ++++++----------- 9 files changed, 139 insertions(+), 186 deletions(-) diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index 1a9cdf23666..bc2ea6377d1 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -467,8 +467,9 @@ func TestBonding(t *testing.T) { require.Len(t, txs, 1) require.Equal(t, resultTx.Height, txs[0].Height) - unbonding := getUndelegation(t, port, addr, operAddrs[0]) - require.Equal(t, int64(30), unbonding.Balance.Amount.Int64()) + ubd := getUnbondingDelegation(t, port, addr, operAddrs[0]) + require.Len(t, ubd.Entries, 1) + require.Equal(t, int64(30), ubd.Entries[0].Balance.Amount.Int64()) // test redelegation resultTx = doBeginRedelegation(t, port, name1, pw, addr, operAddrs[0], operAddrs[1], 30, fees) @@ -502,23 +503,28 @@ func TestBonding(t *testing.T) { redelegation := getRedelegations(t, port, addr, operAddrs[0], operAddrs[1]) require.Len(t, redelegation, 1) - require.Equal(t, "30", redelegation[0].Balance.Amount.String()) + require.Len(t, redelegation[0].Entries, 1) + require.Equal(t, "30", redelegation[0].Entries[0].Balance.Amount.String()) delegatorUbds := getDelegatorUnbondingDelegations(t, port, addr) require.Len(t, delegatorUbds, 1) - require.Equal(t, "30", delegatorUbds[0].Balance.Amount.String()) + require.Len(t, delegatorUbds[0].Entries, 1) + require.Equal(t, "30", delegatorUbds[0].Entries[0].Balance.Amount.String()) delegatorReds := getRedelegations(t, port, addr, nil, nil) require.Len(t, delegatorReds, 1) - require.Equal(t, "30", delegatorReds[0].Balance.Amount.String()) + require.Len(t, delegatorReds[0].Entries, 1) + require.Equal(t, "30", delegatorReds[0].Entries[0].Balance.Amount.String()) validatorUbds := getValidatorUnbondingDelegations(t, port, operAddrs[0]) require.Len(t, validatorUbds, 1) - require.Equal(t, "30", validatorUbds[0].Balance.Amount.String()) + require.Len(t, validatorUbds[0].Entries, 1) + require.Equal(t, "30", validatorUbds[0].Entries[0].Balance.Amount.String()) validatorReds := getRedelegations(t, port, nil, operAddrs[0], nil) require.Len(t, validatorReds, 1) - require.Equal(t, "30", validatorReds[0].Balance.Amount.String()) + require.Len(t, validatorReds[0].Entries, 1) + require.Equal(t, "30", validatorReds[0].Entries[0].Balance.Amount.String()) // TODO Undonding status not currently implemented // require.Equal(t, sdk.Unbonding, bondedValidators[0].Status) diff --git a/client/lcd/test_helpers.go b/client/lcd/test_helpers.go index 436b9d68013..801c4e439c6 100644 --- a/client/lcd/test_helpers.go +++ b/client/lcd/test_helpers.go @@ -942,8 +942,13 @@ func getDelegation(t *testing.T, port string, delegatorAddr sdk.AccAddress, vali } // GET /stake/delegators/{delegatorAddr}/unbonding_delegations/{validatorAddr} Query all unbonding delegations between a delegator and a validator -func getUndelegation(t *testing.T, port string, delegatorAddr sdk.AccAddress, validatorAddr sdk.ValAddress) stake.UnbondingDelegation { - res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/unbonding_delegations/%s", delegatorAddr, validatorAddr), nil) +func getUnbondingDelegation(t *testing.T, port string, delegatorAddr sdk.AccAddress, + validatorAddr sdk.ValAddress) stake.UnbondingDelegation { + + res, body := Request(t, port, "GET", + fmt.Sprintf("/stake/delegators/%s/unbonding_delegations/%s", + delegatorAddr, validatorAddr), nil) + require.Equal(t, http.StatusOK, res.StatusCode, body) var unbond stake.UnbondingDelegation diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index 15ebb14d827..5f649e3ab9c 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -294,7 +294,8 @@ func TestGaiaCLICreateValidator(t *testing.T) { validatorUbds := executeGetValidatorUnbondingDelegations(t, fmt.Sprintf("gaiacli query stake unbonding-delegations-from %s %v", sdk.ValAddress(barAddr), flags)) require.Len(t, validatorUbds, 1) - require.Equal(t, "1", validatorUbds[0].Balance.Amount.String()) + require.Len(t, validatorUbds[0].Entries, 1) + require.Equal(t, "1", validatorUbds[0].Entries[0].Balance.Amount.String()) params := executeGetParams(t, fmt.Sprintf("gaiacli query stake parameters %v", flags)) require.True(t, defaultParams.Equal(params)) diff --git a/x/stake/handler_test.go b/x/stake/handler_test.go index eb6e5f8fb70..4de2da3b3e3 100644 --- a/x/stake/handler_test.go +++ b/x/stake/handler_test.go @@ -991,14 +991,16 @@ func TestBondUnbondRedelegateSlashTwice(t *testing.T) { keeper.Slash(ctx, consAddr0, 0, 20, sdk.NewDecWithPrec(5, 1)) // unbonding delegation should have been slashed by half - unbonding, found := keeper.GetUnbondingDelegation(ctx, del, valA) + ubd, found := keeper.GetUnbondingDelegation(ctx, del, valA) require.True(t, found) - require.Equal(t, int64(2), unbonding.Balance.Amount.Int64()) + require.Len(t, ubd.Entries, 1) + require.Equal(t, int64(2), ubd.Entries[0].Balance.Amount.Int64()) // redelegation should have been slashed by half redelegation, found := keeper.GetRedelegation(ctx, del, valA, valB) require.True(t, found) - require.Equal(t, int64(3), redelegation.Balance.Amount.Int64()) + require.Len(t, redelegation.Entries, 1) + require.Equal(t, int64(3), redelegation.Entries[0].Balance.Amount.Int64()) // destination delegation should have been slashed by half delegation, found = keeper.GetDelegation(ctx, del, valB) @@ -1015,14 +1017,16 @@ func TestBondUnbondRedelegateSlashTwice(t *testing.T) { keeper.Slash(ctx, consAddr0, 2, 10, sdk.NewDecWithPrec(5, 1)) // unbonding delegation should be unchanged - unbonding, found = keeper.GetUnbondingDelegation(ctx, del, valA) + ubd, found = keeper.GetUnbondingDelegation(ctx, del, valA) require.True(t, found) - require.Equal(t, int64(2), unbonding.Balance.Amount.Int64()) + require.Len(t, ubd.Entries, 1) + require.Equal(t, int64(2), ubd.Entries[0].Balance.Amount.Int64()) // redelegation should be unchanged redelegation, found = keeper.GetRedelegation(ctx, del, valA, valB) require.True(t, found) - require.Equal(t, int64(3), redelegation.Balance.Amount.Int64()) + require.Len(t, redelegation.Entries, 1) + require.Equal(t, int64(3), redelegation.Entries[0].Balance.Amount.Int64()) // destination delegation should be unchanged delegation, found = keeper.GetDelegation(ctx, del, valB) diff --git a/x/stake/keeper/delegation_test.go b/x/stake/keeper/delegation_test.go index 37545ab2272..6ff925adbb7 100644 --- a/x/stake/keeper/delegation_test.go +++ b/x/stake/keeper/delegation_test.go @@ -137,13 +137,8 @@ func TestDelegation(t *testing.T) { func TestUnbondingDelegation(t *testing.T) { ctx, _, keeper := CreateTestInput(t, false, 0) - ubd := types.UnbondingDelegation{ - DelegatorAddr: addrDels[0], - ValidatorAddr: addrVals[0], - CreationHeight: 0, - MinTime: time.Unix(0, 0), - Balance: sdk.NewInt64Coin(types.DefaultBondDenom, 5), - } + ubd := types.NewUnbondingDelegation(addrDels[0], addrVals[0], 0, + time.Unix(0, 0), sdk.NewInt64Coin(types.DefaultBondDenom, 5)) // set and retrieve a record keeper.SetUnbondingDelegation(ctx, ubd) @@ -152,7 +147,7 @@ func TestUnbondingDelegation(t *testing.T) { require.True(t, ubd.Equal(resUnbond)) // modify a records, save, and retrieve - ubd.Balance = sdk.NewInt64Coin(types.DefaultBondDenom, 21) + ubd.Entries[0].Balance = sdk.NewInt64Coin(types.DefaultBondDenom, 21) keeper.SetUnbondingDelegation(ctx, ubd) resUnbonds := keeper.GetUnbondingDelegations(ctx, addrDels[0], 5) @@ -338,9 +333,10 @@ func TestUndelegateFromUnbondingValidator(t *testing.T) { // retrieve the unbonding delegation ubd, found := keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) require.True(t, found) - require.True(t, ubd.Balance.IsEqual(sdk.NewInt64Coin(params.BondDenom, 6))) - assert.Equal(t, blockHeight, ubd.CreationHeight) - assert.True(t, blockTime.Add(params.UnbondingTime).Equal(ubd.MinTime)) + require.Len(t, ubd.Entries, 1) + require.True(t, ubd.Entries[0].Balance.IsEqual(sdk.NewInt64Coin(params.BondDenom, 6))) + assert.Equal(t, blockHeight, ubd.Entries[0].CreationHeight) + assert.True(t, blockTime.Add(params.UnbondingTime).Equal(ubd.Entries[0].CompletionTime)) } func TestUndelegateFromUnbondedValidator(t *testing.T) { @@ -490,15 +486,9 @@ func TestUnbondingAllDelegationFromValidator(t *testing.T) { func TestGetRedelegationsFromValidator(t *testing.T) { ctx, _, keeper := CreateTestInput(t, false, 0) - rd := types.Redelegation{ - DelegatorAddr: addrDels[0], - ValidatorSrcAddr: addrVals[0], - ValidatorDstAddr: addrVals[1], - CreationHeight: 0, - MinTime: time.Unix(0, 0), - SharesSrc: sdk.NewDec(5), - SharesDst: sdk.NewDec(5), - } + rd := types.NewRedelegation(addrDels[0], addrVals[0], addrVals[1], 0, + time.Unix(0, 0), sdk.NewInt64Coin(types.DefaultBondDenom, 5), + sdk.NewDec(5), sdk.NewDec(5)) // set and retrieve a record keeper.SetRedelegation(ctx, rd) @@ -520,15 +510,9 @@ func TestGetRedelegationsFromValidator(t *testing.T) { func TestRedelegation(t *testing.T) { ctx, _, keeper := CreateTestInput(t, false, 0) - rd := types.Redelegation{ - DelegatorAddr: addrDels[0], - ValidatorSrcAddr: addrVals[0], - ValidatorDstAddr: addrVals[1], - CreationHeight: 0, - MinTime: time.Unix(0, 0), - SharesSrc: sdk.NewDec(5), - SharesDst: sdk.NewDec(5), - } + rd := types.NewRedelegation(addrDels[0], addrVals[0], addrVals[1], 0, + time.Unix(0, 0), sdk.NewInt64Coin(types.DefaultBondDenom, 5), + sdk.NewDec(5), sdk.NewDec(5)) // test shouldn't have and redelegations has := keeper.HasReceivingRedelegation(ctx, addrDels[0], addrVals[1]) @@ -556,8 +540,8 @@ func TestRedelegation(t *testing.T) { require.True(t, has) // modify a records, save, and retrieve - rd.SharesSrc = sdk.NewDec(21) - rd.SharesDst = sdk.NewDec(21) + rd.Entries[0].SharesSrc = sdk.NewDec(21) + rd.Entries[0].SharesDst = sdk.NewDec(21) keeper.SetRedelegation(ctx, rd) resRed, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) @@ -742,9 +726,10 @@ func TestRedelegateFromUnbondingValidator(t *testing.T) { // retrieve the unbonding delegation ubd, found := keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) require.True(t, found) - require.True(t, ubd.Balance.IsEqual(sdk.NewInt64Coin(params.BondDenom, 6))) - assert.Equal(t, blockHeight, ubd.CreationHeight) - assert.True(t, blockTime.Add(params.UnbondingTime).Equal(ubd.MinTime)) + require.Len(t, ubd.Entries, 1) + require.True(t, ubd.Entries[0].Balance.IsEqual(sdk.NewInt64Coin(params.BondDenom, 6))) + assert.Equal(t, blockHeight, ubd.Entries[0].CreationHeight) + assert.True(t, blockTime.Add(params.UnbondingTime).Equal(ubd.Entries[0].CompletionTime)) } func TestRedelegateFromUnbondedValidator(t *testing.T) { diff --git a/x/stake/keeper/slash_test.go b/x/stake/keeper/slash_test.go index 294bf2fe6c7..9fac4ab8ac6 100644 --- a/x/stake/keeper/slash_test.go +++ b/x/stake/keeper/slash_test.go @@ -70,16 +70,11 @@ func TestSlashUnbondingDelegation(t *testing.T) { ctx, keeper, params := setupHelper(t, 10) fraction := sdk.NewDecWithPrec(5, 1) - // set an unbonding delegation - ubd := types.UnbondingDelegation{ - DelegatorAddr: addrDels[0], - ValidatorAddr: addrVals[0], - CreationHeight: 0, - // expiration timestamp (beyond which the unbonding delegation shouldn't be slashed) - MinTime: time.Unix(0, 0), - InitialBalance: sdk.NewInt64Coin(params.BondDenom, 10), - Balance: sdk.NewInt64Coin(params.BondDenom, 10), - } + // set an unbonding delegation with expiration timestamp (beyond which the + // unbonding delegation shouldn't be slashed) + ubd := types.NewUnbondingDelegation(addrDels[0], addrVals[0], 0, + time.Unix(0, 0), sdk.NewInt64Coin(params.BondDenom, 10)) + keeper.SetUnbondingDelegation(ctx, ubd) // unbonding started prior to the infraction height, stake didn't contribute @@ -100,12 +95,13 @@ func TestSlashUnbondingDelegation(t *testing.T) { require.Equal(t, int64(5), slashAmount.Int64()) ubd, found := keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) require.True(t, found) + require.Len(t, ubd.Entries, 1) - // initialbalance unchanged - require.Equal(t, sdk.NewInt64Coin(params.BondDenom, 10), ubd.InitialBalance) + // initial balance unchanged + require.Equal(t, sdk.NewInt64Coin(params.BondDenom, 10), ubd.Entries[0].InitialBalance) // balance decreased - require.Equal(t, sdk.NewInt64Coin(params.BondDenom, 5), ubd.Balance) + require.Equal(t, sdk.NewInt64Coin(params.BondDenom, 5), ubd.Entries[0].Balance) newPool := keeper.GetPool(ctx) require.Equal(t, int64(5), oldPool.LooseTokens.Sub(newPool.LooseTokens).Int64()) } @@ -115,19 +111,12 @@ func TestSlashRedelegation(t *testing.T) { ctx, keeper, params := setupHelper(t, 10) fraction := sdk.NewDecWithPrec(5, 1) - // set a redelegation - rd := types.Redelegation{ - DelegatorAddr: addrDels[0], - ValidatorSrcAddr: addrVals[0], - ValidatorDstAddr: addrVals[1], - CreationHeight: 0, - // expiration timestamp (beyond which the redelegation shouldn't be slashed) - MinTime: time.Unix(0, 0), - SharesSrc: sdk.NewDec(10), - SharesDst: sdk.NewDec(10), - InitialBalance: sdk.NewInt64Coin(params.BondDenom, 10), - Balance: sdk.NewInt64Coin(params.BondDenom, 10), - } + // set a redelegation with an expiration timestamp beyond which the + // redelegation shouldn't be slashed + rd := types.NewRedelegation(addrDels[0], addrVals[0], addrVals[1], 0, + time.Unix(0, 0), sdk.NewInt64Coin(params.BondDenom, 10), sdk.NewDec(10), + sdk.NewDec(10)) + keeper.SetRedelegation(ctx, rd) // set the associated delegation @@ -162,16 +151,17 @@ func TestSlashRedelegation(t *testing.T) { require.Equal(t, int64(5), slashAmount.Int64()) rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) require.True(t, found) + require.Len(t, rd.Entries, 1) // end block updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) require.Equal(t, 1, len(updates)) // initialbalance unchanged - require.Equal(t, sdk.NewInt64Coin(params.BondDenom, 10), rd.InitialBalance) + require.Equal(t, sdk.NewInt64Coin(params.BondDenom, 10), rd.Entries[0].InitialBalance) // balance decreased - require.Equal(t, sdk.NewInt64Coin(params.BondDenom, 5), rd.Balance) + require.Equal(t, sdk.NewInt64Coin(params.BondDenom, 5), rd.Entries[0].Balance) // shares decreased del, found = keeper.GetDelegation(ctx, addrDels[0], addrVals[1]) @@ -252,16 +242,10 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { consAddr := sdk.ConsAddress(PKs[0].Address()) fraction := sdk.NewDecWithPrec(5, 1) - // set an unbonding delegation - ubd := types.UnbondingDelegation{ - DelegatorAddr: addrDels[0], - ValidatorAddr: addrVals[0], - CreationHeight: 11, - // expiration timestamp (beyond which the unbonding delegation shouldn't be slashed) - MinTime: time.Unix(0, 0), - InitialBalance: sdk.NewInt64Coin(params.BondDenom, 4), - Balance: sdk.NewInt64Coin(params.BondDenom, 4), - } + // set an unbonding delegation with expiration timestamp beyond which the + // unbonding delegation shouldn't be slashed + ubd := types.NewUnbondingDelegation(addrDels[0], addrVals[0], 11, + time.Unix(0, 0), sdk.NewInt64Coin(params.BondDenom, 4)) keeper.SetUnbondingDelegation(ctx, ubd) // slash validator for the first time @@ -278,8 +262,9 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { // read updating unbonding delegation ubd, found = keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) require.True(t, found) + require.Len(t, ubd.Entries, 1) // balance decreased - require.Equal(t, sdk.NewInt(2), ubd.Balance.Amount) + require.Equal(t, sdk.NewInt(2), ubd.Entries[0].Balance.Amount) // read updated pool newPool := keeper.GetPool(ctx) // bonded tokens burned @@ -298,8 +283,9 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { keeper.Slash(ctx, consAddr, 9, 10, fraction) ubd, found = keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) require.True(t, found) + require.Len(t, ubd.Entries, 1) // balance decreased again - require.Equal(t, sdk.NewInt(0), ubd.Balance.Amount) + require.Equal(t, sdk.NewInt(0), ubd.Entries[0].Balance.Amount) // read updated pool newPool = keeper.GetPool(ctx) // bonded tokens burned again @@ -318,8 +304,9 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { keeper.Slash(ctx, consAddr, 9, 10, fraction) ubd, found = keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) require.True(t, found) + require.Len(t, ubd.Entries, 1) // balance unchanged - require.Equal(t, sdk.NewInt(0), ubd.Balance.Amount) + require.Equal(t, sdk.NewInt(0), ubd.Entries[0].Balance.Amount) // read updated pool newPool = keeper.GetPool(ctx) // bonded tokens burned again @@ -338,8 +325,9 @@ func TestSlashWithUnbondingDelegation(t *testing.T) { keeper.Slash(ctx, consAddr, 9, 10, fraction) ubd, found = keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) require.True(t, found) + require.Len(t, ubd.Entries, 1) // balance unchanged - require.Equal(t, sdk.NewInt(0), ubd.Balance.Amount) + require.Equal(t, sdk.NewInt(0), ubd.Entries[0].Balance.Amount) // read updated pool newPool = keeper.GetPool(ctx) // just 1 bonded token burned again since that's all the validator now has @@ -360,17 +348,9 @@ func TestSlashWithRedelegation(t *testing.T) { fraction := sdk.NewDecWithPrec(5, 1) // set a redelegation - rd := types.Redelegation{ - DelegatorAddr: addrDels[0], - ValidatorSrcAddr: addrVals[0], - ValidatorDstAddr: addrVals[1], - CreationHeight: 11, - MinTime: time.Unix(0, 0), - SharesSrc: sdk.NewDec(6), - SharesDst: sdk.NewDec(6), - InitialBalance: sdk.NewInt64Coin(params.BondDenom, 6), - Balance: sdk.NewInt64Coin(params.BondDenom, 6), - } + rd := types.NewRedelegation(addrDels[0], addrVals[0], addrVals[1], 11, + time.Unix(0, 0), sdk.NewInt64Coin(params.BondDenom, 6), sdk.NewDec(6), + sdk.NewDec(6)) keeper.SetRedelegation(ctx, rd) // set the associated delegation @@ -396,8 +376,9 @@ func TestSlashWithRedelegation(t *testing.T) { // read updating redelegation rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) require.True(t, found) + require.Len(t, rd.Entries, 1) // balance decreased - require.Equal(t, sdk.NewInt(3), rd.Balance.Amount) + require.Equal(t, sdk.NewInt(3), rd.Entries[0].Balance.Amount) // read updated pool newPool := keeper.GetPool(ctx) // bonded tokens burned @@ -420,8 +401,9 @@ func TestSlashWithRedelegation(t *testing.T) { // read updating redelegation rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) require.True(t, found) + require.Len(t, rd.Entries, 1) // balance decreased, now zero - require.Equal(t, sdk.NewInt(0), rd.Balance.Amount) + require.Equal(t, sdk.NewInt(0), rd.Entries[0].Balance.Amount) // read updated pool newPool = keeper.GetPool(ctx) // seven bonded tokens burned @@ -441,8 +423,9 @@ func TestSlashWithRedelegation(t *testing.T) { // read updating redelegation rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) require.True(t, found) + require.Len(t, rd.Entries, 1) // balance still zero - require.Equal(t, sdk.NewInt(0), rd.Balance.Amount) + require.Equal(t, sdk.NewInt(0), rd.Entries[0].Balance.Amount) // read updated pool newPool = keeper.GetPool(ctx) // four more bonded tokens burned @@ -465,8 +448,9 @@ func TestSlashWithRedelegation(t *testing.T) { // read updating redelegation rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) require.True(t, found) + require.Len(t, rd.Entries, 1) // balance still zero - require.Equal(t, sdk.NewInt(0), rd.Balance.Amount) + require.Equal(t, sdk.NewInt(0), rd.Entries[0].Balance.Amount) // read updated pool newPool = keeper.GetPool(ctx) // no more bonded tokens burned @@ -482,19 +466,11 @@ func TestSlashBoth(t *testing.T) { ctx, keeper, params := setupHelper(t, 10) fraction := sdk.NewDecWithPrec(5, 1) - // set a redelegation - rdA := types.Redelegation{ - DelegatorAddr: addrDels[0], - ValidatorSrcAddr: addrVals[0], - ValidatorDstAddr: addrVals[1], - CreationHeight: 11, - // expiration timestamp (beyond which the redelegation shouldn't be slashed) - MinTime: time.Unix(0, 0), - SharesSrc: sdk.NewDec(6), - SharesDst: sdk.NewDec(6), - InitialBalance: sdk.NewInt64Coin(params.BondDenom, 6), - Balance: sdk.NewInt64Coin(params.BondDenom, 6), - } + // set a redelegation with expiration timestamp beyond which the + // redelegation shouldn't be slashed + rdA := types.NewRedelegation(addrDels[0], addrVals[0], addrVals[1], 11, + time.Unix(0, 0), sdk.NewInt64Coin(params.BondDenom, 6), sdk.NewDec(6), + sdk.NewDec(6)) keeper.SetRedelegation(ctx, rdA) // set the associated delegation @@ -505,16 +481,10 @@ func TestSlashBoth(t *testing.T) { } keeper.SetDelegation(ctx, delA) - // set an unbonding delegation - ubdA := types.UnbondingDelegation{ - DelegatorAddr: addrDels[0], - ValidatorAddr: addrVals[0], - CreationHeight: 11, - // expiration timestamp (beyond which the unbonding delegation shouldn't be slashed) - MinTime: time.Unix(0, 0), - InitialBalance: sdk.NewInt64Coin(params.BondDenom, 4), - Balance: sdk.NewInt64Coin(params.BondDenom, 4), - } + // set an unbonding delegation with expiration timestamp (beyond which the + // unbonding delegation shouldn't be slashed) + ubdA := types.NewUnbondingDelegation(addrDels[0], addrVals[0], 11, + time.Unix(0, 0), sdk.NewInt64Coin(params.BondDenom, 4)) keeper.SetUnbondingDelegation(ctx, ubdA) // slash validator @@ -528,8 +498,9 @@ func TestSlashBoth(t *testing.T) { // read updating redelegation rdA, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) require.True(t, found) + require.Len(t, rdA.Entries, 1) // balance decreased - require.Equal(t, sdk.NewInt(3), rdA.Balance.Amount) + require.Equal(t, sdk.NewInt(3), rdA.Entries[0].Balance.Amount) // read updated pool newPool := keeper.GetPool(ctx) // loose tokens burned diff --git a/x/stake/querier/querier_test.go b/x/stake/querier/querier_test.go index e332fe2351c..897f77375f7 100644 --- a/x/stake/querier/querier_test.go +++ b/x/stake/querier/querier_test.go @@ -382,8 +382,7 @@ func TestQueryRedelegations(t *testing.T) { keeper.SetValidator(ctx, val2) keeper.Delegate(ctx, addrAcc2, sdk.NewCoin(types.DefaultBondDenom, sdk.NewInt(100)), val1, true) - _, err := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.NoError(t, err) + _ = keeper.ApplyAndReturnValidatorSetUpdates(ctx) keeper.BeginRedelegation(ctx, addrAcc2, val1.GetOperator(), val2.GetOperator(), sdk.NewDec(20)) keeper.ApplyAndReturnValidatorSetUpdates(ctx) diff --git a/x/stake/types/delegation.go b/x/stake/types/delegation.go index fb72a8a511b..7e8d74394a1 100644 --- a/x/stake/types/delegation.go +++ b/x/stake/types/delegation.go @@ -37,6 +37,17 @@ type Delegation struct { Shares sdk.Dec `json:"shares"` } +// NewDelegation creates a new delegation object +func NewDelegation(delegatorAddr sdk.AccAddress, validatorAddr sdk.ValAddress, + shares sdk.Dec) Delegation { + + return Delegation{ + DelegatorAddr: delegatorAddr, + ValidatorAddr: validatorAddr, + Shares: shares, + } +} + // return the delegation func MustMarshalDelegation(cdc *codec.Codec, delegation Delegation) []byte { return cdc.MustMarshalBinaryLengthPrefixed(delegation) diff --git a/x/stake/types/delegation_test.go b/x/stake/types/delegation_test.go index ee7d81bf5b5..1881b68edc3 100644 --- a/x/stake/types/delegation_test.go +++ b/x/stake/types/delegation_test.go @@ -10,16 +10,8 @@ import ( ) func TestDelegationEqual(t *testing.T) { - d1 := Delegation{ - DelegatorAddr: sdk.AccAddress(addr1), - ValidatorAddr: addr2, - Shares: sdk.NewDec(100), - } - d2 := Delegation{ - DelegatorAddr: sdk.AccAddress(addr1), - ValidatorAddr: addr2, - Shares: sdk.NewDec(100), - } + d1 := NewDelegation(sdk.AccAddress(addr1), addr2, sdk.NewDec(100)) + d2 := d1 ok := d1.Equal(d2) require.True(t, ok) @@ -32,11 +24,7 @@ func TestDelegationEqual(t *testing.T) { } func TestDelegationHumanReadableString(t *testing.T) { - d := Delegation{ - DelegatorAddr: sdk.AccAddress(addr1), - ValidatorAddr: addr2, - Shares: sdk.NewDec(100), - } + d := NewDelegation(sdk.AccAddress(addr1), addr2, sdk.NewDec(100)) // NOTE: Being that the validator's keypair is random, we cannot test the // actual contents of the string. @@ -46,69 +34,52 @@ func TestDelegationHumanReadableString(t *testing.T) { } func TestUnbondingDelegationEqual(t *testing.T) { - ud1 := UnbondingDelegation{ - DelegatorAddr: sdk.AccAddress(addr1), - ValidatorAddr: addr2, - } - ud2 := UnbondingDelegation{ - DelegatorAddr: sdk.AccAddress(addr1), - ValidatorAddr: addr2, - } - - ok := ud1.Equal(ud2) + ubd1 := NewUnbondingDelegation(sdk.AccAddress(addr1), addr2, 0, + time.Unix(0, 0), sdk.NewInt64Coin(DefaultBondDenom, 0)) + ubd2 := ubd1 + + ok := ubd1.Equal(ubd2) require.True(t, ok) - ud2.ValidatorAddr = addr3 + ubd2.ValidatorAddr = addr3 - ud2.MinTime = time.Unix(20*20*2, 0) - ok = ud1.Equal(ud2) + ubd2.Entries[0].CompletionTime = time.Unix(20*20*2, 0) + ok = ubd1.Equal(ubd2) require.False(t, ok) } func TestUnbondingDelegationHumanReadableString(t *testing.T) { - ud := UnbondingDelegation{ - DelegatorAddr: sdk.AccAddress(addr1), - ValidatorAddr: addr2, - } + ubd := NewUnbondingDelegation(sdk.AccAddress(addr1), addr2, 0, + time.Unix(0, 0), sdk.NewInt64Coin(DefaultBondDenom, 0)) // NOTE: Being that the validator's keypair is random, we cannot test the // actual contents of the string. - valStr, err := ud.HumanReadableString() + valStr, err := ubd.HumanReadableString() require.Nil(t, err) require.NotEmpty(t, valStr) } func TestRedelegationEqual(t *testing.T) { - r1 := Redelegation{ - DelegatorAddr: sdk.AccAddress(addr1), - ValidatorSrcAddr: addr2, - ValidatorDstAddr: addr3, - } - r2 := Redelegation{ - DelegatorAddr: sdk.AccAddress(addr1), - ValidatorSrcAddr: addr2, - ValidatorDstAddr: addr3, - } + r1 := NewRedelegation(sdk.AccAddress(addr1), addr2, addr3, 0, + time.Unix(0, 0), sdk.NewInt64Coin(DefaultBondDenom, 0), + sdk.NewDec(0), sdk.NewDec(0)) + r2 := r1 ok := r1.Equal(r2) require.True(t, ok) - r2.SharesDst = sdk.NewDec(10) - r2.SharesSrc = sdk.NewDec(20) - r2.MinTime = time.Unix(20*20*2, 0) + r2.Entries[0].SharesDst = sdk.NewDec(10) + r2.Entries[0].SharesSrc = sdk.NewDec(20) + r2.Entries[0].CompletionTime = time.Unix(20*20*2, 0) ok = r1.Equal(r2) require.False(t, ok) } func TestRedelegationHumanReadableString(t *testing.T) { - r := Redelegation{ - DelegatorAddr: sdk.AccAddress(addr1), - ValidatorSrcAddr: addr2, - ValidatorDstAddr: addr3, - SharesDst: sdk.NewDec(10), - SharesSrc: sdk.NewDec(20), - } + r := NewRedelegation(sdk.AccAddress(addr1), addr2, addr3, 0, + time.Unix(0, 0), sdk.NewInt64Coin(DefaultBondDenom, 0), + sdk.NewDec(10), sdk.NewDec(20)) // NOTE: Being that the validator's keypair is random, we cannot test the // actual contents of the string. From 9dd1181fae7e9ad1c4d7b569277927bba60d7580 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Mon, 7 Jan 2019 21:56:32 -0500 Subject: [PATCH 13/26] test cover passes --- x/stake/handler_test.go | 16 ++----- x/stake/keeper/slash.go | 82 +++++++++++++++++--------------- x/stake/keeper/slash_test.go | 4 +- x/stake/types/delegation_test.go | 4 +- 4 files changed, 53 insertions(+), 53 deletions(-) diff --git a/x/stake/handler_test.go b/x/stake/handler_test.go index 4de2da3b3e3..6755a48da60 100644 --- a/x/stake/handler_test.go +++ b/x/stake/handler_test.go @@ -849,7 +849,7 @@ func TestTransitiveRedelegation(t *testing.T) { require.True(t, got.IsOK(), "expected no error") } -func TestConflictingRedelegation(t *testing.T) { +func TestMultipleRedelegation(t *testing.T) { ctx, _, keeper := keep.CreateTestInput(t, false, 1000) validatorAddr := sdk.ValAddress(keep.Addrs[0]) validatorAddr2 := sdk.ValAddress(keep.Addrs[1]) @@ -876,19 +876,11 @@ func TestConflictingRedelegation(t *testing.T) { got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) require.True(t, got.IsOK(), "expected no error, %v", got) - // cannot redelegate again while first redelegation still exists + // should be able to redelegate again while first redelegation still exists got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) - require.True(t, !got.IsOK(), "expected an error, msg: %v", msgBeginRedelegate) - - // progress forward in time - ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(10 * time.Second)) + require.True(t, got.IsOK(), "expected no error, msg: %v", msgBeginRedelegate) - // complete first redelegation - EndBlocker(ctx, keeper) - - // now should be able to redelegate again - got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) - require.True(t, got.IsOK(), "expected no error") + // XXX add more test } func TestUnbondingWhenExcessValidators(t *testing.T) { diff --git a/x/stake/keeper/slash.go b/x/stake/keeper/slash.go index 411908f48a6..4f030b80b0c 100644 --- a/x/stake/keeper/slash.go +++ b/x/stake/keeper/slash.go @@ -145,27 +145,29 @@ func (k Keeper) Unjail(ctx sdk.Context, consAddr sdk.ConsAddress) { // (the amount actually slashed may be less if there's // insufficient stake remaining) func (k Keeper) slashUnbondingDelegation(ctx sdk.Context, unbondingDelegation types.UnbondingDelegation, - infractionHeight int64, slashFactor sdk.Dec) (slashAmount sdk.Int) { + infractionHeight int64, slashFactor sdk.Dec) (totalSlashAmount sdk.Int) { now := ctx.BlockHeader().Time + totalSlashAmount = sdk.ZeroInt() // perform slashing on all entries within the unbonding delegation for i, entry := range unbondingDelegation.Entries { // If unbonding started before this height, stake didn't contribute to infraction if entry.CreationHeight < infractionHeight { - return sdk.ZeroInt() + continue } if entry.IsMature(now) { // Unbonding delegation no longer eligible for slashing, skip it // TODO Settle and delete it automatically? - return sdk.ZeroInt() + continue } // Calculate slash amount proportional to stake contributing to infraction slashAmountDec := slashFactor.MulInt(entry.InitialBalance.Amount) - slashAmount = slashAmountDec.TruncateInt() + slashAmount := slashAmountDec.TruncateInt() + totalSlashAmount = totalSlashAmount.Add(slashAmount) // Don't slash more tokens than held // Possible since the unbonding delegation may already @@ -174,20 +176,21 @@ func (k Keeper) slashUnbondingDelegation(ctx sdk.Context, unbondingDelegation ty unbondingSlashAmount := sdk.MinInt(slashAmount, entry.Balance.Amount) // Update unbonding delegation if necessary - if !unbondingSlashAmount.IsZero() { - entry.Balance.Amount = entry.Balance.Amount.Sub(unbondingSlashAmount) - unbondingDelegation.Entries[i] = entry - k.SetUnbondingDelegation(ctx, unbondingDelegation) - pool := k.GetPool(ctx) - - // Burn loose tokens - // Ref https://github.com/cosmos/cosmos-sdk/pull/1278#discussion_r198657760 - pool.LooseTokens = pool.LooseTokens.Sub(unbondingSlashAmount) - k.SetPool(ctx, pool) + if unbondingSlashAmount.IsZero() { + continue } + entry.Balance.Amount = entry.Balance.Amount.Sub(unbondingSlashAmount) + unbondingDelegation.Entries[i] = entry + k.SetUnbondingDelegation(ctx, unbondingDelegation) + pool := k.GetPool(ctx) + + // Burn loose tokens + // Ref https://github.com/cosmos/cosmos-sdk/pull/1278#discussion_r198657760 + pool.LooseTokens = pool.LooseTokens.Sub(unbondingSlashAmount) + k.SetPool(ctx, pool) } - return slashAmount + return totalSlashAmount } // slash a redelegation and update the pool @@ -197,27 +200,29 @@ func (k Keeper) slashUnbondingDelegation(ctx sdk.Context, unbondingDelegation ty // insufficient stake remaining) // nolint: unparam func (k Keeper) slashRedelegation(ctx sdk.Context, validator types.Validator, redelegation types.Redelegation, - infractionHeight int64, slashFactor sdk.Dec) (slashAmount sdk.Int) { + infractionHeight int64, slashFactor sdk.Dec) (totalSlashAmount sdk.Int) { now := ctx.BlockHeader().Time + totalSlashAmount = sdk.ZeroInt() // perform slashing on all entries within the redelegation for i, entry := range redelegation.Entries { // If redelegation started before this height, stake didn't contribute to infraction if entry.CreationHeight < infractionHeight { - return sdk.ZeroInt() + continue } if entry.IsMature(now) { // Redelegation no longer eligible for slashing, skip it // TODO Delete it automatically? - return sdk.ZeroInt() + continue } // Calculate slash amount proportional to stake contributing to infraction slashAmountDec := slashFactor.MulInt(entry.InitialBalance.Amount) - slashAmount = slashAmountDec.TruncateInt() + slashAmount := slashAmountDec.TruncateInt() + totalSlashAmount = totalSlashAmount.Add(slashAmount) // Don't slash more tokens than held // Possible since the redelegation may already @@ -234,27 +239,28 @@ func (k Keeper) slashRedelegation(ctx sdk.Context, validator types.Validator, re // Unbond from target validator sharesToUnbond := slashFactor.Mul(entry.SharesDst) - if !sharesToUnbond.IsZero() { - delegation, found := k.GetDelegation(ctx, redelegation.DelegatorAddr, redelegation.ValidatorDstAddr) - if !found { - // If deleted, delegation has zero shares, and we can't unbond any more - return slashAmount - } - if sharesToUnbond.GT(delegation.Shares) { - sharesToUnbond = delegation.Shares - } - - tokensToBurn, err := k.unbond(ctx, redelegation.DelegatorAddr, redelegation.ValidatorDstAddr, sharesToUnbond) - if err != nil { - panic(fmt.Errorf("error unbonding delegator: %v", err)) - } + if sharesToUnbond.IsZero() { + continue + } + delegation, found := k.GetDelegation(ctx, redelegation.DelegatorAddr, redelegation.ValidatorDstAddr) + if !found { + // If deleted, delegation has zero shares, and we can't unbond any more + continue + } + if sharesToUnbond.GT(delegation.Shares) { + sharesToUnbond = delegation.Shares + } - // Burn loose tokens - pool := k.GetPool(ctx) - pool.LooseTokens = pool.LooseTokens.Sub(tokensToBurn) - k.SetPool(ctx, pool) + tokensToBurn, err := k.unbond(ctx, redelegation.DelegatorAddr, redelegation.ValidatorDstAddr, sharesToUnbond) + if err != nil { + panic(fmt.Errorf("error unbonding delegator: %v", err)) } + + // Burn loose tokens + pool := k.GetPool(ctx) + pool.LooseTokens = pool.LooseTokens.Sub(tokensToBurn) + k.SetPool(ctx, pool) } - return slashAmount + return totalSlashAmount } diff --git a/x/stake/keeper/slash_test.go b/x/stake/keeper/slash_test.go index 9fac4ab8ac6..e1a94d64d48 100644 --- a/x/stake/keeper/slash_test.go +++ b/x/stake/keeper/slash_test.go @@ -73,7 +73,7 @@ func TestSlashUnbondingDelegation(t *testing.T) { // set an unbonding delegation with expiration timestamp (beyond which the // unbonding delegation shouldn't be slashed) ubd := types.NewUnbondingDelegation(addrDels[0], addrVals[0], 0, - time.Unix(0, 0), sdk.NewInt64Coin(params.BondDenom, 10)) + time.Unix(5, 0), sdk.NewInt64Coin(params.BondDenom, 10)) keeper.SetUnbondingDelegation(ctx, ubd) @@ -114,7 +114,7 @@ func TestSlashRedelegation(t *testing.T) { // set a redelegation with an expiration timestamp beyond which the // redelegation shouldn't be slashed rd := types.NewRedelegation(addrDels[0], addrVals[0], addrVals[1], 0, - time.Unix(0, 0), sdk.NewInt64Coin(params.BondDenom, 10), sdk.NewDec(10), + time.Unix(5, 0), sdk.NewInt64Coin(params.BondDenom, 10), sdk.NewDec(10), sdk.NewDec(10)) keeper.SetRedelegation(ctx, rd) diff --git a/x/stake/types/delegation_test.go b/x/stake/types/delegation_test.go index 1881b68edc3..95f58d67825 100644 --- a/x/stake/types/delegation_test.go +++ b/x/stake/types/delegation_test.go @@ -63,7 +63,9 @@ func TestRedelegationEqual(t *testing.T) { r1 := NewRedelegation(sdk.AccAddress(addr1), addr2, addr3, 0, time.Unix(0, 0), sdk.NewInt64Coin(DefaultBondDenom, 0), sdk.NewDec(0), sdk.NewDec(0)) - r2 := r1 + r2 := NewRedelegation(sdk.AccAddress(addr1), addr2, addr3, 0, + time.Unix(0, 0), sdk.NewInt64Coin(DefaultBondDenom, 0), + sdk.NewDec(0), sdk.NewDec(0)) ok := r1.Equal(r2) require.True(t, ok) From b4d5117114cbcef170d42abc03e6d687026398d5 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Tue, 8 Jan 2019 23:55:48 -0500 Subject: [PATCH 14/26] ... --- x/stake/genesis.go | 8 -------- 1 file changed, 8 deletions(-) diff --git a/x/stake/genesis.go b/x/stake/genesis.go index 5dd0bb609c7..c3f14c35934 100644 --- a/x/stake/genesis.go +++ b/x/stake/genesis.go @@ -47,10 +47,6 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) (res [ keeper.OnDelegationCreated(ctx, delegation.DelegatorAddr, delegation.ValidatorAddr) } - // XXX fix or delete this section - //sort.SliceStable(data.UnbondingDelegations[:], func(i, j int) bool { - //return data.UnbondingDelegations[i].CreationHeight < data.UnbondingDelegations[j].CreationHeight - //}) for _, ubd := range data.UnbondingDelegations { keeper.SetUnbondingDelegation(ctx, ubd) for _, entry := range ubd.Entries { @@ -58,10 +54,6 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) (res [ } } - // XXX fix or delete this section - //sort.SliceStable(data.Redelegations[:], func(i, j int) bool { - //return data.Redelegations[i].CreationHeight < data.Redelegations[j].CreationHeight - //}) for _, red := range data.Redelegations { keeper.SetRedelegation(ctx, red) for _, entry := range red.Entries { From 33ce0f3ea54cd0941fe095eafea8183bf8f17a3a Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 9 Jan 2019 00:55:12 -0500 Subject: [PATCH 15/26] multiple entries fix --- x/stake/handler_test.go | 39 +++++++++++++++++++++++++++-------- x/stake/keeper/delegation.go | 32 ++++++++++++++-------------- x/stake/keeper/test_common.go | 8 ++++++- 3 files changed, 53 insertions(+), 26 deletions(-) diff --git a/x/stake/handler_test.go b/x/stake/handler_test.go index 6755a48da60..fd212356c5e 100644 --- a/x/stake/handler_test.go +++ b/x/stake/handler_test.go @@ -849,10 +849,10 @@ func TestTransitiveRedelegation(t *testing.T) { require.True(t, got.IsOK(), "expected no error") } -func TestMultipleRedelegation(t *testing.T) { +func TestMultipleRedelegationAtSameTime(t *testing.T) { ctx, _, keeper := keep.CreateTestInput(t, false, 1000) - validatorAddr := sdk.ValAddress(keep.Addrs[0]) - validatorAddr2 := sdk.ValAddress(keep.Addrs[1]) + valAddr := sdk.ValAddress(keep.Addrs[0]) + valAddr2 := sdk.ValAddress(keep.Addrs[1]) // set the unbonding time params := keeper.GetParams(ctx) @@ -860,27 +860,48 @@ func TestMultipleRedelegation(t *testing.T) { keeper.SetParams(ctx, params) // create the validators - msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], 10) + msgCreateValidator := NewTestMsgCreateValidator(valAddr, keep.PKs[0], 10) got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") - msgCreateValidator = NewTestMsgCreateValidator(validatorAddr2, keep.PKs[1], 10) + msgCreateValidator = NewTestMsgCreateValidator(valAddr2, keep.PKs[1], 10) got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") // end block to bond them EndBlocker(ctx, keeper) - // begin redelegate - msgBeginRedelegate := NewMsgBeginRedelegate(sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2, sdk.NewDec(5)) + // begin a redelegate + selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator) + msgBeginRedelegate := NewMsgBeginRedelegate(selfDelAddr, + valAddr, valAddr2, sdk.NewDec(5)) got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) require.True(t, got.IsOK(), "expected no error, %v", got) - // should be able to redelegate again while first redelegation still exists + // there should only be one entry in the redelegation object + rd, found := keeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) + require.True(t, found) + require.Len(t, rd.Entries, 1) + + // start a second redelegation at this same time as the first got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) require.True(t, got.IsOK(), "expected no error, msg: %v", msgBeginRedelegate) - // XXX add more test + // now there should be two entries + rd, found = keeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) + require.True(t, found) + require.Len(t, rd.Entries, 2) + + // move forward in time, should complete both redelegations + ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(1 * time.Second)) + EndBlocker(ctx, keeper) + + rd, found = keeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) + require.False(t, found) +} + +func TestMultipleRedelegationAtUniqueTimes(t *testing.T) { + // XXX } func TestUnbondingWhenExcessValidators(t *testing.T) { diff --git a/x/stake/keeper/delegation.go b/x/stake/keeper/delegation.go index 959740dfb22..ffe1c5f7267 100644 --- a/x/stake/keeper/delegation.go +++ b/x/stake/keeper/delegation.go @@ -595,21 +595,19 @@ func (k Keeper) CompleteUnbonding(ctx sdk.Context, delAddr sdk.AccAddress, ctxTime := ctx.BlockHeader().Time // loop through all the entries and complete unbonding mature entries - for i, entry := range ubd.Entries { + for i := 0; i < len(ubd.Entries); i++ { + entry := ubd.Entries[i] if entry.IsMature(ctxTime) { - _, _, err := k.bankKeeper.AddCoins(ctx, ubd.DelegatorAddr, sdk.Coins{entry.Balance}) - if err != nil { - return err - } ubd.RemoveEntry(int64(i)) - - // remove the ubd if there are no more entries - if len(ubd.Entries) == 0 { - k.RemoveUnbondingDelegation(ctx, ubd) - } + i-- } } + // remove the redelegation if there are no more entries + if len(ubd.Entries) == 0 { + k.RemoveRedelegation(ctx, ubd) + } + return nil } @@ -673,16 +671,18 @@ func (k Keeper) CompleteRedelegation(ctx sdk.Context, delAddr sdk.AccAddress, ctxTime := ctx.BlockHeader().Time // loop through all the entries and complete mature redelegation entries - for i, entry := range red.Entries { + for i := 0; i < len(red.Entries); i++ { + entry := red.Entries[i] if entry.IsMature(ctxTime) { red.RemoveEntry(int64(i)) - - // remove the redelegation if there are no more entries - if len(red.Entries) == 0 { - k.RemoveRedelegation(ctx, red) - } + i-- } } + // remove the redelegation if there are no more entries + if len(red.Entries) == 0 { + k.RemoveRedelegation(ctx, red) + } + return nil } diff --git a/x/stake/keeper/test_common.go b/x/stake/keeper/test_common.go index 10d856f05b7..1a093086d28 100644 --- a/x/stake/keeper/test_common.go +++ b/x/stake/keeper/test_common.go @@ -94,7 +94,13 @@ func CreateTestInput(t *testing.T, isCheckTx bool, initCoins int64) (sdk.Context require.Nil(t, err) ctx := sdk.NewContext(ms, abci.Header{ChainID: "foochainid"}, isCheckTx, log.NewNopLogger()) - ctx = ctx.WithConsensusParams(&abci.ConsensusParams{Validator: &abci.ValidatorParams{PubKeyTypes: []string{tmtypes.ABCIPubKeyTypeEd25519}}}) + ctx = ctx.WithConsensusParams( + &abci.ConsensusParams{ + Validator: &abci.ValidatorParams{ + PubKeyTypes: []string{tmtypes.ABCIPubKeyTypeEd25519}, + }, + }, + ) cdc := MakeTestCodec() pk := params.NewKeeper(cdc, keyParams, tkeyParams) From 41a428582ca96422c62c576a7093245e680edb1a Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 9 Jan 2019 02:05:34 -0500 Subject: [PATCH 16/26] ... --- x/stake/keeper/delegation.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/stake/keeper/delegation.go b/x/stake/keeper/delegation.go index ffe1c5f7267..f85bdb0dfd7 100644 --- a/x/stake/keeper/delegation.go +++ b/x/stake/keeper/delegation.go @@ -605,7 +605,7 @@ func (k Keeper) CompleteUnbonding(ctx sdk.Context, delAddr sdk.AccAddress, // remove the redelegation if there are no more entries if len(ubd.Entries) == 0 { - k.RemoveRedelegation(ctx, ubd) + k.RemoveUnbondingDelegation(ctx, ubd) } return nil From 96a28d5c76c5a184d9032995526456591eac7f82 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 9 Jan 2019 02:24:01 -0500 Subject: [PATCH 17/26] more design fix --- x/stake/handler_test.go | 53 +++++++++++++++++++++++++++++++++++- x/stake/keeper/delegation.go | 12 ++++++-- x/stake/types/delegation.go | 2 ++ 3 files changed, 64 insertions(+), 3 deletions(-) diff --git a/x/stake/handler_test.go b/x/stake/handler_test.go index fd212356c5e..49936518f5e 100644 --- a/x/stake/handler_test.go +++ b/x/stake/handler_test.go @@ -1,6 +1,7 @@ package stake import ( + "fmt" "testing" "time" @@ -901,7 +902,57 @@ func TestMultipleRedelegationAtSameTime(t *testing.T) { } func TestMultipleRedelegationAtUniqueTimes(t *testing.T) { - // XXX + ctx, _, keeper := keep.CreateTestInput(t, false, 1000) + valAddr := sdk.ValAddress(keep.Addrs[0]) + valAddr2 := sdk.ValAddress(keep.Addrs[1]) + + // set the unbonding time + params := keeper.GetParams(ctx) + params.UnbondingTime = 10 * time.Second + keeper.SetParams(ctx, params) + + // create the validators + msgCreateValidator := NewTestMsgCreateValidator(valAddr, keep.PKs[0], 10) + got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") + + msgCreateValidator = NewTestMsgCreateValidator(valAddr2, keep.PKs[1], 10) + got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") + + // end block to bond them + EndBlocker(ctx, keeper) + + // begin a redelegate + selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator) + msgBeginRedelegate := NewMsgBeginRedelegate(selfDelAddr, + valAddr, valAddr2, sdk.NewDec(5)) + got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) + require.True(t, got.IsOK(), "expected no error, %v", got) + + // move forward in time and start a second redelegation + ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second)) + got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) + require.True(t, got.IsOK(), "expected no error, msg: %v", msgBeginRedelegate) + + // now there should be two entries + rd, found := keeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) + require.True(t, found) + require.Len(t, rd.Entries, 2) + + // move forward in time, should complete the first redelegation, but not the second + fmt.Println("_________________________") + ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second)) + EndBlocker(ctx, keeper) + rd, found = keeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) + require.True(t, found) + require.Len(t, rd.Entries, 1) + + // move forward in time, should complete the second redelegation + ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second)) + EndBlocker(ctx, keeper) + rd, found = keeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) + require.False(t, found) } func TestUnbondingWhenExcessValidators(t *testing.T) { diff --git a/x/stake/keeper/delegation.go b/x/stake/keeper/delegation.go index f85bdb0dfd7..b989230734c 100644 --- a/x/stake/keeper/delegation.go +++ b/x/stake/keeper/delegation.go @@ -2,6 +2,7 @@ package keeper import ( "bytes" + "fmt" "time" sdk "github.com/cosmos/cosmos-sdk/types" @@ -603,9 +604,11 @@ func (k Keeper) CompleteUnbonding(ctx sdk.Context, delAddr sdk.AccAddress, } } - // remove the redelegation if there are no more entries + // set the unbonding delegation or remove it if there are no more entries if len(ubd.Entries) == 0 { k.RemoveUnbondingDelegation(ctx, ubd) + } else { + k.SetUnbondingDelegation(ctx, ubd) } return nil @@ -673,15 +676,20 @@ func (k Keeper) CompleteRedelegation(ctx sdk.Context, delAddr sdk.AccAddress, // loop through all the entries and complete mature redelegation entries for i := 0; i < len(red.Entries); i++ { entry := red.Entries[i] + fmt.Printf("debug i: %v\n", i) + fmt.Printf("debug entry: %v\n", entry) + fmt.Printf("debug entry.IsMature(ctxTime): %v\n", entry.IsMature(ctxTime)) if entry.IsMature(ctxTime) { red.RemoveEntry(int64(i)) i-- } } - // remove the redelegation if there are no more entries + // set the redelegation or remove it if there are no more entries if len(red.Entries) == 0 { k.RemoveRedelegation(ctx, red) + } else { + k.SetRedelegation(ctx, red) } return nil diff --git a/x/stake/types/delegation.go b/x/stake/types/delegation.go index 7e8d74394a1..6026c747a92 100644 --- a/x/stake/types/delegation.go +++ b/x/stake/types/delegation.go @@ -252,6 +252,8 @@ func NewRedelegationEntry(creationHeight int64, // IsMature - is the current entry mature func (e RedelegationEntry) IsMature(currentTime time.Time) bool { + fmt.Printf("debug CompletionTime: \t%v\n", e.CompletionTime) + fmt.Printf("debug currentTime: \t%v\n", currentTime) return !e.CompletionTime.After(currentTime) } From 8f20ed7815646dc629d88180e7eed5492600596d Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 9 Jan 2019 04:52:33 -0500 Subject: [PATCH 18/26] working --- x/stake/handler_test.go | 101 +++++++++++++++++++++++++++++++++-- x/stake/keeper/delegation.go | 4 -- x/stake/types/delegation.go | 2 - 3 files changed, 98 insertions(+), 9 deletions(-) diff --git a/x/stake/handler_test.go b/x/stake/handler_test.go index 49936518f5e..2c13e8d65d4 100644 --- a/x/stake/handler_test.go +++ b/x/stake/handler_test.go @@ -1,7 +1,6 @@ package stake import ( - "fmt" "testing" "time" @@ -857,7 +856,7 @@ func TestMultipleRedelegationAtSameTime(t *testing.T) { // set the unbonding time params := keeper.GetParams(ctx) - params.UnbondingTime = 1 + params.UnbondingTime = 1 * time.Second keeper.SetParams(ctx, params) // create the validators @@ -941,7 +940,6 @@ func TestMultipleRedelegationAtUniqueTimes(t *testing.T) { require.Len(t, rd.Entries, 2) // move forward in time, should complete the first redelegation, but not the second - fmt.Println("_________________________") ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second)) EndBlocker(ctx, keeper) rd, found = keeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) @@ -955,6 +953,103 @@ func TestMultipleRedelegationAtUniqueTimes(t *testing.T) { require.False(t, found) } +func TestMultipleUnbondingDelegationAtSameTime(t *testing.T) { + ctx, _, keeper := keep.CreateTestInput(t, false, 1000) + valAddr := sdk.ValAddress(keep.Addrs[0]) + + // set the unbonding time + params := keeper.GetParams(ctx) + params.UnbondingTime = 1 * time.Second + keeper.SetParams(ctx, params) + + // create the validator + msgCreateValidator := NewTestMsgCreateValidator(valAddr, keep.PKs[0], 10) + got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") + + // end block to bond + EndBlocker(ctx, keeper) + + // begin an unbonding delegation + selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator) + msgBeginUnbonding := NewMsgBeginUnbonding(selfDelAddr, valAddr, sdk.NewDec(5)) + got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) + require.True(t, got.IsOK(), "expected no error, %v", got) + + // there should only be one entry in the ubd object + ubd, found := keeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) + require.True(t, found) + require.Len(t, ubd.Entries, 1) + + // start a second ubd at this same time as the first + got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) + require.True(t, got.IsOK(), "expected no error, msg: %v", msgBeginUnbonding) + + // now there should be two entries + ubd, found = keeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) + require.True(t, found) + require.Len(t, ubd.Entries, 2) + + // move forwaubd in time, should complete both ubds + ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(1 * time.Second)) + EndBlocker(ctx, keeper) + + ubd, found = keeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) + require.False(t, found) +} + +func TestMultipleUnbondingDelegationAtUniqueTimes(t *testing.T) { + ctx, _, keeper := keep.CreateTestInput(t, false, 1000) + valAddr := sdk.ValAddress(keep.Addrs[0]) + + // set the unbonding time + params := keeper.GetParams(ctx) + params.UnbondingTime = 10 * time.Second + keeper.SetParams(ctx, params) + + // create the validator + msgCreateValidator := NewTestMsgCreateValidator(valAddr, keep.PKs[0], 10) + got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") + + // end block to bond + EndBlocker(ctx, keeper) + + // begin an unbonding delegation + selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator) + msgBeginUnbonding := NewMsgBeginUnbonding(selfDelAddr, valAddr, sdk.NewDec(5)) + got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) + require.True(t, got.IsOK(), "expected no error, %v", got) + + // there should only be one entry in the ubd object + ubd, found := keeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) + require.True(t, found) + require.Len(t, ubd.Entries, 1) + + // move forwaubd in time and start a second redelegation + ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second)) + got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) + require.True(t, got.IsOK(), "expected no error, msg: %v", msgBeginUnbonding) + + // now there should be two entries + ubd, found = keeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) + require.True(t, found) + require.Len(t, ubd.Entries, 2) + + // move forwaubd in time, should complete the first redelegation, but not the second + ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second)) + EndBlocker(ctx, keeper) + ubd, found = keeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) + require.True(t, found) + require.Len(t, ubd.Entries, 1) + + // move forwaubd in time, should complete the second redelegation + ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second)) + EndBlocker(ctx, keeper) + ubd, found = keeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) + require.False(t, found) +} + func TestUnbondingWhenExcessValidators(t *testing.T) { ctx, _, keeper := keep.CreateTestInput(t, false, 1000) validatorAddr1 := sdk.ValAddress(keep.Addrs[0]) diff --git a/x/stake/keeper/delegation.go b/x/stake/keeper/delegation.go index b989230734c..7034ce3e15c 100644 --- a/x/stake/keeper/delegation.go +++ b/x/stake/keeper/delegation.go @@ -2,7 +2,6 @@ package keeper import ( "bytes" - "fmt" "time" sdk "github.com/cosmos/cosmos-sdk/types" @@ -676,9 +675,6 @@ func (k Keeper) CompleteRedelegation(ctx sdk.Context, delAddr sdk.AccAddress, // loop through all the entries and complete mature redelegation entries for i := 0; i < len(red.Entries); i++ { entry := red.Entries[i] - fmt.Printf("debug i: %v\n", i) - fmt.Printf("debug entry: %v\n", entry) - fmt.Printf("debug entry.IsMature(ctxTime): %v\n", entry.IsMature(ctxTime)) if entry.IsMature(ctxTime) { red.RemoveEntry(int64(i)) i-- diff --git a/x/stake/types/delegation.go b/x/stake/types/delegation.go index 6026c747a92..7e8d74394a1 100644 --- a/x/stake/types/delegation.go +++ b/x/stake/types/delegation.go @@ -252,8 +252,6 @@ func NewRedelegationEntry(creationHeight int64, // IsMature - is the current entry mature func (e RedelegationEntry) IsMature(currentTime time.Time) bool { - fmt.Printf("debug CompletionTime: \t%v\n", e.CompletionTime) - fmt.Printf("debug currentTime: \t%v\n", currentTime) return !e.CompletionTime.After(currentTime) } From 069c5a40082313e7f85297c0e23581aa0e3d2c21 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 10 Jan 2019 01:17:10 -0500 Subject: [PATCH 19/26] fix test cover bug --- x/stake/handler_test.go | 3 ++- x/stake/keeper/delegation.go | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/x/stake/handler_test.go b/x/stake/handler_test.go index 2c13e8d65d4..81abf40b283 100644 --- a/x/stake/handler_test.go +++ b/x/stake/handler_test.go @@ -416,6 +416,7 @@ func TestIncrementsMsgUnbond(t *testing.T) { msgBeginUnbonding := NewMsgBeginUnbonding(delegatorAddr, validatorAddr, unbondShares) numUnbonds := 5 for i := 0; i < numUnbonds; i++ { + got := handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), "expected msg %d to be ok, got %v", i, got) var finishTime time.Time @@ -423,7 +424,7 @@ func TestIncrementsMsgUnbond(t *testing.T) { ctx = ctx.WithBlockTime(finishTime) EndBlocker(ctx, keeper) - //Check that the accounts and the bond account have the appropriate values + // check that the accounts and the bond account have the appropriate values validator, found = keeper.GetValidator(ctx, validatorAddr) require.True(t, found) bond, found := keeper.GetDelegation(ctx, delegatorAddr, validatorAddr) diff --git a/x/stake/keeper/delegation.go b/x/stake/keeper/delegation.go index 7034ce3e15c..b48428d991f 100644 --- a/x/stake/keeper/delegation.go +++ b/x/stake/keeper/delegation.go @@ -600,6 +600,11 @@ func (k Keeper) CompleteUnbonding(ctx sdk.Context, delAddr sdk.AccAddress, if entry.IsMature(ctxTime) { ubd.RemoveEntry(int64(i)) i-- + + _, _, err := k.bankKeeper.AddCoins(ctx, ubd.DelegatorAddr, sdk.Coins{entry.Balance}) + if err != nil { + return err + } } } From c161cb5e24b839e46b81ae052521f12744dfa31e Mon Sep 17 00:00:00 2001 From: frog power 4000 Date: Thu, 10 Jan 2019 01:22:07 -0500 Subject: [PATCH 20/26] Update PENDING.md --- PENDING.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/PENDING.md b/PENDING.md index 3b352d91a55..c8ac1200010 100644 --- a/PENDING.md +++ b/PENDING.md @@ -26,6 +26,8 @@ BREAKING CHANGES * [\#3064](https://github.com/cosmos/cosmos-sdk/issues/3064) Sanitize `sdk.Coin` denom. Coins denoms are now case insensitive, i.e. 100fooToken equals to 100FOOTOKEN. * [\#3242](https://github.com/cosmos/cosmos-sdk/issues/3242) Fix infinite gas meter utilization during aborted ante handler executions. + * [x/stake] \#1402 Redelegation and unbonding-delegation structs changed to include multiple an array of entries + * Tendermint @@ -76,7 +78,7 @@ IMPROVEMENTS slashing, and staking modules. * [\#3093](https://github.com/cosmos/cosmos-sdk/issues/3093) Ante handler does no longer read all accounts in one go when processing signatures as signature verification may fail before last signature is checked. - * [x/stake] \#1402 Add global redelegation-unbonding index + * [x/stake] \#1402 Add for multiple simultaneous redelegations or unbonding-delegations within an unbonding period * Tendermint From f13afeaa09a05b2ccd18cb4f341f0ff674c1ceb1 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 10 Jan 2019 01:37:51 -0500 Subject: [PATCH 21/26] update comment around queue completion for redelegations/ubds --- x/stake/keeper/delegation.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/x/stake/keeper/delegation.go b/x/stake/keeper/delegation.go index b48428d991f..80092c56c24 100644 --- a/x/stake/keeper/delegation.go +++ b/x/stake/keeper/delegation.go @@ -229,7 +229,8 @@ func (k Keeper) UBDQueueIterator(ctx sdk.Context, endTime time.Time) sdk.Iterato sdk.InclusiveEndBytes(GetUnbondingDelegationTimeKey(endTime))) } -// Returns a concatenated list of all the timeslices before currTime, and deletes the timeslices from the queue +// Returns a concatenated list of all the timeslices inclusively previous to +// currTime, and deletes the timeslices from the queue func (k Keeper) DequeueAllMatureUBDQueue(ctx sdk.Context, currTime time.Time) (matureUnbonds []types.DVPair) { @@ -409,7 +410,8 @@ func (k Keeper) RedelegationQueueIterator(ctx sdk.Context, endTime time.Time) sd return store.Iterator(RedelegationQueueKey, sdk.InclusiveEndBytes(GetRedelegationTimeKey(endTime))) } -// Returns a concatenated list of all the timeslices before currTime, and deletes the timeslices from the queue +// Returns a concatenated list of all the timeslices inclusively previous to +// currTime, and deletes the timeslices from the queue func (k Keeper) DequeueAllMatureRedelegationQueue(ctx sdk.Context, currTime time.Time) (matureRedelegations []types.DVVTriplet) { store := ctx.KVStore(k.storeKey) // gets an iterator for all timeslices from time 0 until the current Blockheader time From 8906710dbbbbc2bbc40ab80afc6773c6c5006794 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 10 Jan 2019 01:55:19 -0500 Subject: [PATCH 22/26] basic spec updates --- docs/spec/staking/state.md | 65 +++++++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 22 deletions(-) diff --git a/docs/spec/staking/state.md b/docs/spec/staking/state.md index d2f461e103b..ccac0b07961 100644 --- a/docs/spec/staking/state.md +++ b/docs/spec/staking/state.md @@ -96,9 +96,9 @@ type Description struct { ### Delegation Delegations are identified by combining `DelegatorAddr` (the address of the delegator) -with the `OperatorAddr` Delegators are indexed in the store as follows: +with the `ValidatorAddr` Delegators are indexed in the store as follows: -- Delegation: ` 0x0A | DelegatorAddr | OperatorAddr -> amino(delegation)` +- Delegation: ` 0x0A | DelegatorAddr | ValidatorAddr -> amino(delegation)` Atom holders may delegate coins to validators; under this circumstance their funds are held in a `Delegation` data structure. It is owned by one @@ -107,26 +107,29 @@ the transaction is the owner of the bond. ```golang type Delegation struct { - Shares sdk.Dec // delegation shares received - Height int64 // last height bond updated + DelegatorAddr sdk.AccAddress + ValidatorAddr sdk.ValAddress + Shares sdk.Dec // delegation shares received } ``` ### UnbondingDelegation -Shares in a `Delegation` can be unbonded, but they must for some time exist as an `UnbondingDelegation`, where shares can be reduced if Byzantine behavior is detected. +Shares in a `Delegation` can be unbonded, but they must for some time exist as +an `UnbondingDelegation`, where shares can be reduced if Byzantine behavior is +detected. `UnbondingDelegation` are indexed in the store as: -- UnbondingDelegationByDelegator: ` 0x0B | DelegatorAddr | OperatorAddr -> +- UnbondingDelegationByDelegator: ` 0x0B | DelegatorAddr | ValidatorAddr -> amino(unbondingDelegation)` -- UnbondingDelegationByValOwner: ` 0x0C | OperatorAddr | DelegatorAddr | OperatorAddr -> +- UnbondingDelegationByValOwner: ` 0x0C | ValidatorAddr | DelegatorAddr | ValidatorAddr -> nil` - The first map here is used in queries, to lookup all unbonding delegations for - a given delegator, while the second map is used in slashing, to lookup all - unbonding delegations associated with a given validator that need to be - slashed. +The first map here is used in queries, to lookup all unbonding delegations for +a given delegator, while the second map is used in slashing, to lookup all +unbonding delegations associated with a given validator that need to be +slashed. A UnbondingDelegation object is created every time an unbonding is initiated. The unbond must be completed with a second transaction provided by the @@ -134,8 +137,16 @@ delegation owner after the unbonding period has passed. ```golang type UnbondingDelegation struct { - Tokens sdk.Coins // the value in Atoms of the amount of shares which are unbonding - CompleteTime int64 // unix time to complete redelegation + DelegatorAddr sdk.AccAddress // delegator + ValidatorAddr sdk.ValAddress // validator unbonding from operator addr + Entries []UnbondingDelegationEntry // unbonding delegation entries +} + +type UnbondingDelegationEntry struct { + CreationHeight int64 // height which the unbonding took place + CompletionTime time.Time // unix time for unbonding completion + InitialBalance sdk.Coin // atoms initially scheduled to receive at completion + Balance sdk.Coin // atoms to receive at completion } ``` @@ -143,20 +154,20 @@ type UnbondingDelegation struct { Shares in a `Delegation` can be rebonded to a different validator, but they must for some time exist as a `Redelegation`, where shares can be reduced if Byzantine -behavior is detected. This is tracked as moving a delegation from a `FromOperatorAddr` -to a `ToOperatorAddr`. +behavior is detected. This is tracked as moving a delegation from a `ValidatorSrcAddr` +to a `ValidatorDstAddr`. `Redelegation` are indexed in the store as: - - Redelegations: `0x0D | DelegatorAddr | FromOperatorAddr | ToOperatorAddr -> + - Redelegations: `0x0D | DelegatorAddr | ValidatorSrcAddr | ValidatorDstAddr -> amino(redelegation)` - - RedelegationsBySrc: `0x0E | FromOperatorAddr | ToOperatorAddr | + - RedelegationsBySrc: `0x0E | ValidatorSrcAddr | ValidatorDstAddr | DelegatorAddr -> nil` - - RedelegationsByDst: `0x0F | ToOperatorAddr | FromOperatorAddr | DelegatorAddr + - RedelegationsByDst: `0x0F | ValidatorDstAddr | ValidatorSrcAddr | DelegatorAddr -> nil` The first map here is used for queries, to lookup all redelegations for a given -delegator. The second map is used for slashing based on the `FromOperatorAddr`, +delegator. The second map is used for slashing based on the `ValidatorSrcAddr`, while the third map is for slashing based on the ToValOwnerAddr. A redelegation object is created every time a redelegation occurs. The @@ -167,8 +178,18 @@ the original redelegation has been completed. ```golang type Redelegation struct { - SourceShares sdk.Dec // amount of source shares redelegating - DestinationShares sdk.Dec // amount of destination shares created at redelegation - CompleteTime int64 // unix time to complete redelegation + DelegatorAddr sdk.AccAddress // delegator + ValidatorSrcAddr sdk.ValAddress // validator redelegation source operator addr + ValidatorDstAddr sdk.ValAddress // validator redelegation destination operator addr + Entries []RedelegationEntry // redelegation entries +} + +type RedelegationEntry struct { + CreationHeight int64 // height which the redelegation took place + CompletionTime time.Time // unix time for redelegation completion + InitialBalance sdk.Coin // initial balance when redelegation started + Balance sdk.Coin // current balance + SharesSrc sdk.Dec // amount of source shares redelegating + SharesDst sdk.Dec // amount of destination shares redelegating } ``` From 59b64c9978b13b7d6087310f1ec97a936eb70eee Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Fri, 11 Jan 2019 14:16:38 -0500 Subject: [PATCH 23/26] remove ErrConflictingRedelegation --- x/stake/types/errors.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/x/stake/types/errors.go b/x/stake/types/errors.go index c3e52f5e448..266ffde608d 100644 --- a/x/stake/types/errors.go +++ b/x/stake/types/errors.go @@ -178,11 +178,6 @@ func ErrTransitiveRedelegation(codespace sdk.CodespaceType) sdk.Error { "redelegation to this validator already in progress, first redelegation to this validator must complete before next redelegation") } -func ErrConflictingRedelegation(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidDelegation, - "conflicting redelegation from this source validator to this dest validator already exists, you must wait for it to finish") -} - func ErrDelegatorShareExRateInvalid(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidDelegation, "cannot delegate to validators with invalid (zero) ex-rate") From 03631dd79e73fb802bc067b4c89d2a8e37389b51 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Fri, 11 Jan 2019 14:23:12 -0500 Subject: [PATCH 24/26] @cwgoes comments are resolved --- x/stake/keeper/slash.go | 1 - 1 file changed, 1 deletion(-) diff --git a/x/stake/keeper/slash.go b/x/stake/keeper/slash.go index d481c748ee1..b2ba793d123 100644 --- a/x/stake/keeper/slash.go +++ b/x/stake/keeper/slash.go @@ -215,7 +215,6 @@ func (k Keeper) slashRedelegation(ctx sdk.Context, validator types.Validator, re if entry.IsMature(now) { // Redelegation no longer eligible for slashing, skip it - // TODO Delete it automatically? continue } From 9a0d49bfa4b832236c09b2007796c3b9bcef454d Mon Sep 17 00:00:00 2001 From: Jack Zampolin Date: Wed, 16 Jan 2019 05:01:09 -0500 Subject: [PATCH 25/26] Update x/staking/keeper/slash.go Co-Authored-By: rigelrozanski --- x/staking/keeper/slash.go | 1 - 1 file changed, 1 deletion(-) diff --git a/x/staking/keeper/slash.go b/x/staking/keeper/slash.go index 48949729e49..3c698382e71 100644 --- a/x/staking/keeper/slash.go +++ b/x/staking/keeper/slash.go @@ -160,7 +160,6 @@ func (k Keeper) slashUnbondingDelegation(ctx sdk.Context, unbondingDelegation ty if entry.IsMature(now) { // Unbonding delegation no longer eligible for slashing, skip it - // TODO Settle and delete it automatically? continue } From 60a0e1cfba7e55bdfc5093e17dddf90e955b9cda Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 16 Jan 2019 05:05:54 -0500 Subject: [PATCH 26/26] address @alexanderbez comments --- docs/spec/staking/state.md | 38 +++++++++++++++++------------------ x/staking/types/delegation.go | 6 +++--- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/docs/spec/staking/state.md b/docs/spec/staking/state.md index 7ac1046b160..9cecf1c3616 100644 --- a/docs/spec/staking/state.md +++ b/docs/spec/staking/state.md @@ -107,8 +107,8 @@ the transaction is the owner of the bond. ```golang type Delegation struct { - DelegatorAddr sdk.AccAddress - ValidatorAddr sdk.ValAddress + DelegatorAddr sdk.AccAddress + ValidatorAddr sdk.ValAddress Shares sdk.Dec // delegation shares received } ``` @@ -137,16 +137,16 @@ delegation owner after the unbonding period has passed. ```golang type UnbondingDelegation struct { - DelegatorAddr sdk.AccAddress // delegator - ValidatorAddr sdk.ValAddress // validator unbonding from operator addr - Entries []UnbondingDelegationEntry // unbonding delegation entries + DelegatorAddr sdk.AccAddress // delegator + ValidatorAddr sdk.ValAddress // validator unbonding from operator addr + Entries []UnbondingDelegationEntry // unbonding delegation entries } type UnbondingDelegationEntry struct { - CreationHeight int64 // height which the unbonding took place - CompletionTime time.Time // unix time for unbonding completion - InitialBalance sdk.Coin // atoms initially scheduled to receive at completion - Balance sdk.Coin // atoms to receive at completion + CreationHeight int64 // height which the unbonding took place + CompletionTime time.Time // unix time for unbonding completion + InitialBalance sdk.Coin // atoms initially scheduled to receive at completion + Balance sdk.Coin // atoms to receive at completion } ``` @@ -178,18 +178,18 @@ the original redelegation has been completed. ```golang type Redelegation struct { - DelegatorAddr sdk.AccAddress // delegator - ValidatorSrcAddr sdk.ValAddress // validator redelegation source operator addr - ValidatorDstAddr sdk.ValAddress // validator redelegation destination operator addr - Entries []RedelegationEntry // redelegation entries + DelegatorAddr sdk.AccAddress // delegator + ValidatorSrcAddr sdk.ValAddress // validator redelegation source operator addr + ValidatorDstAddr sdk.ValAddress // validator redelegation destination operator addr + Entries []RedelegationEntry // redelegation entries } type RedelegationEntry struct { - CreationHeight int64 // height which the redelegation took place - CompletionTime time.Time // unix time for redelegation completion - InitialBalance sdk.Coin // initial balance when redelegation started - Balance sdk.Coin // current balance - SharesSrc sdk.Dec // amount of source shares redelegating - SharesDst sdk.Dec // amount of destination shares redelegating + CreationHeight int64 // height which the redelegation took place + CompletionTime time.Time // unix time for redelegation completion + InitialBalance sdk.Coin // initial balance when redelegation started + Balance sdk.Coin // current balance (current value held in destination validator) + SharesSrc sdk.Dec // amount of source-validator shares removed by redelegation + SharesDst sdk.Dec // amount of destination-validator shares created by redelegation } ``` diff --git a/x/staking/types/delegation.go b/x/staking/types/delegation.go index 7e8d74394a1..87a4759932c 100644 --- a/x/staking/types/delegation.go +++ b/x/staking/types/delegation.go @@ -213,9 +213,9 @@ type RedelegationEntry struct { CreationHeight int64 `json:"creation_height"` // height which the redelegation took place CompletionTime time.Time `json:"completion_time"` // unix time for redelegation completion InitialBalance sdk.Coin `json:"initial_balance"` // initial balance when redelegation started - Balance sdk.Coin `json:"balance"` // current balance - SharesSrc sdk.Dec `json:"shares_src"` // amount of source shares redelegating - SharesDst sdk.Dec `json:"shares_dst"` // amount of destination shares redelegating + Balance sdk.Coin `json:"balance"` // current balance (current value held in destination validator) + SharesSrc sdk.Dec `json:"shares_src"` // amount of source-validator shares removed by redelegation + SharesDst sdk.Dec `json:"shares_dst"` // amount of destination-validator shares created by redelegation } // NewRedelegation - create a new redelegation object