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

Add multisign batch command #7787

Merged
merged 74 commits into from
Feb 24, 2021
Merged
Show file tree
Hide file tree
Changes from 68 commits
Commits
Show all changes
74 commits
Select commit Hold shift + click to select a range
627e7d4
initial commit
sahith-narahari Oct 21, 2020
66e3415
update signing data
sahith-narahari Oct 23, 2020
afed54d
Merge branch 'master' of github.com:cosmos/cosmos-sdk into sahith/add…
sahith-narahari Oct 29, 2020
97fc039
Merge branch 'master' of github.com:cosmos/cosmos-sdk into sahith/add…
sahith-narahari Oct 29, 2020
4d50e32
Update signature
sahith-narahari Oct 29, 2020
3c5cd6a
code cleanup
sahith-narahari Oct 29, 2020
106e3bc
code cleanup
sahith-narahari Oct 29, 2020
7949505
Add test for ms batch
sahith-narahari Nov 2, 2020
2018ed0
update test
sahith-narahari Nov 3, 2020
600d184
add build flag
sahith-narahari Nov 3, 2020
9b58f35
Merge branch 'master' of github.com:cosmos/cosmos-sdk into sahith/add…
sahith-narahari Nov 3, 2020
af681c5
update flags
sahith-narahari Nov 3, 2020
ad9647b
Merge branch 'master' into sahith/add-batch-ms
sahith-narahari Nov 3, 2020
ad1bc3f
Merge branch 'sahith/add-batch-ms' of github.com:cosmos/cosmos-sdk in…
sahith-narahari Nov 3, 2020
2db8ca7
update tests
sahith-narahari Nov 3, 2020
c6e7665
add test for signbatch multisig
sahith-narahari Nov 3, 2020
f2b9abd
Merge branch 'master' into sahith/add-batch-test
sahith-narahari Nov 3, 2020
df711ac
update test
sahith-narahari Nov 3, 2020
c12c85a
Merge remote-tracking branch 'origin/sahith/add-batch-test' into sahi…
sahith-narahari Nov 3, 2020
9821c77
Merge branch 'master' into sahith/add-batch-test
Nov 5, 2020
54ecb38
Merge branch 'master' of github.com:cosmos/cosmos-sdk into sahith/add…
sahith-narahari Nov 23, 2020
a3f8641
fix sign batch multisig
sahith-narahari Nov 23, 2020
2489013
Merge branch 'master' of github.com:cosmos/cosmos-sdk into sahith/add…
sahith-narahari Nov 23, 2020
701614f
Merge branch 'sahith/add-batch-test' of github.com:cosmos/cosmos-sdk …
sahith-narahari Nov 23, 2020
66e6c3e
add test
sahith-narahari Nov 23, 2020
9879824
Merge branch 'master' of github.com:cosmos/cosmos-sdk into sahith/add…
sahith-narahari Nov 24, 2020
21226ec
update offline usage
sahith-narahari Nov 24, 2020
d0ac318
Merge branch 'sahith/add-batch-test' of github.com:cosmos/cosmos-sdk …
sahith-narahari Nov 24, 2020
b966e2a
Merge branch 'master' of github.com:cosmos/cosmos-sdk into sahith/add…
sahith-narahari Dec 10, 2020
2c07438
update with sign batch fix
sahith-narahari Dec 10, 2020
61d6c10
Merge branch 'master' of github.com:cosmos/cosmos-sdk into sahith/add…
sahith-narahari Dec 14, 2020
190c455
fix lint
sahith-narahari Dec 14, 2020
3db654c
Merge branch 'master' into sahith/add-batch-ms
sahith-narahari Dec 14, 2020
3b64d30
Merge branch 'master' into sahith/add-batch-ms
Dec 15, 2020
033dd80
Merge branch 'master' into sahith/add-batch-ms
sahith-narahari Dec 16, 2020
693008a
Merge branch 'master' of github.com:cosmos/cosmos-sdk into sahith/add…
sahith-narahari Dec 17, 2020
45fd701
update tests
sahith-narahari Dec 17, 2020
dea4a0c
Merge branch 'master' into sahith/add-batch-ms
Dec 19, 2020
7f11ffe
Merge branch 'sahith/add-batch-ms' of github.com:cosmos/cosmos-sdk in…
sahith-narahari Jan 4, 2021
151fcae
Merge branch 'master' of github.com:cosmos/cosmos-sdk into sahith/add…
sahith-narahari Jan 4, 2021
b330737
update test
sahith-narahari Jan 8, 2021
11963b4
update tests
sahith-narahari Jan 10, 2021
10d1dfd
Merge branch 'master' of github.com:cosmos/cosmos-sdk into sahith/add…
sahith-narahari Jan 10, 2021
92bef3c
fix signature only
sahith-narahari Jan 10, 2021
5ebd4a8
update seq
sahith-narahari Jan 11, 2021
9d84474
Merge branch 'master' of github.com:cosmos/cosmos-sdk into sahith/add…
sahith-narahari Jan 12, 2021
7adc5d9
fix conflicts
sahith-narahari Jan 12, 2021
6f6f089
Merge branch 'master' into sahith/add-batch-ms
Feb 19, 2021
d81a1ef
Merge branch 'sahith/add-batch-ms' of github.com:cosmos/cosmos-sdk in…
sahith-narahari Feb 21, 2021
33ee782
Merge branch 'master' of github.com:cosmos/cosmos-sdk into sahith/add…
sahith-narahari Feb 21, 2021
fb4d680
update multisign
sahith-narahari Feb 22, 2021
1425ff3
Merge pull request #25 from allinbits/sahith/update
jgimeno Feb 22, 2021
3aaa994
Merge branch 'master' of github.com:allinbits/cosmos-sdk into sahith/…
sahith-narahari Feb 22, 2021
4b68f1a
revert unintended
sahith-narahari Feb 22, 2021
c8803d6
Merge branch 'master' into sahith/add-batch-ms
Feb 22, 2021
93c8a79
Merge branch 'master' into sahith/add-batch-ms
Feb 22, 2021
5ce860c
fix tests
sahith-narahari Feb 22, 2021
b3e122d
rename flags
sahith-narahari Feb 22, 2021
7ec5b04
Merge branch 'sahith/add-batch-ms' of github.com:cosmos/cosmos-sdk in…
sahith-narahari Feb 22, 2021
e0da11a
Merge branch 'master' into sahith/add-batch-ms
jgimeno Feb 23, 2021
9ddce77
Merge branch 'master' into sahith/add-batch-ms
Feb 23, 2021
98fd191
Merge branch 'master' into sahith/add-batch-ms
Feb 23, 2021
de35def
code refactor
sahith-narahari Feb 23, 2021
c622dac
fix typo
sahith-narahari Feb 23, 2021
e18022d
update docs
sahith-narahari Feb 23, 2021
d39861b
Merge branch 'master' of github.com:cosmos/cosmos-sdk into sahith/add…
sahith-narahari Feb 23, 2021
b6661d1
update test
sahith-narahari Feb 23, 2021
a09350e
Merge branch 'master' into sahith/add-batch-ms
Feb 24, 2021
1397f47
Update x/auth/client/cli/tx_multisign.go
Feb 24, 2021
bb753a5
Merge branch 'master' into sahith/add-batch-ms
Feb 24, 2021
0580c12
use named return values and explicit return
Feb 24, 2021
ba5f3b1
Update x/auth/client/cli/tx_multisign.go
Feb 24, 2021
98dce41
Update x/auth/client/cli/tx_multisign.go
sahith-narahari Feb 24, 2021
9cd2d78
Merge branch 'master' into sahith/add-batch-ms
mergify[bot] Feb 24, 2021
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 simapp/simd/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ func txCommand() *cobra.Command {
authcmd.GetSignCommand(),
authcmd.GetSignBatchCommand(),
authcmd.GetMultiSignCommand(),
authcmd.GetMultiSignBatchCmd(),
authcmd.GetValidateSignaturesCommand(),
flags.LineBreak,
authcmd.GetBroadcastCommand(),
Expand Down
77 changes: 77 additions & 0 deletions x/auth/client/cli/cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -812,6 +812,83 @@ func (s *IntegrationTestSuite) TestSignBatchMultisig() {
s.Require().NoError(err)
}

func (s *IntegrationTestSuite) TestMultisignBatch() {
val := s.network.Validators[0]

// Fetch 2 accounts and a multisig.
account1, err := val.ClientCtx.Keyring.Key("newAccount1")
s.Require().NoError(err)
account2, err := val.ClientCtx.Keyring.Key("newAccount2")
s.Require().NoError(err)
multisigInfo, err := val.ClientCtx.Keyring.Key("multi")

// Send coins from validator to multisig.
sendTokens := sdk.NewInt64Coin(s.cfg.BondDenom, 1000)
_, err = bankcli.MsgSendExec(
val.ClientCtx,
val.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)
s.Require().NoError(s.network.WaitForNextBlock())

generatedStd, err := bankcli.MsgSendExec(
val.ClientCtx,
multisigInfo.GetAddress(),
val.Address,
sdk.NewCoins(
sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(1)),
),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
alessio marked this conversation as resolved.
Show resolved Hide resolved
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
filename := testutil.WriteToNewTempFile(s.T(), strings.Repeat(generatedStd.String(), 3))
val.ClientCtx.HomeDir = strings.Replace(val.ClientCtx.HomeDir, "simd", "simcli", 1)

queryResJSON, err := authtest.QueryAccountExec(val.ClientCtx, multisigInfo.GetAddress())
s.Require().NoError(err)
var account authtypes.AccountI
s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalInterfaceJSON(queryResJSON.Bytes(), &account))

// sign-batch file
res, err := authtest.TxSignBatchExec(val.ClientCtx, account1.GetAddress(), filename.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--multisig", multisigInfo.GetAddress().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())))
s.Require().NoError(err)
s.Require().Equal(3, len(strings.Split(strings.Trim(res.String(), "\n"), "\n")))
// write sigs to file
file1 := testutil.WriteToNewTempFile(s.T(), res.String())

// sign-batch file with account2
res, err = authtest.TxSignBatchExec(val.ClientCtx, account2.GetAddress(), filename.Name(), fmt.Sprintf("--%s=%s", flags.FlagChainID, val.ClientCtx.ChainID), "--multisig", multisigInfo.GetAddress().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())))
s.Require().NoError(err)
s.Require().Equal(3, len(strings.Split(strings.Trim(res.String(), "\n"), "\n")))

