diff --git a/CHANGELOG.md b/CHANGELOG.md index f46475843f..5ebcd32218 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ *TBD* BREAKING CHANGES +* msg.GetSignBytes() returns sorted JSON (by key) * Update Tendermint to v0.22.0 * Default ports changed from 466xx to 266xx * Amino JSON uses type names instead of prefix bytes @@ -41,6 +42,9 @@ BREAKING CHANGES * [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 +DEPRECATED +* [cli] Deprecate `--name` flag in commands that send txs, in favor of `--from` + FEATURES * [gaiacli] You can now attach a simple text-only memo to any transaction, with the `--memo` flag * [lcd] Queried TXs now include the tx hash to identify each tx @@ -102,6 +106,7 @@ BUG FIXES * \#1258 - printing big.rat's can no longer overflow int64 * \#887 - limit the size of rationals that can be passed in from user input * \#1461 - CLI tests now no longer reset your local environment data +* \#1505 - `gaiacli stake validator` no longer panics if validator doesn't exist ## 0.19.0 diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index e919375d90..b8c42c4d2e 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -662,7 +662,7 @@ const msgType3 = "burn" func (msg testBurnMsg) Type() string { return msgType3 } func (msg testBurnMsg) GetSignBytes() []byte { bz, _ := json.Marshal(msg) - return bz + return sdk.MustSortJSON(bz) } func (msg testBurnMsg) ValidateBasic() sdk.Error { if msg.Addr == nil { @@ -685,7 +685,7 @@ const msgType4 = "send" func (msg testSendMsg) Type() string { return msgType4 } func (msg testSendMsg) GetSignBytes() []byte { bz, _ := json.Marshal(msg) - return bz + return sdk.MustSortJSON(bz) } func (msg testSendMsg) ValidateBasic() sdk.Error { if msg.Sender == nil || msg.Receiver == nil { diff --git a/client/context/viper.go b/client/context/viper.go index 948cd7a7dd..c3b83c63a3 100644 --- a/client/context/viper.go +++ b/client/context/viper.go @@ -27,13 +27,20 @@ func NewCoreContextFromViper() CoreContext { chainID = def } } + // TODO: Remove the following deprecation code after Gaia-7000 is launched + keyName := viper.GetString(client.FlagName) + if keyName != "" { + fmt.Println("** Note --name is deprecated and will be removed next release. Please use --from instead **") + } else { + keyName = viper.GetString(client.FlagFrom) + } return CoreContext{ ChainID: chainID, Height: viper.GetInt64(client.FlagHeight), Gas: viper.GetInt64(client.FlagGas), Fee: viper.GetString(client.FlagFee), TrustNode: viper.GetBool(client.FlagTrustNode), - FromAddressName: viper.GetString(client.FlagName), + FromAddressName: keyName, NodeURI: nodeURI, AccountNumber: viper.GetInt64(client.FlagAccountNumber), Sequence: viper.GetInt64(client.FlagSequence), diff --git a/client/flags.go b/client/flags.go index 9fb73ad412..a8cf15e531 100644 --- a/client/flags.go +++ b/client/flags.go @@ -10,6 +10,7 @@ const ( FlagHeight = "height" FlagGas = "gas" FlagTrustNode = "trust-node" + FlagFrom = "from" FlagName = "name" FlagAccountNumber = "account-number" FlagSequence = "sequence" @@ -38,7 +39,8 @@ func GetCommands(cmds ...*cobra.Command) []*cobra.Command { // PostCommands adds common flags for commands to post tx func PostCommands(cmds ...*cobra.Command) []*cobra.Command { for _, c := range cmds { - c.Flags().String(FlagName, "", "Name of private key with which to sign") + c.Flags().String(FlagFrom, "", "Name of private key with which to sign") + c.Flags().String(FlagName, "", "DEPRECATED - Name of private key with which to sign") c.Flags().Int64(FlagAccountNumber, 0, "AccountNumber number to sign the tx") c.Flags().Int64(FlagSequence, 0, "Sequence number to sign the tx") c.Flags().String(FlagMemo, "", "Memo to send along with transaction") diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index 0761bd08f7..93ef825aa6 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -59,7 +59,7 @@ func TestGaiaCLISend(t *testing.T) { fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooCech, flags)) require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("steak").Int64()) - executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --name=foo", flags, barCech), pass) + executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --from=foo", flags, barCech), pass) tests.WaitForNextHeightTM(port) barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags)) @@ -68,7 +68,7 @@ func TestGaiaCLISend(t *testing.T) { require.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("steak").Int64()) // test autosequencing - executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --name=foo", flags, barCech), pass) + executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --from=foo", flags, barCech), pass) tests.WaitForNextHeightTM(port) barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags)) @@ -77,7 +77,7 @@ func TestGaiaCLISend(t *testing.T) { require.Equal(t, int64(30), fooAcc.GetCoins().AmountOf("steak").Int64()) // test memo - executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --name=foo --memo 'testmemo'", flags, barCech), pass) + executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --from=foo --memo 'testmemo'", flags, barCech), pass) tests.WaitForNextHeightTM(port) barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags)) @@ -111,7 +111,7 @@ func TestGaiaCLICreateValidator(t *testing.T) { barCech := sdk.MustBech32ifyAcc(barAddr) barCeshPubKey := sdk.MustBech32ifyValPub(barPubKey) - executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --name=foo", flags, barCech), pass) + executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --from=foo", flags, barCech), pass) tests.WaitForNextHeightTM(port) barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags)) @@ -121,7 +121,7 @@ func TestGaiaCLICreateValidator(t *testing.T) { // create validator cvStr := fmt.Sprintf("gaiacli stake create-validator %v", flags) - cvStr += fmt.Sprintf(" --name=%v", "bar") + cvStr += fmt.Sprintf(" --from=%v", "bar") cvStr += fmt.Sprintf(" --address-validator=%v", barCech) cvStr += fmt.Sprintf(" --pubkey=%v", barCeshPubKey) cvStr += fmt.Sprintf(" --amount=%v", "2steak") @@ -139,7 +139,7 @@ func TestGaiaCLICreateValidator(t *testing.T) { // unbond a single share unbondStr := fmt.Sprintf("gaiacli stake unbond begin %v", flags) - unbondStr += fmt.Sprintf(" --name=%v", "bar") + unbondStr += fmt.Sprintf(" --from=%v", "bar") unbondStr += fmt.Sprintf(" --address-validator=%v", barCech) unbondStr += fmt.Sprintf(" --address-delegator=%v", barCech) unbondStr += fmt.Sprintf(" --shares-amount=%v", "1") @@ -181,7 +181,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) { fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooCech, flags)) require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("steak").Int64()) - executeWrite(t, fmt.Sprintf("gaiacli gov submitproposal %v --proposer=%v --deposit=5steak --type=Text --title=Test --description=test --name=foo", flags, fooCech), pass) + executeWrite(t, fmt.Sprintf("gaiacli gov submitproposal %v --proposer=%v --deposit=5steak --type=Text --title=Test --description=test --from=foo", flags, fooCech), pass) tests.WaitForNextHeightTM(port) fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooCech, flags)) @@ -191,7 +191,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) { require.Equal(t, int64(1), proposal1.ProposalID) require.Equal(t, gov.StatusToString(gov.StatusDepositPeriod), proposal1.Status) - executeWrite(t, fmt.Sprintf("gaiacli gov deposit %v --depositer=%v --deposit=10steak --proposalID=1 --name=foo", flags, fooCech), pass) + executeWrite(t, fmt.Sprintf("gaiacli gov deposit %v --depositer=%v --deposit=10steak --proposalID=1 --from=foo", flags, fooCech), pass) tests.WaitForNextHeightTM(port) fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooCech, flags)) @@ -200,7 +200,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) { require.Equal(t, int64(1), proposal1.ProposalID) require.Equal(t, gov.StatusToString(gov.StatusVotingPeriod), proposal1.Status) - executeWrite(t, fmt.Sprintf("gaiacli gov vote %v --proposalID=1 --voter=%v --option=Yes --name=foo", flags, fooCech), pass) + executeWrite(t, fmt.Sprintf("gaiacli gov vote %v --proposalID=1 --voter=%v --option=Yes --from=foo", flags, fooCech), pass) tests.WaitForNextHeightTM(port) vote := executeGetVote(t, fmt.Sprintf("gaiacli gov query-vote --proposalID=1 --voter=%v --output=json %v", fooCech, flags)) diff --git a/cmd/gaia/testnets/README.md b/cmd/gaia/testnets/README.md index f65b9267ec..e8d1f83e4d 100644 --- a/cmd/gaia/testnets/README.md +++ b/cmd/gaia/testnets/README.md @@ -220,7 +220,7 @@ gaiacli stake create-validator \ --address-validator= --moniker="choose a moniker" \ --chain-id=gaia-6002 \ - --name= + --from= ``` ### Edit Validator Description @@ -237,7 +237,7 @@ gaiacli stake edit-validator --keybase-sig="6A0D65E29A4CBC8E" --details="To infinity and beyond!" --chain-id=gaia-6002 \ - --name= + --from= ``` ### View Validator Description @@ -272,7 +272,7 @@ gaiad start Wait for your full node to catch up to the latest block. Next, run the following command. Note that `` is the address of your validator account, and `` is the name of the validator account. You can find this info by running `gaiacli keys list`. ```bash -gaiacli stake unrevoke --chain-id=gaia-6002 --name= +gaiacli stake unrevoke --chain-id=gaia-6002 --from= ``` **WARNING:** If you don't wait for `gaiad` to sync before running `unrevoke`, you will receive an error message telling you your validator is still jailed. @@ -321,7 +321,7 @@ gaiacli stake delegate \ --amount=10steak \ --address-delegator= \ --address-validator= \ - --name= \ + --from= \ --chain-id=gaia-6002 ``` @@ -338,7 +338,7 @@ gaiacli stake unbond \ --address-delegator= \ --address-validator= \ --shares=MAX \ - --name= \ + --from= \ --chain-id=gaia-6002 ``` @@ -361,7 +361,7 @@ gaiacli stake delegation \ gaiacli send \ --amount=10faucetToken \ --chain-id=gaia-6002 \ - --name= \ + --from= \ --to= ``` diff --git a/docs/_attic/staking/intro.rst b/docs/_attic/staking/intro.rst index 3ed20852b4..14735ef33b 100644 --- a/docs/_attic/staking/intro.rst +++ b/docs/_attic/staking/intro.rst @@ -197,9 +197,9 @@ We'll have ``alice`` send some ``mycoin`` to ``bob``, who has now joined the net :: - gaiacli send --amount=1000mycoin --sequence=0 --name=alice --to=5A35E4CC7B7DC0A5CB49CEA91763213A9AE92AD6 --chain-id=test-chain-Uv1EVU + gaiacli send --amount=1000mycoin --sequence=0 --from=alice --to=5A35E4CC7B7DC0A5CB49CEA91763213A9AE92AD6 --chain-id=test-chain-Uv1EVU -where the ``--sequence`` flag is to be incremented for each transaction, the ``--name`` flag is the sender (alice), and the ``--to`` flag takes ``bob``'s address. You'll see something like: +where the ``--sequence`` flag is to be incremented for each transaction, the ``--from`` flag is the sender (alice), and the ``--to`` flag takes ``bob``'s address. You'll see something like: :: @@ -264,7 +264,7 @@ Now ``bob`` can create a validator with that pubkey. :: - gaiacli stake create-validator --amount=10mycoin --name=bob --address-validator=
--pub-key= --moniker=bobby + gaiacli stake create-validator --amount=10mycoin --from=bob --address-validator=
--pub-key= --moniker=bobby with an output like: @@ -306,13 +306,13 @@ First let's have ``alice`` send some coins to ``charlie``: :: - gaiacli send --amount=1000mycoin --sequence=2 --name=alice --to=48F74F48281C89E5E4BE9092F735EA519768E8EF + gaiacli send --amount=1000mycoin --sequence=2 --from=alice --to=48F74F48281C89E5E4BE9092F735EA519768E8EF Then ``charlie`` will delegate some mycoin to ``bob``: :: - gaiacli stake delegate --amount=10mycoin --address-delegator= --address-validator= --name=charlie + gaiacli stake delegate --amount=10mycoin --address-delegator= --address-validator= --from=charlie You'll see output like: @@ -396,7 +396,7 @@ your VotingPower reduce and your account balance increase. :: - gaiacli stake unbond --amount=5mycoin --name=charlie --address-delegator=
--address-validator=
+ gaiacli stake unbond --amount=5mycoin --from=charlie --address-delegator=
--address-validator=
gaiacli account 48F74F48281C89E5E4BE9092F735EA519768E8EF See the bond decrease with ``gaiacli stake delegation`` like above. diff --git a/docs/_attic/staking/testnet.md b/docs/_attic/staking/testnet.md index b2bbd8f1a3..5228070cf1 100644 --- a/docs/_attic/staking/testnet.md +++ b/docs/_attic/staking/testnet.md @@ -63,7 +63,7 @@ Then, we try to transfer some `steak` to another account: ``` gaiacli account gaiacli account -gaiacli send --amount=10steak --to= --name=foo --chain-id=test-chain +gaiacli send --amount=10steak --to= --from=foo --chain-id=test-chain ``` **Note:** We need to be careful with the `chain-id` and `sequence` @@ -84,7 +84,7 @@ Finally, to relinquish all your power, unbond some coins. You should see your VotingPower reduce and your account balance increase. ``` -gaiacli unbond --chain-id= --name=test +gaiacli unbond --chain-id= --from=test ``` That's it! diff --git a/docs/clients/ledger.md b/docs/clients/ledger.md index 9f6386715d..5ea1224eae 100644 --- a/docs/clients/ledger.md +++ b/docs/clients/ledger.md @@ -23,7 +23,7 @@ NAME: TYPE: ADDRESS: PUBKEY: This key will only be accessible while the Ledger is plugged in and unlocked. To send some coins with this key, run the following: ```bash -$ gaiacli send --name {{ .Key.Name }} --to {{ .Destination.AccAddr }} --chain-id=gaia-7000 +$ gaiacli send --from {{ .Key.Name }} --to {{ .Destination.AccAddr }} --chain-id=gaia-7000 ``` You will be asked to review and confirm the transaction on the Ledger. Once you do this you should see the result in the console! Now you can use your Ledger to manage your Atoms and Stake! diff --git a/docs/core/examples/app1.go b/docs/core/examples/app1.go index f9eceecdb5..a9580fcc29 100644 --- a/docs/core/examples/app1.go +++ b/docs/core/examples/app1.go @@ -85,7 +85,7 @@ func (msg MsgSend) GetSignBytes() []byte { if err != nil { panic(err) } - return bz + return sdk.MustSortJSON(bz) } // Implements Msg. Return the signer. diff --git a/docs/core/examples/app2.go b/docs/core/examples/app2.go index b4d44dca7b..c96a1022fa 100644 --- a/docs/core/examples/app2.go +++ b/docs/core/examples/app2.go @@ -100,7 +100,7 @@ func (msg MsgIssue) GetSignBytes() []byte { if err != nil { panic(err) } - return bz + return sdk.MustSortJSON(bz) } // Implements Msg. Return the signer. diff --git a/examples/README.md b/examples/README.md index a8a483ee62..e3016fb707 100644 --- a/examples/README.md +++ b/examples/README.md @@ -123,12 +123,12 @@ Where `90B0B9BE0914ECEE0B6DB74E67B07A00056B9BBD` is alice's address we got from The following command will send coins from alice, to bob: ``` -basecli send --name=alice --amount=10000mycoin --to=29D721F054537C91F618A0FDBF770DA51EF8C48D +basecli send --from=alice --amount=10000mycoin --to=29D721F054537C91F618A0FDBF770DA51EF8C48D --sequence=0 --chain-id=test-chain-AE4XQo ``` Flag Descriptions: -- `name` is the name you gave your key +- `from` is the name you gave your key - `mycoin` is the name of the token for this basecoin demo, initialized in the genesis.json file - `sequence` is a tally of how many transactions have been made by this account. Since this is the first tx on this account, it is 0 - `chain-id` is the unique ID that helps tendermint identify which network to connect to. You can find it in the terminal output from the gaiad daemon in the header block , or in the genesis.json file at `~/.basecoind/config/genesis.json` @@ -142,16 +142,16 @@ basecli account 29D721F054537C91F618A0FDBF770DA51EF8C48D Now lets send some from bob to charlie. Make sure you send less than bob has, otherwise the transaction will fail: ``` -basecli send --name=bob --amount=5000mycoin --to=2E8E13EEB8E3F0411ACCBC9BE0384732C24FBD5E +basecli send --from=bob --amount=5000mycoin --to=2E8E13EEB8E3F0411ACCBC9BE0384732C24FBD5E --sequence=0 --chain-id=test-chain-AE4XQo ``` -Note how we use the ``--name`` flag to select a different account to send from. +Note how we use the ``--from`` flag to select a different account to send from. Lets now try to send from bob back to alice: ``` -basecli send --name=bob --amount=3000mycoin --to=90B0B9BE0914ECEE0B6DB74E67B07A00056B9BBD +basecli send --from=bob --amount=3000mycoin --to=90B0B9BE0914ECEE0B6DB74E67B07A00056B9BBD --sequence=1 --chain-id=test-chain-AE4XQo ``` diff --git a/examples/democoin/x/cool/types.go b/examples/democoin/x/cool/types.go index 77f49a0ba3..82c9286c68 100644 --- a/examples/democoin/x/cool/types.go +++ b/examples/democoin/x/cool/types.go @@ -58,7 +58,7 @@ func (msg MsgSetTrend) GetSignBytes() []byte { if err != nil { panic(err) } - return b + return sdk.MustSortJSON(b) } //_______________________________________________________________________ @@ -102,5 +102,5 @@ func (msg MsgQuiz) GetSignBytes() []byte { if err != nil { panic(err) } - return b + return sdk.MustSortJSON(b) } diff --git a/examples/democoin/x/oracle/types.go b/examples/democoin/x/oracle/types.go index 041b9ab349..d06f47a4e2 100644 --- a/examples/democoin/x/oracle/types.go +++ b/examples/democoin/x/oracle/types.go @@ -18,7 +18,7 @@ func (msg Msg) GetSignBytes() []byte { if err != nil { panic(err) } - return bz + return sdk.MustSortJSON(bz) } // GetSigners implements sdk.Msg diff --git a/examples/democoin/x/pow/types.go b/examples/democoin/x/pow/types.go index cd77a68af5..3529917dce 100644 --- a/examples/democoin/x/pow/types.go +++ b/examples/democoin/x/pow/types.go @@ -76,5 +76,5 @@ func (msg MsgMine) GetSignBytes() []byte { if err != nil { panic(err) } - return b + return sdk.MustSortJSON(b) } diff --git a/examples/democoin/x/pow/types_test.go b/examples/democoin/x/pow/types_test.go index 9ed5dc102c..1291cb96a6 100644 --- a/examples/democoin/x/pow/types_test.go +++ b/examples/democoin/x/pow/types_test.go @@ -62,7 +62,7 @@ func TestMsgMineGetSignBytes(t *testing.T) { addr := sdk.Address([]byte("sender")) msg := MsgMine{addr, 1, 1, 1, []byte("abc")} res := msg.GetSignBytes() - require.Equal(t, string(res), `{"sender":"73656E646572","difficulty":1,"count":1,"nonce":1,"proof":"YWJj"}`) + require.Equal(t, string(res), `{"count":1,"difficulty":1,"nonce":1,"proof":"YWJj","sender":"73656E646572"}`) } func TestMsgMineGetSigners(t *testing.T) { diff --git a/examples/democoin/x/simplestake/msgs.go b/examples/democoin/x/simplestake/msgs.go index 564e0d9796..91729e3ef7 100644 --- a/examples/democoin/x/simplestake/msgs.go +++ b/examples/democoin/x/simplestake/msgs.go @@ -48,7 +48,7 @@ func (msg MsgBond) GetSignBytes() []byte { if err != nil { panic(err) } - return bz + return sdk.MustSortJSON(bz) } //_______________________________________________________________ diff --git a/examples/kvstore/tx.go b/examples/kvstore/tx.go index 0e94ace285..e1c5cab3a8 100644 --- a/examples/kvstore/tx.go +++ b/examples/kvstore/tx.go @@ -27,7 +27,7 @@ func (tx kvstoreTx) GetMemo() string { } func (tx kvstoreTx) GetSignBytes() []byte { - return tx.bytes + return sdk.MustSortJSON(tx.bytes) } // Should the app be calling this? Or only handlers? diff --git a/server/util.go b/server/util.go index 014f36ad3b..0f1816b166 100644 --- a/server/util.go +++ b/server/util.go @@ -141,24 +141,6 @@ func InsertKeyJSON(cdc *wire.Codec, baseJSON []byte, key string, value json.RawM return json.RawMessage(bz), err } -// SortedJSON takes any JSON and returns it sorted by keys. Also, all white-spaces -// are removed. -// This method can be used to canonicalize JSON to be returned by GetSignBytes, -// e.g. for the ledger integration. -// If the passed JSON isn't valid it will return an error. -func SortJSON(toSortJSON []byte) ([]byte, error) { - var c interface{} - err := json.Unmarshal(toSortJSON, &c) - if err != nil { - return nil, err - } - js, err := json.Marshal(c) - if err != nil { - return nil, err - } - return js, nil -} - // https://stackoverflow.com/questions/23558425/how-do-i-get-the-local-ip-address-in-go // TODO there must be a better way to get external IP func externalIP() (string, error) { diff --git a/server/util_test.go b/server/util_test.go index 09e66ab4a6..6082caa2ce 100644 --- a/server/util_test.go +++ b/server/util_test.go @@ -38,34 +38,3 @@ func TestInsertKeyJSON(t *testing.T) { require.Equal(t, bar, resBar, "appended: %v", appended) } - -func TestSortJSON(t *testing.T) { - cases := []struct { - unsortedJSON string - want string - wantErr bool - }{ - // simple case - {unsortedJSON: `{"cosmos":"foo", "atom":"bar", "tendermint":"foobar"}`, - want: `{"atom":"bar","cosmos":"foo","tendermint":"foobar"}`, wantErr: false}, - // failing case (invalid JSON): - {unsortedJSON: `"cosmos":"foo",,,, "atom":"bar", "tendermint":"foobar"}`, - want: "", wantErr: true}, - // genesis.json - {unsortedJSON: `{"consensus_params":{"block_size_params":{"max_bytes":22020096,"max_txs":100000,"max_gas":-1},"tx_size_params":{"max_bytes":10240,"max_gas":-1},"block_gossip_params":{"block_part_size_bytes":65536},"evidence_params":{"max_age":100000}},"validators":[{"pub_key":{"type":"AC26791624DE60","value":"c7UMMAbjFuc5GhGPy0E5q5tefy12p9Tq0imXqdrKXwo="},"power":100,"name":""}],"app_hash":"","genesis_time":"2018-05-11T15:52:25.424795506Z","chain_id":"test-chain-Q6VeoW","app_state":{"accounts":[{"address":"718C9C23F98C9642569742ADDD9F9AB9743FBD5D","coins":[{"denom":"Token","amount":1000},{"denom":"steak","amount":50}]}],"stake":{"pool":{"total_supply":50,"bonded_shares":"0","unbonded_shares":"0","bonded_pool":0,"unbonded_pool":0,"inflation_last_time":0,"inflation":"7/100"},"params":{"inflation_rate_change":"13/100","inflation_max":"1/5","inflation_min":"7/100","goal_bonded":"67/100","max_validators":100,"bond_denom":"steak"},"candidates":null,"bonds":null}}}`, - want: `{"app_hash":"","app_state":{"accounts":[{"address":"718C9C23F98C9642569742ADDD9F9AB9743FBD5D","coins":[{"amount":1000,"denom":"Token"},{"amount":50,"denom":"steak"}]}],"stake":{"bonds":null,"candidates":null,"params":{"bond_denom":"steak","goal_bonded":"67/100","inflation_max":"1/5","inflation_min":"7/100","inflation_rate_change":"13/100","max_validators":100},"pool":{"bonded_pool":0,"bonded_shares":"0","inflation":"7/100","inflation_last_time":0,"total_supply":50,"unbonded_pool":0,"unbonded_shares":"0"}}},"chain_id":"test-chain-Q6VeoW","consensus_params":{"block_gossip_params":{"block_part_size_bytes":65536},"block_size_params":{"max_bytes":22020096,"max_gas":-1,"max_txs":100000},"evidence_params":{"max_age":100000},"tx_size_params":{"max_bytes":10240,"max_gas":-1}},"genesis_time":"2018-05-11T15:52:25.424795506Z","validators":[{"name":"","power":100,"pub_key":{"type":"AC26791624DE60","value":"c7UMMAbjFuc5GhGPy0E5q5tefy12p9Tq0imXqdrKXwo="}}]}`, - wantErr: false}, - // from the TXSpec: - {unsortedJSON: `{"chain_id":"test-chain-1","sequence":1,"fee_bytes":{"amount":[{"amount":5,"denom":"photon"}],"gas":10000},"msg_bytes":{"inputs":[{"address":"696E707574","coins":[{"amount":10,"denom":"atom"}]}],"outputs":[{"address":"6F7574707574","coins":[{"amount":10,"denom":"atom"}]}]},"alt_bytes":null}`, - want: `{"alt_bytes":null,"chain_id":"test-chain-1","fee_bytes":{"amount":[{"amount":5,"denom":"photon"}],"gas":10000},"msg_bytes":{"inputs":[{"address":"696E707574","coins":[{"amount":10,"denom":"atom"}]}],"outputs":[{"address":"6F7574707574","coins":[{"amount":10,"denom":"atom"}]}]},"sequence":1}`, - wantErr: false}, - } - - for _, tc := range cases { - got, err := SortJSON([]byte(tc.unsortedJSON)) - if tc.wantErr != (err != nil) { - t.Fatalf("got %t, want: %t, err=%s", err != nil, tc.wantErr, err) - } - require.Equal(t, string(got), tc.want) - } -} diff --git a/tests/check_basecli.sh b/tests/check_basecli.sh index ec2c458cb6..ffcf39a517 100755 --- a/tests/check_basecli.sh +++ b/tests/check_basecli.sh @@ -36,7 +36,7 @@ echo; echo "Empty account:" $TO ./build/basecli account $TO # send some money -TX=`echo $PASS | ./build/basecli send --to=$TO --amount=1000mycoin --name=demo --seq=0` +TX=`echo $PASS | ./build/basecli send --to=$TO --amount=1000mycoin --from=demo --seq=0` echo; echo "SendTx"; echo $TX HASH=`echo $TX | cut -d' ' -f6` echo "tx hash:" $HASH diff --git a/types/tx_msg.go b/types/tx_msg.go index c1af91df82..fbadfb49d0 100644 --- a/types/tx_msg.go +++ b/types/tx_msg.go @@ -60,7 +60,7 @@ func (msg *TestMsg) GetSignBytes() []byte { if err != nil { panic(err) } - return bz + return MustSortJSON(bz) } func (msg *TestMsg) ValidateBasic() Error { return nil } func (msg *TestMsg) GetSigners() []Address { diff --git a/types/utils.go b/types/utils.go new file mode 100644 index 0000000000..2e027676a0 --- /dev/null +++ b/types/utils.go @@ -0,0 +1,31 @@ +package types + +import "encoding/json" + +// SortedJSON takes any JSON and returns it sorted by keys. Also, all white-spaces +// are removed. +// This method can be used to canonicalize JSON to be returned by GetSignBytes, +// e.g. for the ledger integration. +// If the passed JSON isn't valid it will return an error. +func SortJSON(toSortJSON []byte) ([]byte, error) { + var c interface{} + err := json.Unmarshal(toSortJSON, &c) + if err != nil { + return nil, err + } + js, err := json.Marshal(c) + if err != nil { + return nil, err + } + return js, nil +} + +// MustSortJSON is like SortJSON but panic if an error occurs, e.g., if +// the passed JSON isn't valid. +func MustSortJSON(toSortJSON []byte) []byte { + js, err := SortJSON(toSortJSON) + if err != nil { + panic(err) + } + return js +} diff --git a/types/utils_test.go b/types/utils_test.go new file mode 100644 index 0000000000..8c84e2ace2 --- /dev/null +++ b/types/utils_test.go @@ -0,0 +1,39 @@ +package types + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestSortJSON(t *testing.T) { + cases := []struct { + unsortedJSON string + want string + wantErr bool + }{ + // simple case + {unsortedJSON: `{"cosmos":"foo", "atom":"bar", "tendermint":"foobar"}`, + want: `{"atom":"bar","cosmos":"foo","tendermint":"foobar"}`, wantErr: false}, + // failing case (invalid JSON): + {unsortedJSON: `"cosmos":"foo",,,, "atom":"bar", "tendermint":"foobar"}`, + want: "", + wantErr: true}, + // genesis.json + {unsortedJSON: `{"consensus_params":{"block_size_params":{"max_bytes":22020096,"max_txs":100000,"max_gas":-1},"tx_size_params":{"max_bytes":10240,"max_gas":-1},"block_gossip_params":{"block_part_size_bytes":65536},"evidence_params":{"max_age":100000}},"validators":[{"pub_key":{"type":"AC26791624DE60","value":"c7UMMAbjFuc5GhGPy0E5q5tefy12p9Tq0imXqdrKXwo="},"power":100,"name":""}],"app_hash":"","genesis_time":"2018-05-11T15:52:25.424795506Z","chain_id":"test-chain-Q6VeoW","app_state":{"accounts":[{"address":"718C9C23F98C9642569742ADDD9F9AB9743FBD5D","coins":[{"denom":"Token","amount":1000},{"denom":"steak","amount":50}]}],"stake":{"pool":{"total_supply":50,"bonded_shares":"0","unbonded_shares":"0","bonded_pool":0,"unbonded_pool":0,"inflation_last_time":0,"inflation":"7/100"},"params":{"inflation_rate_change":"13/100","inflation_max":"1/5","inflation_min":"7/100","goal_bonded":"67/100","max_validators":100,"bond_denom":"steak"},"candidates":null,"bonds":null}}}`, + want: `{"app_hash":"","app_state":{"accounts":[{"address":"718C9C23F98C9642569742ADDD9F9AB9743FBD5D","coins":[{"amount":1000,"denom":"Token"},{"amount":50,"denom":"steak"}]}],"stake":{"bonds":null,"candidates":null,"params":{"bond_denom":"steak","goal_bonded":"67/100","inflation_max":"1/5","inflation_min":"7/100","inflation_rate_change":"13/100","max_validators":100},"pool":{"bonded_pool":0,"bonded_shares":"0","inflation":"7/100","inflation_last_time":0,"total_supply":50,"unbonded_pool":0,"unbonded_shares":"0"}}},"chain_id":"test-chain-Q6VeoW","consensus_params":{"block_gossip_params":{"block_part_size_bytes":65536},"block_size_params":{"max_bytes":22020096,"max_gas":-1,"max_txs":100000},"evidence_params":{"max_age":100000},"tx_size_params":{"max_bytes":10240,"max_gas":-1}},"genesis_time":"2018-05-11T15:52:25.424795506Z","validators":[{"name":"","power":100,"pub_key":{"type":"AC26791624DE60","value":"c7UMMAbjFuc5GhGPy0E5q5tefy12p9Tq0imXqdrKXwo="}}]}`, + wantErr: false}, + // from the TXSpec: + {unsortedJSON: `{"chain_id":"test-chain-1","sequence":1,"fee_bytes":{"amount":[{"amount":5,"denom":"photon"}],"gas":10000},"msg_bytes":{"inputs":[{"address":"696E707574","coins":[{"amount":10,"denom":"atom"}]}],"outputs":[{"address":"6F7574707574","coins":[{"amount":10,"denom":"atom"}]}]},"alt_bytes":null}`, + want: `{"alt_bytes":null,"chain_id":"test-chain-1","fee_bytes":{"amount":[{"amount":5,"denom":"photon"}],"gas":10000},"msg_bytes":{"inputs":[{"address":"696E707574","coins":[{"amount":10,"denom":"atom"}]}],"outputs":[{"address":"6F7574707574","coins":[{"amount":10,"denom":"atom"}]}]},"sequence":1}`, + wantErr: false}, + } + + for _, tc := range cases { + got, err := SortJSON([]byte(tc.unsortedJSON)) + if tc.wantErr != (err != nil) { + t.Fatalf("got %t, want: %t, err=%s", err != nil, tc.wantErr, err) + } + require.Equal(t, string(got), tc.want) + } +} diff --git a/x/auth/stdtx.go b/x/auth/stdtx.go index fd55eebb95..960d9855ea 100644 --- a/x/auth/stdtx.go +++ b/x/auth/stdtx.go @@ -141,7 +141,7 @@ func StdSignBytes(chainID string, accnum int64, sequence int64, fee StdFee, msgs if err != nil { panic(err) } - return bz + return sdk.MustSortJSON(bz) } // StdSignMsg is a convenience structure for passing along diff --git a/x/bank/msgs.go b/x/bank/msgs.go index 1a871979e2..46b1995633 100644 --- a/x/bank/msgs.go +++ b/x/bank/msgs.go @@ -72,7 +72,7 @@ func (msg MsgSend) GetSignBytes() []byte { if err != nil { panic(err) } - return b + return sdk.MustSortJSON(b) } // Implements Msg. @@ -133,7 +133,7 @@ func (msg MsgIssue) GetSignBytes() []byte { if err != nil { panic(err) } - return b + return sdk.MustSortJSON(b) } // Implements Msg. @@ -162,7 +162,7 @@ func (in Input) GetSignBytes() []byte { if err != nil { panic(err) } - return bin + return sdk.MustSortJSON(bin) } // ValidateBasic - validate transaction input @@ -209,7 +209,7 @@ func (out Output) GetSignBytes() []byte { if err != nil { panic(err) } - return bin + return sdk.MustSortJSON(bin) } // ValidateBasic - validate transaction output diff --git a/x/bank/msgs_test.go b/x/bank/msgs_test.go index 3754858ec7..f4e7363d3b 100644 --- a/x/bank/msgs_test.go +++ b/x/bank/msgs_test.go @@ -187,7 +187,7 @@ func TestMsgSendGetSignBytes(t *testing.T) { } res := msg.GetSignBytes() - expected := `{"inputs":[{"address":"cosmosaccaddr1d9h8qat5e4ehc5","coins":[{"denom":"atom","amount":"10"}]}],"outputs":[{"address":"cosmosaccaddr1da6hgur4wse3jx32","coins":[{"denom":"atom","amount":"10"}]}]}` + expected := `{"inputs":[{"address":"cosmosaccaddr1d9h8qat5e4ehc5","coins":[{"amount":"10","denom":"atom"}]}],"outputs":[{"address":"cosmosaccaddr1da6hgur4wse3jx32","coins":[{"amount":"10","denom":"atom"}]}]}` require.Equal(t, expected, string(res)) } @@ -257,7 +257,7 @@ func TestMsgIssueGetSignBytes(t *testing.T) { } res := msg.GetSignBytes() - expected := `{"banker":"cosmosaccaddr1d9h8qat5e4ehc5","outputs":[{"address":"cosmosaccaddr1d3hkzm3dveex7mfdvfsku6cwsauqd","coins":[{"denom":"atom","amount":"10"}]}]}` + expected := `{"banker":"cosmosaccaddr1d9h8qat5e4ehc5","outputs":[{"address":"cosmosaccaddr1d3hkzm3dveex7mfdvfsku6cwsauqd","coins":[{"amount":"10","denom":"atom"}]}]}` require.Equal(t, expected, string(res)) } diff --git a/x/gov/msgs.go b/x/gov/msgs.go index f436d024b1..75a8d51e39 100644 --- a/x/gov/msgs.go +++ b/x/gov/msgs.go @@ -82,7 +82,7 @@ func (msg MsgSubmitProposal) GetSignBytes() []byte { if err != nil { panic(err) } - return b + return sdk.MustSortJSON(b) } // Implements Msg. @@ -149,7 +149,7 @@ func (msg MsgDeposit) GetSignBytes() []byte { if err != nil { panic(err) } - return b + return sdk.MustSortJSON(b) } // Implements Msg. @@ -213,7 +213,7 @@ func (msg MsgVote) GetSignBytes() []byte { if err != nil { panic(err) } - return b + return sdk.MustSortJSON(b) } // Implements Msg. diff --git a/x/ibc/client/cli/README.md b/x/ibc/client/cli/README.md index e91fb55bfc..ab9e8e5558 100644 --- a/x/ibc/client/cli/README.md +++ b/x/ibc/client/cli/README.md @@ -109,7 +109,7 @@ key2 DC26002735D3AA9573707CFA6D77C12349E49868 ## Transfer coins (addr1:chain1 -> addr2:chain2) ```console -> basecli transfer --name key1 --to $ADDR2 --amount 10mycoin --chain $ID2 --chain-id $ID1 --node $NODE1 +> basecli transfer --from key1 --to $ADDR2 --amount 10mycoin --chain $ID2 --chain-id $ID1 --node $NODE1 Password to sign with 'key1': Committed at block 1022. Hash: E16019DCC4AA08CA70AFCFBC96028ABCC51B6AD0 > basecli account $ADDR1 --node $NODE1 @@ -133,7 +133,7 @@ Committed at block 1022. Hash: E16019DCC4AA08CA70AFCFBC96028ABCC51B6AD0 ## Relay IBC packets ```console -> basecli relay --name key2 --from-chain-id $ID1 --from-chain-node $NODE1 --to-chain-id $ID2 --to-chain-node $NODE2 --chain-id $ID2 +> basecli relay --from key2 --from-chain-id $ID1 --from-chain-node $NODE1 --to-chain-id $ID2 --to-chain-node $NODE2 --chain-id $ID2 Password to sign with 'key2': I[04-03|16:18:59.984] Detected IBC packet number=0 I[04-03|16:19:00.869] Relayed IBC packet number=0 diff --git a/x/ibc/types.go b/x/ibc/types.go index a311b98698..33f2a9a8d3 100644 --- a/x/ibc/types.go +++ b/x/ibc/types.go @@ -59,7 +59,7 @@ func (p IBCPacket) GetSignBytes() []byte { if err != nil { panic(err) } - return b + return sdk.MustSortJSON(b) } // validator the ibc packey @@ -131,5 +131,5 @@ func (msg IBCReceiveMsg) GetSignBytes() []byte { if err != nil { panic(err) } - return b + return sdk.MustSortJSON(b) } diff --git a/x/slashing/msg.go b/x/slashing/msg.go index 561c922665..6060079a49 100644 --- a/x/slashing/msg.go +++ b/x/slashing/msg.go @@ -38,7 +38,7 @@ func (msg MsgUnrevoke) GetSignBytes() []byte { if err != nil { panic(err) } - return b + return sdk.MustSortJSON(b) } // quick validity check diff --git a/x/stake/client/cli/query.go b/x/stake/client/cli/query.go index 82149a2fa5..30f833c020 100644 --- a/x/stake/client/cli/query.go +++ b/x/stake/client/cli/query.go @@ -31,8 +31,9 @@ func GetCmdQueryValidator(storeName string, cdc *wire.Codec) *cobra.Command { res, err := ctx.QueryStore(key, storeName) if err != nil { return err + } else if len(res) == 0 { + return fmt.Errorf("No validator found with address %s", args[0]) } - validator := types.MustUnmarshalValidator(cdc, addr, res) switch viper.Get(cli.OutputFlag) { diff --git a/x/stake/types/msg.go b/x/stake/types/msg.go index 878c1ba17b..aa9eea8cbb 100644 --- a/x/stake/types/msg.go +++ b/x/stake/types/msg.go @@ -63,7 +63,7 @@ func (msg MsgCreateValidator) GetSignBytes() []byte { if err != nil { panic(err) } - return b + return sdk.MustSortJSON(b) } // quick validity check @@ -114,7 +114,7 @@ func (msg MsgEditValidator) GetSignBytes() []byte { if err != nil { panic(err) } - return b + return sdk.MustSortJSON(b) } // quick validity check @@ -166,7 +166,7 @@ func (msg MsgDelegate) GetSignBytes() []byte { if err != nil { panic(err) } - return b + return sdk.MustSortJSON(b) } // quick validity check @@ -226,7 +226,7 @@ func (msg MsgBeginRedelegate) GetSignBytes() []byte { if err != nil { panic(err) } - return b + return sdk.MustSortJSON(b) } // quick validity check @@ -286,7 +286,7 @@ func (msg MsgCompleteRedelegate) GetSignBytes() []byte { if err != nil { panic(err) } - return b + return sdk.MustSortJSON(b) } // quick validity check @@ -338,7 +338,7 @@ func (msg MsgBeginUnbonding) GetSignBytes() []byte { if err != nil { panic(err) } - return b + return sdk.MustSortJSON(b) } // quick validity check @@ -387,7 +387,7 @@ func (msg MsgCompleteUnbonding) GetSignBytes() []byte { if err != nil { panic(err) } - return b + return sdk.MustSortJSON(b) } // quick validity check