Skip to content

Commit 6efbedb

Browse files
authored
feat: let sign-batch read multiple files (#13454)
* feat: let `sign-batch` read multiple files * add changelog * fix gosec issue * simplify
1 parent 2151427 commit 6efbedb

File tree

4 files changed

+87
-67
lines changed

4 files changed

+87
-67
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
5252
* (x/auth) [#13210](https://github.com/cosmos/cosmos-sdk/pull/13210) Add `Query/AccountInfo` endpoint for simplified access to basic account info.
5353
* (cli) [#13147](https://github.com/cosmos/cosmos-sdk/pull/13147) Add the `--append` flag to the `sign-batch` CLI cmd to combine the messages and sign those txs which are created with `--generate-only`.
5454
* (x/consensus) [#12905](https://github.com/cosmos/cosmos-sdk/pull/12905) Create a new `x/consensus` module that is now responsible for maintaining Tendermint consensus parameters instead of `x/param`. Legacy types remain in order to facilitate parameter migration from the deprecated `x/params`. App developers should ensure that they execute `baseapp.MigrateParams` during their chain upgrade. These legacy types will be removed in a future release.
55+
* (cli) [#13454](https://github.com/cosmos/cosmos-sdk/pull/13454) `sign-batch` CLI can now read multiple transaction files.
5556

5657
### Improvements
5758

x/auth/client/cli/tx_multisign.go

+5-15
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ type BroadcastReq struct {
2929
Mode string `json:"mode" yaml:"mode"`
3030
}
3131

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

261-
infile := os.Stdin
262-
if args[0] != "-" {
263-
infile, err = os.Open(args[0])
264-
defer func() {
265-
err2 := infile.Close()
266-
if err == nil {
267-
err = err2
268-
}
269-
}()
270-
271-
if err != nil {
272-
return fmt.Errorf("couldn't open %s: %w", args[0], err)
273-
}
261+
// reads tx from args[0]
262+
scanner, err := authclient.ReadTxsFromInput(txCfg, args[0])
263+
if err != nil {
264+
return err
274265
}
275-
scanner := authclient.NewBatchScanner(txCfg, infile)
276266

277267
k, err := getMultisigRecord(clientCtx, args[1])
278268
if err != nil {

x/auth/client/cli/tx_sign.go

+52-51
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,11 @@ const (
2727
// GetSignBatchCommand returns the transaction sign-batch command.
2828
func GetSignBatchCommand() *cobra.Command {
2929
cmd := &cobra.Command{
30-
Use: "sign-batch [file]",
30+
Use: "sign-batch [file] ([file2]...)",
3131
Short: "Sign transaction batch files",
3232
Long: `Sign batch files of transactions generated with --generate-only.
33-
The command processes list of transactions from file (one StdTx each line), generate
34-
signed transactions or signatures and print their JSON encoding, delimited by '\n'.
33+
The command processes list of transactions from a file (one StdTx each line), or multiple files.
34+
Then generates signed transactions or signatures and print their JSON encoding, delimited by '\n'.
3535
As the signatures are generated, the command updates the account and sequence number accordingly.
3636
3737
If the --signature-only flag is set, it will output the signature parts only.
@@ -50,7 +50,7 @@ account key. It implies --signature-only.
5050
`,
5151
PreRun: preSignCmd,
5252
RunE: makeSignBatchCmd(),
53-
Args: cobra.ExactArgs(1),
53+
Args: cobra.MinimumNArgs(1),
5454
}
5555

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

7978
ms, err := cmd.Flags().GetString(flagMultisig)
8079
if err != nil {
@@ -86,17 +85,14 @@ func makeSignBatchCmd() func(cmd *cobra.Command, args []string) error {
8685
if err != nil {
8786
return err
8887
}
89-
9088
defer closeFunc()
9189
clientCtx.WithOutput(cmd.OutOrStdout())
9290

93-
if args[0] != "-" {
94-
infile, err = os.Open(args[0])
95-
if err != nil {
96-
return err
97-
}
91+
// reads tx from args
92+
scanner, err := authclient.ReadTxsFromInput(txCfg, args...)
93+
if err != nil {
94+
return err
9895
}
99-
scanner := authclient.NewBatchScanner(txCfg, infile)
10096

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

124-
appendMessagesToSingleMsg, _ := cmd.Flags().GetBool(flagAppend)
125-
if appendMessagesToSingleMsg {
126-
// It will combine all tx msgs and create single signed transaction
120+
appendMessagesToSingleTx, _ := cmd.Flags().GetBool(flagAppend)
121+
// Combines all tx msgs and create single signed transaction
122+
if appendMessagesToSingleTx {
127123
txBuilder := clientCtx.TxConfig.NewTxBuilder()
128124
msgs := make([]sdk.Msg, 0)
129125
newGasLimit := uint64(0)
@@ -151,39 +147,24 @@ func makeSignBatchCmd() func(cmd *cobra.Command, args []string) error {
151147
// set the gasLimit
152148
txBuilder.SetGasLimit(newGasLimit)
153149

150+
// sign the txs
154151
if ms == "" {
155152
from, _ := cmd.Flags().GetString(flags.FlagFrom)
156-
_, fromName, _, err := client.GetFromFields(clientCtx, txFactory.Keybase(), from)
157-
if err != nil {
158-
return fmt.Errorf("error getting account from keybase: %w", err)
159-
}
160-
err = authclient.SignTx(txFactory, clientCtx, fromName, txBuilder, true, true)
161-
if err != nil {
153+
if err := sign(clientCtx, txBuilder, txFactory, from); err != nil {
162154
return err
163155
}
164156
} else {
165-
multisigAddr, _, _, err := client.GetFromFields(clientCtx, txFactory.Keybase(), ms)
166-
if err != nil {
167-
return fmt.Errorf("error getting account from keybase: %w", err)
168-
}
169-
err = authclient.SignTxWithSignerAddress(
170-
txFactory, clientCtx, multisigAddr, clientCtx.GetFromName(), txBuilder, clientCtx.Offline, true)
171-
if err != nil {
157+
if err := multisigSign(clientCtx, txBuilder, txFactory, ms); err != nil {
172158
return err
173159
}
174160
}
175161

176-
if err != nil {
177-
return err
178-
}
179-
180162
json, err := marshalSignatureJSON(txCfg, txBuilder, printSignatureOnly)
181163
if err != nil {
182164
return err
183165
}
184166

185167
cmd.Printf("%s\n", json)
186-
187168
} else {
188169
// It will generate signed tx for each tx
189170
for sequence := txFactory.Sequence(); scanner.Scan(); sequence++ {
@@ -193,37 +174,23 @@ func makeSignBatchCmd() func(cmd *cobra.Command, args []string) error {
193174
if err != nil {
194175
return err
195176
}
177+
178+
// sign the txs
196179
if ms == "" {
197180
from, _ := cmd.Flags().GetString(flags.FlagFrom)
198-
_, fromName, _, err := client.GetFromFields(clientCtx, txFactory.Keybase(), from)
199-
if err != nil {
200-
return fmt.Errorf("error getting account from keybase: %w", err)
201-
}
202-
err = authclient.SignTx(txFactory, clientCtx, fromName, txBuilder, true, true)
203-
if err != nil {
181+
if err := sign(clientCtx, txBuilder, txFactory, from); err != nil {
204182
return err
205183
}
206184
} else {
207-
multisigAddr, _, _, err := client.GetFromFields(clientCtx, txFactory.Keybase(), ms)
208-
if err != nil {
209-
return fmt.Errorf("error getting account from keybase: %w", err)
210-
}
211-
err = authclient.SignTxWithSignerAddress(
212-
txFactory, clientCtx, multisigAddr, clientCtx.GetFromName(), txBuilder, clientCtx.Offline, true)
213-
if err != nil {
185+
if err := multisigSign(clientCtx, txBuilder, txFactory, ms); err != nil {
214186
return err
215187
}
216188
}
217189

218-
if err != nil {
219-
return err
220-
}
221-
222190
json, err := marshalSignatureJSON(txCfg, txBuilder, printSignatureOnly)
223191
if err != nil {
224192
return err
225193
}
226-
227194
cmd.Printf("%s\n", json)
228195
}
229196
}
@@ -236,6 +203,40 @@ func makeSignBatchCmd() func(cmd *cobra.Command, args []string) error {
236203
}
237204
}
238205

206+
func sign(clientCtx client.Context, txBuilder client.TxBuilder, txFactory tx.Factory, from string) error {
207+
_, fromName, _, err := client.GetFromFields(clientCtx, txFactory.Keybase(), from)
208+
if err != nil {
209+
return fmt.Errorf("error getting account from keybase: %w", err)
210+
}
211+
212+
if err = authclient.SignTx(txFactory, clientCtx, fromName, txBuilder, true, true); err != nil {
213+
return err
214+
}
215+
216+
return nil
217+
}
218+
219+
func multisigSign(clientCtx client.Context, txBuilder client.TxBuilder, txFactory tx.Factory, multisig string) error {
220+
multisigAddr, _, _, err := client.GetFromFields(clientCtx, txFactory.Keybase(), multisig)
221+
if err != nil {
222+
return fmt.Errorf("error getting account from keybase: %w", err)
223+
}
224+
225+
if err = authclient.SignTxWithSignerAddress(
226+
txFactory,
227+
clientCtx,
228+
multisigAddr,
229+
clientCtx.GetFromName(),
230+
txBuilder,
231+
clientCtx.Offline,
232+
true,
233+
); err != nil {
234+
return err
235+
}
236+
237+
return nil
238+
}
239+
239240
func setOutputFile(cmd *cobra.Command) (func(), error) {
240241
outputDoc, _ := cmd.Flags().GetString(flags.FlagOutputDocument)
241242
if outputDoc == "" {

x/auth/client/tx.go

+29-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"fmt"
77
"io"
88
"os"
9+
"path/filepath"
910
"strings"
1011

1112
"github.com/cosmos/gogoproto/jsonpb"
@@ -90,7 +91,7 @@ func SignTxWithSignerAddress(txFactory tx.Factory, clientCtx client.Context, add
9091
return tx.Sign(txFactory, name, txBuilder, overwrite)
9192
}
9293

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

@@ -107,6 +108,33 @@ func ReadTxFromFile(ctx client.Context, filename string) (tx sdk.Tx, err error)
107108
return ctx.TxConfig.TxJSONDecoder()(bytes)
108109
}
109110

111+
// ReadTxsFromInput reads multiples txs from the given filename(s). Can pass "-" to read from stdin.
112+
// Unlike ReadTxFromFile, this function does not decode the txs.
113+
func ReadTxsFromInput(txCfg client.TxConfig, filenames ...string) (scanner *BatchScanner, err error) {
114+
if len(filenames) == 0 {
115+
return nil, fmt.Errorf("no file name provided")
116+
}
117+
118+
var infile io.Reader = os.Stdin
119+
if filenames[0] != "-" {
120+
buf := new(bytes.Buffer)
121+
for _, f := range filenames {
122+
bytes, err := os.ReadFile(filepath.Clean(f))
123+
if err != nil {
124+
return nil, fmt.Errorf("couldn't read %s: %w", f, err)
125+
}
126+
127+
if _, err := buf.WriteString(string(bytes)); err != nil {
128+
return nil, fmt.Errorf("couldn't write to merged file: %w", err)
129+
}
130+
}
131+
132+
infile = buf
133+
}
134+
135+
return NewBatchScanner(txCfg, infile), nil
136+
}
137+
110138
// NewBatchScanner returns a new BatchScanner to read newline-delimited StdTx transactions from r.
111139
func NewBatchScanner(cfg client.TxConfig, r io.Reader) *BatchScanner {
112140
return &BatchScanner{Scanner: bufio.NewScanner(r), cfg: cfg}

0 commit comments

Comments
 (0)