diff --git a/CHANGELOG.md b/CHANGELOG.md index 56bad46c3..b35664140 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,8 +37,9 @@ BREAKING CHANGES * Add REST endpoint to unrevoke a validator previously revoked for downtime * Add REST endpoint to retrieve liveness signing information for a validator * [types] renamed rational.Evaluate to rational.Round{Int64, Int} -* [stake] most index keys nolonger hold a value - inputs are rearranged to form the desired key +* [x/stake] most index keys nolonger hold a value - inputs are rearranged to form the desired key * [lcd] Switch key creation output to return bech32 +* [x/stake] store-value for delegation, validator, ubd, and red do not hold duplicate information contained store-key FEATURES * [gaiacli] You can now attach a simple text-only memo to any transaction, with the `--memo` flag diff --git a/types/account.go b/types/account.go index ce872d8b5..0cdc75fe2 100644 --- a/types/account.go +++ b/types/account.go @@ -13,8 +13,12 @@ import ( //Address is a go crypto-style Address type Address = cmn.HexBytes -// Bech32 prefixes +// nolint const ( + // expected address length + AddrLen = 20 + + // Bech32 prefixes Bech32PrefixAccAddr = "cosmosaccaddr" Bech32PrefixAccPub = "cosmosaccpub" Bech32PrefixValAddr = "cosmosvaladdr" diff --git a/x/slashing/handler_test.go b/x/slashing/handler_test.go index c2c5d9166..d5a6b15db 100644 --- a/x/slashing/handler_test.go +++ b/x/slashing/handler_test.go @@ -15,7 +15,8 @@ func TestCannotUnrevokeUnlessRevoked(t *testing.T) { slh := NewHandler(keeper) amtInt := int64(100) addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt) - got := stake.NewHandler(sk)(ctx, newTestMsgCreateValidator(addr, val, amt)) + msg := newTestMsgCreateValidator(addr, val, amt) + got := stake.NewHandler(sk)(ctx, msg) require.True(t, got.IsOK()) stake.EndBlocker(ctx, sk) require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}}) diff --git a/x/slashing/test_common.go b/x/slashing/test_common.go index edf119bc7..77b553317 100644 --- a/x/slashing/test_common.go +++ b/x/slashing/test_common.go @@ -23,16 +23,16 @@ import ( // TODO remove dependencies on staking (should only refer to validator set type from sdk) var ( - addrs = []sdk.Address{ - testAddr("A58856F0FD53BF058B4909A21AEC019107BA6160"), - testAddr("A58856F0FD53BF058B4909A21AEC019107BA6161"), - testAddr("A58856F0FD53BF058B4909A21AEC019107BA6162"), - } pks = []crypto.PubKey{ newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB50"), newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB51"), newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB52"), } + addrs = []sdk.Address{ + pks[0].Address(), + pks[1].Address(), + pks[2].Address(), + } initCoins sdk.Int = sdk.NewInt(200) ) diff --git a/x/stake/client/cli/query.go b/x/stake/client/cli/query.go index 5a22f2c41..39c7771f0 100644 --- a/x/stake/client/cli/query.go +++ b/x/stake/client/cli/query.go @@ -11,6 +11,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/x/stake" + "github.com/cosmos/cosmos-sdk/x/stake/types" ) // get the command to query a validator @@ -31,8 +32,8 @@ func GetCmdQueryValidator(storeName string, cdc *wire.Codec) *cobra.Command { if err != nil { return err } - validator := new(stake.Validator) - cdc.MustUnmarshalBinary(res, validator) + + validator := types.MustUnmarshalValidator(cdc, addr, res) switch viper.Get(cli.OutputFlag) { case "text": @@ -74,9 +75,9 @@ func GetCmdQueryValidators(storeName string, cdc *wire.Codec) *cobra.Command { // parse out the validators var validators []stake.Validator - for _, KV := range resKVs { - var validator stake.Validator - cdc.MustUnmarshalBinary(KV.Value, &validator) + for _, kv := range resKVs { + addr := kv.Key[1:] + validator := types.MustUnmarshalValidator(cdc, addr, kv.Value) validators = append(validators, validator) } @@ -130,7 +131,7 @@ func GetCmdQueryDelegation(storeName string, cdc *wire.Codec) *cobra.Command { } // parse out the delegation - delegation := new(stake.Delegation) + delegation := types.MustUnmarshalDelegation(cdc, key, res) switch viper.Get(cli.OutputFlag) { case "text": @@ -140,7 +141,6 @@ func GetCmdQueryDelegation(storeName string, cdc *wire.Codec) *cobra.Command { } fmt.Println(resp) case "json": - cdc.MustUnmarshalBinary(res, delegation) output, err := wire.MarshalJSONIndent(cdc, delegation) if err != nil { return err @@ -178,9 +178,8 @@ func GetCmdQueryDelegations(storeName string, cdc *wire.Codec) *cobra.Command { // parse out the validators var delegations []stake.Delegation - for _, KV := range resKVs { - var delegation stake.Delegation - cdc.MustUnmarshalBinary(KV.Value, &delegation) + for _, kv := range resKVs { + delegation := types.MustUnmarshalDelegation(cdc, kv.Key, kv.Value) delegations = append(delegations, delegation) } @@ -222,7 +221,7 @@ func GetCmdQueryUnbondingDelegation(storeName string, cdc *wire.Codec) *cobra.Co } // parse out the unbonding delegation - ubd := new(stake.UnbondingDelegation) + ubd := types.MustUnmarshalUBD(cdc, key, res) switch viper.Get(cli.OutputFlag) { case "text": @@ -232,7 +231,6 @@ func GetCmdQueryUnbondingDelegation(storeName string, cdc *wire.Codec) *cobra.Co } fmt.Println(resp) case "json": - cdc.MustUnmarshalBinary(res, ubd) output, err := wire.MarshalJSONIndent(cdc, ubd) if err != nil { return err @@ -270,9 +268,8 @@ func GetCmdQueryUnbondingDelegations(storeName string, cdc *wire.Codec) *cobra.C // parse out the validators var ubds []stake.UnbondingDelegation - for _, KV := range resKVs { - var ubd stake.UnbondingDelegation - cdc.MustUnmarshalBinary(KV.Value, &ubd) + for _, kv := range resKVs { + ubd := types.MustUnmarshalUBD(cdc, kv.Key, kv.Value) ubds = append(ubds, ubd) } @@ -317,7 +314,7 @@ func GetCmdQueryRedelegation(storeName string, cdc *wire.Codec) *cobra.Command { } // parse out the unbonding delegation - red := new(stake.Redelegation) + red := types.MustUnmarshalRED(cdc, key, res) switch viper.Get(cli.OutputFlag) { case "text": @@ -327,7 +324,6 @@ func GetCmdQueryRedelegation(storeName string, cdc *wire.Codec) *cobra.Command { } fmt.Println(resp) case "json": - cdc.MustUnmarshalBinary(res, red) output, err := wire.MarshalJSONIndent(cdc, red) if err != nil { return err @@ -365,9 +361,8 @@ func GetCmdQueryRedelegations(storeName string, cdc *wire.Codec) *cobra.Command // parse out the validators var reds []stake.Redelegation - for _, KV := range resKVs { - var red stake.Redelegation - cdc.MustUnmarshalBinary(KV.Value, &red) + for _, kv := range resKVs { + red := types.MustUnmarshalRED(cdc, kv.Key, kv.Value) reds = append(reds, red) } diff --git a/x/stake/client/rest/query.go b/x/stake/client/rest/query.go index 12ef882e5..090445f0a 100644 --- a/x/stake/client/rest/query.go +++ b/x/stake/client/rest/query.go @@ -9,7 +9,9 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" + "github.com/cosmos/cosmos-sdk/x/stake" + "github.com/cosmos/cosmos-sdk/x/stake/types" ) const storeName = "stake" @@ -75,11 +77,10 @@ func delegationHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerF return } - var delegation stake.Delegation - err = cdc.UnmarshalBinary(res, &delegation) + delegation, err := types.UnmarshalDelegation(cdc, key, res) if err != nil { - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(fmt.Sprintf("couldn't decode delegation. Error: %s", err.Error()))) + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte(err.Error())) return } @@ -132,11 +133,10 @@ func ubdHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerFunc { return } - var ubd stake.UnbondingDelegation - err = cdc.UnmarshalBinary(res, &ubd) + ubd, err := types.UnmarshalUBD(cdc, key, res) if err != nil { w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(fmt.Sprintf("couldn't decode unbonding-delegation. Error: %s", err.Error()))) + w.Write([]byte(fmt.Sprintf("couldn't query unbonding-delegation. Error: %s", err.Error()))) return } @@ -197,11 +197,10 @@ func redHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerFunc { return } - var red stake.Redelegation - err = cdc.UnmarshalBinary(res, &red) + red, err := types.UnmarshalRED(cdc, key, res) if err != nil { w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(fmt.Sprintf("couldn't decode redelegation. Error: %s", err.Error()))) + w.Write([]byte(fmt.Sprintf("couldn't query unbonding-delegation. Error: %s", err.Error()))) return } @@ -291,15 +290,19 @@ func validatorsHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerF // parse out the validators validators := make([]StakeValidatorOutput, len(kvs)) for i, kv := range kvs { - var validator stake.Validator - var bech32Validator StakeValidatorOutput - err = cdc.UnmarshalBinary(kv.Value, &validator) - if err == nil { - bech32Validator, err = bech32StakeValidatorOutput(validator) - } + + addr := kv.Key[1:] + validator, err := types.UnmarshalValidator(cdc, addr, kv.Value) if err != nil { w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(fmt.Sprintf("couldn't decode validator. Error: %s", err.Error()))) + w.Write([]byte(fmt.Sprintf("couldn't query unbonding-delegation. Error: %s", err.Error()))) + return + } + + bech32Validator, err := bech32StakeValidatorOutput(validator) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte(err.Error())) return } validators[i] = bech32Validator diff --git a/x/stake/keeper/delegation.go b/x/stake/keeper/delegation.go index bb8170a6a..353154ce2 100644 --- a/x/stake/keeper/delegation.go +++ b/x/stake/keeper/delegation.go @@ -12,12 +12,13 @@ func (k Keeper) GetDelegation(ctx sdk.Context, delegatorAddr, validatorAddr sdk.Address) (delegation types.Delegation, found bool) { store := ctx.KVStore(k.storeKey) - delegatorBytes := store.Get(GetDelegationKey(delegatorAddr, validatorAddr)) - if delegatorBytes == nil { + key := GetDelegationKey(delegatorAddr, validatorAddr) + value := store.Get(key) + if value == nil { return delegation, false } - k.cdc.MustUnmarshalBinary(delegatorBytes, &delegation) + delegation = types.MustUnmarshalDelegation(k.cdc, key, value) return delegation, true } @@ -31,9 +32,7 @@ func (k Keeper) GetAllDelegations(ctx sdk.Context) (delegations []types.Delegati if !iterator.Valid() { break } - bondBytes := iterator.Value() - var delegation types.Delegation - k.cdc.MustUnmarshalBinary(bondBytes, &delegation) + delegation := types.MustUnmarshalDelegation(k.cdc, iterator.Key(), iterator.Value()) delegations = append(delegations, delegation) iterator.Next() } @@ -55,9 +54,7 @@ func (k Keeper) GetDelegations(ctx sdk.Context, delegator sdk.Address, if !iterator.Valid() || i > int(maxRetrieve-1) { break } - bondBytes := iterator.Value() - var delegation types.Delegation - k.cdc.MustUnmarshalBinary(bondBytes, &delegation) + delegation := types.MustUnmarshalDelegation(k.cdc, iterator.Key(), iterator.Value()) delegations[i] = delegation iterator.Next() } @@ -68,7 +65,7 @@ func (k Keeper) GetDelegations(ctx sdk.Context, delegator sdk.Address, // set the delegation func (k Keeper) SetDelegation(ctx sdk.Context, delegation types.Delegation) { store := ctx.KVStore(k.storeKey) - b := k.cdc.MustMarshalBinary(delegation) + b := types.MustMarshalDelegation(k.cdc, delegation) store.Set(GetDelegationKey(delegation.DelegatorAddr, delegation.ValidatorAddr), b) } @@ -85,49 +82,48 @@ func (k Keeper) GetUnbondingDelegation(ctx sdk.Context, DelegatorAddr, ValidatorAddr sdk.Address) (ubd types.UnbondingDelegation, found bool) { store := ctx.KVStore(k.storeKey) - ubdKey := GetUBDKey(DelegatorAddr, ValidatorAddr) - bz := store.Get(ubdKey) - if bz == nil { + key := GetUBDKey(DelegatorAddr, ValidatorAddr) + value := store.Get(key) + if value == nil { return ubd, false } - k.cdc.MustUnmarshalBinary(bz, &ubd) + ubd = types.MustUnmarshalUBD(k.cdc, key, value) return ubd, true } // load all unbonding delegations from a particular validator -func (k Keeper) GetUnbondingDelegationsFromValidator(ctx sdk.Context, valAddr sdk.Address) (unbondingDelegations []types.UnbondingDelegation) { +func (k Keeper) GetUnbondingDelegationsFromValidator(ctx sdk.Context, valAddr sdk.Address) (ubds []types.UnbondingDelegation) { store := ctx.KVStore(k.storeKey) iterator := sdk.KVStorePrefixIterator(store, GetUBDsByValIndexKey(valAddr)) for { if !iterator.Valid() { break } - unbondingKey := GetUBDKeyFromValIndexKey(iterator.Key()) - unbondingBytes := store.Get(unbondingKey) - var unbondingDelegation types.UnbondingDelegation - k.cdc.MustUnmarshalBinary(unbondingBytes, &unbondingDelegation) - unbondingDelegations = append(unbondingDelegations, unbondingDelegation) + key := GetUBDKeyFromValIndexKey(iterator.Key()) + value := store.Get(key) + ubd := types.MustUnmarshalUBD(k.cdc, key, value) + ubds = append(ubds, ubd) iterator.Next() } iterator.Close() - return unbondingDelegations + return ubds } // set the unbonding delegation and associated index func (k Keeper) SetUnbondingDelegation(ctx sdk.Context, ubd types.UnbondingDelegation) { store := ctx.KVStore(k.storeKey) - bz := k.cdc.MustMarshalBinary(ubd) - ubdKey := GetUBDKey(ubd.DelegatorAddr, ubd.ValidatorAddr) - store.Set(ubdKey, bz) - store.Set(GetUBDByValIndexKey(ubd.DelegatorAddr, ubd.ValidatorAddr), []byte{}) + bz := types.MustMarshalUBD(k.cdc, ubd) + key := GetUBDKey(ubd.DelegatorAddr, ubd.ValidatorAddr) + store.Set(key, bz) + store.Set(GetUBDByValIndexKey(ubd.DelegatorAddr, ubd.ValidatorAddr), []byte{}) // index, store empty bytes } // remove the unbonding delegation object and associated index func (k Keeper) RemoveUnbondingDelegation(ctx sdk.Context, ubd types.UnbondingDelegation) { store := ctx.KVStore(k.storeKey) - ubdKey := GetUBDKey(ubd.DelegatorAddr, ubd.ValidatorAddr) - store.Delete(ubdKey) + key := GetUBDKey(ubd.DelegatorAddr, ubd.ValidatorAddr) + store.Delete(key) store.Delete(GetUBDByValIndexKey(ubd.DelegatorAddr, ubd.ValidatorAddr)) } @@ -138,33 +134,32 @@ func (k Keeper) GetRedelegation(ctx sdk.Context, DelegatorAddr, ValidatorSrcAddr, ValidatorDstAddr sdk.Address) (red types.Redelegation, found bool) { store := ctx.KVStore(k.storeKey) - redKey := GetREDKey(DelegatorAddr, ValidatorSrcAddr, ValidatorDstAddr) - bz := store.Get(redKey) - if bz == nil { + key := GetREDKey(DelegatorAddr, ValidatorSrcAddr, ValidatorDstAddr) + value := store.Get(key) + if value == nil { return red, false } - k.cdc.MustUnmarshalBinary(bz, &red) + red = types.MustUnmarshalRED(k.cdc, key, value) return red, true } // load all redelegations from a particular validator -func (k Keeper) GetRedelegationsFromValidator(ctx sdk.Context, valAddr sdk.Address) (redelegations []types.Redelegation) { +func (k Keeper) GetRedelegationsFromValidator(ctx sdk.Context, valAddr sdk.Address) (reds []types.Redelegation) { store := ctx.KVStore(k.storeKey) iterator := sdk.KVStorePrefixIterator(store, GetREDsFromValSrcIndexKey(valAddr)) for { if !iterator.Valid() { break } - redelegationKey := GetREDKeyFromValSrcIndexKey(iterator.Key()) - redelegationBytes := store.Get(redelegationKey) - var redelegation types.Redelegation - k.cdc.MustUnmarshalBinary(redelegationBytes, &redelegation) - redelegations = append(redelegations, redelegation) + key := GetREDKeyFromValSrcIndexKey(iterator.Key()) + value := store.Get(key) + red := types.MustUnmarshalRED(k.cdc, key, value) + reds = append(reds, red) iterator.Next() } iterator.Close() - return redelegations + return reds } // has a redelegation @@ -187,9 +182,9 @@ func (k Keeper) HasReceivingRedelegation(ctx sdk.Context, // set a redelegation and associated index func (k Keeper) SetRedelegation(ctx sdk.Context, red types.Redelegation) { store := ctx.KVStore(k.storeKey) - bz := k.cdc.MustMarshalBinary(red) - redKey := GetREDKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr) - store.Set(redKey, bz) + bz := types.MustMarshalRED(k.cdc, red) + key := GetREDKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr) + store.Set(key, bz) store.Set(GetREDByValSrcIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr), []byte{}) store.Set(GetREDByValDstIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr), []byte{}) } diff --git a/x/stake/keeper/key.go b/x/stake/keeper/key.go index cfe8ded82..32c54f519 100644 --- a/x/stake/keeper/key.go +++ b/x/stake/keeper/key.go @@ -131,11 +131,11 @@ func GetUBDByValIndexKey(delegatorAddr, validatorAddr sdk.Address) []byte { // rearrange the ValIndexKey to get the UBDKey func GetUBDKeyFromValIndexKey(IndexKey []byte) []byte { addrs := IndexKey[1:] // remove prefix bytes - if len(addrs) != 40 { + if len(addrs) != 2*sdk.AddrLen { panic("unexpected key length") } - valAddr := addrs[:20] - delAddr := addrs[20:] + valAddr := addrs[:sdk.AddrLen] + delAddr := addrs[sdk.AddrLen:] return GetUBDKey(delAddr, valAddr) } @@ -189,12 +189,12 @@ func GetREDByValDstIndexKey(delegatorAddr, validatorSrcAddr, // rearrange the ValSrcIndexKey to get the REDKey func GetREDKeyFromValSrcIndexKey(IndexKey []byte) []byte { addrs := IndexKey[1:] // remove prefix bytes - if len(addrs) != 60 { + if len(addrs) != 3*sdk.AddrLen { panic("unexpected key length") } - valSrcAddr := addrs[:20] - delAddr := addrs[20:40] - valDstAddr := addrs[40:] + valSrcAddr := addrs[:sdk.AddrLen] + delAddr := addrs[sdk.AddrLen : 2*sdk.AddrLen] + valDstAddr := addrs[2*sdk.AddrLen:] return GetREDKey(delAddr, valSrcAddr, valDstAddr) } @@ -202,12 +202,12 @@ func GetREDKeyFromValSrcIndexKey(IndexKey []byte) []byte { // rearrange the ValDstIndexKey to get the REDKey func GetREDKeyFromValDstIndexKey(IndexKey []byte) []byte { addrs := IndexKey[1:] // remove prefix bytes - if len(addrs) != 60 { + if len(addrs) != 3*sdk.AddrLen { panic("unexpected key length") } - valDstAddr := addrs[:20] - delAddr := addrs[20:40] - valSrcAddr := addrs[40:] + valDstAddr := addrs[:sdk.AddrLen] + delAddr := addrs[sdk.AddrLen : 2*sdk.AddrLen] + valSrcAddr := addrs[2*sdk.AddrLen:] return GetREDKey(delAddr, valSrcAddr, valDstAddr) } diff --git a/x/stake/keeper/sdk_types.go b/x/stake/keeper/sdk_types.go index bedbc1559..b8be3e34f 100644 --- a/x/stake/keeper/sdk_types.go +++ b/x/stake/keeper/sdk_types.go @@ -16,9 +16,8 @@ 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() { - bz := iterator.Value() - var validator types.Validator - k.cdc.MustUnmarshalBinary(bz, &validator) + addr := iterator.Key()[1:] + validator := types.MustUnmarshalValidator(k.cdc, addr, iterator.Value()) stop := fn(i, validator) // XXX is this safe will the validator unexposed fields be able to get written to? if stop { break @@ -91,9 +90,7 @@ func (k Keeper) IterateDelegations(ctx sdk.Context, delAddr sdk.Address, fn func iterator := sdk.KVStorePrefixIterator(store, key) i := int64(0) for ; iterator.Valid(); iterator.Next() { - bz := iterator.Value() - var delegation types.Delegation - k.cdc.MustUnmarshalBinary(bz, &delegation) + delegation := types.MustUnmarshalDelegation(k.cdc, iterator.Key(), iterator.Value()) stop := fn(i, delegation) // XXX is this safe will the fields be able to get written to? if stop { break diff --git a/x/stake/keeper/validator.go b/x/stake/keeper/validator.go index c2711788b..164c50049 100644 --- a/x/stake/keeper/validator.go +++ b/x/stake/keeper/validator.go @@ -14,11 +14,11 @@ import ( // get a single validator func (k Keeper) GetValidator(ctx sdk.Context, addr sdk.Address) (validator types.Validator, found bool) { store := ctx.KVStore(k.storeKey) - b := store.Get(GetValidatorKey(addr)) - if b == nil { + value := store.Get(GetValidatorKey(addr)) + if value == nil { return validator, false } - k.cdc.MustUnmarshalBinary(b, &validator) + validator = types.MustUnmarshalValidator(k.cdc, addr, value) return validator, true } @@ -35,15 +35,13 @@ func (k Keeper) GetValidatorByPubKey(ctx sdk.Context, pubkey crypto.PubKey) (val // set the main record holding validator details func (k Keeper) SetValidator(ctx sdk.Context, validator types.Validator) { store := ctx.KVStore(k.storeKey) - // set main store - bz := k.cdc.MustMarshalBinary(validator) + bz := types.MustMarshalValidator(k.cdc, validator) store.Set(GetValidatorKey(validator.Owner), bz) } // validator index func (k Keeper) SetValidatorByPubKeyIndex(ctx sdk.Context, validator types.Validator) { store := ctx.KVStore(k.storeKey) - // set pointer by pubkey store.Set(GetValidatorByPubKeyIndexKey(validator.PubKey), validator.Owner) } @@ -75,9 +73,8 @@ func (k Keeper) GetAllValidators(ctx sdk.Context) (validators []types.Validator) if !iterator.Valid() { break } - bz := iterator.Value() - var validator types.Validator - k.cdc.MustUnmarshalBinary(bz, &validator) + addr := iterator.Key()[1:] + validator := types.MustUnmarshalValidator(k.cdc, addr, iterator.Value()) validators = append(validators, validator) iterator.Next() } @@ -96,9 +93,8 @@ func (k Keeper) GetValidators(ctx sdk.Context, maxRetrieve int16) (validators [] if !iterator.Valid() || i > int(maxRetrieve-1) { break } - bz := iterator.Value() - var validator types.Validator - k.cdc.MustUnmarshalBinary(bz, &validator) + addr := iterator.Key()[1:] + validator := types.MustUnmarshalValidator(k.cdc, addr, iterator.Value()) validators[i] = validator iterator.Next() } @@ -205,8 +201,7 @@ func (k Keeper) UpdateValidator(ctx sdk.Context, validator types.Validator) type // always update the main list ordered by owner address before exiting defer func() { - bz := k.cdc.MustMarshalBinary(validator) - store.Set(GetValidatorKey(ownerAddr), bz) + k.SetValidator(ctx, validator) }() // retrieve the old validator record @@ -441,8 +436,7 @@ func (k Keeper) unbondValidator(ctx sdk.Context, validator types.Validator) type k.SetPool(ctx, pool) // save the now unbonded validator record - bzVal := k.cdc.MustMarshalBinary(validator) - store.Set(GetValidatorKey(validator.Owner), bzVal) + k.SetValidator(ctx, validator) // add to accumulated changes for tendermint bzABCI := k.cdc.MustMarshalBinary(validator.ABCIValidatorZero()) @@ -469,8 +463,7 @@ func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) types. k.SetPool(ctx, pool) // save the now bonded validator record to the three referenced stores - bzVal := k.cdc.MustMarshalBinary(validator) - store.Set(GetValidatorKey(validator.Owner), bzVal) + k.SetValidator(ctx, validator) store.Set(GetValidatorsBondedIndexKey(validator.Owner), []byte{}) // add to accumulated changes for tendermint diff --git a/x/stake/types/delegation.go b/x/stake/types/delegation.go index a7d0a1f8c..f7d31a640 100644 --- a/x/stake/types/delegation.go +++ b/x/stake/types/delegation.go @@ -2,9 +2,11 @@ package types import ( "bytes" + "errors" "fmt" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/wire" ) // Delegation represents the bond with tokens held by an account. It is @@ -17,7 +19,54 @@ type Delegation struct { Height int64 `json:"height"` // Last height bond updated } -// Equal returns a boolean determining if two Delegation types are identical. +type delegationValue struct { + Shares sdk.Rat + Height int64 +} + +// return the delegation without fields contained within the key for the store +func MustMarshalDelegation(cdc *wire.Codec, delegation Delegation) []byte { + val := delegationValue{ + delegation.Shares, + delegation.Height, + } + return cdc.MustMarshalBinary(val) +} + +// return the delegation without fields contained within the key for the store +func MustUnmarshalDelegation(cdc *wire.Codec, key, value []byte) Delegation { + delegation, err := UnmarshalDelegation(cdc, key, value) + if err != nil { + panic(err) + } + return delegation +} + +// return the delegation without fields contained within the key for the store +func UnmarshalDelegation(cdc *wire.Codec, key, value []byte) (delegation Delegation, err error) { + var storeValue delegationValue + err = cdc.UnmarshalBinary(value, &storeValue) + if err != nil { + return + } + + addrs := key[1:] // remove prefix bytes + if len(addrs) != 2*sdk.AddrLen { + err = errors.New("unexpected key length") + return + } + delAddr := sdk.Address(addrs[:sdk.AddrLen]) + valAddr := sdk.Address(addrs[sdk.AddrLen:]) + + return Delegation{ + DelegatorAddr: delAddr, + ValidatorAddr: valAddr, + Shares: storeValue.Shares, + Height: storeValue.Height, + }, nil +} + +// nolint func (d Delegation) Equal(d2 Delegation) bool { return bytes.Equal(d.DelegatorAddr, d2.DelegatorAddr) && bytes.Equal(d.ValidatorAddr, d2.ValidatorAddr) && @@ -66,8 +115,60 @@ type UnbondingDelegation struct { Balance sdk.Coin `json:"balance"` // atoms to receive at completion } -// Equal returns a boolean determining if two UnbondingDelegation types are -// identical. +type ubdValue struct { + CreationHeight int64 + MinTime int64 + InitialBalance sdk.Coin + Balance sdk.Coin +} + +// return the unbonding delegation without fields contained within the key for the store +func MustMarshalUBD(cdc *wire.Codec, ubd UnbondingDelegation) []byte { + val := ubdValue{ + ubd.CreationHeight, + ubd.MinTime, + ubd.InitialBalance, + ubd.Balance, + } + return cdc.MustMarshalBinary(val) +} + +// unmarshal a unbonding delegation from a store key and value +func MustUnmarshalUBD(cdc *wire.Codec, key, value []byte) UnbondingDelegation { + ubd, err := UnmarshalUBD(cdc, key, value) + if err != nil { + panic(err) + } + return ubd +} + +// unmarshal a unbonding delegation from a store key and value +func UnmarshalUBD(cdc *wire.Codec, key, value []byte) (ubd UnbondingDelegation, err error) { + var storeValue ubdValue + err = cdc.UnmarshalBinary(value, &storeValue) + if err != nil { + return + } + + addrs := key[1:] // remove prefix bytes + if len(addrs) != 2*sdk.AddrLen { + err = errors.New("unexpected key length") + return + } + delAddr := sdk.Address(addrs[:sdk.AddrLen]) + valAddr := sdk.Address(addrs[sdk.AddrLen:]) + + return UnbondingDelegation{ + DelegatorAddr: delAddr, + ValidatorAddr: valAddr, + CreationHeight: storeValue.CreationHeight, + MinTime: storeValue.MinTime, + InitialBalance: storeValue.InitialBalance, + Balance: storeValue.Balance, + }, nil +} + +// nolint func (d UnbondingDelegation) Equal(d2 UnbondingDelegation) bool { bz1 := MsgCdc.MustMarshalBinary(&d) bz2 := MsgCdc.MustMarshalBinary(&d2) @@ -112,7 +213,68 @@ type Redelegation struct { SharesDst sdk.Rat `json:"shares_dst"` // amount of destination shares redelegating } -// Equal returns a boolean determining if two Redelegation types are identical. +type redValue struct { + CreationHeight int64 + MinTime int64 + InitialBalance sdk.Coin + Balance sdk.Coin + SharesSrc sdk.Rat + SharesDst sdk.Rat +} + +// return the redelegation without fields contained within the key for the store +func MustMarshalRED(cdc *wire.Codec, red Redelegation) []byte { + val := redValue{ + red.CreationHeight, + red.MinTime, + red.InitialBalance, + red.Balance, + red.SharesSrc, + red.SharesDst, + } + return cdc.MustMarshalBinary(val) +} + +// unmarshal a redelegation from a store key and value +func MustUnmarshalRED(cdc *wire.Codec, key, value []byte) Redelegation { + red, err := UnmarshalRED(cdc, key, value) + if err != nil { + panic(err) + } + return red +} + +// unmarshal a redelegation from a store key and value +func UnmarshalRED(cdc *wire.Codec, key, value []byte) (red Redelegation, err error) { + var storeValue redValue + err = cdc.UnmarshalBinary(value, &storeValue) + if err != nil { + return + } + + addrs := key[1:] // remove prefix bytes + if len(addrs) != 3*sdk.AddrLen { + err = errors.New("unexpected key length") + return + } + delAddr := sdk.Address(addrs[:sdk.AddrLen]) + valSrcAddr := sdk.Address(addrs[sdk.AddrLen : 2*sdk.AddrLen]) + valDstAddr := sdk.Address(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 +} + +// nolint func (d Redelegation) Equal(d2 Redelegation) bool { bz1 := MsgCdc.MustMarshalBinary(&d) bz2 := MsgCdc.MustMarshalBinary(&d2) diff --git a/x/stake/types/validator.go b/x/stake/types/validator.go index c55ae725a..480416d01 100644 --- a/x/stake/types/validator.go +++ b/x/stake/types/validator.go @@ -2,12 +2,15 @@ package types import ( "bytes" + "errors" "fmt" - sdk "github.com/cosmos/cosmos-sdk/types" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto" tmtypes "github.com/tendermint/tendermint/types" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/wire" ) const doNotModifyDescVal = "[do-not-modify]" @@ -61,7 +64,85 @@ func NewValidator(owner sdk.Address, pubKey crypto.PubKey, description Descripti } } -// Equal returns a boolean reflecting if two given validators are identical. +// what's kept in the store value +type validatorValue struct { + PubKey crypto.PubKey + Revoked bool + PoolShares PoolShares + DelegatorShares sdk.Rat + Description Description + BondHeight int64 + BondIntraTxCounter int16 + ProposerRewardPool sdk.Coins + Commission sdk.Rat + CommissionMax sdk.Rat + CommissionChangeRate sdk.Rat + CommissionChangeToday sdk.Rat + PrevBondedShares sdk.Rat +} + +// return the redelegation without fields contained within the key for the store +func MustMarshalValidator(cdc *wire.Codec, validator Validator) []byte { + val := validatorValue{ + PubKey: validator.PubKey, + Revoked: validator.Revoked, + PoolShares: validator.PoolShares, + DelegatorShares: validator.DelegatorShares, + Description: validator.Description, + BondHeight: validator.BondHeight, + BondIntraTxCounter: validator.BondIntraTxCounter, + ProposerRewardPool: validator.ProposerRewardPool, + Commission: validator.Commission, + CommissionMax: validator.CommissionMax, + CommissionChangeRate: validator.CommissionChangeRate, + CommissionChangeToday: validator.CommissionChangeToday, + PrevBondedShares: validator.PrevBondedShares, + } + return cdc.MustMarshalBinary(val) +} + +// unmarshal a redelegation from a store key and value +func MustUnmarshalValidator(cdc *wire.Codec, ownerAddr, value []byte) Validator { + validator, err := UnmarshalValidator(cdc, ownerAddr, value) + if err != nil { + panic(err) + } + + return validator +} + +// unmarshal a redelegation from a store key and value +func UnmarshalValidator(cdc *wire.Codec, ownerAddr, value []byte) (validator Validator, err error) { + var storeValue validatorValue + err = cdc.UnmarshalBinary(value, &storeValue) + if err != nil { + return + } + + if len(ownerAddr) != 20 { + err = errors.New("unexpected address length") + return + } + + return Validator{ + Owner: ownerAddr, + PubKey: storeValue.PubKey, + Revoked: storeValue.Revoked, + PoolShares: storeValue.PoolShares, + DelegatorShares: storeValue.DelegatorShares, + Description: storeValue.Description, + BondHeight: storeValue.BondHeight, + BondIntraTxCounter: storeValue.BondIntraTxCounter, + ProposerRewardPool: storeValue.ProposerRewardPool, + Commission: storeValue.Commission, + CommissionMax: storeValue.CommissionMax, + CommissionChangeRate: storeValue.CommissionChangeRate, + CommissionChangeToday: storeValue.CommissionChangeToday, + PrevBondedShares: storeValue.PrevBondedShares, + }, nil +} + +// only the vitals - does not check bond height of IntraTxCounter func (v Validator) Equal(c2 Validator) bool { return v.PubKey.Equals(c2.PubKey) && bytes.Equal(v.Owner, c2.Owner) &&