diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index 7fc98aef6f..977c03cf72 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -478,12 +478,12 @@ func TestValidatorsQuery(t *testing.T) { // make sure all the validators were found (order unknown because sorted by operator addr) foundVal := false - pkBech := sdk.MustBech32ifyConsPub(pks[0]) - if validators[0].ConsPubKey == pkBech { + + if validators[0].ConsPubKey == pks[0] { foundVal = true } - require.True(t, foundVal, "pkBech %v, operator %v", pkBech, validators[0].OperatorAddr) + require.True(t, foundVal, "pk %v, operator %v", pks[0], validators[0].OperatorAddr) } func TestValidatorQuery(t *testing.T) { @@ -950,11 +950,11 @@ func getBondingTxs(t *testing.T, port string, delegatorAddr sdk.AccAddress, quer return txs } -func getDelegatorValidators(t *testing.T, port string, delegatorAddr sdk.AccAddress) []stake.BechValidator { +func getDelegatorValidators(t *testing.T, port string, delegatorAddr sdk.AccAddress) []stake.Validator { res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/validators", delegatorAddr), nil) require.Equal(t, http.StatusOK, res.StatusCode, body) - var bondedValidators []stake.BechValidator + var bondedValidators []stake.Validator err := cdc.UnmarshalJSON([]byte(body), &bondedValidators) require.Nil(t, err) @@ -962,11 +962,11 @@ func getDelegatorValidators(t *testing.T, port string, delegatorAddr sdk.AccAddr return bondedValidators } -func getDelegatorValidator(t *testing.T, port string, delAddr sdk.AccAddress, valAddr sdk.ValAddress) stake.BechValidator { +func getDelegatorValidator(t *testing.T, port string, delAddr sdk.AccAddress, valAddr sdk.ValAddress) stake.Validator { res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/validators/%s", delAddr, valAddr), nil) require.Equal(t, http.StatusOK, res.StatusCode, body) - var bondedValidator stake.BechValidator + var bondedValidator stake.Validator err := cdc.UnmarshalJSON([]byte(body), &bondedValidator) require.Nil(t, err) @@ -1086,19 +1086,19 @@ func doBeginRedelegation(t *testing.T, port, seed, name, password string, return results[0] } -func getValidators(t *testing.T, port string) []stake.BechValidator { +func getValidators(t *testing.T, port string) []stake.Validator { res, body := Request(t, port, "GET", "/stake/validators", nil) require.Equal(t, http.StatusOK, res.StatusCode, body) - var validators []stake.BechValidator + var validators []stake.Validator err := cdc.UnmarshalJSON([]byte(body), &validators) require.Nil(t, err) return validators } -func getValidator(t *testing.T, port string, valAddr sdk.ValAddress) stake.BechValidator { +func getValidator(t *testing.T, port string, valAddr sdk.ValAddress) stake.Validator { res, body := Request(t, port, "GET", fmt.Sprintf("/stake/validators/%s", valAddr.String()), nil) require.Equal(t, http.StatusOK, res.StatusCode, body) - var validator stake.BechValidator + var validator stake.Validator err := cdc.UnmarshalJSON([]byte(body), &validator) require.Nil(t, err) return validator diff --git a/x/stake/client/rest/query.go b/x/stake/client/rest/query.go index 5d280daf3d..7a0602ee2d 100644 --- a/x/stake/client/rest/query.go +++ b/x/stake/client/rest/query.go @@ -376,7 +376,7 @@ func delegatorValidatorsHandlerFn(cliCtx context.CLIContext, cdc *wire.Codec) ht return func(w http.ResponseWriter, r *http.Request) { var valAddr sdk.ValAddress - var bondedValidators []types.BechValidator + var bondedValidators []types.Validator // read parameters vars := mux.Vars(r) @@ -544,14 +544,7 @@ func validatorHandlerFn(cliCtx context.CLIContext, cdc *wire.Codec) http.Handler return } - bech32Validator, err := validator.Bech32Validator() - if err != nil { - w.WriteHeader(http.StatusBadRequest) - w.Write([]byte(err.Error())) - return - } - - output, err = cdc.MarshalJSON(bech32Validator) + output, err = cdc.MarshalJSON(validator) if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(fmt.Sprintf("Error: %s", err.Error()))) diff --git a/x/stake/client/rest/utils.go b/x/stake/client/rest/utils.go index d8ad5fec55..13f3abb74c 100644 --- a/x/stake/client/rest/utils.go +++ b/x/stake/client/rest/utils.go @@ -25,35 +25,31 @@ func contains(stringSlice []string, txType string) bool { } func getDelegatorValidator(cliCtx context.CLIContext, cdc *wire.Codec, delAddr sdk.AccAddress, valAddr sdk.ValAddress) ( - bech32Validator types.BechValidator, httpStatusCode int, errMsg string, err error) { + validator types.Validator, httpStatusCode int, errMsg string, err error) { key := stake.GetDelegationKey(delAddr, valAddr) res, err := cliCtx.QueryStore(key, storeName) if err != nil { - return types.BechValidator{}, http.StatusInternalServerError, "couldn't query delegation. Error: ", err + return types.Validator{}, http.StatusInternalServerError, "couldn't query delegation. Error: ", err } if len(res) == 0 { - return types.BechValidator{}, http.StatusNoContent, "", nil + return types.Validator{}, http.StatusNoContent, "", nil } key = stake.GetValidatorKey(valAddr) res, err = cliCtx.QueryStore(key, storeName) if err != nil { - return types.BechValidator{}, http.StatusInternalServerError, "couldn't query validator. Error: ", err + return types.Validator{}, http.StatusInternalServerError, "couldn't query validator. Error: ", err } if len(res) == 0 { - return types.BechValidator{}, http.StatusNoContent, "", nil + return types.Validator{}, http.StatusNoContent, "", nil } - validator, err := types.UnmarshalValidator(cdc, valAddr, res) + validator, err = types.UnmarshalValidator(cdc, valAddr, res) if err != nil { - return types.BechValidator{}, http.StatusBadRequest, "", err - } - bech32Validator, err = validator.Bech32Validator() - if err != nil { - return types.BechValidator{}, http.StatusBadRequest, "", err + return types.Validator{}, http.StatusBadRequest, "", err } - return bech32Validator, http.StatusOK, "", nil + return validator, http.StatusOK, "", nil } func getDelegatorDelegations( @@ -143,8 +139,8 @@ func queryTxs(node rpcclient.Client, cdc *wire.Codec, tag string, delegatorAddr } // gets all validators -func getValidators(validatorKVs []sdk.KVPair, cdc *wire.Codec) ([]types.BechValidator, error) { - validators := make([]types.BechValidator, len(validatorKVs)) +func getValidators(validatorKVs []sdk.KVPair, cdc *wire.Codec) ([]types.Validator, error) { + validators := make([]types.Validator, len(validatorKVs)) for i, kv := range validatorKVs { addr := kv.Key[1:] @@ -153,11 +149,7 @@ func getValidators(validatorKVs []sdk.KVPair, cdc *wire.Codec) ([]types.BechVali return nil, err } - bech32Validator, err := validator.Bech32Validator() - if err != nil { - return nil, err - } - validators[i] = bech32Validator + validators[i] = validator } return validators, nil } @@ -165,7 +157,7 @@ func getValidators(validatorKVs []sdk.KVPair, cdc *wire.Codec) ([]types.BechVali // gets all Bech32 validators from a key // nolint: unparam func getBech32Validators(storeName string, cliCtx context.CLIContext, cdc *wire.Codec) ( - validators []types.BechValidator, httpStatusCode int, errMsg string, err error) { + validators []types.Validator, httpStatusCode int, errMsg string, err error) { // Get all validators using key kvs, err := cliCtx.QuerySubspace(stake.ValidatorsKey, storeName) diff --git a/x/stake/stake.go b/x/stake/stake.go index 2782957ceb..d60e402995 100644 --- a/x/stake/stake.go +++ b/x/stake/stake.go @@ -10,7 +10,6 @@ import ( type ( Keeper = keeper.Keeper Validator = types.Validator - BechValidator = types.BechValidator Description = types.Description Delegation = types.Delegation UnbondingDelegation = types.UnbondingDelegation diff --git a/x/stake/types/validator.go b/x/stake/types/validator.go index c0efdb357c..31af4daaa3 100644 --- a/x/stake/types/validator.go +++ b/x/stake/types/validator.go @@ -21,8 +21,8 @@ import ( // exchange rate. Voting power can be calculated as total bonds multiplied by // exchange rate. type Validator struct { - OperatorAddr sdk.ValAddress `json:"operator_address"` // address of the validator's operator - ConsPubKey crypto.PubKey `json:"consensus_pubkey"` // the consensus public key of the validator + OperatorAddr sdk.ValAddress `json:"operator_address"` // address of the validator's operator; bech encoded in JSON + ConsPubKey crypto.PubKey `json:"consensus_pubkey"` // the consensus public key of the validator; bech encoded in JSON Jailed bool `json:"jailed"` // has the validator been jailed from bonded status? Status sdk.BondStatus `json:"status"` // validator status (bonded/unbonding/unbonded) @@ -55,7 +55,7 @@ func NewValidator(operator sdk.ValAddress, pubKey crypto.PubKey, description Des BondHeight: int64(0), BondIntraTxCounter: int16(0), UnbondingHeight: int64(0), - UnbondingMinTime: time.Unix(0, 0), + UnbondingMinTime: time.Unix(0, 0).UTC(), Commission: sdk.ZeroDec(), CommissionMax: sdk.ZeroDec(), CommissionChangeRate: sdk.ZeroDec(), @@ -172,8 +172,8 @@ func (v Validator) HumanReadableString() (string, error) { //___________________________________________________________________ -// validator struct for bech output -type BechValidator struct { +// this is a helper struct used for JSON de- and encoding only +type bechValidator struct { OperatorAddr sdk.ValAddress `json:"operator_address"` // the bech32 address of the validator's operator ConsPubKey string `json:"consensus_pubkey"` // the bech32 consensus public key of the validator Jailed bool `json:"jailed"` // has the validator been jailed from bonded status? @@ -195,33 +195,60 @@ type BechValidator struct { CommissionChangeToday sdk.Dec `json:"commission_change_today"` // XXX commission rate change today, reset each day (UTC time) } -// get the bech validator from the the regular validator -func (v Validator) Bech32Validator() (BechValidator, error) { +// MarshalJSON marshals the validator to JSON using Bech32 +func (v Validator) MarshalJSON() ([]byte, error) { bechConsPubKey, err := sdk.Bech32ifyConsPub(v.ConsPubKey) if err != nil { - return BechValidator{}, err + return nil, err } - return BechValidator{ - OperatorAddr: v.OperatorAddr, - ConsPubKey: bechConsPubKey, - Jailed: v.Jailed, - - Status: v.Status, - Tokens: v.Tokens, - DelegatorShares: v.DelegatorShares, - - Description: v.Description, - BondHeight: v.BondHeight, - BondIntraTxCounter: v.BondIntraTxCounter, - UnbondingHeight: v.UnbondingHeight, - UnbondingMinTime: v.UnbondingMinTime, - + return wire.Cdc.MarshalJSON(bechValidator{ + OperatorAddr: v.OperatorAddr, + ConsPubKey: bechConsPubKey, + Jailed: v.Jailed, + Status: v.Status, + Tokens: v.Tokens, + DelegatorShares: v.DelegatorShares, + Description: v.Description, + BondHeight: v.BondHeight, + BondIntraTxCounter: v.BondIntraTxCounter, + UnbondingHeight: v.UnbondingHeight, + UnbondingMinTime: v.UnbondingMinTime, Commission: v.Commission, CommissionMax: v.CommissionMax, CommissionChangeRate: v.CommissionChangeRate, CommissionChangeToday: v.CommissionChangeToday, - }, nil + }) +} + +// UnmarshalJSON unmarshals the validator from JSON using Bech32 +func (v *Validator) UnmarshalJSON(data []byte) error { + bv := &bechValidator{} + if err := wire.Cdc.UnmarshalJSON(data, bv); err != nil { + return err + } + consPubKey, err := sdk.GetConsPubKeyBech32(bv.ConsPubKey) + if err != nil { + return err + } + *v = Validator{ + OperatorAddr: bv.OperatorAddr, + ConsPubKey: consPubKey, + Jailed: bv.Jailed, + Tokens: bv.Tokens, + Status: bv.Status, + DelegatorShares: bv.DelegatorShares, + Description: bv.Description, + BondHeight: bv.BondHeight, + BondIntraTxCounter: bv.BondIntraTxCounter, + UnbondingHeight: bv.UnbondingHeight, + UnbondingMinTime: bv.UnbondingMinTime, + Commission: bv.Commission, + CommissionMax: bv.CommissionMax, + CommissionChangeRate: bv.CommissionChangeRate, + CommissionChangeToday: bv.CommissionChangeToday, + } + return nil } //___________________________________________________________________ diff --git a/x/stake/types/validator_test.go b/x/stake/types/validator_test.go index 60c5f9d74f..70ab5f105e 100644 --- a/x/stake/types/validator_test.go +++ b/x/stake/types/validator_test.go @@ -6,6 +6,8 @@ import ( "time" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/wire" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" tmtypes "github.com/tendermint/tendermint/types" @@ -260,3 +262,15 @@ func TestHumanReadableString(t *testing.T) { require.Nil(t, err) require.NotEmpty(t, valStr) } + +func TestValidatorMarshalUnmarshalJSON(t *testing.T) { + validator := NewValidator(addr1, pk1, Description{}) + js, err := wire.Cdc.MarshalJSON(validator) + require.NoError(t, err) + require.NotEmpty(t, js) + require.Contains(t, string(js), "\"consensus_pubkey\":\"cosmosvalconspu") + got := &Validator{} + err = wire.Cdc.UnmarshalJSON(js, got) + assert.NoError(t, err) + assert.Equal(t, validator, *got) +}