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

     1  package tx_test
     2  
     3  import (
     4  	"context"
     5  	"testing"
     6  
     7  	"github.com/stretchr/testify/require"
     8  
     9  	clienttx "github.com/cosmos/cosmos-sdk/client/tx"
    10  	codectypes "github.com/cosmos/cosmos-sdk/codec/types"
    11  	"github.com/cosmos/cosmos-sdk/testutil/testdata"
    12  	_ "github.com/cosmos/cosmos-sdk/testutil/testdata/testpb"
    13  	sdk "github.com/cosmos/cosmos-sdk/types"
    14  	moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil"
    15  	"github.com/cosmos/cosmos-sdk/types/tx/signing"
    16  	authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
    17  )
    18  
    19  var (
    20  	// The final TX has 3 signers, in this order.
    21  	tipperPriv, tipperPk, tipperAddr       = testdata.KeyTestPubAddr()
    22  	aux2Priv, aux2Pk, aux2Addr             = testdata.KeyTestPubAddr()
    23  	feepayerPriv, feepayerPk, feepayerAddr = testdata.KeyTestPubAddr()
    24  
    25  	msg  = testdata.NewTestMsg(tipperAddr, aux2Addr)
    26  	memo = "test-memo"
    27  
    28  	chainID = "test-chain"
    29  	gas     = testdata.NewTestGasLimit()
    30  	fee     = testdata.NewTestFeeAmount()
    31  	extOpt  = &testdata.Cat{}
    32  )
    33  
    34  // TestBuilderWithAux creates a tx with 2 aux signers:
    35  // - 1st one is tipper,
    36  // - 2nd one is just an aux signer.
    37  // Then it tests integrating the 2 AuxSignerData into a
    38  // client.TxBuilder created by the fee payer.
    39  func TestBuilderWithAux(t *testing.T) {
    40  	encodingConfig := moduletestutil.MakeTestEncodingConfig()
    41  	interfaceRegistry := encodingConfig.InterfaceRegistry
    42  	txConfig := encodingConfig.TxConfig
    43  
    44  	testdata.RegisterInterfaces(interfaceRegistry)
    45  
    46  	// Create an AuxTxBuilder for tipper (1st signer)
    47  	txBuilder, txSig := makeTxBuilder(t)
    48  	txSignerData, err := txBuilder.GetAuxSignerData()
    49  	require.NoError(t, err)
    50  
    51  	// Create an AuxTxBuilder for aux2 (2nd signer)
    52  	aux2Builder := clienttx.NewAuxTxBuilder()
    53  	aux2Builder.SetAddress(aux2Addr.String())
    54  	aux2Builder.SetAccountNumber(11)
    55  	aux2Builder.SetSequence(12)
    56  	aux2Builder.SetTimeoutHeight(3)
    57  	aux2Builder.SetMemo(memo)
    58  	aux2Builder.SetChainID(chainID)
    59  	err = aux2Builder.SetMsgs(msg)
    60  	require.NoError(t, err)
    61  	err = aux2Builder.SetPubKey(aux2Pk)
    62  	require.NoError(t, err)
    63  	extOptAny, err := codectypes.NewAnyWithValue(extOpt)
    64  	require.NoError(t, err)
    65  	aux2Builder.SetExtensionOptions(extOptAny)
    66  	aux2Builder.SetNonCriticalExtensionOptions(extOptAny)
    67  	err = aux2Builder.SetSignMode(signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON)
    68  	require.NoError(t, err)
    69  	signBz, err := aux2Builder.GetSignBytes()
    70  	require.NoError(t, err)
    71  	aux2Sig, err := aux2Priv.Sign(signBz)
    72  	require.NoError(t, err)
    73  	aux2Builder.SetSignature(aux2Sig)
    74  	aux2SignerData, err := aux2Builder.GetAuxSignerData()
    75  	require.NoError(t, err)
    76  
    77  	// Fee payer (3rd and last signer) creates a TxBuilder.
    78  	w := txConfig.NewTxBuilder()
    79  	// Note: we're testing calling AddAuxSignerData in the wrong order, i.e.
    80  	// adding the aux2 signer data first before the tipper.
    81  	err = w.AddAuxSignerData(aux2SignerData)
    82  	require.NoError(t, err)
    83  
    84  	// Test that when adding another AuxSignerData, the 2nd data should match
    85  	// the 1st one.
    86  	testcases := []struct {
    87  		name     string
    88  		malleate func()
    89  		expErr   bool
    90  	}{
    91  		{"address and msg signer mistacher", func() { txBuilder.SetAddress("foobar") }, true},
    92  		{"memo mismatch", func() { txBuilder.SetMemo("mismatch") }, true},
    93  		{"timeout height mismatch", func() { txBuilder.SetTimeoutHeight(98) }, true},
    94  		{"extension options length mismatch", func() { txBuilder.SetExtensionOptions() }, true},
    95  		{"extension options member mismatch", func() { txBuilder.SetExtensionOptions(&codectypes.Any{}) }, true},
    96  		{"non-critical extension options length mismatch", func() { txBuilder.SetNonCriticalExtensionOptions() }, true},
    97  		{"non-critical extension options member mismatch", func() { txBuilder.SetNonCriticalExtensionOptions(&codectypes.Any{}) }, true},
    98  		{"happy case", func() {}, false},
    99  	}
   100  	for _, tc := range testcases {
   101  		tc := tc
   102  		t.Run(tc.name, func(t *testing.T) {
   103  			txBuilder, txSig = makeTxBuilder(t)
   104  
   105  			tc.malleate()
   106  
   107  			_, err := txBuilder.GetSignBytes()
   108  			require.NoError(t, err)
   109  			txSignerData, err = txBuilder.GetAuxSignerData()
   110  			require.NoError(t, err)
   111  
   112  			err = w.AddAuxSignerData(txSignerData)
   113  			if tc.expErr {
   114  				require.Error(t, err)
   115  			} else {
   116  				require.NoError(t, err)
   117  			}
   118  		})
   119  	}
   120  
   121  	w.SetFeePayer(feepayerAddr)
   122  	w.SetFeeAmount(fee)
   123  	w.SetGasLimit(gas)
   124  	sigs, err := w.(authsigning.SigVerifiableTx).GetSignaturesV2()
   125  	require.NoError(t, err)
   126  	txSigV2 := sigs[0]
   127  	aux2SigV2 := sigs[1]
   128  	// Set all signer infos.
   129  	w.SetSignatures(txSigV2, aux2SigV2, signing.SignatureV2{
   130  		PubKey:   feepayerPk,
   131  		Sequence: 15,
   132  	})
   133  	signerData := authsigning.SignerData{
   134  		Address:       feepayerAddr.String(),
   135  		ChainID:       chainID,
   136  		AccountNumber: 11,
   137  		Sequence:      15,
   138  		PubKey:        feepayerPk,
   139  	}
   140  
   141  	signBz, err = authsigning.GetSignBytesAdapter(
   142  		context.Background(), txConfig.SignModeHandler(), signing.SignMode_SIGN_MODE_DIRECT,
   143  		signerData, w.GetTx())
   144  
   145  	require.NoError(t, err)
   146  	feepayerSig, err := feepayerPriv.Sign(signBz)
   147  	require.NoError(t, err)
   148  	// Set all signatures.
   149  	w.SetSignatures(txSigV2, aux2SigV2, signing.SignatureV2{
   150  		PubKey: feepayerPk,
   151  		Data: &signing.SingleSignatureData{
   152  			SignMode:  signing.SignMode_SIGN_MODE_DIRECT,
   153  			Signature: feepayerSig,
   154  		},
   155  		Sequence: 22,
   156  	})
   157  
   158  	// Make sure tx is correct.
   159  	txBz, err := txConfig.TxEncoder()(w.GetTx())
   160  	require.NoError(t, err)
   161  	tx, err := txConfig.TxDecoder()(txBz)
   162  	require.NoError(t, err)
   163  	require.Equal(t, tx.(sdk.FeeTx).FeePayer(), []byte(feepayerAddr))
   164  	require.Equal(t, tx.(sdk.FeeTx).GetFee(), fee)
   165  	require.Equal(t, tx.(sdk.FeeTx).GetGas(), gas)
   166  	require.Equal(t, msg, tx.GetMsgs()[0])
   167  	require.Equal(t, memo, tx.(sdk.TxWithMemo).GetMemo())
   168  	require.Equal(t, uint64(3), tx.(sdk.TxWithTimeoutHeight).GetTimeoutHeight())
   169  	sigs, err = tx.(authsigning.Tx).GetSignaturesV2()
   170  	require.NoError(t, err)
   171  	require.Len(t, sigs, 3)
   172  	require.Equal(t, signing.SignatureV2{
   173  		PubKey:   tipperPk,
   174  		Data:     &signing.SingleSignatureData{SignMode: signing.SignMode_SIGN_MODE_DIRECT_AUX, Signature: txSig},
   175  		Sequence: 2,
   176  	}, sigs[0])
   177  	require.Equal(t, signing.SignatureV2{
   178  		PubKey:   aux2Pk,
   179  		Data:     &signing.SingleSignatureData{SignMode: signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON, Signature: aux2Sig},
   180  		Sequence: 12,
   181  	}, sigs[1])
   182  	require.Equal(t, signing.SignatureV2{
   183  		PubKey:   feepayerPk,
   184  		Data:     &signing.SingleSignatureData{SignMode: signing.SignMode_SIGN_MODE_DIRECT, Signature: feepayerSig},
   185  		Sequence: 22,
   186  	}, sigs[2])
   187  }
   188  
   189  func makeTxBuilder(t *testing.T) (clienttx.AuxTxBuilder, []byte) {
   190  	t.Helper()
   191  	txBuilder := clienttx.NewAuxTxBuilder()
   192  	txBuilder.SetAddress(tipperAddr.String())
   193  	txBuilder.SetAccountNumber(1)
   194  	txBuilder.SetSequence(2)
   195  	txBuilder.SetTimeoutHeight(3)
   196  	txBuilder.SetMemo(memo)
   197  	txBuilder.SetChainID(chainID)
   198  	err := txBuilder.SetMsgs(msg)
   199  	require.NoError(t, err)
   200  	err = txBuilder.SetPubKey(tipperPk)
   201  	require.NoError(t, err)
   202  	extOptAny, err := codectypes.NewAnyWithValue(extOpt)
   203  	require.NoError(t, err)
   204  	txBuilder.SetExtensionOptions(extOptAny)
   205  	txBuilder.SetNonCriticalExtensionOptions(extOptAny)
   206  	err = txBuilder.SetSignMode(signing.SignMode_SIGN_MODE_DIRECT_AUX)
   207  	require.NoError(t, err)
   208  	signBz, err := txBuilder.GetSignBytes()
   209  	require.NoError(t, err)
   210  	tipperSig, err := tipperPriv.Sign(signBz)
   211  	require.NoError(t, err)
   212  	txBuilder.SetSignature(tipperSig)
   213  
   214  	return txBuilder, tipperSig
   215  }