github.com/cosmos/cosmos-sdk@v0.50.10/x/auth/tx/testutil/suite.go (about)

     1  package testutil
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  
     7  	"github.com/stretchr/testify/suite"
     8  
     9  	signingv1beta1 "cosmossdk.io/api/cosmos/tx/signing/v1beta1"
    10  
    11  	"github.com/cosmos/cosmos-sdk/client"
    12  	kmultisig "github.com/cosmos/cosmos-sdk/crypto/keys/multisig"
    13  	cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
    14  	"github.com/cosmos/cosmos-sdk/crypto/types/multisig"
    15  	"github.com/cosmos/cosmos-sdk/testutil/testdata"
    16  	sdk "github.com/cosmos/cosmos-sdk/types"
    17  	signingtypes "github.com/cosmos/cosmos-sdk/types/tx/signing"
    18  	"github.com/cosmos/cosmos-sdk/x/auth/signing"
    19  )
    20  
    21  // TxConfigTestSuite provides a test suite that can be used to test that a TxConfig implementation is correct.
    22  type TxConfigTestSuite struct {
    23  	suite.Suite
    24  	TxConfig client.TxConfig
    25  }
    26  
    27  // NewTxConfigTestSuite returns a new TxConfigTestSuite with the provided TxConfig implementation
    28  func NewTxConfigTestSuite(txConfig client.TxConfig) *TxConfigTestSuite {
    29  	return &TxConfigTestSuite{TxConfig: txConfig}
    30  }
    31  
    32  func (s *TxConfigTestSuite) TestTxBuilderGetTx() {
    33  	txBuilder := s.TxConfig.NewTxBuilder()
    34  	tx := txBuilder.GetTx()
    35  	s.Require().NotNil(tx)
    36  	s.Require().Equal(len(tx.GetMsgs()), 0)
    37  }
    38  
    39  func (s *TxConfigTestSuite) TestTxBuilderSetFeeAmount() {
    40  	txBuilder := s.TxConfig.NewTxBuilder()
    41  	feeAmount := sdk.Coins{
    42  		sdk.NewInt64Coin("atom", 20000000),
    43  	}
    44  	txBuilder.SetFeeAmount(feeAmount)
    45  	feeTx := txBuilder.GetTx()
    46  	s.Require().Equal(feeAmount, feeTx.GetFee())
    47  }
    48  
    49  func (s *TxConfigTestSuite) TestTxBuilderSetGasLimit() {
    50  	const newGas uint64 = 300000
    51  	txBuilder := s.TxConfig.NewTxBuilder()
    52  	txBuilder.SetGasLimit(newGas)
    53  	feeTx := txBuilder.GetTx()
    54  	s.Require().Equal(newGas, feeTx.GetGas())
    55  }
    56  
    57  func (s *TxConfigTestSuite) TestTxBuilderSetMemo() {
    58  	const newMemo string = "newfoomemo"
    59  	txBuilder := s.TxConfig.NewTxBuilder()
    60  	txBuilder.SetMemo(newMemo)
    61  	txWithMemo := txBuilder.GetTx()
    62  	s.Require().Equal(txWithMemo.GetMemo(), newMemo)
    63  }
    64  
    65  func (s *TxConfigTestSuite) TestTxBuilderSetMsgs() {
    66  	_, _, addr1 := testdata.KeyTestPubAddr()
    67  	_, _, addr2 := testdata.KeyTestPubAddr()
    68  	msg1 := testdata.NewTestMsg(addr1)
    69  	msg2 := testdata.NewTestMsg(addr2)
    70  	msgs := []sdk.Msg{msg1, msg2}
    71  
    72  	txBuilder := s.TxConfig.NewTxBuilder()
    73  
    74  	err := txBuilder.SetMsgs(msgs...)
    75  	s.Require().NoError(err)
    76  	tx := txBuilder.GetTx()
    77  	s.Require().Equal(msgs, tx.GetMsgs())
    78  	signers, err := tx.GetSigners()
    79  	s.Require().NoError(err)
    80  	s.Require().Equal([][]byte{addr1, addr2}, signers)
    81  	s.Require().Equal([]byte(addr1), tx.FeePayer())
    82  	s.Require().Error(tx.ValidateBasic()) // should fail because of no signatures
    83  }
    84  
    85  func (s *TxConfigTestSuite) TestTxBuilderSetSignatures() {
    86  	privKey, pubkey, addr := testdata.KeyTestPubAddr()
    87  	privKey2, pubkey2, _ := testdata.KeyTestPubAddr()
    88  	multisigPk := kmultisig.NewLegacyAminoPubKey(2, []cryptotypes.PubKey{pubkey, pubkey2})
    89  
    90  	txBuilder := s.TxConfig.NewTxBuilder()
    91  
    92  	// set test msg
    93  	msg := testdata.NewTestMsg(addr)
    94  	msigAddr := sdk.AccAddress(multisigPk.Address())
    95  	msg2 := testdata.NewTestMsg(msigAddr)
    96  	err := txBuilder.SetMsgs(msg, msg2)
    97  	txBuilder.SetFeeAmount(testdata.NewTestFeeAmount())
    98  	s.Require().NoError(err)
    99  
   100  	// check that validation fails
   101  	s.Require().Error(txBuilder.GetTx().ValidateBasic())
   102  
   103  	signModeHandler := s.TxConfig.SignModeHandler()
   104  	s.Require().Contains(signModeHandler.SupportedModes(), signingv1beta1.SignMode_SIGN_MODE_DIRECT)
   105  	defaultSignMode, err := signing.APISignModeToInternal(s.TxConfig.SignModeHandler().DefaultMode())
   106  	s.Require().NoError(err)
   107  
   108  	// set SignatureV2 without actual signature bytes
   109  	seq1 := uint64(2) // Arbitrary account sequence
   110  	sigData1 := &signingtypes.SingleSignatureData{SignMode: defaultSignMode}
   111  	sig1 := signingtypes.SignatureV2{PubKey: pubkey, Data: sigData1, Sequence: seq1}
   112  
   113  	mseq := uint64(4) // Arbitrary account sequence
   114  	msigData := multisig.NewMultisig(2)
   115  	multisig.AddSignature(msigData, &signingtypes.SingleSignatureData{SignMode: defaultSignMode}, 0)
   116  	multisig.AddSignature(msigData, &signingtypes.SingleSignatureData{SignMode: defaultSignMode}, 1)
   117  	msig := signingtypes.SignatureV2{PubKey: multisigPk, Data: msigData, Sequence: mseq}
   118  
   119  	// fail validation without required signers
   120  	err = txBuilder.SetSignatures(sig1)
   121  	s.Require().NoError(err)
   122  	sigTx := txBuilder.GetTx()
   123  	s.Require().Error(sigTx.ValidateBasic())
   124  
   125  	err = txBuilder.SetSignatures(sig1, msig)
   126  	s.Require().NoError(err)
   127  	sigTx = txBuilder.GetTx()
   128  	sigsV2, err := sigTx.GetSignaturesV2()
   129  	s.Require().NoError(err)
   130  	s.Require().Len(sigsV2, 2)
   131  	s.Require().True(sigEquals(sig1, sigsV2[0]))
   132  	s.Require().True(sigEquals(msig, sigsV2[1]))
   133  	signers, err := sigTx.GetSigners()
   134  	s.Require().NoError(err)
   135  	s.Require().Equal([][]byte{addr, msigAddr}, signers)
   136  	s.Require().NoError(sigTx.ValidateBasic())
   137  
   138  	// sign transaction
   139  	signerData := signing.SignerData{
   140  		Address:       addr.String(),
   141  		ChainID:       "test",
   142  		AccountNumber: 1,
   143  		Sequence:      seq1,
   144  		PubKey:        pubkey,
   145  	}
   146  	signBytes, err := signing.GetSignBytesAdapter(context.Background(),
   147  		s.TxConfig.SignModeHandler(), defaultSignMode, signerData, sigTx)
   148  	s.Require().NoError(err)
   149  	sigBz, err := privKey.Sign(signBytes)
   150  	s.Require().NoError(err)
   151  
   152  	signerData = signing.SignerData{
   153  		Address:       msigAddr.String(),
   154  		ChainID:       "test",
   155  		AccountNumber: 3,
   156  		Sequence:      mseq,
   157  		PubKey:        multisigPk,
   158  	}
   159  	mSignBytes, err := signing.GetSignBytesAdapter(context.Background(),
   160  		s.TxConfig.SignModeHandler(), defaultSignMode, signerData, sigTx)
   161  	s.Require().NoError(err)
   162  	mSigBz1, err := privKey.Sign(mSignBytes)
   163  	s.Require().NoError(err)
   164  	mSigBz2, err := privKey2.Sign(mSignBytes)
   165  	s.Require().NoError(err)
   166  	msigData = multisig.NewMultisig(2)
   167  	multisig.AddSignature(msigData, &signingtypes.SingleSignatureData{
   168  		SignMode: defaultSignMode, Signature: mSigBz1,
   169  	}, 0)
   170  	multisig.AddSignature(msigData, &signingtypes.SingleSignatureData{
   171  		SignMode: defaultSignMode, Signature: mSigBz2,
   172  	}, 0)
   173  
   174  	// set signature
   175  	sigData1.Signature = sigBz
   176  	sig1 = signingtypes.SignatureV2{PubKey: pubkey, Data: sigData1, Sequence: seq1}
   177  	msig = signingtypes.SignatureV2{PubKey: multisigPk, Data: msigData, Sequence: mseq}
   178  	err = txBuilder.SetSignatures(sig1, msig)
   179  	s.Require().NoError(err)
   180  	sigTx = txBuilder.GetTx()
   181  	sigsV2, err = sigTx.GetSignaturesV2()
   182  	s.Require().NoError(err)
   183  	s.Require().Len(sigsV2, 2)
   184  	s.Require().True(sigEquals(sig1, sigsV2[0]))
   185  	s.Require().True(sigEquals(msig, sigsV2[1]))
   186  	signers, err = sigTx.GetSigners()
   187  	s.Require().NoError(err)
   188  	s.Require().Equal([][]byte{addr, msigAddr}, signers)
   189  	s.Require().NoError(sigTx.ValidateBasic())
   190  }
   191  
   192  func sigEquals(sig1, sig2 signingtypes.SignatureV2) bool {
   193  	if !sig1.PubKey.Equals(sig2.PubKey) {
   194  		return false
   195  	}
   196  
   197  	if sig1.Data == nil && sig2.Data == nil {
   198  		return true
   199  	}
   200  
   201  	return sigDataEquals(sig1.Data, sig2.Data)
   202  }
   203  
   204  func sigDataEquals(data1, data2 signingtypes.SignatureData) bool {
   205  	switch data1 := data1.(type) {
   206  	case *signingtypes.SingleSignatureData:
   207  		data2, ok := data2.(*signingtypes.SingleSignatureData)
   208  		if !ok {
   209  			return false
   210  		}
   211  
   212  		if data1.SignMode != data2.SignMode {
   213  			return false
   214  		}
   215  
   216  		return bytes.Equal(data1.Signature, data2.Signature)
   217  	case *signingtypes.MultiSignatureData:
   218  		data2, ok := data2.(*signingtypes.MultiSignatureData)
   219  		if !ok {
   220  			return false
   221  		}
   222  		if !data1.BitArray.Equal(data2.BitArray) || len(data1.Signatures) != len(data2.Signatures) {
   223  			return false
   224  		}
   225  
   226  		for i, s := range data1.Signatures {
   227  			if !sigDataEquals(s, data2.Signatures[i]) {
   228  				return false
   229  			}
   230  		}
   231  
   232  		return true
   233  	default:
   234  		return false
   235  	}
   236  }
   237  
   238  func (s *TxConfigTestSuite) TestTxEncodeDecode() {
   239  	log := s.T().Log
   240  	_, pubkey, addr := testdata.KeyTestPubAddr()
   241  	feeAmount := sdk.Coins{sdk.NewInt64Coin("atom", 150)}
   242  	gasLimit := uint64(50000)
   243  	memo := "foomemo"
   244  	msg := testdata.NewTestMsg(addr)
   245  	dummySig := []byte("dummySig")
   246  	sig := signingtypes.SignatureV2{
   247  		PubKey: pubkey,
   248  		Data: &signingtypes.SingleSignatureData{
   249  			SignMode:  signingtypes.SignMode_SIGN_MODE_LEGACY_AMINO_JSON,
   250  			Signature: dummySig,
   251  		},
   252  	}
   253  
   254  	txBuilder := s.TxConfig.NewTxBuilder()
   255  	txBuilder.SetFeeAmount(feeAmount)
   256  	txBuilder.SetGasLimit(gasLimit)
   257  	txBuilder.SetMemo(memo)
   258  	err := txBuilder.SetMsgs(msg)
   259  	s.Require().NoError(err)
   260  	err = txBuilder.SetSignatures(sig)
   261  	s.Require().NoError(err)
   262  	tx := txBuilder.GetTx()
   263  
   264  	log("encode transaction")
   265  	txBytes, err := s.TxConfig.TxEncoder()(tx)
   266  	s.Require().NoError(err)
   267  	s.Require().NotNil(txBytes)
   268  	log("decode transaction", s.TxConfig)
   269  	tx2, err := s.TxConfig.TxDecoder()(txBytes)
   270  
   271  	s.Require().NoError(err)
   272  	tx3, ok := tx2.(signing.Tx)
   273  	s.Require().True(ok)
   274  	s.Require().Equal([]sdk.Msg{msg}, tx3.GetMsgs())
   275  	s.Require().Equal(feeAmount, tx3.GetFee())
   276  	s.Require().Equal(gasLimit, tx3.GetGas())
   277  	s.Require().Equal(memo, tx3.GetMemo())
   278  	tx3Sigs, err := tx3.GetSignaturesV2()
   279  	s.Require().NoError(err)
   280  	s.Require().Equal([]signingtypes.SignatureV2{sig}, tx3Sigs)
   281  	pks, err := tx3.GetPubKeys()
   282  	s.Require().NoError(err)
   283  	s.Require().Equal([]cryptotypes.PubKey{pubkey}, pks)
   284  
   285  	log("JSON encode transaction")
   286  	jsonTxBytes, err := s.TxConfig.TxJSONEncoder()(tx)
   287  	s.Require().NoError(err)
   288  	s.Require().NotNil(jsonTxBytes)
   289  
   290  	log("JSON decode transaction")
   291  	tx2, err = s.TxConfig.TxJSONDecoder()(jsonTxBytes)
   292  	s.Require().NoError(err)
   293  	tx3, ok = tx2.(signing.Tx)
   294  	s.Require().True(ok)
   295  	s.Require().Equal([]sdk.Msg{msg}, tx3.GetMsgs())
   296  	s.Require().Equal(feeAmount, tx3.GetFee())
   297  	s.Require().Equal(gasLimit, tx3.GetGas())
   298  	s.Require().Equal(memo, tx3.GetMemo())
   299  	tx3Sigs, err = tx3.GetSignaturesV2()
   300  	s.Require().NoError(err)
   301  	s.Require().Equal([]signingtypes.SignatureV2{sig}, tx3Sigs)
   302  	pks, err = tx3.GetPubKeys()
   303  	s.Require().NoError(err)
   304  	s.Require().Equal([]cryptotypes.PubKey{pubkey}, pks)
   305  }
   306  
   307  func (s *TxConfigTestSuite) TestWrapTxBuilder() {
   308  	_, _, addr := testdata.KeyTestPubAddr()
   309  	feeAmount := sdk.Coins{sdk.NewInt64Coin("atom", 150)}
   310  	gasLimit := uint64(50000)
   311  	memo := "foomemo"
   312  	msg := testdata.NewTestMsg(addr)
   313  
   314  	txBuilder := s.TxConfig.NewTxBuilder()
   315  	txBuilder.SetFeeAmount(feeAmount)
   316  	txBuilder.SetGasLimit(gasLimit)
   317  	txBuilder.SetMemo(memo)
   318  	err := txBuilder.SetMsgs(msg)
   319  	s.Require().NoError(err)
   320  
   321  	newTxBldr, err := s.TxConfig.WrapTxBuilder(txBuilder.GetTx())
   322  	s.Require().NoError(err)
   323  	s.Require().Equal(txBuilder, newTxBldr)
   324  }