github.com/cosmos/cosmos-sdk@v0.50.10/x/auth/client/cli/validate_sigs.go (about) 1 package cli 2 3 import ( 4 "bytes" 5 "fmt" 6 7 "github.com/spf13/cobra" 8 "google.golang.org/protobuf/types/known/anypb" 9 10 txsigning "cosmossdk.io/x/tx/signing" 11 12 "github.com/cosmos/cosmos-sdk/client" 13 "github.com/cosmos/cosmos-sdk/client/flags" 14 "github.com/cosmos/cosmos-sdk/client/tx" 15 codectypes "github.com/cosmos/cosmos-sdk/codec/types" 16 sdk "github.com/cosmos/cosmos-sdk/types" 17 authclient "github.com/cosmos/cosmos-sdk/x/auth/client" 18 authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" 19 ) 20 21 func GetValidateSignaturesCommand() *cobra.Command { 22 cmd := &cobra.Command{ 23 Use: "validate-signatures [file]", 24 Short: "validate transactions signatures", 25 Long: `Print the addresses that must sign the transaction, those who have already 26 signed it, and make sure that signatures are in the correct order. 27 28 The command would check whether all required signers have signed the transactions, whether 29 the signatures were collected in the right order, and if the signature is valid over the 30 given transaction. If the --offline flag is also set, signature validation over the 31 transaction will be not be performed as that will require RPC communication with a full node. 32 `, 33 PreRun: preSignCmd, 34 RunE: makeValidateSignaturesCmd(), 35 Args: cobra.ExactArgs(1), 36 } 37 38 flags.AddTxFlagsToCmd(cmd) 39 40 return cmd 41 } 42 43 func makeValidateSignaturesCmd() func(cmd *cobra.Command, args []string) error { 44 return func(cmd *cobra.Command, args []string) error { 45 clientCtx, err := client.GetClientTxContext(cmd) 46 if err != nil { 47 return err 48 } 49 clientCtx, txBldr, stdTx, err := readTxAndInitContexts(clientCtx, cmd, args[0]) 50 if err != nil { 51 return err 52 } 53 54 if !printAndValidateSigs(cmd, clientCtx, txBldr.ChainID(), stdTx, clientCtx.Offline) { 55 return fmt.Errorf("signatures validation failed") 56 } 57 58 return nil 59 } 60 } 61 62 // printAndValidateSigs will validate the signatures of a given transaction over its 63 // expected signers. In addition, if offline has not been supplied, the signature is 64 // verified over the transaction sign bytes. Returns false if the validation fails. 65 func printAndValidateSigs( 66 cmd *cobra.Command, clientCtx client.Context, chainID string, tx sdk.Tx, offline bool, 67 ) bool { 68 sigTx := tx.(authsigning.SigVerifiableTx) 69 signModeHandler := clientCtx.TxConfig.SignModeHandler() 70 addrCdc := clientCtx.TxConfig.SigningContext().AddressCodec() 71 72 cmd.Println("Signers:") 73 signers, err := sigTx.GetSigners() 74 if err != nil { 75 panic(err) 76 } 77 78 for i, signer := range signers { 79 signerStr, err := addrCdc.BytesToString(signer) 80 if err != nil { 81 panic(err) 82 } 83 cmd.Printf(" %v: %v\n", i, signerStr) 84 } 85 86 success := true 87 sigs, err := sigTx.GetSignaturesV2() 88 if err != nil { 89 panic(err) 90 } 91 cmd.Println("") 92 cmd.Println("Signatures:") 93 94 if len(sigs) != len(signers) { 95 success = false 96 } 97 98 for i, sig := range sigs { 99 var ( 100 pubKey = sig.PubKey 101 multiSigHeader string 102 multiSigMsg string 103 sigAddr = sdk.AccAddress(pubKey.Address()) 104 sigSanity = "OK" 105 ) 106 107 if i >= len(signers) || !bytes.Equal(sigAddr, signers[i]) { 108 sigSanity = "ERROR: signature does not match its respective signer" 109 success = false 110 } 111 112 // validate the actual signature over the transaction bytes since we can 113 // reach out to a full node to query accounts. 114 if !offline && success { 115 accNum, accSeq, err := clientCtx.AccountRetriever.GetAccountNumberSequence(clientCtx, sigAddr) 116 if err != nil { 117 cmd.PrintErrf("failed to get account: %s\n", sigAddr) 118 return false 119 } 120 121 signingData := authsigning.SignerData{ 122 Address: sigAddr.String(), 123 ChainID: chainID, 124 AccountNumber: accNum, 125 Sequence: accSeq, 126 PubKey: pubKey, 127 } 128 anyPk, err := codectypes.NewAnyWithValue(pubKey) 129 if err != nil { 130 cmd.PrintErrf("failed to pack public key: %v", err) 131 return false 132 } 133 txSignerData := txsigning.SignerData{ 134 ChainID: signingData.ChainID, 135 AccountNumber: signingData.AccountNumber, 136 Sequence: signingData.Sequence, 137 Address: signingData.Address, 138 PubKey: &anypb.Any{ 139 TypeUrl: anyPk.TypeUrl, 140 Value: anyPk.Value, 141 }, 142 } 143 144 adaptableTx, ok := tx.(authsigning.V2AdaptableTx) 145 if !ok { 146 cmd.PrintErrf("expected V2AdaptableTx, got %T", tx) 147 return false 148 } 149 txData := adaptableTx.GetSigningTxData() 150 151 err = authsigning.VerifySignature(cmd.Context(), pubKey, txSignerData, sig.Data, signModeHandler, txData) 152 if err != nil { 153 cmd.PrintErrf("failed to verify signature: %v", err) 154 return false 155 } 156 } 157 158 cmd.Printf(" %d: %s\t\t\t[%s]%s%s\n", i, sigAddr.String(), sigSanity, multiSigHeader, multiSigMsg) 159 } 160 161 cmd.Println("") 162 163 return success 164 } 165 166 func readTxAndInitContexts(clientCtx client.Context, cmd *cobra.Command, filename string) (client.Context, tx.Factory, sdk.Tx, error) { 167 stdTx, err := authclient.ReadTxFromFile(clientCtx, filename) 168 if err != nil { 169 return clientCtx, tx.Factory{}, nil, err 170 } 171 172 txFactory, err := tx.NewFactoryCLI(clientCtx, cmd.Flags()) 173 if err != nil { 174 return clientCtx, tx.Factory{}, nil, err 175 } 176 177 return clientCtx, txFactory, stdTx, nil 178 }