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 <alessio@tendermint.com>
Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com>
Co-authored-by: Alexander Bezobchuk <alexanderbez@users.noreply.github.com>
This commit is contained in:
Jonathan Gimeno 2020-07-14 20:37:14 +02:00 committed by GitHub
parent 5656e8647b
commit 351192aa0b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 762 additions and 539 deletions

View File

@ -129,14 +129,14 @@ func txCommand() *cobra.Command {
} }
cmd.AddCommand( cmd.AddCommand(
authcmd.GetSignCommand(initClientCtx), authcmd.GetSignCommand(),
authcmd.GetSignBatchCommand(encodingConfig.Amino), authcmd.GetSignBatchCommand(),
authcmd.GetMultiSignCommand(initClientCtx), authcmd.GetMultiSignCommand(),
authcmd.GetValidateSignaturesCommand(initClientCtx), authcmd.GetValidateSignaturesCommand(),
flags.LineBreak, flags.LineBreak,
authcmd.GetBroadcastCommand(initClientCtx), authcmd.GetBroadcastCommand(),
authcmd.GetEncodeCommand(initClientCtx), authcmd.GetEncodeCommand(),
authcmd.GetDecodeCommand(initClientCtx), authcmd.GetDecodeCommand(),
flags.LineBreak, flags.LineBreak,
) )

View File

@ -181,7 +181,7 @@ func AddFlags(cmd string, flags []string) string {
return strings.TrimSpace(cmd) 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)) require.Nil(t, c.UnmarshalJSON([]byte(s), &stdTx))
return return
} }

27
testutil/cli/cmd.go Normal file
View File

@ -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
}

View File