// multisign the file
file2 := testutil.WriteToNewTempFile(s.T(), res.String())
res, err = authtest.TxMultiSignBatchExec(val.ClientCtx, filename.Name(), multisigInfo.GetName(), file1.Name(), file2.Name())
s.Require().NoError(err)
alessio marked this conversation as resolved.
Show resolved Hide resolved
signedTxs := strings.Split(strings.Trim(res.String(), "\n"), "\n")

// Broadcast transactions.
for _, signedTx := range signedTxs {
signedTxFile := testutil.WriteToNewTempFile(s.T(), signedTx)
val.ClientCtx.BroadcastMode = flags.BroadcastBlock
res, err = authtest.TxBroadcastExec(val.ClientCtx, signedTxFile.Name())
s.T().Log(res)
s.Require().NoError(err)
s.Require().NoError(s.network.WaitForNextBlock())
}
}

func (s *IntegrationTestSuite) TestGetAccountCmd() {
val := s.network.Validators[0]
_, _, addr1 := testdata.KeyTestPubAddr()
Expand Down
219 changes: 204 additions & 15 deletions x/auth/client/cli/tx_multisign.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package cli

import (
"bufio"
"fmt"
"io/ioutil"
"os"
"strings"

"github.com/spf13/cobra"
"github.com/spf13/viper"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
Expand All @@ -16,6 +16,7 @@ import (
kmultisig "github.com/cosmos/cosmos-sdk/crypto/keys/multisig"
"github.com/cosmos/cosmos-sdk/crypto/types/multisig"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/errors"
signingtypes "github.com/cosmos/cosmos-sdk/types/tx/signing"
"github.com/cosmos/cosmos-sdk/version"
authclient "github.com/cosmos/cosmos-sdk/x/auth/client"
Expand All @@ -35,14 +36,17 @@ Read signature(s) from [signature] file(s), generate a multisig signature compli
multisig key [name], and attach it to the transaction read from [file].

Example:
$ %s multisign transaction.json k1k2k3 k1sig.json k2sig.json k3sig.json
$ %s tx multisign transaction.json k1k2k3 k1sig.json k2sig.json k3sig.json

If the flag --signature-only flag is on, it outputs a JSON representation
of the generated signature only.

The --offline flag makes sure that the client will not reach out to an external node.
Thus account number or sequence number lookups will not be performed and it is
recommended to set such parameters manually.

The current multisig implementation doesn't support sign_mode_direct and defaults
alessio marked this conversation as resolved.
Show resolved Hide resolved
to amino-json sign mode.'
`,
version.AppName,
),
Expand Down Expand Up @@ -82,20 +86,9 @@ func makeMultiSignCmd() func(cmd *cobra.Command, args []string) (err error) {
return err
}

backend, _ := cmd.Flags().GetString(flags.FlagKeyringBackend)

inBuf := bufio.NewReader(cmd.InOrStdin())
kb, err := keyring.New(sdk.KeyringServiceName(), backend, clientCtx.HomeDir, inBuf)
if err != nil {
return
}

multisigInfo, err := kb.Key(args[1])
multisigInfo, err := getMultisigInfo(clientCtx, args[1])
if err != nil {
return
}
if multisigInfo.GetType() != keyring.TypeMulti {
return fmt.Errorf("%q must be of type %s: %s", args[1], keyring.TypeMulti, multisigInfo.GetType())
return err
}

multisigPub := multisigInfo.GetPubKey().(*kmultisig.LegacyAminoPubKey)
Expand Down Expand Up @@ -196,10 +189,206 @@ func makeMultiSignCmd() func(cmd *cobra.Command, args []string) (err error) {
}
}

func GetMultiSignBatchCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "multisign-batch [file] [name] [[signature-file]...]",
Short: "Assemble multisig transactions in batch from batch signatures",
Long: strings.TrimSpace(
fmt.Sprintf(`SAssemble a batch of multisig transactions generated by batch sign command.
alessio marked this conversation as resolved.
Show resolved Hide resolved

Read signature(s) from [signature] file(s), generates multisig signatures compliant to the
multisig key [name], and attach it to the transactions read from [file].

Example:
$ %s tx multisign-batch transactions.json k1k2k3 k1sigs.json k2sigs.json k3sig.json
sahith-narahari marked this conversation as resolved.
Show resolved Hide resolved

The current multisig implementation doesn't support sign_mode_direct and defaults
to amino-json sign mode.'
`, version.AppName,
),
),
PreRun: preSignCmd,
RunE: makeBatchMultisignCmd(),
Args: cobra.MinimumNArgs(3),
}

cmd.Flags().Bool(flagNoAutoIncrement, false, "disable sequence auto increment")
cmd.Flags().String(
flagMultisig, "",
"Address of the multisig account on behalf of which the transaction shall be signed",
)
flags.AddTxFlagsToCmd(cmd)

return cmd
}

func makeBatchMultisignCmd() func(cmd *cobra.Command, args []string) error {
return func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}

txCfg := clientCtx.TxConfig
txFactory := tx.NewFactoryCLI(clientCtx, cmd.Flags())
if txFactory.SignMode() == signingtypes.SignMode_SIGN_MODE_UNSPECIFIED {
txFactory = txFactory.WithSignMode(signingtypes.SignMode_SIGN_MODE_LEGACY_AMINO_JSON)
}
alessio marked this conversation as resolved.
Show resolved Hide resolved

var 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)
}
alessio marked this conversation as resolved.
Show resolved Hide resolved
}
scanner := authclient.NewBatchScanner(txCfg, infile)

multisigInfo, err := getMultisigInfo(clientCtx, args[1])
if err != nil {
return err
}

var signatureBatch [][]signingtypes.SignatureV2
for i := 2; i < len(args); i++ {
sigs, err := readSignaturesFromFile(clientCtx, args[i])
if err != nil {
return err
}

signatureBatch = append(signatureBatch, sigs)
}

if !clientCtx.Offline {
accnum, seq, err := clientCtx.AccountRetriever.GetAccountNumberSequence(clientCtx, multisigInfo.GetAddress())
if err != nil {
return err
}

txFactory = txFactory.WithAccountNumber(accnum).WithSequence(seq)
}

for i := 0; scanner.Scan(); i++ {
txBldr, err := txCfg.WrapTxBuilder(scanner.Tx())
if err != nil {
return err
}

multisigPub := multisigInfo.GetPubKey().(*kmultisig.LegacyAminoPubKey)
multisigSig := multisig.NewMultisig(len(multisigPub.PubKeys))
signingData := signing.SignerData{
ChainID: txFactory.ChainID(),
AccountNumber: txFactory.AccountNumber(),
Sequence: txFactory.Sequence(),
}

for _, sig := range signatureBatch {
err = signing.VerifySignature(sig[i].PubKey, signingData, sig[i].Data, txCfg.SignModeHandler(), txBldr.GetTx())
if err != nil {
return fmt.Errorf("couldn't verify signature: %w %v", err, sig)
}

if err := multisig.AddSignatureV2(multisigSig, sig[i], multisigPub.GetPubKeys()); err != nil {
return err
}
}

sigV2 := signingtypes.SignatureV2{
PubKey: multisigPub,
Data: multisigSig,
Sequence: txFactory.Sequence(),
}

err = txBldr.SetSignatures(sigV2)
if err != nil {
return err
}

sigOnly, _ := cmd.Flags().GetBool(flagSigOnly)
aminoJSON, _ := cmd.Flags().GetBool(flagAmino)

var json []byte

if aminoJSON {
stdTx, err := tx.ConvertTxToStdTx(clientCtx.LegacyAmino, txBldr.GetTx())
if err != nil {
return err
}

req := rest.BroadcastReq{
Tx: stdTx,
Mode: "block|sync|async",
}

json, _ = clientCtx.LegacyAmino.MarshalJSON(req)

} else {
json, err = marshalSignatureJSON(txCfg, txBldr, sigOnly)
if err != nil {
return err
}
}

err = clientCtx.PrintString(fmt.Sprintf("%s\n", json))
if err != nil {
return err
}

if viper.GetBool(flagNoAutoIncrement) {
continue
}
sequence := txFactory.Sequence() + 1
txFactory = txFactory.WithSequence(sequence)
}

return nil
}
}
sahith-narahari marked this conversation as resolved.
Show resolved Hide resolved

func unmarshalSignatureJSON(clientCtx client.Context, filename string) (sigs []signingtypes.SignatureV2, err error) {
var bytes []byte
if bytes, err = ioutil.ReadFile(filename); err != nil {
return
}
return clientCtx.TxConfig.UnmarshalSignatureJSON(bytes)
}

func readSignaturesFromFile(ctx client.Context, filename string) (sigs []signingtypes.SignatureV2, err error) {
bz, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}

newString := strings.TrimSuffix(string(bz), "\n")
lines := strings.Split(newString, "\n")

for _, bz := range lines {
sig, err := ctx.TxConfig.UnmarshalSignatureJSON([]byte(bz))
if err != nil {
return nil, err
}

sigs = append(sigs, sig...)
}
return sigs, nil
}

func getMultisigInfo(clientCtx client.Context, name string) (keyring.Info, error) {
kb := clientCtx.Keyring
multisigInfo, err := kb.Key(name)
if err != nil {
return nil, errors.Wrap(err, "error getting keybase multisig account")
}
if multisigInfo.GetType() != keyring.TypeMulti {
return nil, fmt.Errorf("%q must be of type %s: %s", name, keyring.TypeMulti, multisigInfo.GetType())
}

return multisigInfo, nil
}
9 changes: 5 additions & 4 deletions x/auth/client/cli/tx_sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@ import (
)

const (
flagMultisig = "multisig"
flagOverwrite = "overwrite"
flagSigOnly = "signature-only"
flagAmino = "amino"
flagMultisig = "multisig"
flagOverwrite = "overwrite"
flagSigOnly = "signature-only"
flagAmino = "amino"
flagNoAutoIncrement = "no-auto-increment"
)

// GetSignBatchCommand returns the transaction sign-batch command.
Expand Down
14 changes: 14 additions & 0 deletions x/auth/client/testutil/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,18 @@ func QueryAccountExec(clientCtx client.Context, address fmt.Stringer, extraArgs
return clitestutil.ExecTestCLICmd(clientCtx, cli.GetAccountCmd(), append(args, extraArgs...))
}

func TxMultiSignBatchExec(clientCtx client.Context, filename string, from string, sigFile1 string, sigFile2 string, extraArgs ...string) (testutil.BufferWriter, error) {
args := []string{
fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest),
filename,
from,
sigFile1,
sigFile2,
}

args = append(args, extraArgs...)

return clitestutil.ExecTestCLICmd(clientCtx, cli.GetMultiSignBatchCmd(), args)
}

// DONTCOVER