Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: let sign-batch read multiple files #13454

Merged
merged 7 commits into from
Oct 7, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 5 additions & 15 deletions x/auth/client/cli/tx_multisign.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ type BroadcastReq struct {
Mode string `json:"mode" yaml:"mode"`
}

// GetSignCommand returns the sign command
// GetMultiSignCommand returns the multi-sign command
func GetMultiSignCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "multi-sign [file] [name] [[signature]...]",
Expand Down Expand Up @@ -258,21 +258,11 @@ func makeBatchMultisignCmd() func(cmd *cobra.Command, args []string) error {
txFactory = txFactory.WithSignMode(signingtypes.SignMode_SIGN_MODE_LEGACY_AMINO_JSON)
}

infile := os.Stdin
if args[0] != "-" {
infile, err = os.Open(args[0])
defer func() {
err2 := infile.Close()
if err == nil {
err = err2
}
}()

if err != nil {
return fmt.Errorf("couldn't open %s: %w", args[0], err)
}
// reads tx from args[0]
scanner, err := authclient.ReadTxsFromInput(txCfg, args[0])
if err != nil {
return err
}
scanner := authclient.NewBatchScanner(txCfg, infile)

k, err := getMultisigRecord(clientCtx, args[1])
if err != nil {
Expand Down
103 changes: 52 additions & 51 deletions x/auth/client/cli/tx_sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ const (
// GetSignBatchCommand returns the transaction sign-batch command.
func GetSignBatchCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "sign-batch [file]",
Use: "sign-batch [file] ([file2]...)",
Short: "Sign transaction batch files",
Long: `Sign batch files of transactions generated with --generate-only.
The command processes list of transactions from file (one StdTx each line), generate
signed transactions or signatures and print their JSON encoding, delimited by '\n'.
The command processes list of transactions from a file (one StdTx each line), or multiple files.
Then generates signed transactions or signatures and print their JSON encoding, delimited by '\n'.
As the signatures are generated, the command updates the account and sequence number accordingly.

If the --signature-only flag is set, it will output the signature parts only.
Expand All @@ -50,7 +50,7 @@ account key. It implies --signature-only.
`,
PreRun: preSignCmd,
RunE: makeSignBatchCmd(),
Args: cobra.ExactArgs(1),
Args: cobra.MinimumNArgs(1),
}

cmd.Flags().String(flagMultisig, "", "Address or key name of the multisig account on behalf of which the transaction shall be signed")
Expand All @@ -74,7 +74,6 @@ func makeSignBatchCmd() func(cmd *cobra.Command, args []string) error {
txFactory := tx.NewFactoryCLI(clientCtx, cmd.Flags())
txCfg := clientCtx.TxConfig
printSignatureOnly, _ := cmd.Flags().GetBool(flagSigOnly)
infile := os.Stdin

ms, err := cmd.Flags().GetString(flagMultisig)
if err != nil {
Expand All @@ -86,17 +85,14 @@ func makeSignBatchCmd() func(cmd *cobra.Command, args []string) error {
if err != nil {
return err
}

defer closeFunc()
clientCtx.WithOutput(cmd.OutOrStdout())

if args[0] != "-" {
infile, err = os.Open(args[0])
if err != nil {
return err
}
// reads tx from args
scanner, err := authclient.ReadTxsFromInput(txCfg, args...)
if err != nil {
return err
}
scanner := authclient.NewBatchScanner(txCfg, infile)

if !clientCtx.Offline {
if ms == "" {
Expand All @@ -121,9 +117,9 @@ func makeSignBatchCmd() func(cmd *cobra.Command, args []string) error {
}
}

appendMessagesToSingleMsg, _ := cmd.Flags().GetBool(flagAppend)
if appendMessagesToSingleMsg {
// It will combine all tx msgs and create single signed transaction
appendMessagesToSingleTx, _ := cmd.Flags().GetBool(flagAppend)

Check warning

Code scanning / gosec

Returned error is not propagated up the stack.

Returned error is not propagated up the stack.
// Combines all tx msgs and create single signed transaction
if appendMessagesToSingleTx {
txBuilder := clientCtx.TxConfig.NewTxBuilder()
msgs := make([]sdk.Msg, 0)
newGasLimit := uint64(0)
Expand Down Expand Up @@ -151,39 +147,24 @@ func makeSignBatchCmd() func(cmd *cobra.Command, args []string) error {
// set the gasLimit
txBuilder.SetGasLimit(newGasLimit)

// sign the txs
if ms == "" {
from, _ := cmd.Flags().GetString(flags.FlagFrom)
_, fromName, _, err := client.GetFromFields(clientCtx, txFactory.Keybase(), from)
if err != nil {
return fmt.Errorf("error getting account from keybase: %w", err)
}
err = authclient.SignTx(txFactory, clientCtx, fromName, txBuilder, true, true)
if err != nil {
if err := sign(clientCtx, txBuilder, txFactory, from); err != nil {
return err
}
} else {
multisigAddr, _, _, err := client.GetFromFields(clientCtx, txFactory.Keybase(), ms)
if err != nil {
return fmt.Errorf("error getting account from keybase: %w", err)
}
err = authclient.SignTxWithSignerAddress(
txFactory, clientCtx, multisigAddr, clientCtx.GetFromName(), txBuilder, clientCtx.Offline, true)
if err != nil {
if err := multisigSign(clientCtx, txBuilder, txFactory, ms); err != nil {
return err
}
}

if err != nil {
return err
}

json, err := marshalSignatureJSON(txCfg, txBuilder, printSignatureOnly)
if err != nil {
return err
}

cmd.Printf("%s\n", json)

} else {
// It will generate signed tx for each tx
for sequence := txFactory.Sequence(); scanner.Scan(); sequence++ {
Expand All @@ -193,37 +174,23 @@ func makeSignBatchCmd() func(cmd *cobra.Command, args []string) error {
if err != nil {
return err
}

// sign the txs
if ms == "" {
from, _ := cmd.Flags().GetString(flags.FlagFrom)
_, fromName, _, err := client.GetFromFields(clientCtx, txFactory.Keybase(), from)
if err != nil {
return fmt.Errorf("error getting account from keybase: %w", err)
}
err = authclient.SignTx(txFactory, clientCtx, fromName, txBuilder, true, true)
if err != nil {
if err := sign(clientCtx, txBuilder, txFactory, from); err != nil {
return err
}
} else {
multisigAddr, _, _, err := client.GetFromFields(clientCtx, txFactory.Keybase(), ms)
if err != nil {
return fmt.Errorf("error getting account from keybase: %w", err)
}
err = authclient.SignTxWithSignerAddress(
txFactory, clientCtx, multisigAddr, clientCtx.GetFromName(), txBuilder, clientCtx.Offline, true)
if err != nil {
if err := multisigSign(clientCtx, txBuilder, txFactory, ms); err != nil {
return err
}
}

if err != nil {
return err
}

json, err := marshalSignatureJSON(txCfg, txBuilder, printSignatureOnly)
if err != nil {
return err
}

cmd.Printf("%s\n", json)
}
}
Expand All @@ -236,6 +203,40 @@ func makeSignBatchCmd() func(cmd *cobra.Command, args []string) error {
}
}

func sign(clientCtx client.Context, txBuilder client.TxBuilder, txFactory tx.Factory, from string) error {
_, fromName, _, err := client.GetFromFields(clientCtx, txFactory.Keybase(), from)
if err != nil {
return fmt.Errorf("error getting account from keybase: %w", err)
}

if err = authclient.SignTx(txFactory, clientCtx, fromName, txBuilder, true, true); err != nil {
return err
}

return nil
}

func multisigSign(clientCtx client.Context, txBuilder client.TxBuilder, txFactory tx.Factory, multisig string) error {
multisigAddr, _, _, err := client.GetFromFields(clientCtx, txFactory.Keybase(), multisig)
if err != nil {
return fmt.Errorf("error getting account from keybase: %w", err)
}

if err = authclient.SignTxWithSignerAddress(
txFactory,
clientCtx,
multisigAddr,
clientCtx.GetFromName(),
txBuilder,
clientCtx.Offline,
true,
); err != nil {
return err
}

return nil
}

func setOutputFile(cmd *cobra.Command) (func(), error) {
outputDoc, _ := cmd.Flags().GetString(flags.FlagOutputDocument)
if outputDoc == "" {
Expand Down
34 changes: 33 additions & 1 deletion x/auth/client/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ func SignTxWithSignerAddress(txFactory tx.Factory, clientCtx client.Context, add
return tx.Sign(txFactory, name, txBuilder, overwrite)
}

// Read and decode a StdTx from the given filename. Can pass "-" to read from stdin.
// Read and decode a StdTx from the given filename. Can pass "-" to read from stdin.
func ReadTxFromFile(ctx client.Context, filename string) (tx sdk.Tx, err error) {
var bytes []byte

Expand All @@ -107,6 +107,38 @@ func ReadTxFromFile(ctx client.Context, filename string) (tx sdk.Tx, err error)
return ctx.TxConfig.TxJSONDecoder()(bytes)
}

// ReadTxsFromInput reads multiples txs from the given filename(s). Can pass "-" to read from stdin.
// Unlike ReadTxFromFile, this function does not decode the txs.
func ReadTxsFromInput(txCfg client.TxConfig, filenames ...string) (scanner *BatchScanner, err error) {
if len(filenames) == 0 {
return nil, fmt.Errorf("no file name provided")
}

var infile io.Reader = os.Stdin
if filenames[0] != "-" {
buf := new(bytes.Buffer)
for _, f := range filenames {
file, err := os.Open(f)
github-advanced-security[bot] marked this conversation as resolved.
Fixed
Show resolved Hide resolved
if err != nil {
return nil, fmt.Errorf("couldn't open %s: %w", f, err)
}

content, err := io.ReadAll(file)
if err != nil {
return nil, fmt.Errorf("couldn't read %s: %w", f, err)
}

if _, err := buf.WriteString(string(content)); err != nil {
return nil, fmt.Errorf("couldn't write to merged file: %w", err)
}
}

infile = buf
}

return NewBatchScanner(txCfg, infile), nil
}

// NewBatchScanner returns a new BatchScanner to read newline-delimited StdTx transactions from r.
func NewBatchScanner(cfg client.TxConfig, r io.Reader) *BatchScanner {
return &BatchScanner{Scanner: bufio.NewScanner(r), cfg: cfg}
Expand Down