diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d6541691..e34a1468b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Changelog BREAKING CHANGES +* msg.GetSignBytes() now returns bech32-encoded addresses in all cases FEATURES diff --git a/types/account.go b/types/account.go index 00d180a1c..381fb7af8 100644 --- a/types/account.go +++ b/types/account.go @@ -26,21 +26,57 @@ func Bech32ifyAcc(addr Address) (string, error) { return bech32.ConvertAndEncode(Bech32PrefixAccAddr, addr.Bytes()) } +// MustBech32ifyAcc panics on bech32-encoding failure +func MustBech32ifyAcc(addr Address) string { + enc, err := Bech32ifyAcc(addr) + if err != nil { + panic(err) + } + return enc +} + // Bech32ifyAccPub takes AccountPubKey and returns the bech32 encoded string func Bech32ifyAccPub(pub crypto.PubKey) (string, error) { return bech32.ConvertAndEncode(Bech32PrefixAccPub, pub.Bytes()) } +// MustBech32ifyAccPub panics on bech32-encoding failure +func MustBech32ifyAccPub(pub crypto.PubKey) string { + enc, err := Bech32ifyAccPub(pub) + if err != nil { + panic(err) + } + return enc +} + // Bech32ifyVal returns the bech32 encoded string for a validator address func Bech32ifyVal(addr Address) (string, error) { return bech32.ConvertAndEncode(Bech32PrefixValAddr, addr.Bytes()) } +// MustBech32ifyVal panics on bech32-encoding failure +func MustBech32ifyVal(addr Address) string { + enc, err := Bech32ifyVal(addr) + if err != nil { + panic(err) + } + return enc +} + // Bech32ifyValPub returns the bech32 encoded string for a validator pubkey func Bech32ifyValPub(pub crypto.PubKey) (string, error) { return bech32.ConvertAndEncode(Bech32PrefixValPub, pub.Bytes()) } +// MustBech32ifyValPub pancis on bech32-encoding failure +func MustBech32ifyValPub(pub crypto.PubKey) string { + enc, err := Bech32ifyValPub(pub) + if err != nil { + panic(err) + } + return enc +} + // create an Address from a string func GetAccAddressHex(address string) (addr Address, err error) { if len(address) == 0 { @@ -98,7 +134,7 @@ func GetValAddressBech32(address string) (addr Address, err error) { return Address(bz), nil } -//Decode a validator publickey into a public key +// decode a validator public key into a PubKey func GetValPubKeyBech32(pubkey string) (pk crypto.PubKey, err error) { bz, err := getFromBech32(pubkey, Bech32PrefixValPub) if err != nil { diff --git a/x/auth/stdtx.go b/x/auth/stdtx.go index 4858ae0b4..e08f77ee4 100644 --- a/x/auth/stdtx.go +++ b/x/auth/stdtx.go @@ -1,6 +1,8 @@ package auth import ( + "encoding/json" + sdk "github.com/cosmos/cosmos-sdk/types" crypto "github.com/tendermint/go-crypto" ) @@ -83,11 +85,11 @@ func (fee StdFee) Bytes() []byte { // and the Sequence numbers for each signature (prevent // inchain replay and enforce tx ordering per account). type StdSignDoc struct { - ChainID string `json:"chain_id"` - Sequences []int64 `json:"sequences"` - FeeBytes []byte `json:"fee_bytes"` - MsgBytes []byte `json:"msg_bytes"` - AltBytes []byte `json:"alt_bytes"` + ChainID string `json:"chain_id"` + Sequences []int64 `json:"sequences"` + FeeBytes json.RawMessage `json:"fee_bytes"` + MsgBytes json.RawMessage `json:"msg_bytes"` + AltBytes json.RawMessage `json:"alt_bytes"` } // StdSignBytes returns the bytes to sign for a transaction. @@ -96,8 +98,8 @@ func StdSignBytes(chainID string, sequences []int64, fee StdFee, msg sdk.Msg) [] bz, err := msgCdc.MarshalJSON(StdSignDoc{ ChainID: chainID, Sequences: sequences, - FeeBytes: fee.Bytes(), - MsgBytes: msg.GetSignBytes(), + FeeBytes: json.RawMessage(fee.Bytes()), + MsgBytes: json.RawMessage(msg.GetSignBytes()), }) if err != nil { panic(err) diff --git a/x/bank/msgs.go b/x/bank/msgs.go index 7836056de..48e62d835 100644 --- a/x/bank/msgs.go +++ b/x/bank/msgs.go @@ -1,6 +1,8 @@ package bank import ( + "encoding/json" + sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -53,7 +55,20 @@ func (msg MsgSend) ValidateBasic() sdk.Error { // Implements Msg. func (msg MsgSend) GetSignBytes() []byte { - b, err := msgCdc.MarshalJSON(msg) // XXX: ensure some canonical form + var inputs, outputs []json.RawMessage + for _, input := range msg.Inputs { + inputs = append(inputs, input.GetSignBytes()) + } + for _, output := range msg.Outputs { + outputs = append(outputs, output.GetSignBytes()) + } + b, err := msgCdc.MarshalJSON(struct { + Inputs []json.RawMessage `json:"inputs"` + Outputs []json.RawMessage `json:"outputs"` + }{ + Inputs: inputs, + Outputs: outputs, + }) if err != nil { panic(err) } @@ -78,6 +93,8 @@ type MsgIssue struct { Outputs []Output `json:"outputs"` } +var _ sdk.Msg = MsgIssue{} + // NewMsgIssue - construct arbitrary multi-in, multi-out send msg. func NewMsgIssue(banker sdk.Address, out []Output) MsgIssue { return MsgIssue{Banker: banker, Outputs: out} @@ -102,7 +119,17 @@ func (msg MsgIssue) ValidateBasic() sdk.Error { // Implements Msg. func (msg MsgIssue) GetSignBytes() []byte { - b, err := msgCdc.MarshalJSON(msg) // XXX: ensure some canonical form + var outputs []json.RawMessage + for _, output := range msg.Outputs { + outputs = append(outputs, output.GetSignBytes()) + } + b, err := msgCdc.MarshalJSON(struct { + Banker string `json:"banker"` + Outputs []json.RawMessage `json:"outputs"` + }{ + Banker: sdk.MustBech32ifyAcc(msg.Banker), + Outputs: outputs, + }) if err != nil { panic(err) } @@ -123,6 +150,21 @@ type Input struct { Coins sdk.Coins `json:"coins"` } +// Return bytes to sign for Input +func (in Input) GetSignBytes() []byte { + bin, err := msgCdc.MarshalJSON(struct { + Address string `json:"address"` + Coins sdk.Coins `json:"coins"` + }{ + Address: sdk.MustBech32ifyAcc(in.Address), + Coins: in.Coins, + }) + if err != nil { + panic(err) + } + return bin +} + // ValidateBasic - validate transaction input func (in Input) ValidateBasic() sdk.Error { if len(in.Address) == 0 { @@ -155,6 +197,21 @@ type Output struct { Coins sdk.Coins `json:"coins"` } +// Return bytes to sign for Output +func (out Output) GetSignBytes() []byte { + bin, err := msgCdc.MarshalJSON(struct { + Address string `json:"address"` + Coins sdk.Coins `json:"coins"` + }{ + Address: sdk.MustBech32ifyAcc(out.Address), + Coins: out.Coins, + }) + if err != nil { + panic(err) + } + return bin +} + // ValidateBasic - validate transaction output func (out Output) ValidateBasic() sdk.Error { if len(out.Address) == 0 { diff --git a/x/bank/msgs_test.go b/x/bank/msgs_test.go index 8f9791c8d..90b4869db 100644 --- a/x/bank/msgs_test.go +++ b/x/bank/msgs_test.go @@ -187,12 +187,7 @@ func TestMsgSendGetSignBytes(t *testing.T) { } res := msg.GetSignBytes() - unmarshaledMsg := &MsgSend{} - msgCdc.UnmarshalJSON(res, unmarshaledMsg) - assert.Equal(t, &msg, unmarshaledMsg) - - // TODO bad results - expected := `{"type":"EAFDE32A2C87F8","value":{"inputs":[{"address":"696E707574","coins":[{"denom":"atom","amount":10}]}],"outputs":[{"address":"6F7574707574","coins":[{"denom":"atom","amount":10}]}]}}` + expected := `{"inputs":[{"address":"cosmosaccaddr1d9h8qat5e4ehc5","coins":[{"denom":"atom","amount":10}]}],"outputs":[{"address":"cosmosaccaddr1da6hgur4wse3jx32","coins":[{"denom":"atom","amount":10}]}]}` assert.Equal(t, expected, string(res)) } @@ -262,12 +257,7 @@ func TestMsgIssueGetSignBytes(t *testing.T) { } res := msg.GetSignBytes() - unmarshaledMsg := &MsgIssue{} - msgCdc.UnmarshalJSON(res, unmarshaledMsg) - assert.Equal(t, &msg, unmarshaledMsg) - - // TODO bad results - expected := `{"type":"72E617C06ABAD0","value":{"banker":"696E707574","outputs":[{"address":"6C6F616E2D66726F6D2D62616E6B","coins":[{"denom":"atom","amount":10}]}]}}` + expected := `{"banker":"cosmosaccaddr1d9h8qat5e4ehc5","outputs":[{"address":"cosmosaccaddr1d3hkzm3dveex7mfdvfsku6cwsauqd","coins":[{"denom":"atom","amount":10}]}]}` assert.Equal(t, expected, string(res)) } diff --git a/x/ibc/types.go b/x/ibc/types.go index 09a853b20..4924aec4b 100644 --- a/x/ibc/types.go +++ b/x/ibc/types.go @@ -1,11 +1,20 @@ package ibc import ( - sdk "github.com/cosmos/cosmos-sdk/types" + "encoding/json" + sdk "github.com/cosmos/cosmos-sdk/types" wire "github.com/cosmos/cosmos-sdk/wire" ) +var ( + msgCdc *wire.Codec +) + +func init() { + msgCdc = wire.NewCodec() +} + // ------------------------------ // IBCPacket @@ -32,12 +41,33 @@ func NewIBCPacket(srcAddr sdk.Address, destAddr sdk.Address, coins sdk.Coins, } } +//nolint +func (p IBCPacket) GetSignBytes() []byte { + b, err := msgCdc.MarshalJSON(struct { + SrcAddr string + DestAddr string + Coins sdk.Coins + SrcChain string + DestChain string + }{ + SrcAddr: sdk.MustBech32ifyAcc(p.SrcAddr), + DestAddr: sdk.MustBech32ifyAcc(p.DestAddr), + Coins: p.Coins, + SrcChain: p.SrcChain, + DestChain: p.DestChain, + }) + if err != nil { + panic(err) + } + return b +} + // validator the ibc packey -func (ibcp IBCPacket) ValidateBasic() sdk.Error { - if ibcp.SrcChain == ibcp.DestChain { +func (p IBCPacket) ValidateBasic() sdk.Error { + if p.SrcChain == p.DestChain { return ErrIdenticalChains(DefaultCodespace).Trace("") } - if !ibcp.Coins.IsValid() { + if !p.Coins.IsValid() { return sdk.ErrInvalidCoins("") } return nil @@ -60,12 +90,7 @@ func (msg IBCTransferMsg) GetSigners() []sdk.Address { return []sdk.Address{msg. // get the sign bytes for ibc transfer message func (msg IBCTransferMsg) GetSignBytes() []byte { - cdc := wire.NewCodec() - bz, err := cdc.MarshalBinary(msg) - if err != nil { - panic(err) - } - return bz + return msg.IBCPacket.GetSignBytes() } // validate ibc transfer message @@ -94,10 +119,17 @@ func (msg IBCReceiveMsg) GetSigners() []sdk.Address { return []sdk.Address{msg.R // get the sign bytes for ibc receive message func (msg IBCReceiveMsg) GetSignBytes() []byte { - cdc := wire.NewCodec() - bz, err := cdc.MarshalBinary(msg) + b, err := msgCdc.MarshalJSON(struct { + IBCPacket json.RawMessage + Relayer string + Sequence int64 + }{ + IBCPacket: json.RawMessage(msg.IBCPacket.GetSignBytes()), + Relayer: sdk.MustBech32ifyAcc(msg.Relayer), + Sequence: msg.Sequence, + }) if err != nil { panic(err) } - return bz + return b } diff --git a/x/slashing/msg.go b/x/slashing/msg.go index d2676af81..561c92266 100644 --- a/x/slashing/msg.go +++ b/x/slashing/msg.go @@ -30,7 +30,11 @@ func (msg MsgUnrevoke) GetSigners() []sdk.Address { return []sdk.Address{msg.Val // get the bytes for the message signer to sign on func (msg MsgUnrevoke) GetSignBytes() []byte { - b, err := cdc.MarshalJSON(msg) + b, err := cdc.MarshalJSON(struct { + ValidatorAddr string `json:"address"` + }{ + ValidatorAddr: sdk.MustBech32ifyVal(msg.ValidatorAddr), + }) if err != nil { panic(err) } diff --git a/x/slashing/msg_test.go b/x/slashing/msg_test.go new file mode 100644 index 000000000..be7797107 --- /dev/null +++ b/x/slashing/msg_test.go @@ -0,0 +1,16 @@ +package slashing + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func TestMsgUnrevokeGetSignBytes(t *testing.T) { + addr := sdk.Address("abcd") + msg := NewMsgUnrevoke(addr) + bytes := msg.GetSignBytes() + assert.Equal(t, string(bytes), `{"address":"cosmosvaladdr1v93xxeqamr0mv"}`) +} diff --git a/x/stake/msg.go b/x/stake/msg.go index 40bf609ee..a0922bb87 100644 --- a/x/stake/msg.go +++ b/x/stake/msg.go @@ -45,7 +45,20 @@ func (msg MsgCreateValidator) GetSigners() []sdk.Address { // get the bytes for the message signer to sign on func (msg MsgCreateValidator) GetSignBytes() []byte { - return msgCdc.MustMarshalBinary(msg) + b, err := msgCdc.MarshalJSON(struct { + Description + ValidatorAddr string `json:"address"` + PubKey string `json:"pubkey"` + Bond sdk.Coin `json:"bond"` + }{ + Description: msg.Description, + ValidatorAddr: sdk.MustBech32ifyVal(msg.ValidatorAddr), + PubKey: sdk.MustBech32ifyValPub(msg.PubKey), + }) + if err != nil { + panic(err) + } + return b } // quick validity check @@ -89,7 +102,13 @@ func (msg MsgEditValidator) GetSigners() []sdk.Address { // get the bytes for the message signer to sign on func (msg MsgEditValidator) GetSignBytes() []byte { - b, err := msgCdc.MarshalJSON(msg) + b, err := msgCdc.MarshalJSON(struct { + Description + ValidatorAddr string `json:"address"` + }{ + Description: msg.Description, + ValidatorAddr: sdk.MustBech32ifyVal(msg.ValidatorAddr), + }) if err != nil { panic(err) } @@ -133,7 +152,15 @@ func (msg MsgDelegate) GetSigners() []sdk.Address { // get the bytes for the message signer to sign on func (msg MsgDelegate) GetSignBytes() []byte { - b, err := msgCdc.MarshalJSON(msg) + b, err := msgCdc.MarshalJSON(struct { + DelegatorAddr string `json:"delegator_addr"` + ValidatorAddr string `json:"validator_addr"` + Bond sdk.Coin `json:"bond"` + }{ + DelegatorAddr: sdk.MustBech32ifyAcc(msg.DelegatorAddr), + ValidatorAddr: sdk.MustBech32ifyVal(msg.ValidatorAddr), + Bond: msg.Bond, + }) if err != nil { panic(err) } @@ -180,7 +207,15 @@ func (msg MsgUnbond) GetSigners() []sdk.Address { return []sdk.Address{msg.Deleg // get the bytes for the message signer to sign on func (msg MsgUnbond) GetSignBytes() []byte { - b, err := msgCdc.MarshalJSON(msg) + b, err := msgCdc.MarshalJSON(struct { + DelegatorAddr string `json:"delegator_addr"` + ValidatorAddr string `json:"validator_addr"` + Shares string `json:"shares"` + }{ + DelegatorAddr: sdk.MustBech32ifyAcc(msg.DelegatorAddr), + ValidatorAddr: sdk.MustBech32ifyVal(msg.ValidatorAddr), + Shares: msg.Shares, + }) if err != nil { panic(err) }