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