From 351192aa0b52a42b66ff06e81cfa7a9e26667a7f Mon Sep 17 00:00:00 2001 From: Jonathan Gimeno Date: Tue, 14 Jul 2020 20:37:14 +0200 Subject: [PATCH] x/auth: in-process test refactor (#6573) * remove unused functions * create helper func to send tx * refactor to use test help to send tx by client * Commit before getting backend. * Temporal commit * temp commit * remove the creation of txbuilder from cli * fix imports * update changelog * Remove unused function. * Add flag home into tx sign command. * migrade TestCLIValidateSignatures to use new test suite * migrate test one * Add changes to make sign batch. * make test pass * refactor common logic * First part of cli sign. * Add test for sign batch. * refactor a little and improve the test * migrate broadcast command * fix linter * Remove printf for debug in bank module. * Fix unused err var. * fix linter * fix test * fix tests client * Fix linter. * Temp commit signature. * encode tx * migrate tests * Fix imports. * Remove changelog * fix tests * Fix tests. * Update x/bank/client/testutil/cli_helpers.go * Remove alias. * Remove wait for N block func. * export callCmd function into its own file. * fix imports * bring back to inner functions * apply mock io * the helpers use mockio * fix bug * Add Helpers. * return to put the function in testutil package * return BufferWriter in ExecTestCLICmd Co-authored-by: Alessio Treglia Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Co-authored-by: Alexander Bezobchuk --- simapp/simd/cmd/root.go | 14 +- tests/cli/helpers.go | 2 +- testutil/cli/cmd.go | 27 + testutil/ioutil.go | 2 +- x/auth/client/cli/broadcast.go | 4 +- x/auth/client/cli/broadcast_test.go | 46 -- x/auth/client/cli/cli_test.go | 899 ++++++++++++++++---------- x/auth/client/cli/decode.go | 4 +- x/auth/client/cli/encode.go | 8 +- x/auth/client/cli/encode_test.go | 22 +- x/auth/client/cli/tx.go | 10 +- x/auth/client/cli/tx_multisign.go | 18 +- x/auth/client/cli/tx_sign.go | 63 +- x/auth/client/cli/validate_sigs.go | 10 +- x/auth/client/testutil/helpers.go | 103 ++- x/auth/client/tx.go | 4 +- x/auth/module.go | 2 +- x/auth/types/account_retriever.go | 4 +- x/bank/client/cli/cli_test.go | 2 +- x/bank/client/testutil/cli_helpers.go | 71 +- 20 files changed, 769 insertions(+), 546 deletions(-) create mode 100644 testutil/cli/cmd.go delete mode 100644 x/auth/client/cli/broadcast_test.go diff --git a/simapp/simd/cmd/root.go b/simapp/simd/cmd/root.go index d29ba512351f..b8f05b4958af 100644 --- a/simapp/simd/cmd/root.go +++ b/simapp/simd/cmd/root.go @@ -129,14 +129,14 @@ func txCommand() *cobra.Command { } cmd.AddCommand( - authcmd.GetSignCommand(initClientCtx), - authcmd.GetSignBatchCommand(encodingConfig.Amino), - authcmd.GetMultiSignCommand(initClientCtx), - authcmd.GetValidateSignaturesCommand(initClientCtx), + authcmd.GetSignCommand(), + authcmd.GetSignBatchCommand(), + authcmd.GetMultiSignCommand(), + authcmd.GetValidateSignaturesCommand(), flags.LineBreak, - authcmd.GetBroadcastCommand(initClientCtx), - authcmd.GetEncodeCommand(initClientCtx), - authcmd.GetDecodeCommand(initClientCtx), + authcmd.GetBroadcastCommand(), + authcmd.GetEncodeCommand(), + authcmd.GetDecodeCommand(), flags.LineBreak, ) diff --git a/tests/cli/helpers.go b/tests/cli/helpers.go index daaa7dacdec6..945b2f3decd3 100644 --- a/tests/cli/helpers.go +++ b/tests/cli/helpers.go @@ -181,7 +181,7 @@ func AddFlags(cmd string, flags []string) string { return strings.TrimSpace(cmd) } -func UnmarshalStdTx(t require.TestingT, c *codec.Codec, s string) (stdTx authtypes.StdTx) { +func UnmarshalStdTx(t require.TestingT, c codec.JSONMarshaler, s string) (stdTx authtypes.StdTx) { require.Nil(t, c.UnmarshalJSON([]byte(s), &stdTx)) return } diff --git a/testutil/cli/cmd.go b/testutil/cli/cmd.go new file mode 100644 index 000000000000..1f09ae92966c --- /dev/null +++ b/testutil/cli/cmd.go @@ -0,0 +1,27 @@ +package cli + +import ( + "context" + + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/testutil" +) + +// ExecTestCLICmd builds the client context, mocks the output and executes the command. +func ExecTestCLICmd(clientCtx client.Context, cmd *cobra.Command, extraArgs []string) (testutil.BufferWriter, error) { + cmd.SetArgs(extraArgs) + + _, out := testutil.ApplyMockIO(cmd) + clientCtx = clientCtx.WithOutput(out) + + ctx := context.Background() + ctx = context.WithValue(ctx, client.ClientContextKey, &clientCtx) + + if err := cmd.ExecuteContext(ctx); err != nil { + return out, err + } + + return out, nil +} diff --git a/testutil/ioutil.go b/testutil/ioutil.go index 622806f25c4f..cdf92db2451c 100644 --- a/testutil/ioutil.go +++ b/testutil/ioutil.go @@ -65,7 +65,7 @@ func ApplyMockIODiscardOutErr(c *cobra.Command) BufferReader { // the caller must call to remove the file when it is // no longer needed. func WriteToNewTempFile(t testing.TB, s string) (*os.File, func()) { - fp, err := ioutil.TempFile("", t.Name()+"_") + fp, err := ioutil.TempFile("", strings.ReplaceAll(t.Name(), "/", "_")+"_") require.Nil(t, err) _, err = fp.WriteString(s) diff --git a/x/auth/client/cli/broadcast.go b/x/auth/client/cli/broadcast.go index 216820178306..89c902febce6 100644 --- a/x/auth/client/cli/broadcast.go +++ b/x/auth/client/cli/broadcast.go @@ -12,7 +12,7 @@ import ( ) // GetBroadcastCommand returns the tx broadcast command. -func GetBroadcastCommand(clientCtx client.Context) *cobra.Command { +func GetBroadcastCommand() *cobra.Command { cmd := &cobra.Command{ Use: "broadcast [file_path]", Short: "Broadcast transactions generated offline", @@ -25,7 +25,7 @@ $ tx broadcast ./mytxn.json `), Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - clientCtx = clientCtx.Init() + clientCtx := client.GetClientContextFromCmd(cmd) if offline, _ := cmd.Flags().GetBool(flags.FlagOffline); offline { return errors.New("cannot broadcast tx during offline mode") diff --git a/x/auth/client/cli/broadcast_test.go b/x/auth/client/cli/broadcast_test.go deleted file mode 100644 index fee6de1c2a14..000000000000 --- a/x/auth/client/cli/broadcast_test.go +++ /dev/null @@ -1,46 +0,0 @@ -package cli - -import ( - "fmt" - "io/ioutil" - "path/filepath" - "testing" - - "github.com/stretchr/testify/require" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" - simappparams "github.com/cosmos/cosmos-sdk/simapp/params" - "github.com/cosmos/cosmos-sdk/testutil" -) - -func TestGetBroadcastCommand_OfflineFlag(t *testing.T) { - clientCtx := client.Context{}.WithOffline(true) - clientCtx = clientCtx.WithTxGenerator(simappparams.MakeEncodingConfig().TxGenerator) - - cmd := GetBroadcastCommand(clientCtx) - _ = testutil.ApplyMockIODiscardOutErr(cmd) - cmd.SetArgs([]string{fmt.Sprintf("--%s=true", flags.FlagOffline), ""}) - - require.EqualError(t, cmd.Execute(), "cannot broadcast tx during offline mode") -} - -func TestGetBroadcastCommand_WithoutOfflineFlag(t *testing.T) { - clientCtx := client.Context{} - clientCtx = clientCtx.WithTxGenerator(simappparams.MakeEncodingConfig().TxGenerator) - cmd := GetBroadcastCommand(clientCtx) - - testDir, cleanFunc := testutil.NewTestCaseDir(t) - t.Cleanup(cleanFunc) - - // Create new file with tx - txContents := []byte("{\"type\":\"cosmos-sdk/StdTx\",\"value\":{\"msg\":[{\"type\":\"cosmos-sdk/MsgSend\",\"value\":{\"from_address\":\"cosmos1cxlt8kznps92fwu3j6npahx4mjfutydyene2qw\",\"to_address\":\"cosmos1wc8mpr8m3sy3ap3j7fsgqfzx36um05pystems4\",\"amount\":[{\"denom\":\"stake\",\"amount\":\"10000\"}]}}],\"fee\":{\"amount\":[],\"gas\":\"200000\"},\"signatures\":null,\"memo\":\"\"}}") - txFileName := filepath.Join(testDir, "tx.json") - err := ioutil.WriteFile(txFileName, txContents, 0644) - require.NoError(t, err) - - err = cmd.RunE(cmd, []string{txFileName}) - - // We test it tries to broadcast but we set unsupported tx to get the error. - require.EqualError(t, err, "unsupported return type ; supported types: sync, async, block") -} diff --git a/x/auth/client/cli/cli_test.go b/x/auth/client/cli/cli_test.go index 5b0ea986b55f..750df016df46 100644 --- a/x/auth/client/cli/cli_test.go +++ b/x/auth/client/cli/cli_test.go @@ -1,452 +1,677 @@ -// +build cli_test - package cli_test import ( + "context" "fmt" + "io/ioutil" + "path/filepath" "strings" "testing" + "time" "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + tmcrypto "github.com/tendermint/tendermint/crypto" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/tests" + codec2 "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/crypto/hd" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + "github.com/cosmos/cosmos-sdk/crypto/types/multisig" + simappparams "github.com/cosmos/cosmos-sdk/simapp/params" "github.com/cosmos/cosmos-sdk/tests/cli" - sdktestutil "github.com/cosmos/cosmos-sdk/testutil" + "github.com/cosmos/cosmos-sdk/testutil" + "github.com/cosmos/cosmos-sdk/testutil/network" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth/client/testutil" + cli2 "github.com/cosmos/cosmos-sdk/x/auth/client/cli" + authtest "github.com/cosmos/cosmos-sdk/x/auth/client/testutil" + "github.com/cosmos/cosmos-sdk/x/auth/types" bankcli "github.com/cosmos/cosmos-sdk/x/bank/client/testutil" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" ) -func TestCLIValidateSignatures(t *testing.T) { - t.SkipNow() - t.Parallel() - f := cli.InitFixtures(t) - - // start simd server - proc := f.SDStart() - t.Cleanup(func() { proc.Stop(false) }) +type IntegrationTestSuite struct { + suite.Suite - f.ValidateGenesis() + cfg network.Config + network *network.Network +} - fooAddr := f.KeyAddress(cli.KeyFoo) - barAddr := f.KeyAddress(cli.KeyBar) +func (s *IntegrationTestSuite) SetupSuite() { + s.T().Log("setting up integration test suite") - // generate sendTx with default gas - success, stdout, stderr := bankcli.TxSend(f, fooAddr.String(), barAddr, sdk.NewInt64Coin("stake", 10), "--generate-only") - require.True(t, success) - require.Empty(t, stderr) + cfg := network.DefaultConfig() + cfg.NumValidators = 1 - // write unsigned tx to file - unsignedTxFile, cleanup := sdktestutil.WriteToNewTempFile(t, stdout) - t.Cleanup(cleanup) + s.cfg = cfg + s.network = network.New(s.T(), cfg) - // validate we can successfully sign - success, stdout, _ = testutil.TxSign(f, cli.KeyFoo, unsignedTxFile.Name()) - require.True(t, success) + _, err := s.network.WaitForHeight(1) + s.Require().NoError(err) +} - stdTx := cli.UnmarshalStdTx(t, f.Cdc, stdout) +func (s *IntegrationTestSuite) TearDownSuite() { + s.T().Log("tearing down integration test suite") + s.network.Cleanup() +} - require.Equal(t, len(stdTx.Msgs), 1) - require.Equal(t, 1, len(stdTx.GetSignatures())) - require.Equal(t, fooAddr.String(), stdTx.GetSigners()[0].String()) +func (s *IntegrationTestSuite) TestCLIValidateSignatures() { + val := s.network.Validators[0] + res, err := bankcli.MsgSendExec( + val.ClientCtx, + val.Address, + val.Address, + sdk.NewCoins( + sdk.NewCoin(fmt.Sprintf("%stoken", val.Moniker), sdk.NewInt(10)), + sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10)), + ), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + fmt.Sprintf("--%s=true", flags.FlagGenerateOnly), + ) + s.Require().NoError(err) + + var tx types.StdTx + err = val.ClientCtx.JSONMarshaler.UnmarshalJSON(res.Bytes(), &tx) + s.Require().NoError(err) - // write signed tx to file - signedTxFile, cleanup := sdktestutil.WriteToNewTempFile(t, stdout) - t.Cleanup(cleanup) + // write unsigned tx to file + unsignedTx, cleanup := testutil.WriteToNewTempFile(s.T(), res.String()) + defer cleanup() - // validate signatures - success, _, _ = testutil.TxValidateSignatures(f, signedTxFile.Name()) - require.True(t, success) + res, err = authtest.TxSignExec(val.ClientCtx, val.Address, unsignedTx.Name()) + s.Require().NoError(err) - // modify the transaction - stdTx.Memo = "MODIFIED-ORIGINAL-TX-BAD" - bz := cli.MarshalStdTx(t, f.Cdc, stdTx) - modSignedTxFile, cleanup := sdktestutil.WriteToNewTempFile(t, string(bz)) - t.Cleanup(cleanup) + var signedTx types.StdTx + err = val.ClientCtx.JSONMarshaler.UnmarshalJSON(res.Bytes(), &signedTx) + s.Require().NoError(err) - // validate signature validation failure due to different transaction sig bytes - success, _, _ = testutil.TxValidateSignatures(f, modSignedTxFile.Name()) - require.False(t, success) + signedTxFile, cleanup := testutil.WriteToNewTempFile(s.T(), res.String()) + defer cleanup() - // Cleanup testing directories - f.Cleanup() -} + res, err = authtest.TxValidateSignaturesExec(val.ClientCtx, signedTxFile.Name()) + s.Require().NoError(err) -func TestCLISignBatch(t *testing.T) { - t.SkipNow() - t.Parallel() - f := cli.InitFixtures(t) + signedTx.Memo = "MODIFIED STD TX" + bz, err := val.ClientCtx.JSONMarshaler.MarshalJSON(signedTx) + s.Require().NoError(err) - fooAddr := f.KeyAddress(cli.KeyFoo) - barAddr := f.KeyAddress(cli.KeyBar) + modifiedTxFile, cleanup := testutil.WriteToNewTempFile(s.T(), string(bz)) + defer cleanup() - sendTokens := sdk.TokensFromConsensusPower(10) - success, generatedStdTx, stderr := bankcli.TxSend(f, fooAddr.String(), barAddr, sdk.NewCoin(cli.Denom, sendTokens), "--generate-only") + res, err = authtest.TxValidateSignaturesExec(val.ClientCtx, modifiedTxFile.Name()) + s.Require().EqualError(err, "signatures validation failed") +} - require.True(t, success) - require.Empty(t, stderr) +func (s *IntegrationTestSuite) TestCLISignBatch() { + val := s.network.Validators[0] + generatedStd, err := bankcli.MsgSendExec( + val.ClientCtx, + val.Address, + val.Address, + sdk.NewCoins( + sdk.NewCoin(fmt.Sprintf("%stoken", val.Moniker), sdk.NewInt(10)), + sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10)), + ), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + fmt.Sprintf("--%s=true", flags.FlagGenerateOnly), + ) + + s.Require().NoError(err) // Write the output to disk - batchfile, cleanup1 := sdktestutil.WriteToNewTempFile(t, strings.Repeat(generatedStdTx, 3)) - t.Cleanup(cleanup1) + filename, cleanup1 := testutil.WriteToNewTempFile(s.T(), strings.Repeat(generatedStd.String(), 3)) + defer cleanup1() // sign-batch file - offline is set but account-number and sequence are not - success, _, stderr = testutil.TxSignBatch(f, cli.KeyFoo, batchfile.Name(), "--offline") - require.Contains(t, stderr, "required flag(s) \"account-number\", \"sequence\" not set") - require.False(t, success) + val.ClientCtx.HomeDir = strings.Replace(val.ClientCtx.HomeDir, "simd", "simcli", 1) + res, err := authtest.TxSignBatchExec(val.ClientCtx, val.Address, filename.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--offline") + s.Require().EqualError(err, "required flag(s) \"account-number\", \"sequence\" not set") // sign-batch file - success, stdout, stderr := testutil.TxSignBatch(f, cli.KeyFoo, batchfile.Name()) - require.True(t, success) - require.Empty(t, stderr) - require.Equal(t, 3, len(strings.Split(strings.Trim(stdout, "\n"), "\n"))) + res, err = authtest.TxSignBatchExec(val.ClientCtx, val.Address, filename.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID)) + s.Require().NoError(err) + s.Require().Equal(3, len(strings.Split(strings.Trim(res.String(), "\n"), "\n"))) // sign-batch file - success, stdout, stderr = testutil.TxSignBatch(f, cli.KeyFoo, batchfile.Name(), "--signature-only") - require.True(t, success) - require.Empty(t, stderr) - require.Equal(t, 3, len(strings.Split(strings.Trim(stdout, "\n"), "\n"))) + res, err = authtest.TxSignBatchExec(val.ClientCtx, val.Address, filename.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--signature-only") + s.Require().NoError(err) + s.Require().Equal(3, len(strings.Split(strings.Trim(res.String(), "\n"), "\n"))) - malformedFile, cleanup2 := sdktestutil.WriteToNewTempFile(t, fmt.Sprintf("%smalformed", generatedStdTx)) - t.Cleanup(cleanup2) + // Sign batch malformed tx file. + malformedFile, cleanup2 := testutil.WriteToNewTempFile(s.T(), fmt.Sprintf("%smalformed", generatedStd)) + defer cleanup2() - // sign-batch file - success, stdout, stderr = testutil.TxSignBatch(f, cli.KeyFoo, malformedFile.Name()) - require.False(t, success) - require.Equal(t, 1, len(strings.Split(strings.Trim(stdout, "\n"), "\n"))) - require.Equal(t, "ERROR: cannot parse disfix JSON wrapper: invalid character 'm' looking for beginning of value\n", stderr) + res, err = authtest.TxSignBatchExec(val.ClientCtx, val.Address, malformedFile.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID)) + s.Require().EqualError(err, "cannot parse disfix JSON wrapper: invalid character 'm' looking for beginning of value") - // sign-batch file - success, stdout, _ = testutil.TxSignBatch(f, cli.KeyFoo, malformedFile.Name(), "--signature-only") - require.False(t, success) - require.Equal(t, 1, len(strings.Split(strings.Trim(stdout, "\n"), "\n"))) - - f.Cleanup() + // Sign batch malformed tx file signature only. + res, err = authtest.TxSignBatchExec(val.ClientCtx, val.Address, malformedFile.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--signature-only") + s.Require().EqualError(err, "cannot parse disfix JSON wrapper: invalid character 'm' looking for beginning of value") } -func TestCLISendGenerateSignAndBroadcast(t *testing.T) { - t.SkipNow() - t.Parallel() - f := cli.InitFixtures(t) - - // start simd server - proc := f.SDStart() - t.Cleanup(func() { proc.Stop(false) }) +func (s *IntegrationTestSuite) TestCLISendGenerateSignAndBroadcast() { + val1 := s.network.Validators[0] - fooAddr := f.KeyAddress(cli.KeyFoo) - barAddr := f.KeyAddress(cli.KeyBar) + account, _, err := val1.ClientCtx.Keyring.NewMnemonic("newAccount", keyring.English, sdk.FullFundraiserPath, hd.Secp256k1) + s.Require().NoError(err) - // Test generate sendTx with default gas sendTokens := sdk.TokensFromConsensusPower(10) - success, stdout, stderr := bankcli.TxSend(f, fooAddr.String(), barAddr, sdk.NewCoin(cli.Denom, sendTokens), "--generate-only") - require.True(t, success) - require.Empty(t, stderr) - msg := cli.UnmarshalStdTx(t, f.Cdc, stdout) - require.Equal(t, msg.Fee.Gas, uint64(flags.DefaultGasLimit)) - require.Equal(t, len(msg.Msgs), 1) - require.Equal(t, 0, len(msg.GetSignatures())) - // Test generate sendTx with --gas=$amount - success, stdout, stderr = bankcli.TxSend(f, fooAddr.String(), barAddr, sdk.NewCoin(cli.Denom, sendTokens), "--gas=100", "--generate-only") - require.True(t, success) - require.Empty(t, stderr) + normalGeneratedTx, err := bankcli.MsgSendExec( + val1.ClientCtx, + val1.Address, + account.GetAddress(), + sdk.NewCoins( + sdk.NewCoin(s.cfg.BondDenom, sendTokens), + ), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + fmt.Sprintf("--%s=true", flags.FlagGenerateOnly), + ) + s.Require().NoError(err) + + normalGeneratedStdTx := cli.UnmarshalStdTx(s.T(), val1.ClientCtx.JSONMarshaler, normalGeneratedTx.String()) + s.Require().Equal(normalGeneratedStdTx.Fee.Gas, uint64(flags.DefaultGasLimit)) + s.Require().Equal(len(normalGeneratedStdTx.Msgs), 1) + s.Require().Equal(0, len(normalGeneratedStdTx.GetSignatures())) - msg = cli.UnmarshalStdTx(t, f.Cdc, stdout) - require.Equal(t, msg.Fee.Gas, uint64(100)) - require.Equal(t, len(msg.Msgs), 1) - require.Equal(t, 0, len(msg.GetSignatures())) + // Test generate sendTx with --gas=$amount + limitedGasGeneratedTx, err := bankcli.MsgSendExec( + val1.ClientCtx, + val1.Address, + account.GetAddress(), + sdk.NewCoins( + sdk.NewCoin(s.cfg.BondDenom, sendTokens), + ), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + fmt.Sprintf("--gas=%d", 100), + fmt.Sprintf("--%s=true", flags.FlagGenerateOnly), + ) + s.Require().NoError(err) + + limitedGasStdTx := cli.UnmarshalStdTx(s.T(), val1.ClientCtx.JSONMarshaler, limitedGasGeneratedTx.String()) + s.Require().Equal(limitedGasStdTx.Fee.Gas, uint64(100)) + s.Require().Equal(len(limitedGasStdTx.Msgs), 1) + s.Require().Equal(0, len(limitedGasStdTx.GetSignatures())) // Test generate sendTx, estimate gas - success, stdout, stderr = bankcli.TxSend(f, fooAddr.String(), barAddr, sdk.NewCoin(cli.Denom, sendTokens), "--generate-only") - require.True(t, success) - require.Empty(t, stderr) - msg = cli.UnmarshalStdTx(t, f.Cdc, stdout) - require.True(t, msg.Fee.Gas > 0) - require.Equal(t, len(msg.Msgs), 1) + finalGeneratedTx, err := bankcli.MsgSendExec( + val1.ClientCtx, + val1.Address, + account.GetAddress(), + sdk.NewCoins( + sdk.NewCoin(s.cfg.BondDenom, sendTokens), + ), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + fmt.Sprintf("--gas=%d", flags.DefaultGasLimit), + fmt.Sprintf("--%s=true", flags.FlagGenerateOnly), + ) + s.Require().NoError(err) + + finalStdTx := cli.UnmarshalStdTx(s.T(), val1.ClientCtx.JSONMarshaler, finalGeneratedTx.String()) + s.Require().Equal(uint64(flags.DefaultGasLimit), finalStdTx.Fee.Gas) + s.Require().Equal(len(finalStdTx.Msgs), 1) // Write the output to disk - unsignedTxFile, cleanup := sdktestutil.WriteToNewTempFile(t, stdout) - t.Cleanup(cleanup) + unsignedTxFile, cleanup := testutil.WriteToNewTempFile(s.T(), finalGeneratedTx.String()) + defer cleanup() // Test validate-signatures - success, stdout, _ = testutil.TxValidateSignatures(f, unsignedTxFile.Name()) - require.False(t, success) - require.Equal(t, fmt.Sprintf("Signers:\n 0: %v\n\nSignatures:\n\n", fooAddr.String()), stdout) + res, err := authtest.TxValidateSignaturesExec(val1.ClientCtx, unsignedTxFile.Name()) + s.Require().EqualError(err, "signatures validation failed") + s.Require().True(strings.Contains(res.String(), fmt.Sprintf("Signers:\n 0: %v\n\nSignatures:\n\n", val1.Address.String()))) // Test sign // Does not work in offline mode - success, stdout, stderr = testutil.TxSign(f, cli.KeyFoo, unsignedTxFile.Name(), "--offline") - require.Contains(t, stderr, "required flag(s) \"account-number\", \"sequence\" not set") - require.False(t, success) + res, err = authtest.TxSignExec(val1.ClientCtx, val1.Address, unsignedTxFile.Name(), "--offline") + s.Require().EqualError(err, "required flag(s) \"account-number\", \"sequence\" not set") // But works offline if we set account number and sequence - success, _, _ = testutil.TxSign(f, cli.KeyFoo, unsignedTxFile.Name(), "--offline", "--account-number", "1", "--sequence", "1") - require.True(t, success) + val1.ClientCtx.HomeDir = strings.Replace(val1.ClientCtx.HomeDir, "simd", "simcli", 1) + res, err = authtest.TxSignExec(val1.ClientCtx, val1.Address, unsignedTxFile.Name(), "--offline", "--account-number", "1", "--sequence", "1") + s.Require().NoError(err) // Sign transaction - success, stdout, _ = testutil.TxSign(f, cli.KeyFoo, unsignedTxFile.Name()) - require.True(t, success) - msg = cli.UnmarshalStdTx(t, f.Cdc, stdout) - require.Equal(t, len(msg.Msgs), 1) - require.Equal(t, 1, len(msg.GetSignatures())) - require.Equal(t, fooAddr.String(), msg.GetSigners()[0].String()) + signedTx, err := authtest.TxSignExec(val1.ClientCtx, val1.Address, unsignedTxFile.Name()) + s.Require().NoError(err) + + signedFinalTx := cli.UnmarshalStdTx(s.T(), val1.ClientCtx.JSONMarshaler, signedTx.String()) + s.Require().Equal(len(signedFinalTx.Msgs), 1) + s.Require().Equal(1, len(signedFinalTx.GetSignatures())) + s.Require().Equal(val1.Address.String(), signedFinalTx.GetSigners()[0].String()) // Write the output to disk - signedTxFile, cleanup := sdktestutil.WriteToNewTempFile(t, stdout) - t.Cleanup(cleanup) + signedTxFile, cleanup2 := testutil.WriteToNewTempFile(s.T(), signedTx.String()) + defer cleanup2() - // Test validate-signatures - success, stdout, _ = testutil.TxValidateSignatures(f, signedTxFile.Name()) - require.True(t, success) - require.Equal(t, fmt.Sprintf("Signers:\n 0: %v\n\nSignatures:\n 0: %v\t\t\t[OK]\n\n", fooAddr.String(), - fooAddr.String()), stdout) + // Validate Signature + res, err = authtest.TxValidateSignaturesExec(val1.ClientCtx, signedTxFile.Name()) + s.Require().NoError(err) + s.Require().True(strings.Contains(res.String(), "[OK]")) // Ensure foo has right amount of funds - startTokens := sdk.TokensFromConsensusPower(50) - require.Equal(t, startTokens, bankcli.QueryBalances(f, fooAddr).AmountOf(cli.Denom)) + startTokens := sdk.TokensFromConsensusPower(400) + resp, err := bankcli.QueryBalancesExec(val1.ClientCtx, val1.Address) + s.Require().NoError(err) + + var coins sdk.Coins + err = val1.ClientCtx.JSONMarshaler.UnmarshalJSON(resp.Bytes(), &coins) + s.Require().NoError(err) + s.Require().Equal(startTokens, coins.AmountOf(cli.Denom)) // Test broadcast // Does not work in offline mode - success, _, stderr = testutil.TxBroadcast(f, signedTxFile.Name(), "--offline") - require.Contains(t, stderr, "cannot broadcast tx during offline mode") - require.False(t, success) - tests.WaitForNextNBlocksTM(1, f.Port) - - success, stdout, _ = testutil.TxBroadcast(f, signedTxFile.Name()) - require.True(t, success) - tests.WaitForNextNBlocksTM(1, f.Port) - - // Ensure account state - require.Equal(t, sendTokens, bankcli.QueryBalances(f, barAddr).AmountOf(cli.Denom)) - require.Equal(t, startTokens.Sub(sendTokens), bankcli.QueryBalances(f, fooAddr).AmountOf(cli.Denom)) - - f.Cleanup() -} - -func TestCLIMultisignInsufficientCosigners(t *testing.T) { - t.SkipNow() - t.Parallel() - f := cli.InitFixtures(t) - - // start simd server with minimum fees - proc := f.SDStart() - t.Cleanup(func() { proc.Stop(false) }) - - fooBarBazAddr := f.KeyAddress(cli.KeyFooBarBaz) - barAddr := f.KeyAddress(cli.KeyBar) - - // Send some tokens from one account to the other - success, _, _ := bankcli.TxSend(f, cli.KeyFoo, fooBarBazAddr, sdk.NewInt64Coin(cli.Denom, 10), "-y") - require.True(t, success) - tests.WaitForNextNBlocksTM(1, f.Port) - - // Test generate sendTx with multisig - success, stdout, _ := bankcli.TxSend(f, fooBarBazAddr.String(), barAddr, sdk.NewInt64Coin(cli.Denom, 5), "--generate-only") - require.True(t, success) + res, err = authtest.TxBroadcastExec(val1.ClientCtx, signedTxFile.Name(), "--offline") + s.Require().EqualError(err, "cannot broadcast tx during offline mode") - // Write the output to disk - unsignedTxFile, cleanup := sdktestutil.WriteToNewTempFile(t, stdout) - t.Cleanup(cleanup) - - // Sign with foo's key - success, stdout, _ = testutil.TxSign(f, cli.KeyFoo, unsignedTxFile.Name(), "--multisig", fooBarBazAddr.String(), "-y") - require.True(t, success) + err = waitForNextBlock(s.network) + s.Require().NoError(err) - // Write the output to disk - fooSignatureFile, cleanup := sdktestutil.WriteToNewTempFile(t, stdout) - t.Cleanup(cleanup) + // Broadcast correct transaction. + val1.ClientCtx.BroadcastMode = flags.BroadcastBlock + res, err = authtest.TxBroadcastExec(val1.ClientCtx, signedTxFile.Name()) + s.Require().NoError(err) - // Multisign, not enough signatures - success, stdout, _ = testutil.TxMultisign(f, unsignedTxFile.Name(), cli.KeyFooBarBaz, []string{fooSignatureFile.Name()}) - require.True(t, success) + err = waitForNextBlock(s.network) + s.Require().NoError(err) - // Write the output to disk - signedTxFile, cleanup := sdktestutil.WriteToNewTempFile(t, stdout) - t.Cleanup(cleanup) + // Ensure destiny account state + resp, err = bankcli.QueryBalancesExec(val1.ClientCtx, account.GetAddress()) + s.Require().NoError(err) - // Validate the multisignature - success, _, _ = testutil.TxValidateSignatures(f, signedTxFile.Name()) - require.False(t, success) + err = val1.ClientCtx.JSONMarshaler.UnmarshalJSON(resp.Bytes(), &coins) + s.Require().NoError(err) + s.Require().Equal(sendTokens, coins.AmountOf(cli.Denom)) - // Broadcast the transaction - success, stdOut, _ := testutil.TxBroadcast(f, signedTxFile.Name()) - require.Contains(t, stdOut, "signature verification failed") - require.True(t, success) + // Ensure origin account state + resp, err = bankcli.QueryBalancesExec(val1.ClientCtx, val1.Address) + s.Require().NoError(err) - // Cleanup testing directories - f.Cleanup() + err = val1.ClientCtx.JSONMarshaler.UnmarshalJSON(resp.Bytes(), &coins) + s.Require().NoError(err) + s.Require().Equal(sdk.NewInt(389999990), coins.AmountOf(cli.Denom)) } -func TestCLIEncode(t *testing.T) { - t.SkipNow() - t.Parallel() - f := cli.InitFixtures(t) - - // start simd server - proc := f.SDStart() - t.Cleanup(func() { proc.Stop(false) }) - - // Build a testing transaction and write it to disk - barAddr := f.KeyAddress(cli.KeyBar) - keyAddr := f.KeyAddress(cli.KeyFoo) - - sendTokens := sdk.TokensFromConsensusPower(10) - success, stdout, stderr := bankcli.TxSend(f, keyAddr.String(), barAddr, sdk.NewCoin(cli.Denom, sendTokens), "--generate-only", "--memo", "deadbeef") - require.True(t, success) - require.Empty(t, stderr) - - // Write it to disk - jsonTxFile, cleanup := sdktestutil.WriteToNewTempFile(t, stdout) - t.Cleanup(cleanup) - - // Run the encode command - success, base64Encoded, _ := testutil.TxEncode(f, jsonTxFile.Name()) - require.True(t, success) - trimmedBase64 := strings.Trim(base64Encoded, "\"\n") - // Check that the transaction decodes as expected - success, stdout, stderr = testutil.TxDecode(f, trimmedBase64) - decodedTx := cli.UnmarshalStdTx(t, f.Cdc, stdout) - require.Equal(t, "deadbeef", decodedTx.Memo) +func (s *IntegrationTestSuite) TestCLIMultisignInsufficientCosigners() { + s.T().SkipNow() // TODO check encoding. + val1 := s.network.Validators[0] + + codec := codec2.New() + sdk.RegisterCodec(codec) + banktypes.RegisterCodec(codec) + val1.ClientCtx.Codec = codec + + // Generate 2 accounts and a multisig. + account1, _, err := val1.ClientCtx.Keyring.NewMnemonic("newAccount1", keyring.English, sdk.FullFundraiserPath, hd.Secp256k1) + s.Require().NoError(err) + + account2, _, err := val1.ClientCtx.Keyring.NewMnemonic("newAccount2", keyring.English, sdk.FullFundraiserPath, hd.Secp256k1) + s.Require().NoError(err) + + multi := multisig.NewPubKeyMultisigThreshold(2, []tmcrypto.PubKey{account1.GetPubKey(), account2.GetPubKey()}) + multisigInfo, err := val1.ClientCtx.Keyring.SaveMultisig("multi", multi) + s.Require().NoError(err) + + // Send coins from validator to multisig. + _, err = bankcli.MsgSendExec( + val1.ClientCtx, + val1.Address, + multisigInfo.GetAddress(), + sdk.NewCoins( + sdk.NewInt64Coin(cli.Denom, 10), + ), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + fmt.Sprintf("--gas=%d", flags.DefaultGasLimit), + ) + s.Require().NoError(err) + + err = waitForNextBlock(s.network) + s.Require().NoError(err) + + // Generate multisig transaction. + multiGeneratedTx, err := bankcli.MsgSendExec( + val1.ClientCtx, + multisigInfo.GetAddress(), + val1.Address, + sdk.NewCoins( + sdk.NewInt64Coin(cli.Denom, 5), + ), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + fmt.Sprintf("--%s=true", flags.FlagGenerateOnly), + ) + s.Require().NoError(err) + + // Save tx to file + multiGeneratedTxFile, cleanup := testutil.WriteToNewTempFile(s.T(), multiGeneratedTx.String()) + defer cleanup() + + // Multisign, sign with one signature + val1.ClientCtx.HomeDir = strings.Replace(val1.ClientCtx.HomeDir, "simd", "simcli", 1) + account1Signature, err := authtest.TxSignExec(val1.ClientCtx, account1.GetAddress(), multiGeneratedTxFile.Name(), "--multisig", multisigInfo.GetAddress().String()) + s.Require().NoError(err) + + sign1File, cleanup2 := testutil.WriteToNewTempFile(s.T(), account1Signature.String()) + defer cleanup2() + + multiSigWith1Signature, err := authtest.TxMultiSignExec(val1.ClientCtx, multisigInfo.GetName(), multiGeneratedTxFile.Name(), sign1File.Name()) + s.Require().NoError(err) + + // Save tx to file + multiSigWith1SignatureFile, cleanup3 := testutil.WriteToNewTempFile(s.T(), multiSigWith1Signature.String()) + defer cleanup3() + + exec, err := authtest.TxValidateSignaturesExec(val1.ClientCtx, multiSigWith1SignatureFile.Name()) + s.Require().NoError(err) + + fmt.Printf("%s", exec) } -func TestCLIMultisignSortSignatures(t *testing.T) { - t.SkipNow() - t.Parallel() - f := cli.InitFixtures(t) +func (s *IntegrationTestSuite) TestCLIEncode() { + val1 := s.network.Validators[0] - // start simd server with minimum fees - proc := f.SDStart() - t.Cleanup(func() { proc.Stop(false) }) + sendTokens := sdk.TokensFromConsensusPower(10) - fooBarBazAddr := f.KeyAddress(cli.KeyFooBarBaz) - barAddr := f.KeyAddress(cli.KeyBar) + normalGeneratedTx, err := bankcli.MsgSendExec( + val1.ClientCtx, + val1.Address, + val1.Address, + sdk.NewCoins( + sdk.NewCoin(s.cfg.BondDenom, sendTokens), + ), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + fmt.Sprintf("--%s=true", flags.FlagGenerateOnly), "--memo", "deadbeef", + ) + s.Require().NoError(err) + + // Save tx to file + savedTxFile, cleanup := testutil.WriteToNewTempFile(s.T(), normalGeneratedTx.String()) + defer cleanup() + + // Enconde + encodeExec, err := authtest.TxEncodeExec(val1.ClientCtx, savedTxFile.Name()) + s.Require().NoError(err) + + trimmedBase64 := strings.Trim(encodeExec.String(), "\"\n") + // Check that the transaction decodes as expected - // Send some tokens from one account to the other - success, _, _ := bankcli.TxSend(f, cli.KeyFoo, fooBarBazAddr, sdk.NewInt64Coin(cli.Denom, 10), "-y") - require.True(t, success) - tests.WaitForNextNBlocksTM(1, f.Port) + decodedTx, err := authtest.TxDecodeExec(val1.ClientCtx, trimmedBase64) + s.Require().NoError(err) - // Ensure account balances match expected - require.Equal(t, int64(10), bankcli.QueryBalances(f, fooBarBazAddr).AmountOf(cli.Denom).Int64()) + theTx := cli.UnmarshalStdTx(s.T(), val1.ClientCtx.JSONMarshaler, decodedTx.String()) + s.Require().Equal("deadbeef", theTx.Memo) +} - // Test generate sendTx with multisig - success, stdout, _ := bankcli.TxSend(f, fooBarBazAddr.String(), barAddr, sdk.NewInt64Coin(cli.Denom, 5), "--generate-only") - require.True(t, success) +func (s *IntegrationTestSuite) TestCLIMultisignSortSignatures() { + s.T().SkipNow() + val1 := s.network.Validators[0] + + codec := codec2.New() + sdk.RegisterCodec(codec) + banktypes.RegisterCodec(codec) + val1.ClientCtx.Codec = codec + + // Generate 2 accounts and a multisig. + account1, _, err := val1.ClientCtx.Keyring.NewMnemonic("newAccount1", keyring.English, sdk.FullFundraiserPath, hd.Secp256k1) + s.Require().NoError(err) + + account2, _, err := val1.ClientCtx.Keyring.NewMnemonic("newAccount2", keyring.English, sdk.FullFundraiserPath, hd.Secp256k1) + s.Require().NoError(err) + + multi := multisig.NewPubKeyMultisigThreshold(2, []tmcrypto.PubKey{account1.GetPubKey(), account2.GetPubKey()}) + multisigInfo, err := val1.ClientCtx.Keyring.SaveMultisig("multi", multi) + s.Require().NoError(err) + + // Send coins from validator to multisig. + sendTokens := sdk.NewInt64Coin(cli.Denom, 10) + _, err = bankcli.MsgSendExec( + val1.ClientCtx, + val1.Address, + multisigInfo.GetAddress(), + sdk.NewCoins( + sendTokens, + ), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + fmt.Sprintf("--gas=%d", flags.DefaultGasLimit), + ) + s.Require().NoError(err) + + err = waitForNextBlock(s.network) + s.Require().NoError(err) + + resp, err := bankcli.QueryBalancesExec(val1.ClientCtx, multisigInfo.GetAddress()) + s.Require().NoError(err) + + var coins sdk.Coins + err = val1.ClientCtx.JSONMarshaler.UnmarshalJSON(resp.Bytes(), &coins) + s.Require().NoError(err) + s.Require().Equal(sendTokens.Amount, coins.AmountOf(cli.Denom)) + + // Generate multisig transaction. + multiGeneratedTx, err := bankcli.MsgSendExec( + val1.ClientCtx, + multisigInfo.GetAddress(), + val1.Address, + sdk.NewCoins( + sdk.NewInt64Coin(cli.Denom, 5), + ), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + fmt.Sprintf("--%s=true", flags.FlagGenerateOnly), + ) + s.Require().NoError(err) + + // Save tx to file + multiGeneratedTxFile, cleanup := testutil.WriteToNewTempFile(s.T(), multiGeneratedTx.String()) + defer cleanup() + + // Sign with account1 + val1.ClientCtx.HomeDir = strings.Replace(val1.ClientCtx.HomeDir, "simd", "simcli", 1) + account1Signature, err := authtest.TxSignExec(val1.ClientCtx, account1.GetAddress(), multiGeneratedTxFile.Name(), "--multisig", multisigInfo.GetAddress().String()) + s.Require().NoError(err) + + sign1File, cleanup2 := testutil.WriteToNewTempFile(s.T(), account1Signature.String()) + defer cleanup2() + + // Sign with account1 + account2Signature, err := authtest.TxSignExec(val1.ClientCtx, account2.GetAddress(), multiGeneratedTxFile.Name(), "--multisig", multisigInfo.GetAddress().String()) + s.Require().NoError(err) + + sign2File, cleanup3 := testutil.WriteToNewTempFile(s.T(), account2Signature.String()) + defer cleanup3() + + multiSigWith2Signatures, err := authtest.TxMultiSignExec(val1.ClientCtx, multisigInfo.GetName(), multiGeneratedTxFile.Name(), sign1File.Name(), sign2File.Name()) + s.Require().NoError(err) // Write the output to disk - unsignedTxFile, cleanup := sdktestutil.WriteToNewTempFile(t, stdout) - t.Cleanup(cleanup) - - // Sign with foo's key - success, stdout, _ = testutil.TxSign(f, cli.KeyFoo, unsignedTxFile.Name(), "--multisig", fooBarBazAddr.String()) - require.True(t, success) + signedTxFile, cleanup4 := testutil.WriteToNewTempFile(s.T(), multiSigWith2Signatures.String()) + defer cleanup4() - // Write the output to disk - fooSignatureFile, cleanup := sdktestutil.WriteToNewTempFile(t, stdout) - t.Cleanup(cleanup) + _, err = authtest.TxValidateSignaturesExec(val1.ClientCtx, signedTxFile.Name()) + s.Require().NoError(err) - // Sign with baz's key - success, stdout, _ = testutil.TxSign(f, cli.KeyBaz, unsignedTxFile.Name(), "--multisig", fooBarBazAddr.String()) - require.True(t, success) + val1.ClientCtx.BroadcastMode = flags.BroadcastBlock + _, err = authtest.TxBroadcastExec(val1.ClientCtx, signedTxFile.Name()) + s.Require().NoError(err) - // Write the output to disk - bazSignatureFile, cleanup := sdktestutil.WriteToNewTempFile(t, stdout) - t.Cleanup(cleanup) + err = waitForNextBlock(s.network) + s.Require().NoError(err) +} - // Multisign, keys in different order - success, stdout, _ = testutil.TxMultisign(f, unsignedTxFile.Name(), cli.KeyFooBarBaz, []string{ - bazSignatureFile.Name(), fooSignatureFile.Name()}) - require.True(t, success) +func (s *IntegrationTestSuite) TestCLIMultisign() { + s.T().SkipNow() + val1 := s.network.Validators[0] + + codec := codec2.New() + sdk.RegisterCodec(codec) + banktypes.RegisterCodec(codec) + val1.ClientCtx.Codec = codec + + // Generate 2 accounts and a multisig. + account1, _, err := val1.ClientCtx.Keyring.NewMnemonic("newAccount1", keyring.English, sdk.FullFundraiserPath, hd.Secp256k1) + s.Require().NoError(err) + + account2, _, err := val1.ClientCtx.Keyring.NewMnemonic("newAccount2", keyring.English, sdk.FullFundraiserPath, hd.Secp256k1) + s.Require().NoError(err) + + multi := multisig.NewPubKeyMultisigThreshold(2, []tmcrypto.PubKey{account1.GetPubKey(), account2.GetPubKey()}) + multisigInfo, err := val1.ClientCtx.Keyring.SaveMultisig("multi", multi) + s.Require().NoError(err) + + // Send coins from validator to multisig. + sendTokens := sdk.NewInt64Coin(cli.Denom, 10) + _, err = bankcli.MsgSendExec( + val1.ClientCtx, + val1.Address, + multisigInfo.GetAddress(), + sdk.NewCoins( + sendTokens, + ), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + fmt.Sprintf("--gas=%d", flags.DefaultGasLimit), + ) + + err = waitForNextBlock(s.network) + s.Require().NoError(err) + + resp, err := bankcli.QueryBalancesExec(val1.ClientCtx, multisigInfo.GetAddress()) + s.Require().NoError(err) + + var coins sdk.Coins + err = val1.ClientCtx.JSONMarshaler.UnmarshalJSON(resp.Bytes(), &coins) + s.Require().NoError(err) + s.Require().Equal(sendTokens.Amount, coins.AmountOf(cli.Denom)) + + // Generate multisig transaction. + multiGeneratedTx, err := bankcli.MsgSendExec( + val1.ClientCtx, + multisigInfo.GetAddress(), + val1.Address, + sdk.NewCoins( + sdk.NewInt64Coin(cli.Denom, 5), + ), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + fmt.Sprintf("--%s=true", flags.FlagGenerateOnly), + ) + s.Require().NoError(err) + + // Save tx to file + multiGeneratedTxFile, cleanup := testutil.WriteToNewTempFile(s.T(), multiGeneratedTx.String()) + defer cleanup() + + // Sign with account1 + val1.ClientCtx.HomeDir = strings.Replace(val1.ClientCtx.HomeDir, "simd", "simcli", 1) + account1Signature, err := authtest.TxSignExec(val1.ClientCtx, account1.GetAddress(), multiGeneratedTxFile.Name(), "--multisig", multisigInfo.GetAddress().String()) + s.Require().NoError(err) + + sign1File, cleanup2 := testutil.WriteToNewTempFile(s.T(), account1Signature.String()) + defer cleanup2() + + // Sign with account1 + account2Signature, err := authtest.TxSignExec(val1.ClientCtx, account2.GetAddress(), multiGeneratedTxFile.Name(), "--multisig", multisigInfo.GetAddress().String()) + s.Require().NoError(err) + + sign2File, cleanup3 := testutil.WriteToNewTempFile(s.T(), account2Signature.String()) + defer cleanup3() + + // Does not work in offline mode. + val1.ClientCtx.Offline = true + _, err = authtest.TxMultiSignExec(val1.ClientCtx, multisigInfo.GetName(), multiGeneratedTxFile.Name(), sign1File.Name(), sign2File.Name()) + s.Require().EqualError(err, "couldn't verify signature") + + val1.ClientCtx.Offline = false + multiSigWith2Signatures, err := authtest.TxMultiSignExec(val1.ClientCtx, multisigInfo.GetName(), multiGeneratedTxFile.Name(), sign1File.Name(), sign2File.Name()) + s.Require().NoError(err) // Write the output to disk - signedTxFile, cleanup := sdktestutil.WriteToNewTempFile(t, stdout) - t.Cleanup(cleanup) + signedTxFile, cleanup4 := testutil.WriteToNewTempFile(s.T(), multiSigWith2Signatures.String()) + defer cleanup4() - // Validate the multisignature - success, _, _ = testutil.TxValidateSignatures(f, signedTxFile.Name()) - require.True(t, success) + _, err = authtest.TxValidateSignaturesExec(val1.ClientCtx, signedTxFile.Name()) + s.Require().NoError(err) - // Broadcast the transaction - success, _, _ = testutil.TxBroadcast(f, signedTxFile.Name()) - require.True(t, success) + val1.ClientCtx.BroadcastMode = flags.BroadcastBlock + _, err = authtest.TxBroadcastExec(val1.ClientCtx, signedTxFile.Name()) + s.Require().NoError(err) - // Cleanup testing directories - f.Cleanup() + err = waitForNextBlock(s.network) + s.Require().NoError(err) } -func TestCLIMultisign(t *testing.T) { - t.SkipNow() - t.Parallel() - f := cli.InitFixtures(t) - - // start simd server with minimum fees - proc := f.SDStart() - t.Cleanup(func() { proc.Stop(false) }) - - fooBarBazAddr := f.KeyAddress(cli.KeyFooBarBaz) - bazAddr := f.KeyAddress(cli.KeyBaz) +func TestGetBroadcastCommand_OfflineFlag(t *testing.T) { + clientCtx := client.Context{}.WithOffline(true) + clientCtx = clientCtx.WithTxGenerator(simappparams.MakeEncodingConfig().TxGenerator) - // Send some tokens from one account to the other - success, _, _ := bankcli.TxSend(f, cli.KeyFoo, fooBarBazAddr, sdk.NewInt64Coin(cli.Denom, 10), "-y") - require.True(t, success) - tests.WaitForNextNBlocksTM(1, f.Port) + cmd := cli2.GetBroadcastCommand() + _ = testutil.ApplyMockIODiscardOutErr(cmd) + cmd.SetArgs([]string{fmt.Sprintf("--%s=true", flags.FlagOffline), ""}) - // Ensure account balances match expected - require.Equal(t, int64(10), bankcli.QueryBalances(f, fooBarBazAddr).AmountOf(cli.Denom).Int64()) - - // Test generate sendTx with multisig - success, stdout, stderr := bankcli.TxSend(f, fooBarBazAddr.String(), bazAddr, sdk.NewInt64Coin(cli.Denom, 10), "--generate-only") - require.True(t, success) - require.Empty(t, stderr) - - // Write the output to disk - unsignedTxFile, cleanup := sdktestutil.WriteToNewTempFile(t, stdout) - t.Cleanup(cleanup) + require.EqualError(t, cmd.Execute(), "cannot broadcast tx during offline mode") +} - // Sign with foo's key - success, stdout, _ = testutil.TxSign(f, cli.KeyFoo, unsignedTxFile.Name(), "--multisig", fooBarBazAddr.String(), "-y") - require.True(t, success) +func TestGetBroadcastCommand_WithoutOfflineFlag(t *testing.T) { + clientCtx := client.Context{} + clientCtx = clientCtx.WithTxGenerator(simappparams.MakeEncodingConfig().TxGenerator) - // Write the output to disk - fooSignatureFile, cleanup := sdktestutil.WriteToNewTempFile(t, stdout) - t.Cleanup(cleanup) + ctx := context.Background() + ctx = context.WithValue(ctx, client.ClientContextKey, &clientCtx) - // Sign with bar's key - success, stdout, _ = testutil.TxSign(f, cli.KeyBar, unsignedTxFile.Name(), "--multisig", fooBarBazAddr.String(), "-y") - require.True(t, success) + cmd := cli2.GetBroadcastCommand() - // Write the output to disk - barSignatureFile, cleanup := sdktestutil.WriteToNewTempFile(t, stdout) - t.Cleanup(cleanup) + testDir, cleanFunc := testutil.NewTestCaseDir(t) + t.Cleanup(cleanFunc) - // Multisign + // Create new file with tx + txContents := []byte("{\"type\":\"cosmos-sdk/StdTx\",\"value\":{\"msg\":[{\"type\":\"cosmos-sdk/MsgSend\",\"value\":{\"from_address\":\"cosmos1cxlt8kznps92fwu3j6npahx4mjfutydyene2qw\",\"to_address\":\"cosmos1wc8mpr8m3sy3ap3j7fsgqfzx36um05pystems4\",\"amount\":[{\"denom\":\"stake\",\"amount\":\"10000\"}]}}],\"fee\":{\"amount\":[],\"gas\":\"200000\"},\"signatures\":null,\"memo\":\"\"}}") + txFileName := filepath.Join(testDir, "tx.json") + err := ioutil.WriteFile(txFileName, txContents, 0644) + require.NoError(t, err) - // Does not work in offline mode - success, stdout, _ = testutil.TxMultisign(f, unsignedTxFile.Name(), cli.KeyFooBarBaz, []string{ - fooSignatureFile.Name(), barSignatureFile.Name()}, "--offline") - require.Contains(t, "couldn't verify signature", stdout) - require.False(t, success) + cmd.SetArgs([]string{txFileName}) + err = cmd.ExecuteContext(ctx) - // Success multisign - success, stdout, _ = testutil.TxMultisign(f, unsignedTxFile.Name(), cli.KeyFooBarBaz, []string{ - fooSignatureFile.Name(), barSignatureFile.Name()}) - require.True(t, success) + // We test it tries to broadcast but we set unsupported tx to get the error. + require.EqualError(t, err, "unsupported return type ; supported types: sync, async, block") +} - // Write the output to disk - signedTxFile, cleanup := sdktestutil.WriteToNewTempFile(t, stdout) - t.Cleanup(cleanup) +func TestIntegrationTestSuite(t *testing.T) { + suite.Run(t, new(IntegrationTestSuite)) +} - // Validate the multisignature - success, _, _ = testutil.TxValidateSignatures(f, signedTxFile.Name()) - require.True(t, success) +func waitForNextBlock(network *network.Network) error { + lastBlock, err := network.LatestHeight() + if err != nil { + return err + } - // Broadcast the transaction - success, _, _ = testutil.TxBroadcast(f, signedTxFile.Name()) - require.True(t, success) + _, err = network.WaitForHeightWithTimeout(lastBlock+1, 10*time.Second) + if err != nil { + return err + } - // Cleanup testing directories - f.Cleanup() + return err } diff --git a/x/auth/client/cli/decode.go b/x/auth/client/cli/decode.go index 661108c80eab..8d11e8805af8 100644 --- a/x/auth/client/cli/decode.go +++ b/x/auth/client/cli/decode.go @@ -14,13 +14,13 @@ const flagHex = "hex" // GetDecodeCommand returns the decode command to take serialized bytes and turn // it into a JSON-encoded transaction. -func GetDecodeCommand(clientCtx client.Context) *cobra.Command { +func GetDecodeCommand() *cobra.Command { cmd := &cobra.Command{ Use: "decode [amino-byte-string]", Short: "Decode an binary encoded transaction string.", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) (err error) { - clientCtx = clientCtx.Init().WithOutput(cmd.OutOrStdout()) + clientCtx := client.GetClientContextFromCmd(cmd) var txBytes []byte if useHex, _ := cmd.Flags().GetBool(flagHex); useHex { diff --git a/x/auth/client/cli/encode.go b/x/auth/client/cli/encode.go index 0f425a9c00ab..d73e6aa78849 100644 --- a/x/auth/client/cli/encode.go +++ b/x/auth/client/cli/encode.go @@ -19,7 +19,7 @@ func (txr txEncodeRespStr) String() string { // GetEncodeCommand returns the encode command to take a JSONified transaction and turn it into // Amino-serialized bytes -func GetEncodeCommand(clientCtx client.Context) *cobra.Command { +func GetEncodeCommand() *cobra.Command { cmd := &cobra.Command{ Use: "encode [file]", Short: "Encode transactions generated offline", @@ -28,15 +28,15 @@ Read a transaction from , serialize it to the Amino wire protocol, and out If you supply a dash (-) argument in place of an input filename, the command reads from standard input.`, Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - cliCtx := clientCtx.Init() + clientCtx := client.GetClientContextFromCmd(cmd) - tx, err := authclient.ReadTxFromFile(cliCtx, args[0]) + tx, err := authclient.ReadTxFromFile(clientCtx, args[0]) if err != nil { return err } // re-encode it - txBytes, err := cliCtx.TxGenerator.TxEncoder()(tx) + txBytes, err := clientCtx.TxGenerator.TxEncoder()(tx) if err != nil { return err } diff --git a/x/auth/client/cli/encode_test.go b/x/auth/client/cli/encode_test.go index 550e1133cc96..cbb5b0a1827b 100644 --- a/x/auth/client/cli/encode_test.go +++ b/x/auth/client/cli/encode_test.go @@ -1,6 +1,7 @@ package cli import ( + "context" "encoding/base64" "testing" @@ -15,11 +16,8 @@ import ( func TestGetCommandEncode(t *testing.T) { encodingConfig := simappparams.MakeEncodingConfig() - clientCtx := client.Context{}. - WithTxGenerator(encodingConfig.TxGenerator). - WithJSONMarshaler(encodingConfig.Marshaler) - cmd := GetEncodeCommand(clientCtx) + cmd := GetEncodeCommand() _ = testutil.ApplyMockIODiscardOutErr(cmd) authtypes.RegisterCodec(encodingConfig.Amino) @@ -37,7 +35,14 @@ func TestGetCommandEncode(t *testing.T) { txFileName := txFile.Name() t.Cleanup(cleanup) - err = cmd.RunE(cmd, []string{txFileName}) + ctx := context.Background() + clientCtx := client.Context{}. + WithTxGenerator(encodingConfig.TxGenerator). + WithJSONMarshaler(encodingConfig.Marshaler) + ctx = context.WithValue(ctx, client.ClientContextKey, &clientCtx) + + cmd.SetArgs([]string{txFileName}) + err = cmd.ExecuteContext(ctx) require.NoError(t, err) } @@ -48,7 +53,7 @@ func TestGetCommandDecode(t *testing.T) { WithTxGenerator(encodingConfig.TxGenerator). WithJSONMarshaler(encodingConfig.Marshaler) - cmd := GetDecodeCommand(clientCtx) + cmd := GetDecodeCommand() _ = testutil.ApplyMockIODiscardOutErr(cmd) sdk.RegisterCodec(encodingConfig.Amino) @@ -67,7 +72,10 @@ func TestGetCommandDecode(t *testing.T) { // Convert the transaction into base64 encoded string base64Encoded := base64.StdEncoding.EncodeToString(txBytes) + ctx := context.Background() + ctx = context.WithValue(ctx, client.ClientContextKey, &clientCtx) + // Execute the command cmd.SetArgs([]string{base64Encoded}) - require.NoError(t, cmd.Execute()) + require.NoError(t, cmd.ExecuteContext(ctx)) } diff --git a/x/auth/client/cli/tx.go b/x/auth/client/cli/tx.go index 9bc30f396ec0..42b20ae8d5f3 100644 --- a/x/auth/client/cli/tx.go +++ b/x/auth/client/cli/tx.go @@ -8,7 +8,7 @@ import ( ) // GetTxCmd returns the transaction commands for this module -func GetTxCmd(clientCtx client.Context) *cobra.Command { +func GetTxCmd() *cobra.Command { txCmd := &cobra.Command{ Use: types.ModuleName, Short: "Auth transaction subcommands", @@ -17,10 +17,10 @@ func GetTxCmd(clientCtx client.Context) *cobra.Command { RunE: client.ValidateCmd, } txCmd.AddCommand( - GetMultiSignCommand(clientCtx), - GetSignCommand(clientCtx), - GetValidateSignaturesCommand(clientCtx), - GetSignBatchCommand(clientCtx.Codec), + GetMultiSignCommand(), + GetSignCommand(), + GetValidateSignaturesCommand(), + GetSignBatchCommand(), ) return txCmd } diff --git a/x/auth/client/cli/tx_multisign.go b/x/auth/client/cli/tx_multisign.go index 48227e6caf55..0633e43c73e6 100644 --- a/x/auth/client/cli/tx_multisign.go +++ b/x/auth/client/cli/tx_multisign.go @@ -22,7 +22,7 @@ import ( ) // GetSignCommand returns the sign command -func GetMultiSignCommand(clientCtx client.Context) *cobra.Command { +func GetMultiSignCommand() *cobra.Command { cmd := &cobra.Command{ Use: "multisign [file] [name] [[signature]...]", Short: "Generate multisig signatures for transactions generated offline", @@ -45,20 +45,21 @@ recommended to set such parameters manually. version.AppName, ), ), - RunE: makeMultiSignCmd(clientCtx), + RunE: makeMultiSignCmd(), Args: cobra.MinimumNArgs(3), } cmd.Flags().Bool(flagSigOnly, false, "Print only the generated signature, then exit") cmd.Flags().String(flags.FlagOutputDocument, "", "The document will be written to the given file instead of STDOUT") flags.AddTxFlagsToCmd(cmd) + cmd.Flags().String(flags.FlagChainID, "", "network chain ID") return cmd } -func makeMultiSignCmd(clientCtx client.Context) func(cmd *cobra.Command, args []string) error { +func makeMultiSignCmd() func(cmd *cobra.Command, args []string) error { return func(cmd *cobra.Command, args []string) (err error) { - clientCtx = clientCtx.Init() + clientCtx := client.GetClientContextFromCmd(cmd) cdc := clientCtx.Codec tx, err := authclient.ReadTxFromFile(clientCtx, args[0]) stdTx := tx.(types.StdTx) @@ -67,10 +68,9 @@ func makeMultiSignCmd(clientCtx client.Context) func(cmd *cobra.Command, args [] } backend, _ := cmd.Flags().GetString(flags.FlagKeyringBackend) - homeDir, _ := cmd.Flags().GetString(flags.FlagHome) inBuf := bufio.NewReader(cmd.InOrStdin()) - kb, err := keyring.New(sdk.KeyringServiceName(), backend, homeDir, inBuf) + kb, err := keyring.New(sdk.KeyringServiceName(), backend, clientCtx.HomeDir, inBuf) if err != nil { return } @@ -85,13 +85,13 @@ func makeMultiSignCmd(clientCtx client.Context) func(cmd *cobra.Command, args [] multisigPub := multisigInfo.GetPubKey().(multisig.PubKeyMultisigThreshold) multisigSig := multisig.NewMultisig(len(multisigPub.PubKeys)) - txBldr, err := types.NewTxBuilderFromFlags(inBuf, cmd.Flags(), homeDir) + txBldr, err := types.NewTxBuilderFromFlags(inBuf, cmd.Flags(), clientCtx.HomeDir) if err != nil { return errors.Wrap(err, "error creating tx builder from flags") } if !clientCtx.Offline { - accnum, seq, err := types.NewAccountRetriever(authclient.Codec).GetAccountNumberSequence(clientCtx, multisigInfo.GetAddress()) + accnum, seq, err := types.NewAccountRetriever(clientCtx.JSONMarshaler).GetAccountNumberSequence(clientCtx, multisigInfo.GetAddress()) if err != nil { return err } @@ -148,7 +148,7 @@ func makeMultiSignCmd(clientCtx client.Context) func(cmd *cobra.Command, args [] outputDoc, _ := cmd.Flags().GetString(flags.FlagOutputDocument) if outputDoc == "" { - fmt.Printf("%s\n", json) + cmd.Printf("%s\n", json) return } diff --git a/x/auth/client/cli/tx_sign.go b/x/auth/client/cli/tx_sign.go index f967a5434396..3dc052d12927 100644 --- a/x/auth/client/cli/tx_sign.go +++ b/x/auth/client/cli/tx_sign.go @@ -22,7 +22,7 @@ const ( ) // GetSignBatchCommand returns the transaction sign-batch command. -func GetSignBatchCommand(codec *codec.Codec) *cobra.Command { +func GetSignBatchCommand() *cobra.Command { cmd := &cobra.Command{ Use: "sign-batch [file]", Short: "Sign transaction batch files", @@ -44,25 +44,25 @@ The --multisig= flag generates a signature on behalf of a multisig account key. It implies --signature-only. `, PreRun: preSignCmd, - RunE: makeSignBatchCmd(codec), + RunE: makeSignBatchCmd(), Args: cobra.ExactArgs(1), } cmd.Flags().String(flagMultisig, "", "Address of the multisig account on behalf of which the transaction shall be signed") cmd.Flags().String(flags.FlagOutputDocument, "", "The document will be written to the given file instead of STDOUT") cmd.Flags().Bool(flagSigOnly, true, "Print only the generated signature, then exit") + cmd.Flags().String(flags.FlagChainID, "", "network chain ID") cmd.MarkFlagRequired(flags.FlagFrom) flags.AddTxFlagsToCmd(cmd) return cmd } -func makeSignBatchCmd(cdc *codec.Codec) func(cmd *cobra.Command, args []string) error { +func makeSignBatchCmd() func(cmd *cobra.Command, args []string) error { return func(cmd *cobra.Command, args []string) error { - inBuf := bufio.NewReader(cmd.InOrStdin()) clientCtx := client.GetClientContextFromCmd(cmd) - txBldr, err := types.NewTxBuilderFromFlags(inBuf, cmd.Flags(), clientCtx.HomeDir) + txBldr, err := types.NewTxBuilderFromFlags(bufio.NewReader(cmd.InOrStdin()), cmd.Flags(), clientCtx.HomeDir) if err != nil { return err } @@ -98,7 +98,7 @@ func makeSignBatchCmd(cdc *codec.Codec) func(cmd *cobra.Command, args []string) } } - scanner := authclient.NewBatchScanner(cdc, infile) + scanner := authclient.NewBatchScanner(clientCtx.JSONMarshaler, infile) for sequence := txBldr.Sequence(); scanner.Scan(); sequence++ { var stdTx types.StdTx @@ -107,17 +107,24 @@ func makeSignBatchCmd(cdc *codec.Codec) func(cmd *cobra.Command, args []string) txBldr = txBldr.WithSequence(sequence) if multisigAddr.Empty() { - homeDir, _ := cmd.Flags().GetString(flags.FlagFrom) - stdTx, err = authclient.SignStdTx(txBldr, clientCtx, homeDir, unsignedStdTx, false, true) + from, _ := cmd.Flags().GetString(flags.FlagFrom) + _, fromName, err := client.GetFromFields(txBldr.Keybase(), from, clientCtx.GenerateOnly) + if err != nil { + return fmt.Errorf("error getting account from keybase: %w", err) + } + + stdTx, err = authclient.SignStdTx(txBldr, clientCtx, fromName, unsignedStdTx, false, true) + if err != nil { + return err + } } else { stdTx, err = authclient.SignStdTxWithSignerAddress(txBldr, clientCtx, multisigAddr, clientCtx.GetFromName(), unsignedStdTx, true) + if err != nil { + return err + } } - if err != nil { - return err - } - - json, err := getSignatureJSON(cdc, stdTx, generateSignatureOnly) + json, err := getSignatureJSON(clientCtx.JSONMarshaler, stdTx, generateSignatureOnly) if err != nil { return err } @@ -151,7 +158,7 @@ func setOutputFile(cmd *cobra.Command) (func(), error) { } // GetSignCommand returns the transaction sign command. -func GetSignCommand(clientCtx client.Context) *cobra.Command { +func GetSignCommand() *cobra.Command { cmd := &cobra.Command{ Use: "sign [file]", Short: "Sign transactions generated offline", @@ -171,7 +178,7 @@ key. It implies --signature-only. Full multisig signed transactions may eventual be generated via the 'multisign' command. `, PreRun: preSignCmd, - RunE: makeSignCmd(clientCtx), + RunE: makeSignCmd(), Args: cobra.ExactArgs(1), } @@ -180,6 +187,7 @@ be generated via the 'multisign' command. cmd.Flags().Bool(flagSigOnly, false, "Print only the generated signature, then exit") cmd.Flags().String(flags.FlagOutputDocument, "", "The document will be written to the given file instead of STDOUT") cmd.Flags().String(flags.FlagHome, "", "The application home directory") + cmd.Flags().String(flags.FlagChainID, "", "The network chain ID") cmd.MarkFlagRequired(flags.FlagFrom) flags.AddTxFlagsToCmd(cmd) @@ -195,8 +203,10 @@ func preSignCmd(cmd *cobra.Command, _ []string) { } } -func makeSignCmd(clientCtx client.Context) func(cmd *cobra.Command, args []string) error { +func makeSignCmd() func(cmd *cobra.Command, args []string) error { return func(cmd *cobra.Command, args []string) error { + clientCtx := client.GetClientContextFromCmd(cmd) + clientCtx, txBldr, tx, err := readStdTxAndInitContexts(clientCtx, cmd, args[0]) if err != nil { return err @@ -208,6 +218,12 @@ func makeSignCmd(clientCtx client.Context) func(cmd *cobra.Command, args []strin generateSignatureOnly, _ := cmd.Flags().GetBool(flagSigOnly) multisigAddrStr, _ := cmd.Flags().GetString(flagMultisig) + from, _ := cmd.Flags().GetString(flags.FlagFrom) + _, fromName, err := client.GetFromFields(txBldr.Keybase(), from, clientCtx.GenerateOnly) + if err != nil { + return fmt.Errorf("error getting account from keybase: %w", err) + } + if multisigAddrStr != "" { var multisigAddr sdk.AccAddress @@ -215,28 +231,31 @@ func makeSignCmd(clientCtx client.Context) func(cmd *cobra.Command, args []strin if err != nil { return err } + newTx, err = authclient.SignStdTxWithSignerAddress( - txBldr, clientCtx, multisigAddr, clientCtx.GetFromName(), stdTx, clientCtx.Offline, + txBldr, clientCtx, multisigAddr, fromName, stdTx, clientCtx.Offline, ) generateSignatureOnly = true } else { append, _ := cmd.Flags().GetBool(flagAppend) appendSig := append && !generateSignatureOnly - newTx, err = authclient.SignStdTx(txBldr, clientCtx, clientCtx.GetFromName(), stdTx, appendSig, clientCtx.Offline) + newTx, err = authclient.SignStdTx(txBldr, clientCtx, fromName, stdTx, appendSig, clientCtx.Offline) + if err != nil { + return err + } } - if err != nil { return err } - json, err := getSignatureJSON(clientCtx.Codec, newTx, generateSignatureOnly) + json, err := getSignatureJSON(clientCtx.JSONMarshaler, newTx, generateSignatureOnly) if err != nil { return err } outputDoc, _ := cmd.Flags().GetString(flags.FlagOutputDocument) if outputDoc == "" { - fmt.Printf("%s\n", json) + cmd.Printf("%s\n", json) return nil } @@ -251,7 +270,7 @@ func makeSignCmd(clientCtx client.Context) func(cmd *cobra.Command, args []strin } } -func getSignatureJSON(cdc *codec.Codec, newTx types.StdTx, generateSignatureOnly bool) ([]byte, error) { +func getSignatureJSON(cdc codec.JSONMarshaler, newTx types.StdTx, generateSignatureOnly bool) ([]byte, error) { if generateSignatureOnly { return cdc.MarshalJSON(newTx.Signatures[0]) } diff --git a/x/auth/client/cli/validate_sigs.go b/x/auth/client/cli/validate_sigs.go index 9be473676e08..7d39335b2500 100644 --- a/x/auth/client/cli/validate_sigs.go +++ b/x/auth/client/cli/validate_sigs.go @@ -15,7 +15,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth/types" ) -func GetValidateSignaturesCommand(clientCtx client.Context) *cobra.Command { +func GetValidateSignaturesCommand() *cobra.Command { cmd := &cobra.Command{ Use: "validate-signatures [file]", Short: "Validate transactions signatures", @@ -28,17 +28,19 @@ given transaction. If the --offline flag is also set, signature validation over transaction will be not be performed as that will require RPC communication with a full node. `, PreRun: preSignCmd, - RunE: makeValidateSignaturesCmd(clientCtx), + RunE: makeValidateSignaturesCmd(), Args: cobra.ExactArgs(1), } + cmd.Flags().String(flags.FlagChainID, "", "The network chain ID") flags.AddTxFlagsToCmd(cmd) return cmd } -func makeValidateSignaturesCmd(clientCtx client.Context) func(cmd *cobra.Command, args []string) error { +func makeValidateSignaturesCmd() func(cmd *cobra.Command, args []string) error { return func(cmd *cobra.Command, args []string) error { + clientCtx := client.GetClientContextFromCmd(cmd) clientCtx, txBldr, tx, err := readStdTxAndInitContexts(clientCtx, cmd, args[0]) if err != nil { return err @@ -91,7 +93,7 @@ func printAndValidateSigs( // Validate the actual signature over the transaction bytes since we can // reach out to a full node to query accounts. if !offline && success { - acc, err := types.NewAccountRetriever(authclient.Codec).GetAccount(clientCtx, sigAddr) + acc, err := types.NewAccountRetriever(clientCtx.JSONMarshaler).GetAccount(clientCtx, sigAddr) if err != nil { cmd.Printf("failed to get account: %s\n", sigAddr) return false diff --git a/x/auth/client/testutil/helpers.go b/x/auth/client/testutil/helpers.go index bf460889807b..14f7d8100035 100644 --- a/x/auth/client/testutil/helpers.go +++ b/x/auth/client/testutil/helpers.go @@ -4,57 +4,94 @@ import ( "fmt" "strings" - clientkeys "github.com/cosmos/cosmos-sdk/client/keys" - "github.com/cosmos/cosmos-sdk/tests/cli" + "github.com/cosmos/cosmos-sdk/testutil" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" + "github.com/cosmos/cosmos-sdk/x/auth/client/cli" ) -// TxSign is simcli sign -func TxSign(f *cli.Fixtures, signer, fileName string, flags ...string) (bool, string, string) { - cmd := fmt.Sprintf("%s tx sign %v --keyring-backend=test --from=%s %v", f.SimdBinary, f.Flags(), signer, fileName) +func TxSignExec(clientCtx client.Context, from fmt.Stringer, filename string, extraArgs ...string) (testutil.BufferWriter, error) { + args := []string{ + fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest), + fmt.Sprintf("--from=%s", from.String()), + fmt.Sprintf("--%s=%s", flags.FlagHome, strings.Replace(clientCtx.HomeDir, "simd", "simcli", 1)), + fmt.Sprintf("--%s=%s", flags.FlagChainID, clientCtx.ChainID), + filename, + } + + args = append(args, extraArgs...) - return cli.ExecuteWriteRetStdStreams(f.T, cli.AddFlags(cmd, flags), clientkeys.DefaultKeyPass) + return clitestutil.ExecTestCLICmd(clientCtx, cli.GetSignCommand(), args) } -// TxBroadcast is simcli tx broadcast -func TxBroadcast(f *cli.Fixtures, fileName string, flags ...string) (bool, string, string) { - cmd := fmt.Sprintf("%s tx broadcast %v %v", f.SimdBinary, f.Flags(), fileName) - return cli.ExecuteWriteRetStdStreams(f.T, cli.AddFlags(cmd, flags), clientkeys.DefaultKeyPass) +func TxBroadcastExec(clientCtx client.Context, filename string, extraArgs ...string) (testutil.BufferWriter, error) { + args := []string{ + filename, + } + + args = append(args, extraArgs...) + + return clitestutil.ExecTestCLICmd(clientCtx, cli.GetBroadcastCommand(), args) } -// TxEncode is simcli tx encode -func TxEncode(f *cli.Fixtures, fileName string, flags ...string) (bool, string, string) { - cmd := fmt.Sprintf("%s tx encode %v %v", f.SimdBinary, f.Flags(), fileName) - return cli.ExecuteWriteRetStdStreams(f.T, cli.AddFlags(cmd, flags), clientkeys.DefaultKeyPass) +func TxEncodeExec(clientCtx client.Context, filename string, extraArgs ...string) (testutil.BufferWriter, error) { + args := []string{ + fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest), + filename, + } + + args = append(args, extraArgs...) + + return clitestutil.ExecTestCLICmd(clientCtx, cli.GetEncodeCommand(), args) } -// TxValidateSignatures is simcli tx validate-signatures -func TxValidateSignatures(f *cli.Fixtures, fileName string, flags ...string) (bool, string, string) { - cmd := fmt.Sprintf("%s tx validate-signatures %v --keyring-backend=test %v", f.SimdBinary, - f.Flags(), fileName) +func TxValidateSignaturesExec(clientCtx client.Context, filename string) (testutil.BufferWriter, error) { + args := []string{ + fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest), + fmt.Sprintf("--%s=%s", flags.FlagChainID, clientCtx.ChainID), + filename, + } - return cli.ExecuteWriteRetStdStreams(f.T, cli.AddFlags(cmd, flags), clientkeys.DefaultKeyPass) + return clitestutil.ExecTestCLICmd(clientCtx, cli.GetValidateSignaturesCommand(), args) } -// TxMultisign is simcli tx multisign -func TxMultisign(f *cli.Fixtures, fileName, name string, signaturesFiles []string, - flags ...string) (bool, string, string) { +func TxMultiSignExec(clientCtx client.Context, from string, filename string, extraArgs ...string) (testutil.BufferWriter, error) { + args := []string{ + fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest), + fmt.Sprintf("--%s=%s", flags.FlagChainID, clientCtx.ChainID), + filename, + from, + } + + args = append(args, extraArgs...) - cmd := fmt.Sprintf("%s tx multisign --keyring-backend=test %v %s %s %s", f.SimdBinary, f.Flags(), - fileName, name, strings.Join(signaturesFiles, " "), - ) - return cli.ExecuteWriteRetStdStreams(f.T, cli.AddFlags(cmd, flags)) + return clitestutil.ExecTestCLICmd(clientCtx, cli.GetMultiSignCommand(), args) } -func TxSignBatch(f *cli.Fixtures, signer, fileName string, flags ...string) (bool, string, string) { - cmd := fmt.Sprintf("%s tx sign-batch %v --keyring-backend=test --from=%s %v", f.SimdBinary, f.Flags(), signer, fileName) +func TxSignBatchExec(clientCtx client.Context, from fmt.Stringer, filename string, extraArgs ...string) (testutil.BufferWriter, error) { + args := []string{ + fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest), + fmt.Sprintf("--from=%s", from.String()), + filename, + } + + args = append(args, extraArgs...) - return cli.ExecuteWriteRetStdStreams(f.T, cli.AddFlags(cmd, flags), clientkeys.DefaultKeyPass) + return clitestutil.ExecTestCLICmd(clientCtx, cli.GetSignBatchCommand(), args) } -// TxDecode is simcli tx decode -func TxDecode(f *cli.Fixtures, encodedTx string, flags ...string) (bool, string, string) { - cmd := fmt.Sprintf("%s tx decode %v %v", f.SimdBinary, f.Flags(), encodedTx) - return cli.ExecuteWriteRetStdStreams(f.T, cli.AddFlags(cmd, flags), clientkeys.DefaultKeyPass) +func TxDecodeExec(clientCtx client.Context, encodedTx string, extraArgs ...string) (testutil.BufferWriter, error) { + args := []string{ + fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest), + encodedTx, + } + + args = append(args, extraArgs...) + + return clitestutil.ExecTestCLICmd(clientCtx, cli.GetDecodeCommand(), args) } // DONTCOVER diff --git a/x/auth/client/tx.go b/x/auth/client/tx.go index bafdf3b74daf..14f914655070 100644 --- a/x/auth/client/tx.go +++ b/x/auth/client/tx.go @@ -236,7 +236,7 @@ func ReadTxFromFile(ctx client.Context, filename string) (tx sdk.Tx, err error) } // NewBatchScanner returns a new BatchScanner to read newline-delimited StdTx transactions from r. -func NewBatchScanner(cdc *codec.Codec, r io.Reader) *BatchScanner { +func NewBatchScanner(cdc codec.JSONMarshaler, r io.Reader) *BatchScanner { return &BatchScanner{Scanner: bufio.NewScanner(r), cdc: cdc} } @@ -245,7 +245,7 @@ func NewBatchScanner(cdc *codec.Codec, r io.Reader) *BatchScanner { type BatchScanner struct { *bufio.Scanner stdTx authtypes.StdTx - cdc *codec.Codec + cdc codec.JSONMarshaler unmarshalErr error } diff --git a/x/auth/module.go b/x/auth/module.go index 7ef1a83a2493..3bf8136a45ba 100644 --- a/x/auth/module.go +++ b/x/auth/module.go @@ -67,7 +67,7 @@ func (AppModuleBasic) RegisterRESTRoutes(clientCtx client.Context, rtr *mux.Rout // GetTxCmd returns the root tx command for the auth module. func (AppModuleBasic) GetTxCmd(clientCtx client.Context) *cobra.Command { - return cli.GetTxCmd(clientCtx) + return cli.GetTxCmd() } // GetQueryCmd returns the root query command for the auth module. diff --git a/x/auth/types/account_retriever.go b/x/auth/types/account_retriever.go index 295b78e337d0..07bd5e3347a9 100644 --- a/x/auth/types/account_retriever.go +++ b/x/auth/types/account_retriever.go @@ -11,11 +11,11 @@ import ( // AccountRetriever defines the properties of a type that can be used to // retrieve accounts. type AccountRetriever struct { - codec codec.Marshaler + codec codec.JSONMarshaler } // NewAccountRetriever initialises a new AccountRetriever instance. -func NewAccountRetriever(codec codec.Marshaler) AccountRetriever { +func NewAccountRetriever(codec codec.JSONMarshaler) AccountRetriever { return AccountRetriever{codec: codec} } diff --git a/x/bank/client/cli/cli_test.go b/x/bank/client/cli/cli_test.go index 2041ec2d965d..239277b76c4d 100644 --- a/x/bank/client/cli/cli_test.go +++ b/x/bank/client/cli/cli_test.go @@ -280,7 +280,7 @@ func (s *IntegrationTestSuite) TestNewSendTxCmd() { s.Require().Error(err) } else { s.Require().NoError(err) - s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(bz, tc.respType), string(bz)) + s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(bz.Bytes(), tc.respType), bz.String()) txResp := tc.respType.(*sdk.TxResponse) s.Require().Equal(tc.expectedCode, txResp.Code) diff --git a/x/bank/client/testutil/cli_helpers.go b/x/bank/client/testutil/cli_helpers.go index 6ba757e1fd71..b2fd1e22851d 100644 --- a/x/bank/client/testutil/cli_helpers.go +++ b/x/bank/client/testutil/cli_helpers.go @@ -1,11 +1,12 @@ package testutil import ( - "bytes" - "context" - "encoding/json" "fmt" + "github.com/cosmos/cosmos-sdk/testutil" + + clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" + "github.com/stretchr/testify/require" "github.com/cosmos/cosmos-sdk/client" @@ -13,30 +14,21 @@ import ( "github.com/cosmos/cosmos-sdk/tests" "github.com/cosmos/cosmos-sdk/tests/cli" sdk "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" bankcli "github.com/cosmos/cosmos-sdk/x/bank/client/cli" ) -func MsgSendExec(clientCtx client.Context, from, to, amount fmt.Stringer, extraArgs ...string) ([]byte, error) { - buf := new(bytes.Buffer) - clientCtx = clientCtx.WithOutput(buf) - - ctx := context.Background() - ctx = context.WithValue(ctx, client.ClientContextKey, &clientCtx) - +func MsgSendExec(clientCtx client.Context, from, to, amount fmt.Stringer, extraArgs ...string) (testutil.BufferWriter, error) { args := []string{from.String(), to.String(), amount.String()} args = append(args, extraArgs...) - cmd := bankcli.NewSendTxCmd() - cmd.SetErr(buf) - cmd.SetOut(buf) - cmd.SetArgs(args) + return clitestutil.ExecTestCLICmd(clientCtx, bankcli.NewSendTxCmd(), args) +} - if err := cmd.ExecuteContext(ctx); err != nil { - return nil, err - } +func QueryBalancesExec(clientCtx client.Context, address fmt.Stringer, extraArgs ...string) (testutil.BufferWriter, error) { + args := []string{address.String()} + args = append(args, extraArgs...) - return buf.Bytes(), nil + return clitestutil.ExecTestCLICmd(clientCtx, bankcli.GetBalancesCmd(), args) } // ---------------------------------------------------------------------------- @@ -51,24 +43,6 @@ func TxSend(f *cli.Fixtures, from string, to sdk.AccAddress, amount sdk.Coin, fl return cli.ExecuteWriteRetStdStreams(f.T, cli.AddFlags(cmd, flags), clientkeys.DefaultKeyPass) } -// QueryAccount is simcli query account -func QueryAccount(f *cli.Fixtures, address sdk.AccAddress, flags ...string) authtypes.BaseAccount { - cmd := fmt.Sprintf("%s query account %s %v", f.SimdBinary, address, f.Flags()) - - out, _ := tests.ExecuteT(f.T, cli.AddFlags(cmd, flags), "") - - var initRes map[string]json.RawMessage - err := json.Unmarshal([]byte(out), &initRes) - require.NoError(f.T, err, "out %v, err %v", out, err) - value := initRes["value"] - - var acc authtypes.BaseAccount - err = f.Cdc.UnmarshalJSON(value, &acc) - require.NoError(f.T, err, "value %v, err %v", string(value), err) - - return acc -} - // QueryBalances executes the bank query balances command for a given address and // flag set. func QueryBalances(f *cli.Fixtures, address sdk.AccAddress, flags ...string) sdk.Coins { @@ -81,26 +55,3 @@ func QueryBalances(f *cli.Fixtures, address sdk.AccAddress, flags ...string) sdk return balances } - -// QueryTotalSupply returns the total supply of coins -func QueryTotalSupply(f *cli.Fixtures, flags ...string) (totalSupply sdk.Coins) { - cmd := fmt.Sprintf("%s query bank total %s", f.SimdBinary, f.Flags()) - res, errStr := tests.ExecuteT(f.T, cmd, "") - require.Empty(f.T, errStr) - - err := f.Cdc.UnmarshalJSON([]byte(res), &totalSupply) - require.NoError(f.T, err) - return totalSupply -} - -// QueryTotalSupplyOf returns the total supply of a given coin denom -func QueryTotalSupplyOf(f *cli.Fixtures, denom string, flags ...string) sdk.Int { - cmd := fmt.Sprintf("%s query bank total %s %s", f.SimdBinary, denom, f.Flags()) - res, errStr := tests.ExecuteT(f.T, cmd, "") - require.Empty(f.T, errStr) - - var supplyOf sdk.Int - err := f.Cdc.UnmarshalJSON([]byte(res), &supplyOf) - require.NoError(f.T, err) - return supplyOf -}