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(cli): add --append flag to sign-batch cli cmd #13147

Merged
merged 33 commits into from
Sep 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
14afa31
feat(cli): add `multi-msg-sign`
gsk967 Sep 4, 2022
419b65d
chore: update the changelog
gsk967 Sep 4, 2022
8c87572
chore: fix the lint issue
gsk967 Sep 4, 2022
fe690ca
chore: address the pr comments
gsk967 Sep 5, 2022
f5e4c65
Merge branch 'main' into sai/multi_msg_sign_13066
gsk967 Sep 5, 2022
1774549
Merge branch 'main' into sai/multi_msg_sign_13066
gsk967 Sep 5, 2022
f932afa
Merge branch 'main' into sai/multi_msg_sign_13066
gsk967 Sep 5, 2022
7e8f9f0
Merge branch 'main' into sai/multi_msg_sign_13066
gsk967 Sep 6, 2022
9956878
Merge branch 'main' into sai/multi_msg_sign_13066
anilcse Sep 6, 2022
abb13b5
Merge branch 'main' into sai/multi_msg_sign_13066
gsk967 Sep 7, 2022
606758b
Merge branch 'sai/multi_msg_sign_13066' of github.com:gsk967/cosmos-s…
gsk967 Sep 7, 2022
07b4a71
Merge branch 'main' into sai/multi_msg_sign_13066
gsk967 Sep 7, 2022
ea907b1
Merge branch 'main' into sai/multi_msg_sign_13066
gsk967 Sep 8, 2022
a2c1d44
Merge branch 'main' into sai/multi_msg_sign_13066
gsk967 Sep 8, 2022
d90d78a
Merge branch 'main' into sai/multi_msg_sign_13066
gsk967 Sep 8, 2022
a7b7234
chore: address the pr comments
gsk967 Sep 8, 2022
fa44e9c
Merge remote-tracking branch 'mine/sai/multi_msg_sign_13066' into sai…
gsk967 Sep 8, 2022
ff3ee19
Merge branch 'main' into sai/multi_msg_sign_13066
gsk967 Sep 12, 2022
947d528
Merge branch 'main' into sai/multi_msg_sign_13066
gsk967 Sep 12, 2022
0c20e5a
Merge branch 'main' into sai/multi_msg_sign_13066
gsk967 Sep 22, 2022
565ed1a
refactor: refactored `sign-batch` to generate single signed tx
gsk967 Sep 22, 2022
6fb556e
chore: updated the changelog
gsk967 Sep 22, 2022
861e5c5
fix: fix the lint
gsk967 Sep 22, 2022
a5c6e15
test: fix the tests on auth
gsk967 Sep 22, 2022
6fc9145
Merge branch 'main' into sai/multi_msg_sign_13066
gsk967 Sep 23, 2022
382d63a
Merge branch 'main' into sai/multi_msg_sign_13066
julienrbrt Sep 23, 2022
9fd6081
Merge branch 'main' into sai/multi_msg_sign_13066
gsk967 Sep 24, 2022
4206be9
Merge branch 'main' into sai/multi_msg_sign_13066
gsk967 Sep 24, 2022
42a0d2f
Merge branch 'main' into sai/multi_msg_sign_13066
julienrbrt Sep 24, 2022
7ff9c11
Merge branch 'main' into sai/multi_msg_sign_13066
julienrbrt Sep 25, 2022
162e22e
Merge branch 'main' into sai/multi_msg_sign_13066
gsk967 Sep 26, 2022
d0780aa
Merge branch 'main' into sai/multi_msg_sign_13066
gsk967 Sep 26, 2022
ea5d655
Merge branch 'main' into sai/multi_msg_sign_13066
alexanderbez Sep 26, 2022
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
* (ledger) [#12935](https://github.com/cosmos/cosmos-sdk/pull/12935) Generalize Ledger integration to allow for different apps or keytypes that use SECP256k1.
* (x/bank) [#11981](https://github.com/cosmos/cosmos-sdk/pull/11981) Create the `SetSendEnabled` endpoint for managing the bank's SendEnabled settings.
* (x/auth) [#13210](https://github.com/cosmos/cosmos-sdk/pull/13210) Add `Query/AccountInfo` endpoint for simplified access to basic account info.
* (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`.

### Improvements
gsk967 marked this conversation as resolved.
Show resolved Hide resolved

Expand Down
276 changes: 178 additions & 98 deletions x/auth/client/cli/tx_sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/tx"
kmultisig "github.com/cosmos/cosmos-sdk/crypto/keys/multisig"
sdk "github.com/cosmos/cosmos-sdk/types"

authclient "github.com/cosmos/cosmos-sdk/x/auth/client"
)
Expand All @@ -20,6 +21,7 @@ const (
flagSigOnly = "signature-only"
flagAmino = "amino"
flagNoAutoIncrement = "no-auto-increment"
flagAppend = "append"
)

// GetSignBatchCommand returns the transaction sign-batch command.
Expand Down Expand Up @@ -53,7 +55,9 @@ account key. It implies --signature-only.

cmd.Flags().String(flagMultisig, "", "Address or key name 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().Bool(flagSigOnly, false, "Print only the generated signature, then exit")
cmd.Flags().Bool(flagAppend, false, "Combine all message and generate single signed transaction for broadcast.")

flags.AddTxFlagsToCmd(cmd)

cmd.MarkFlagRequired(flags.FlagFrom)
Expand Down Expand Up @@ -117,13 +121,36 @@ func makeSignBatchCmd() func(cmd *cobra.Command, args []string) error {
}
}

for sequence := txFactory.Sequence(); scanner.Scan(); sequence++ {
unsignedStdTx := scanner.Tx()
txFactory = txFactory.WithSequence(sequence)
txBuilder, err := txCfg.WrapTxBuilder(unsignedStdTx)
if err != nil {
return err
appendMessagesToSingleMsg, _ := 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.
if appendMessagesToSingleMsg {
// It will combine all tx msgs and create single signed transaction
txBuilder := clientCtx.TxConfig.NewTxBuilder()
msgs := make([]sdk.Msg, 0)
newGasLimit := uint64(0)

for scanner.Scan() {
unsignedStdTx := scanner.Tx()
fe, err := clientCtx.TxConfig.WrapTxBuilder(unsignedStdTx)
if err != nil {
return err
}
// increment the gas
newGasLimit += fe.GetTx().GetGas()
// append messages
msgs = append(msgs, unsignedStdTx.GetMsgs()...)
}
// set the new appened msgs into builder
txBuilder.SetMsgs(msgs...)

Check warning

Code scanning / gosec

Errors unhandled.

Errors unhandled.

// set the memo,fees,feeGranter,feePayer from cmd flags
txBuilder.SetMemo(txFactory.Memo())
txBuilder.SetFeeAmount(txFactory.Fees())
txBuilder.SetFeeGranter(clientCtx.FeeGranter)
txBuilder.SetFeePayer(clientCtx.FeePayer)

// set the gasLimit
txBuilder.SetGasLimit(newGasLimit)

if ms == "" {
from, _ := cmd.Flags().GetString(flags.FlagFrom)
_, fromName, _, err := client.GetFromFields(clientCtx, txFactory.Keybase(), from)
Expand Down Expand Up @@ -156,6 +183,49 @@ func makeSignBatchCmd() func(cmd *cobra.Command, args []string) error {
}

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

} else {
// It will generate signed tx for each tx
for sequence := txFactory.Sequence(); scanner.Scan(); sequence++ {
unsignedStdTx := scanner.Tx()
txFactory = txFactory.WithSequence(sequence)
txBuilder, err := txCfg.WrapTxBuilder(unsignedStdTx)
if err != nil {
return err
}
if ms == "" {
from, _ := cmd.Flags().GetString(flags.FlagFrom)

Check warning

Code scanning / gosec

Returned error is not propagated up the stack.

Returned error is not propagated up the stack.
_, 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 {
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 {
return err
}
}

if err != nil {
return err
}

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

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

if err := scanner.UnmarshalErr(); err != nil {
Expand Down Expand Up @@ -235,129 +305,139 @@ func makeSignCmd() func(cmd *cobra.Command, args []string) error {
if err != nil {
return err
}
f := cmd.Flags()

clientCtx, txF, newTx, err := readTxAndInitContexts(clientCtx, cmd, args[0])
if err != nil {
return err
}

txCfg := clientCtx.TxConfig
txBuilder, err := txCfg.WrapTxBuilder(newTx)
return signTx(cmd, clientCtx, txF, newTx)
}
}

func signTx(cmd *cobra.Command, clientCtx client.Context, txF tx.Factory, newTx sdk.Tx) error {
f := cmd.Flags()
txCfg := clientCtx.TxConfig
txBuilder, err := txCfg.WrapTxBuilder(newTx)
if err != nil {
return err
}

printSignatureOnly, err := cmd.Flags().GetBool(flagSigOnly)
if err != nil {
gsk967 marked this conversation as resolved.
Show resolved Hide resolved
return err
}

multisig, err := cmd.Flags().GetString(flagMultisig)
if err != nil {
return err
}

from, err := cmd.Flags().GetString(flags.FlagFrom)
if err != nil {
return err
}

_, fromName, _, err := client.GetFromFields(clientCtx, txF.Keybase(), from)
if err != nil {
return fmt.Errorf("error getting account from keybase: %w", err)
}

overwrite, err := f.GetBool(flagOverwrite)
if err != nil {
return err
}

if multisig != "" {
// Bech32 decode error, maybe it's a name, we try to fetch from keyring
multisigAddr, multisigName, _, err := client.GetFromFields(clientCtx, txF.Keybase(), multisig)
if err != nil {
return err
return fmt.Errorf("error getting account from keybase: %w", err)
}

printSignatureOnly, _ := cmd.Flags().GetBool(flagSigOnly)
multisig, _ := cmd.Flags().GetString(flagMultisig)
multisigkey, err := getMultisigRecord(clientCtx, multisigName)
if err != nil {
return err
}
from, _ := cmd.Flags().GetString(flags.FlagFrom)
_, fromName, _, err := client.GetFromFields(clientCtx, txF.Keybase(), from)
multisigPubKey, err := multisigkey.GetPubKey()
if err != nil {
return fmt.Errorf("error getting account from keybase: %w", err)
return err
}
multisigLegacyPub := multisigPubKey.(*kmultisig.LegacyAminoPubKey)

overwrite, _ := f.GetBool(flagOverwrite)
if multisig != "" {
// Bech32 decode error, maybe it's a name, we try to fetch from keyring
multisigAddr, multisigName, _, err := client.GetFromFields(clientCtx, txF.Keybase(), multisig)
if err != nil {
return fmt.Errorf("error getting account from keybase: %w", err)
}
multisigkey, err := getMultisigRecord(clientCtx, multisigName)
if err != nil {
return err
}
multisigPubKey, err := multisigkey.GetPubKey()
if err != nil {
return err
}
multisigLegacyPub := multisigPubKey.(*kmultisig.LegacyAminoPubKey)

fromRecord, err := clientCtx.Keyring.Key(fromName)
if err != nil {
return fmt.Errorf("error getting account from keybase: %w", err)
}
fromPubKey, err := fromRecord.GetPubKey()
if err != nil {
return err
}

var found bool
for _, pubkey := range multisigLegacyPub.GetPubKeys() {
if pubkey.Equals(fromPubKey) {
found = true
}
}
if !found {
return fmt.Errorf("signing key is not a part of multisig key")
}
err = authclient.SignTxWithSignerAddress(
txF, clientCtx, multisigAddr, fromName, txBuilder, clientCtx.Offline, overwrite)
if err != nil {
return err
}
printSignatureOnly = true
} else {
err = authclient.SignTx(txF, clientCtx, clientCtx.GetFromName(), txBuilder, clientCtx.Offline, overwrite)
fromRecord, err := clientCtx.Keyring.Key(fromName)
if err != nil {
return fmt.Errorf("error getting account from keybase: %w", err)
}
fromPubKey, err := fromRecord.GetPubKey()
if err != nil {
return err
}

aminoJSON, err := f.GetBool(flagAmino)
var found bool
for _, pubkey := range multisigLegacyPub.GetPubKeys() {
if pubkey.Equals(fromPubKey) {
found = true
}
}
if !found {
return fmt.Errorf("signing key is not a part of multisig key")
}
err = authclient.SignTxWithSignerAddress(
txF, clientCtx, multisigAddr, fromName, txBuilder, clientCtx.Offline, overwrite)
if err != nil {
return err
}
printSignatureOnly = true
} else {
err = authclient.SignTx(txF, clientCtx, clientCtx.GetFromName(), txBuilder, clientCtx.Offline, overwrite)
}
if err != nil {
return err
}

aminoJSON, err := f.GetBool(flagAmino)
if err != nil {
return err
}

bMode, err := f.GetString(flags.FlagBroadcastMode)
bMode, err := f.GetString(flags.FlagBroadcastMode)
if err != nil {
return err
}

// set output
closeFunc, err := setOutputFile(cmd)
if err != nil {
return err
}

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

var json []byte
if aminoJSON {
stdTx, err := tx.ConvertTxToStdTx(clientCtx.LegacyAmino, txBuilder.GetTx())
if err != nil {
return err
}

var json []byte
if aminoJSON {
stdTx, err := tx.ConvertTxToStdTx(clientCtx.LegacyAmino, txBuilder.GetTx())
if err != nil {
return err
}
req := BroadcastReq{
Tx: stdTx,
Mode: bMode,
}
json, err = clientCtx.LegacyAmino.MarshalJSON(req)
if err != nil {
return err
}
} else {
json, err = marshalSignatureJSON(txCfg, txBuilder, printSignatureOnly)
if err != nil {
return err
}
req := BroadcastReq{
Tx: stdTx,
Mode: bMode,
}

outputDoc, _ := cmd.Flags().GetString(flags.FlagOutputDocument)
if outputDoc == "" {
cmd.Printf("%s\n", json)
return nil
json, err = clientCtx.LegacyAmino.MarshalJSON(req)
if err != nil {
return err
}

fp, err := os.OpenFile(outputDoc, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o644)
} else {
json, err = marshalSignatureJSON(txCfg, txBuilder, printSignatureOnly)
if err != nil {
return err
}
defer func() {
err2 := fp.Close()
if err == nil {
err = err2
}
}()

_, err = fp.Write(append(json, '\n'))
return err
}

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

return err
}

func marshalSignatureJSON(txConfig client.TxConfig, txBldr client.TxBuilder, signatureOnly bool) ([]byte, error) {
Expand Down
8 changes: 4 additions & 4 deletions x/auth/client/testutil/suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -1243,7 +1243,7 @@ func (s *IntegrationTestSuite) TestSignBatchMultisig() {
addr1, err := account1.GetAddress()
s.Require().NoError(err)
// sign-batch file
res, err := TxSignBatchExec(val.ClientCtx, addr1, filename.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--multisig", addr.String())
res, err := TxSignBatchExec(val.ClientCtx, addr1, filename.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--multisig", addr.String(), "--signature-only")
s.Require().NoError(err)
s.Require().Equal(1, len(strings.Split(strings.Trim(res.String(), "\n"), "\n")))
// write sigs to file
Expand All @@ -1252,7 +1252,7 @@ func (s *IntegrationTestSuite) TestSignBatchMultisig() {
addr2, err := account2.GetAddress()
s.Require().NoError(err)
// sign-batch file with account2
res, err = TxSignBatchExec(val.ClientCtx, addr2, filename.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--multisig", addr.String())
res, err = TxSignBatchExec(val.ClientCtx, addr2, filename.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--multisig", addr.String(), "--signature-only")
s.Require().NoError(err)
s.Require().Equal(1, len(strings.Split(strings.Trim(res.String(), "\n"), "\n")))
// write sigs to file2
Expand Down Expand Up @@ -1310,7 +1310,7 @@ func (s *IntegrationTestSuite) TestMultisignBatch() {
// sign-batch file
addr1, err := account1.GetAddress()
s.Require().NoError(err)
res, err := TxSignBatchExec(val.ClientCtx, addr1, filename.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--multisig", addr.String(), fmt.Sprintf("--%s", flags.FlagOffline), fmt.Sprintf("--%s=%s", flags.FlagAccountNumber, fmt.Sprint(account.GetAccountNumber())), fmt.Sprintf("--%s=%s", flags.FlagSequence, fmt.Sprint(account.GetSequence())))
res, err := TxSignBatchExec(val.ClientCtx, addr1, filename.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--multisig", addr.String(), fmt.Sprintf("--%s", flags.FlagOffline), fmt.Sprintf("--%s=%s", flags.FlagAccountNumber, fmt.Sprint(account.GetAccountNumber())), fmt.Sprintf("--%s=%s", flags.FlagSequence, fmt.Sprint(account.GetSequence())), "--signature-only")
s.Require().NoError(err)
s.Require().Equal(3, len(strings.Split(strings.Trim(res.String(), "\n"), "\n")))
// write sigs to file
Expand All @@ -1319,7 +1319,7 @@ func (s *IntegrationTestSuite) TestMultisignBatch() {
// sign-batch file with account2
addr2, err := account2.GetAddress()
s.Require().NoError(err)
res, err = TxSignBatchExec(val.ClientCtx, addr2, filename.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--multisig", addr.String(), fmt.Sprintf("--%s", flags.FlagOffline), fmt.Sprintf("--%s=%s", flags.FlagAccountNumber, fmt.Sprint(account.GetAccountNumber())), fmt.Sprintf("--%s=%s", flags.FlagSequence, fmt.Sprint(account.GetSequence())))
res, err = TxSignBatchExec(val.ClientCtx, addr2, filename.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--multisig", addr.String(), fmt.Sprintf("--%s", flags.FlagOffline), fmt.Sprintf("--%s=%s", flags.FlagAccountNumber, fmt.Sprint(account.GetAccountNumber())), fmt.Sprintf("--%s=%s", flags.FlagSequence, fmt.Sprint(account.GetSequence())), "--signature-only")
s.Require().NoError(err)
s.Require().Equal(3, len(strings.Split(strings.Trim(res.String(), "\n"), "\n")))

Expand Down