@ -65,7 +65,7 @@ func ApplyMockIODiscardOutErr(c *cobra.Command) BufferReader {
// the caller must call to remove the file when it is // the caller must call to remove the file when it is
// no longer needed. // no longer needed.
func WriteToNewTempFile(t testing.TB, s string) (*os.File, func()) { 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) require.Nil(t, err)
_, err = fp.WriteString(s) _, err = fp.WriteString(s)

View File

@ -12,7 +12,7 @@ import (
) )
// GetBroadcastCommand returns the tx broadcast command. // GetBroadcastCommand returns the tx broadcast command.
func GetBroadcastCommand(clientCtx client.Context) *cobra.Command { func GetBroadcastCommand() *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "broadcast [file_path]", Use: "broadcast [file_path]",
Short: "Broadcast transactions generated offline", Short: "Broadcast transactions generated offline",
@ -25,7 +25,7 @@ $ <appcli> tx broadcast ./mytxn.json
`), `),
Args: cobra.ExactArgs(1), Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
clientCtx = clientCtx.Init() clientCtx := client.GetClientContextFromCmd(cmd)
if offline, _ := cmd.Flags().GetBool(flags.FlagOffline); offline { if offline, _ := cmd.Flags().GetBool(flags.FlagOffline); offline {
return errors.New("cannot broadcast tx during offline mode") return errors.New("cannot broadcast tx during offline mode")

View File

@ -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")
}

File diff suppressed because it is too large Load Diff

View File

@ -14,13 +14,13 @@ const flagHex = "hex"
// GetDecodeCommand returns the decode command to take serialized bytes and turn // GetDecodeCommand returns the decode command to take serialized bytes and turn
// it into a JSON-encoded transaction. // it into a JSON-encoded transaction.
func GetDecodeCommand(clientCtx client.Context) *cobra.Command { func GetDecodeCommand() *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "decode [amino-byte-string]", Use: "decode [amino-byte-string]",
Short: "Decode an binary encoded transaction string.", Short: "Decode an binary encoded transaction string.",
Args: cobra.ExactArgs(1), Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) (err error) { RunE: func(cmd *cobra.Command, args []string) (err error) {
clientCtx = clientCtx.Init().WithOutput(cmd.OutOrStdout()) clientCtx := client.GetClientContextFromCmd(cmd)
var txBytes []byte var txBytes []byte
if useHex, _ := cmd.Flags().GetBool(flagHex); useHex { if useHex, _ := cmd.Flags().GetBool(flagHex); useHex {

View File

@ -19,7 +19,7 @@ func (txr txEncodeRespStr) String() string {
// GetEncodeCommand returns the encode command to take a JSONified transaction and turn it into // GetEncodeCommand returns the encode command to take a JSONified transaction and turn it into
// Amino-serialized bytes // Amino-serialized bytes
func GetEncodeCommand(clientCtx client.Context) *cobra.Command { func GetEncodeCommand() *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "encode [file]", Use: "encode [file]",
Short: "Encode transactions generated offline", Short: "Encode transactions generated offline",
@ -28,15 +28,15 @@ Read a transaction from <file>, 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.`, If you supply a dash (-) argument in place of an input filename, the command reads from standard input.`,
Args: cobra.ExactArgs(1), Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error { 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 { if err != nil {
return err return err
} }
// re-encode it // re-encode it
txBytes, err := cliCtx.TxGenerator.TxEncoder()(tx) txBytes, err := clientCtx.TxGenerator.TxEncoder()(tx)
if err != nil { if err != nil {
return err return err
} }

View File

@ -1,6 +1,7 @@
package cli package cli
import ( import (
"context"
"encoding/base64" "encoding/base64"
"testing" "testing"
@ -15,11 +16,8 @@ import (
func TestGetCommandEncode(t *testing.T) { func TestGetCommandEncode(t *testing.T) {
encodingConfig := simappparams.MakeEncodingConfig() encodingConfig := simappparams.MakeEncodingConfig()
clientCtx := client.Context{}.
WithTxGenerator(encodingConfig.TxGenerator).
WithJSONMarshaler(encodingConfig.Marshaler)
cmd := GetEncodeCommand(clientCtx) cmd := GetEncodeCommand()
_ = testutil.ApplyMockIODiscardOutErr(cmd) _ = testutil.ApplyMockIODiscardOutErr(cmd)
authtypes.RegisterCodec(encodingConfig.Amino) authtypes.RegisterCodec(encodingConfig.Amino)
@ -37,7 +35,14 @@ func TestGetCommandEncode(t *testing.T) {
txFileName := txFile.Name() txFileName := txFile.Name()
t.Cleanup(cleanup) 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) require.NoError(t, err)
} }
@ -48,7 +53,7 @@ func TestGetCommandDecode(t *testing.T) {
WithTxGenerator(encodingConfig.TxGenerator). WithTxGenerator(encodingConfig.TxGenerator).
WithJSONMarshaler(encodingConfig.Marshaler) WithJSONMarshaler(encodingConfig.Marshaler)
cmd := GetDecodeCommand(clientCtx) cmd := GetDecodeCommand()
_ = testutil.ApplyMockIODiscardOutErr(cmd) _ = testutil.ApplyMockIODiscardOutErr(cmd)
sdk.RegisterCodec(encodingConfig.Amino) sdk.RegisterCodec(encodingConfig.Amino)
@ -67,7 +72,10 @@ func TestGetCommandDecode(t *testing.T) {
// Convert the transaction into base64 encoded string // Convert the transaction into base64 encoded string
base64Encoded := base64.StdEncoding.EncodeToString(txBytes) base64Encoded := base64.StdEncoding.EncodeToString(txBytes)
ctx := context.Background()
ctx = context.WithValue(ctx, client.ClientContextKey, &clientCtx)
// Execute the command // Execute the command
cmd.SetArgs([]string{base64Encoded}) cmd.SetArgs([]string{base64Encoded})
require.NoError(t, cmd.Execute()) require.NoError(t, cmd.ExecuteContext(ctx))
} }

View File

@ -8,7 +8,7 @@ import (
) )
// GetTxCmd returns the transaction commands for this module // GetTxCmd returns the transaction commands for this module
func GetTxCmd(clientCtx client.Context) *cobra.Command { func GetTxCmd() *cobra.Command {
txCmd := &cobra.Command{ txCmd := &cobra.Command{
Use: types.ModuleName, Use: types.ModuleName,
Short: "Auth transaction subcommands", Short: "Auth transaction subcommands",
@ -17,10 +17,10 @@ func GetTxCmd(clientCtx client.Context) *cobra.Command {
RunE: client.ValidateCmd, RunE: client.ValidateCmd,
} }
txCmd.AddCommand( txCmd.AddCommand(
GetMultiSignCommand(clientCtx), GetMultiSignCommand(),
GetSignCommand(clientCtx), GetSignCommand(),
GetValidateSignaturesCommand(clientCtx), GetValidateSignaturesCommand(),
GetSignBatchCommand(clientCtx.Codec), GetSignBatchCommand(),
) )
return txCmd return txCmd
} }

View File

@ -22,7 +22,7 @@ import (
) )
// GetSignCommand returns the sign command // GetSignCommand returns the sign command
func GetMultiSignCommand(clientCtx client.Context) *cobra.Command { func GetMultiSignCommand() *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "multisign [file] [name] [[signature]...]", Use: "multisign [file] [name] [[signature]...]",
Short: "Generate multisig signatures for transactions generated offline", Short: "Generate multisig signatures for transactions generated offline",
@ -45,20 +45,21 @@ recommended to set such parameters manually.
version.AppName, version.AppName,
), ),
), ),
RunE: makeMultiSignCmd(clientCtx), RunE: makeMultiSignCmd(),
Args: cobra.MinimumNArgs(3), Args: cobra.MinimumNArgs(3),
} }
cmd.Flags().Bool(flagSigOnly, false, "Print only the generated signature, then exit") 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.FlagOutputDocument, "", "The document will be written to the given file instead of STDOUT")
flags.AddTxFlagsToCmd(cmd) flags.AddTxFlagsToCmd(cmd)
cmd.Flags().String(flags.FlagChainID, "", "network chain ID")
return cmd 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) { return func(cmd *cobra.Command, args []string) (err error) {
clientCtx = clientCtx.Init() clientCtx := client.GetClientContextFromCmd(cmd)
cdc := clientCtx.Codec cdc := clientCtx.Codec
tx, err := authclient.ReadTxFromFile(clientCtx, args[0]) tx, err := authclient.ReadTxFromFile(clientCtx, args[0])
stdTx := tx.(types.StdTx) stdTx := tx.(types.StdTx)
@ -67,10 +68,9 @@ func makeMultiSignCmd(clientCtx client.Context) func(cmd *cobra.Command, args []
} }
backend, _ := cmd.Flags().GetString(flags.FlagKeyringBackend) backend, _ := cmd.Flags().GetString(flags.FlagKeyringBackend)
homeDir, _ := cmd.Flags().GetString(flags.FlagHome)
inBuf := bufio.NewReader(cmd.InOrStdin()) 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 { if err != nil {
return return
} }
@ -85,13 +85,13 @@ func makeMultiSignCmd(clientCtx client.Context) func(cmd *cobra.Command, args []
multisigPub := multisigInfo.GetPubKey().(multisig.PubKeyMultisigThreshold) multisigPub := multisigInfo.GetPubKey().(multisig.PubKeyMultisigThreshold)
multisigSig := multisig.NewMultisig(len(multisigPub.PubKeys)) 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 { if err != nil {
return errors.Wrap(err, "error creating tx builder from flags") return errors.Wrap(err, "error creating tx builder from flags")
} }
if !clientCtx.Offline { 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 { if err != nil {
return err return err
} }
@ -148,7 +148,7 @@ func makeMultiSignCmd(clientCtx client.Context) func(cmd *cobra.Command, args []
outputDoc, _ := cmd.Flags().GetString(flags.FlagOutputDocument) outputDoc, _ := cmd.Flags().GetString(flags.FlagOutputDocument)
if outputDoc == "" { if outputDoc == "" {
fmt.Printf("%s\n", json) cmd.Printf("%s\n", json)
return return
} }

View File

@ -22,7 +22,7 @@ const (
) )
// GetSignBatchCommand returns the transaction sign-batch command. // GetSignBatchCommand returns the transaction sign-batch command.
func GetSignBatchCommand(codec *codec.Codec) *cobra.Command { func GetSignBatchCommand() *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "sign-batch [file]", Use: "sign-batch [file]",
Short: "Sign transaction batch files", Short: "Sign transaction batch files",
@ -44,25 +44,25 @@ The --multisig=<multisig_key> flag generates a signature on behalf of a multisig
account key. It implies --signature-only. account key. It implies --signature-only.
`, `,
PreRun: preSignCmd, PreRun: preSignCmd,
RunE: makeSignBatchCmd(codec), RunE: makeSignBatchCmd(),
Args: cobra.ExactArgs(1), 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(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().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().Bool(flagSigOnly, true, "Print only the generated signature, then exit")
cmd.Flags().String(flags.FlagChainID, "", "network chain ID")
cmd.MarkFlagRequired(flags.FlagFrom) cmd.MarkFlagRequired(flags.FlagFrom)
flags.AddTxFlagsToCmd(cmd) flags.AddTxFlagsToCmd(cmd)
return 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 { return func(cmd *cobra.Command, args []string) error {
inBuf := bufio.NewReader(cmd.InOrStdin())
clientCtx := client.GetClientContextFromCmd(cmd) 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 { if err != nil {
return err 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++ { for sequence := txBldr.Sequence(); scanner.Scan(); sequence++ {
var stdTx types.StdTx var stdTx types.StdTx
@ -107,17 +107,24 @@ func makeSignBatchCmd(cdc *codec.Codec) func(cmd *cobra.Command, args []string)
txBldr = txBldr.WithSequence(sequence) txBldr = txBldr.WithSequence(sequence)
if multisigAddr.Empty() { if multisigAddr.Empty() {
homeDir, _ := cmd.Flags().GetString(flags.FlagFrom) from, _ := cmd.Flags().GetString(flags.FlagFrom)
stdTx, err = authclient.SignStdTx(txBldr, clientCtx, homeDir, unsignedStdTx, false, true) _, fromName, err := client.GetFromFields(txBldr.Keybase(), from, clientCtx.GenerateOnly)
} else { if err != nil {
stdTx, err = authclient.SignStdTxWithSignerAddress(txBldr, clientCtx, multisigAddr, clientCtx.GetFromName(), unsignedStdTx, true) return fmt.Errorf("error getting account from keybase: %w", err)
} }
stdTx, err = authclient.SignStdTx(txBldr, clientCtx, fromName, unsignedStdTx, false, true)
if err != nil { if err != nil {
return err return err
} }
} else {
stdTx, err = authclient.SignStdTxWithSignerAddress(txBldr, clientCtx, multisigAddr, clientCtx.GetFromName(), unsignedStdTx, true)
if err != nil {
return err
}
}
json, err := getSignatureJSON(cdc, stdTx, generateSignatureOnly) json, err := getSignatureJSON(clientCtx.JSONMarshaler, stdTx, generateSignatureOnly)
if err != nil { if err != nil {
return err return err
} }
@ -151,7 +158,7 @@ func setOutputFile(cmd *cobra.Command) (func(), error) {
} }
// GetSignCommand returns the transaction sign command. // GetSignCommand returns the transaction sign command.
func GetSignCommand(clientCtx client.Context) *cobra.Command { func GetSignCommand() *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "sign [file]", Use: "sign [file]",
Short: "Sign transactions generated offline", 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. be generated via the 'multisign' command.
`, `,
PreRun: preSignCmd, PreRun: preSignCmd,
RunE: makeSignCmd(clientCtx), RunE: makeSignCmd(),
Args: cobra.ExactArgs(1), 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().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.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.FlagHome, "", "The application home directory")
cmd.Flags().String(flags.FlagChainID, "", "The network chain ID")
cmd.MarkFlagRequired(flags.FlagFrom) cmd.MarkFlagRequired(flags.FlagFrom)
flags.AddTxFlagsToCmd(cmd) 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 { return func(cmd *cobra.Command, args []string) error {
clientCtx := client.GetClientContextFromCmd(cmd)
clientCtx, txBldr, tx, err := readStdTxAndInitContexts(clientCtx, cmd, args[0]) clientCtx, txBldr, tx, err := readStdTxAndInitContexts(clientCtx, cmd, args[0])
if err != nil { if err != nil {
return err return err
@ -208,6 +218,12 @@ func makeSignCmd(clientCtx client.Context) func(cmd *cobra.Command, args []strin
generateSignatureOnly, _ := cmd.Flags().GetBool(flagSigOnly) generateSignatureOnly, _ := cmd.Flags().GetBool(flagSigOnly)
multisigAddrStr, _ := cmd.Flags().GetString(flagMultisig) 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 != "" { if multisigAddrStr != "" {
var multisigAddr sdk.AccAddress var multisigAddr sdk.AccAddress
@ -215,28 +231,31 @@ func makeSignCmd(clientCtx client.Context) func(cmd *cobra.Command, args []strin
if err != nil { if err != nil {
return err return err
} }
newTx, err = authclient.SignStdTxWithSignerAddress( newTx, err = authclient.SignStdTxWithSignerAddress(
txBldr, clientCtx, multisigAddr, clientCtx.GetFromName(), stdTx, clientCtx.Offline, txBldr, clientCtx, multisigAddr, fromName, stdTx, clientCtx.Offline,
) )
generateSignatureOnly = true generateSignatureOnly = true
} else { } else {
append, _ := cmd.Flags().GetBool(flagAppend) append, _ := cmd.Flags().GetBool(flagAppend)
appendSig := append && !generateSignatureOnly 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 { if err != nil {
return err return err
} }
json, err := getSignatureJSON(clientCtx.Codec, newTx, generateSignatureOnly) json, err := getSignatureJSON(clientCtx.JSONMarshaler, newTx, generateSignatureOnly)
if err != nil { if err != nil {
return err return err
} }
outputDoc, _ := cmd.Flags().GetString(flags.FlagOutputDocument) outputDoc, _ := cmd.Flags().GetString(flags.FlagOutputDocument)
if outputDoc == "" { if outputDoc == "" {
fmt.Printf("%s\n", json) cmd.Printf("%s\n", json)
return nil 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 { if generateSignatureOnly {
return cdc.MarshalJSON(newTx.Signatures[0]) return cdc.MarshalJSON(newTx.Signatures[0])
} }

View File

@ -15,7 +15,7 @@ import (
"github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/cosmos/cosmos-sdk/x/auth/types"
) )
func GetValidateSignaturesCommand(clientCtx client.Context) *cobra.Command { func GetValidateSignaturesCommand() *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "validate-signatures [file]", Use: "validate-signatures [file]",
Short: "Validate transactions signatures", 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. transaction will be not be performed as that will require RPC communication with a full node.
`, `,
PreRun: preSignCmd, PreRun: preSignCmd,
RunE: makeValidateSignaturesCmd(clientCtx), RunE: makeValidateSignaturesCmd(),
Args: cobra.ExactArgs(1), Args: cobra.ExactArgs(1),
} }
cmd.Flags().String(flags.FlagChainID, "", "The network chain ID")
flags.AddTxFlagsToCmd(cmd) flags.AddTxFlagsToCmd(cmd)
return 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 { return func(cmd *cobra.Command, args []string) error {
clientCtx := client.GetClientContextFromCmd(cmd)
clientCtx, txBldr, tx, err := readStdTxAndInitContexts(clientCtx, cmd, args[0]) clientCtx, txBldr, tx, err := readStdTxAndInitContexts(clientCtx, cmd, args[0])
if err != nil { if err != nil {
return err return err
@ -91,7 +93,7 @@ func printAndValidateSigs(
// Validate the actual signature over the transaction bytes since we can // Validate the actual signature over the transaction bytes since we can
// reach out to a full node to query accounts. // reach out to a full node to query accounts.
if !offline && success { if !offline && success {
acc, err := types.NewAccountRetriever(authclient.Codec).GetAccount(clientCtx, sigAddr) acc, err := types.NewAccountRetriever(clientCtx.JSONMarshaler).GetAccount(clientCtx, sigAddr)
if err != nil { if err != nil {
cmd.Printf("failed to get account: %s\n", sigAddr) cmd.Printf("failed to get account: %s\n", sigAddr)
return false return false

View File

@ -4,57 +4,94 @@ import (
"fmt" "fmt"
"strings" "strings"
clientkeys "github.com/cosmos/cosmos-sdk/client/keys" "github.com/cosmos/cosmos-sdk/testutil"
"github.com/cosmos/cosmos-sdk/tests/cli"
"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 TxSignExec(clientCtx client.Context, from fmt.Stringer, filename string, extraArgs ...string) (testutil.BufferWriter, error) {
func TxSign(f *cli.Fixtures, signer, fileName string, flags ...string) (bool, string, string) { args := []string{
cmd := fmt.Sprintf("%s tx sign %v --keyring-backend=test --from=%s %v", f.SimdBinary, f.Flags(), signer, fileName) fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest),
fmt.Sprintf("--from=%s", from.String()),
return cli.ExecuteWriteRetStdStreams(f.T, cli.AddFlags(cmd, flags), clientkeys.DefaultKeyPass) fmt.Sprintf("--%s=%s", flags.FlagHome, strings.Replace(clientCtx.HomeDir, "simd", "simcli", 1)),
fmt.Sprintf("--%s=%s", flags.FlagChainID, clientCtx.ChainID),
filename,
} }
// TxBroadcast is simcli tx broadcast args = append(args, extraArgs...)
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 clitestutil.ExecTestCLICmd(clientCtx, cli.GetSignCommand(), args)
return cli.ExecuteWriteRetStdStreams(f.T, cli.AddFlags(cmd, flags), clientkeys.DefaultKeyPass)
} }
// TxEncode is simcli tx encode func TxBroadcastExec(clientCtx client.Context, filename string, extraArgs ...string) (testutil.BufferWriter, error) {
func TxEncode(f *cli.Fixtures, fileName string, flags ...string) (bool, string, string) { args := []string{
cmd := fmt.Sprintf("%s tx encode %v %v", f.SimdBinary, f.Flags(), fileName) filename,
return cli.ExecuteWriteRetStdStreams(f.T, cli.AddFlags(cmd, flags), clientkeys.DefaultKeyPass)
} }
// TxValidateSignatures is simcli tx validate-signatures args = append(args, extraArgs...)
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)
return cli.ExecuteWriteRetStdStreams(f.T, cli.AddFlags(cmd, flags), clientkeys.DefaultKeyPass) return clitestutil.ExecTestCLICmd(clientCtx, cli.GetBroadcastCommand(), args)
} }
// TxMultisign is simcli tx multisign func TxEncodeExec(clientCtx client.Context, filename string, extraArgs ...string) (testutil.BufferWriter, error) {
func TxMultisign(f *cli.Fixtures, fileName, name string, signaturesFiles []string, args := []string{
flags ...string) (bool, string, string) { fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest),
filename,
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))
} }
func TxSignBatch(f *cli.Fixtures, signer, fileName string, flags ...string) (bool, string, string) { args = append(args, extraArgs...)
cmd := fmt.Sprintf("%s tx sign-batch %v --keyring-backend=test --from=%s %v", f.SimdBinary, f.Flags(), signer, fileName)
return cli.ExecuteWriteRetStdStreams(f.T, cli.AddFlags(cmd, flags), clientkeys.DefaultKeyPass) return clitestutil.ExecTestCLICmd(clientCtx, cli.GetEncodeCommand(), args)
} }
// TxDecode is simcli tx decode func TxValidateSignaturesExec(clientCtx client.Context, filename string) (testutil.BufferWriter, error) {
func TxDecode(f *cli.Fixtures, encodedTx string, flags ...string) (bool, string, string) { args := []string{
cmd := fmt.Sprintf("%s tx decode %v %v", f.SimdBinary, f.Flags(), encodedTx) fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest),
return cli.ExecuteWriteRetStdStreams(f.T, cli.AddFlags(cmd, flags), clientkeys.DefaultKeyPass) fmt.Sprintf("--%s=%s", flags.FlagChainID, clientCtx.ChainID),
filename,
}
return clitestutil.ExecTestCLICmd(clientCtx, cli.GetValidateSignaturesCommand(), args)
}
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...)
return clitestutil.ExecTestCLICmd(clientCtx, cli.GetMultiSignCommand(), args)
}
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 clitestutil.ExecTestCLICmd(clientCtx, cli.GetSignBatchCommand(), args)
}
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 // DONTCOVER

View File

@ -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. // 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} return &BatchScanner{Scanner: bufio.NewScanner(r), cdc: cdc}
} }
@ -245,7 +245,7 @@ func NewBatchScanner(cdc *codec.Codec, r io.Reader) *BatchScanner {
type BatchScanner struct { type BatchScanner struct {
*bufio.Scanner *bufio.Scanner
stdTx authtypes.StdTx stdTx authtypes.StdTx
cdc *codec.Codec cdc codec.JSONMarshaler
unmarshalErr error unmarshalErr error
} }

View File

@ -67,7 +67,7 @@ func (AppModuleBasic) RegisterRESTRoutes(clientCtx client.Context, rtr *mux.Rout
// GetTxCmd returns the root tx command for the auth module. // GetTxCmd returns the root tx command for the auth module.
func (AppModuleBasic) GetTxCmd(clientCtx client.Context) *cobra.Command { 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. // GetQueryCmd returns the root query command for the auth module.

View File

@ -11,11 +11,11 @@ import (
// AccountRetriever defines the properties of a type that can be used to // AccountRetriever defines the properties of a type that can be used to
// retrieve accounts. // retrieve accounts.
type AccountRetriever struct { type AccountRetriever struct {
codec codec.Marshaler codec codec.JSONMarshaler
} }
// NewAccountRetriever initialises a new AccountRetriever instance. // NewAccountRetriever initialises a new AccountRetriever instance.
func NewAccountRetriever(codec codec.Marshaler) AccountRetriever { func NewAccountRetriever(codec codec.JSONMarshaler) AccountRetriever {
return AccountRetriever{codec: codec} return AccountRetriever{codec: codec}
} }

View File

@ -280,7 +280,7 @@ func (s *IntegrationTestSuite) TestNewSendTxCmd() {
s.Require().Error(err) s.Require().Error(err)
} else { } else {
s.Require().NoError(err) 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) txResp := tc.respType.(*sdk.TxResponse)
s.Require().Equal(tc.expectedCode, txResp.Code) s.Require().Equal(tc.expectedCode, txResp.Code)

View File

@ -1,11 +1,12 @@
package testutil package testutil
import ( import (
"bytes"
"context"
"encoding/json"
"fmt" "fmt"
"github.com/cosmos/cosmos-sdk/testutil"
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client"
@ -13,30 +14,21 @@ import (
"github.com/cosmos/cosmos-sdk/tests" "github.com/cosmos/cosmos-sdk/tests"
"github.com/cosmos/cosmos-sdk/tests/cli" "github.com/cosmos/cosmos-sdk/tests/cli"
sdk "github.com/cosmos/cosmos-sdk/types" 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" bankcli "github.com/cosmos/cosmos-sdk/x/bank/client/cli"
) )
func MsgSendExec(clientCtx client.Context, from, to, amount fmt.Stringer, extraArgs ...string) ([]byte, error) { func MsgSendExec(clientCtx client.Context, from, to, amount fmt.Stringer, extraArgs ...string) (testutil.BufferWriter, error) {
buf := new(bytes.Buffer)
clientCtx = clientCtx.WithOutput(buf)
ctx := context.Background()
ctx = context.WithValue(ctx, client.ClientContextKey, &clientCtx)
args := []string{from.String(), to.String(), amount.String()} args := []string{from.String(), to.String(), amount.String()}
args = append(args, extraArgs...) args = append(args, extraArgs...)
cmd := bankcli.NewSendTxCmd() return clitestutil.ExecTestCLICmd(clientCtx, bankcli.NewSendTxCmd(), args)
cmd.SetErr(buf)
cmd.SetOut(buf)
cmd.SetArgs(args)
if err := cmd.ExecuteContext(ctx); err != nil {
return nil, err
} }
return buf.Bytes(), nil func QueryBalancesExec(clientCtx client.Context, address fmt.Stringer, extraArgs ...string) (testutil.BufferWriter, error) {
args := []string{address.String()}
args = append(args, extraArgs...)
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) 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 // QueryBalances executes the bank query balances command for a given address and
// flag set. // flag set.
func QueryBalances(f *cli.Fixtures, address sdk.AccAddress, flags ...string) sdk.Coins { 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 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
}