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  }