diff --git a/PENDING.md b/PENDING.md index 4ca3e6df546..0b74551def9 100644 --- a/PENDING.md +++ b/PENDING.md @@ -95,3 +95,4 @@ BUG FIXES * \#1787 Fixed bug where Tally fails due to revoked/unbonding validator * \#1787 Fixed bug where Tally fails due to revoked/unbonding validator * [basecoin] Fixes coin transaction failure and account query [discussion](https://forum.cosmos.network/t/unmarshalbinarybare-expected-to-read-prefix-bytes-75fbfab8-since-it-is-registered-concrete-but-got-0a141dfa/664/6) +* [cli] \#1997 Handle panics gracefully when `gaiacli stake {delegation,unbond}` fail to unmarshal delegation. diff --git a/x/stake/client/cli/query.go b/x/stake/client/cli/query.go index 5ac303f9fe5..dc2c8e30d27 100644 --- a/x/stake/client/cli/query.go +++ b/x/stake/client/cli/query.go @@ -139,7 +139,10 @@ func GetCmdQueryDelegation(storeName string, cdc *wire.Codec) *cobra.Command { } // parse out the delegation - delegation := types.MustUnmarshalDelegation(cdc, key, res) + delegation, err := types.UnmarshalDelegation(cdc, key, res) + if err != nil { + return err + } switch viper.Get(cli.OutputFlag) { case "text": diff --git a/x/stake/client/cli/tx.go b/x/stake/client/cli/tx.go index 4c86777f343..ecc7689b59f 100644 --- a/x/stake/client/cli/tx.go +++ b/x/stake/client/cli/tx.go @@ -273,11 +273,12 @@ func getShares( if err != nil { return sharesAmount, errors.Errorf("cannot find delegation to determine percent Error: %v", err) } - - delegation := types.MustUnmarshalDelegation(cdc, key, resQuery) + delegation, err := types.UnmarshalDelegation(cdc, key, resQuery) + if err != nil { + return sdk.ZeroRat(), err + } sharesAmount = sharesPercent.Mul(delegation.Shares) } - return } diff --git a/x/stake/types/delegation.go b/x/stake/types/delegation.go index 77fd327a5e4..3f0c055c708 100644 --- a/x/stake/types/delegation.go +++ b/x/stake/types/delegation.go @@ -2,7 +2,6 @@ package types import ( "bytes" - "errors" "fmt" "time" @@ -48,12 +47,13 @@ func UnmarshalDelegation(cdc *wire.Codec, key, value []byte) (delegation Delegat var storeValue delegationValue err = cdc.UnmarshalBinary(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 = errors.New("unexpected key length") + err = fmt.Errorf("%v", ErrBadDelegationAddr(DefaultCodespace).Data()) return } delAddr := sdk.AccAddress(addrs[:sdk.AddrLen]) @@ -143,7 +143,7 @@ func UnmarshalUBD(cdc *wire.Codec, key, value []byte) (ubd UnbondingDelegation, addrs := key[1:] // remove prefix bytes if len(addrs) != 2*sdk.AddrLen { - err = errors.New("unexpected key length") + err = fmt.Errorf("%v", ErrBadDelegationAddr(DefaultCodespace).Data()) return } delAddr := sdk.AccAddress(addrs[:sdk.AddrLen]) @@ -235,7 +235,7 @@ func UnmarshalRED(cdc *wire.Codec, key, value []byte) (red Redelegation, err err addrs := key[1:] // remove prefix bytes if len(addrs) != 3*sdk.AddrLen { - err = errors.New("unexpected key length") + err = fmt.Errorf("%v", ErrBadRedelegationAddr(DefaultCodespace).Data()) return } delAddr := sdk.AccAddress(addrs[:sdk.AddrLen]) diff --git a/x/stake/types/errors.go b/x/stake/types/errors.go index b3e279c8eea..87401cbe2b5 100644 --- a/x/stake/types/errors.go +++ b/x/stake/types/errors.go @@ -17,6 +17,7 @@ const ( CodeInvalidDelegation CodeType = 102 CodeInvalidInput CodeType = 103 CodeValidatorJailed CodeType = 104 + CodeInvalidAddress CodeType = sdk.CodeInvalidAddress CodeUnauthorized CodeType = sdk.CodeUnauthorized CodeInternal CodeType = sdk.CodeInternal CodeUnknownRequest CodeType = sdk.CodeUnknownRequest @@ -27,6 +28,10 @@ func ErrNilValidatorAddr(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidInput, "validator address is nil") } +func ErrBadValidatorAddr(codespace sdk.CodespaceType) sdk.Error { + return sdk.NewError(codespace, CodeInvalidAddress, "validator address is invalid") +} + func ErrNoValidatorFound(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidValidator, "validator does not exist for that address") } @@ -68,6 +73,10 @@ func ErrBadDenom(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidDelegation, "invalid coin denomination") } +func ErrBadDelegationAddr(codespace sdk.CodespaceType) sdk.Error { + return sdk.NewError(codespace, CodeInvalidInput, "unexpected address length for this (address, validator) pair") +} + func ErrBadDelegationAmount(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidDelegation, "amount must be > 0") } @@ -125,6 +134,10 @@ func ErrExistingUnbondingDelegation(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidDelegation, "existing unbonding delegation found") } +func ErrBadRedelegationAddr(codespace sdk.CodespaceType) sdk.Error { + return sdk.NewError(codespace, CodeInvalidInput, "unexpected address length for this (address, srcValidator, dstValidator) tuple") +} + func ErrNoRedelegation(codespace sdk.CodespaceType) sdk.Error { return sdk.NewError(codespace, CodeInvalidDelegation, "no redelegation found") } diff --git a/x/stake/types/validator.go b/x/stake/types/validator.go index 837b8f8e8a0..7b637cae338 100644 --- a/x/stake/types/validator.go +++ b/x/stake/types/validator.go @@ -2,7 +2,6 @@ package types import ( "bytes" - "errors" "fmt" abci "github.com/tendermint/tendermint/abci/types" @@ -115,17 +114,16 @@ func MustUnmarshalValidator(cdc *wire.Codec, ownerAddr, value []byte) Validator // unmarshal a redelegation from a store key and value func UnmarshalValidator(cdc *wire.Codec, ownerAddr, value []byte) (validator Validator, err error) { + if len(ownerAddr) != sdk.AddrLen { + err = fmt.Errorf("%v", ErrBadValidatorAddr(DefaultCodespace).Data()) + return + } 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,