* WIP test the grounds * Update ADR020 * Fix compile errors * Fix ADR * Make ante tests pass * Fix remaining ante handler tests * Simplify code * Fix x/bank app_test * Fix tests * Remove useless accSeq from signerdata * Fix test * Update simapp/helpers/test_helpers.go Co-authored-by: Alexander Bezobchuk <alexanderbez@users.noreply.github.com> * Update simapp/helpers/test_helpers.go Co-authored-by: Alexander Bezobchuk <alexanderbez@users.noreply.github.com> * Update x/auth/client/cli/tx_multisign.go Co-authored-by: Alexander Bezobchuk <alexanderbez@users.noreply.github.com> * Address rewview * Update x/auth/ante/sigverify.go Co-authored-by: Simon Warta <2603011+webmaster128@users.noreply.github.com> * Update x/auth/ante/sigverify_test.go Co-authored-by: Simon Warta <2603011+webmaster128@users.noreply.github.com> * Update x/auth/tx/builder_test.go Co-authored-by: Simon Warta <2603011+webmaster128@users.noreply.github.com> * Update x/auth/tx/builder_test.go Co-authored-by: Simon Warta <2603011+webmaster128@users.noreply.github.com> * Update x/auth/tx/direct_test.go Co-authored-by: Simon Warta <2603011+webmaster128@users.noreply.github.com> * Update x/auth/tx/builder_test.go Co-authored-by: Simon Warta <2603011+webmaster128@users.noreply.github.com> * AccSeq -> Seq * Address reviews * Better variable naming * Fix variable assign * Remove old SetSignerInfo * Fix test * proto-gen * Make proto-gen * Reput gw comment * Add Changelog * Update x/bank/app_test.go Co-authored-by: Alexander Bezobchuk <alexanderbez@users.noreply.github.com> * Update x/bank/app_test.go Co-authored-by: Alexander Bezobchuk <alexanderbez@users.noreply.github.com> Co-authored-by: Alexander Bezobchuk <alexanderbez@users.noreply.github.com> Co-authored-by: SaReN <sahithnarahari@gmail.com> Co-authored-by: Simon Warta <2603011+webmaster128@users.noreply.github.com>
177 lines
5.0 KiB
Go
177 lines
5.0 KiB
Go
package cli
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"os"
|
|
"strings"
|
|
|
|
"github.com/spf13/cobra"
|
|
|
|
"github.com/cosmos/cosmos-sdk/client"
|
|
"github.com/cosmos/cosmos-sdk/client/flags"
|
|
"github.com/cosmos/cosmos-sdk/client/tx"
|
|
"github.com/cosmos/cosmos-sdk/crypto/keyring"
|
|
"github.com/cosmos/cosmos-sdk/crypto/types/multisig"
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
signingtypes "github.com/cosmos/cosmos-sdk/types/tx/signing"
|
|
"github.com/cosmos/cosmos-sdk/version"
|
|
authclient "github.com/cosmos/cosmos-sdk/x/auth/client"
|
|
"github.com/cosmos/cosmos-sdk/x/auth/signing"
|
|
)
|
|
|
|
// GetSignCommand returns the sign command
|
|
func GetMultiSignCommand() *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Use: "multisign [file] [name] [[signature]...]",
|
|
Short: "Generate multisig signatures for transactions generated offline",
|
|
Long: strings.TrimSpace(
|
|
fmt.Sprintf(`Sign transactions created with the --generate-only flag that require multisig signatures.
|
|
|
|
Read signature(s) from [signature] file(s), generate a multisig signature compliant to the
|
|
multisig key [name], and attach it to the transaction read from [file].
|
|
|
|
Example:
|
|
$ %s 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.
|
|
`,
|
|
version.AppName,
|
|
),
|
|
),
|
|
RunE: makeMultiSignCmd(),
|
|
Args: cobra.MinimumNArgs(3),
|
|
}
|
|
|
|
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")
|
|
flags.AddTxFlagsToCmd(cmd)
|
|
cmd.Flags().String(flags.FlagChainID, "", "network chain ID")
|
|
|
|
return cmd
|
|
}
|
|
|
|
func makeMultiSignCmd() func(cmd *cobra.Command, args []string) error {
|
|
return func(cmd *cobra.Command, args []string) (err error) {
|
|
clientCtx := client.GetClientContextFromCmd(cmd)
|
|
clientCtx, err = client.ReadTxCommandFlags(clientCtx, cmd.Flags())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
parsedTx, err := authclient.ReadTxFromFile(clientCtx, args[0])
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
txFactory := tx.NewFactoryCLI(clientCtx, cmd.Flags())
|
|
if txFactory.SignMode() == signingtypes.SignMode_SIGN_MODE_UNSPECIFIED {
|
|
txFactory = txFactory.WithSignMode(signingtypes.SignMode_SIGN_MODE_LEGACY_AMINO_JSON)
|
|
}
|
|
|
|
txCfg := clientCtx.TxConfig
|
|
txBuilder, err := txCfg.WrapTxBuilder(parsedTx)
|
|
if err != nil {
|
|
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])
|
|
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())
|
|
}
|
|
|
|
multisigPub := multisigInfo.GetPubKey().(multisig.PubKeyMultisigThreshold)
|
|
multisigSig := multisig.NewMultisig(len(multisigPub.PubKeys))
|
|
if !clientCtx.Offline {
|
|
accnum, seq, err := clientCtx.AccountRetriever.GetAccountNumberSequence(clientCtx, multisigInfo.GetAddress())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
txFactory = txFactory.WithAccountNumber(accnum).WithSequence(seq)
|
|
}
|
|
|
|
// read each signature and add it to the multisig if valid
|
|
for i := 2; i < len(args); i++ {
|
|
sigs, err := unmarshalSignatureJSON(clientCtx, args[i])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
signingData := signing.SignerData{
|
|
ChainID: txFactory.ChainID(),
|
|
AccountNumber: txFactory.AccountNumber(),
|
|
Sequence: txFactory.Sequence(),
|
|
}
|
|
|
|
for _, sig := range sigs {
|
|
err = signing.VerifySignature(sig.PubKey, signingData, sig.Data, txCfg.SignModeHandler(), txBuilder.GetTx())
|
|
if err != nil {
|
|
return fmt.Errorf("couldn't verify signature: %w", err)
|
|
}
|
|
|
|
if err := multisig.AddSignatureV2(multisigSig, sig, multisigPub.PubKeys); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
|
|
sigV2 := signingtypes.SignatureV2{
|
|
PubKey: multisigPub,
|
|
Data: multisigSig,
|
|
Sequence: txFactory.Sequence(),
|
|
}
|
|
|
|
err = txBuilder.SetSignatures(sigV2)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
sigOnly, _ := cmd.Flags().GetBool(flagSigOnly)
|
|
|
|
json, err := marshalSignatureJSON(txCfg, txBuilder, sigOnly)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
outputDoc, _ := cmd.Flags().GetString(flags.FlagOutputDocument)
|
|
if outputDoc == "" {
|
|
cmd.Printf("%s\n", json)
|
|
return
|
|
}
|
|
|
|
fp, err := os.OpenFile(outputDoc, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer fp.Close()
|
|
|
|
return clientCtx.PrintString(fmt.Sprintf("%s\n", json))
|
|
}
|
|
}
|
|
|
|
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)
|
|
}
|