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

     1  package tx
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/stretchr/testify/require"
     7  
     8  	errorsmod "cosmossdk.io/errors"
     9  	sdkmath "cosmossdk.io/math"
    10  
    11  	"github.com/cosmos/cosmos-sdk/codec"
    12  	"github.com/cosmos/cosmos-sdk/codec/legacy"
    13  	"github.com/cosmos/cosmos-sdk/codec/testutil"
    14  	codectypes "github.com/cosmos/cosmos-sdk/codec/types"
    15  	"github.com/cosmos/cosmos-sdk/testutil/testdata"
    16  	sdk "github.com/cosmos/cosmos-sdk/types"
    17  	sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
    18  	txtypes "github.com/cosmos/cosmos-sdk/types/tx"
    19  	"github.com/cosmos/cosmos-sdk/types/tx/signing"
    20  )
    21  
    22  func TestTxBuilder(t *testing.T) {
    23  	_, pubkey, addr := testdata.KeyTestPubAddr()
    24  
    25  	marshaler := codec.NewProtoCodec(codectypes.NewInterfaceRegistry())
    26  	txBuilder := newBuilder(marshaler)
    27  
    28  	memo := "testmemo"
    29  	msgs := []sdk.Msg{testdata.NewTestMsg(addr)}
    30  	accSeq := uint64(2) // Arbitrary account sequence
    31  	any, err := codectypes.NewAnyWithValue(pubkey)
    32  	require.NoError(t, err)
    33  
    34  	var signerInfo []*txtypes.SignerInfo
    35  	signerInfo = append(signerInfo, &txtypes.SignerInfo{
    36  		PublicKey: any,
    37  		ModeInfo: &txtypes.ModeInfo{
    38  			Sum: &txtypes.ModeInfo_Single_{
    39  				Single: &txtypes.ModeInfo_Single{
    40  					Mode: signing.SignMode_SIGN_MODE_DIRECT,
    41  				},
    42  			},
    43  		},
    44  		Sequence: accSeq,
    45  	})
    46  
    47  	sig := signing.SignatureV2{
    48  		PubKey: pubkey,
    49  		Data: &signing.SingleSignatureData{
    50  			SignMode:  signing.SignMode_SIGN_MODE_DIRECT,
    51  			Signature: legacy.Cdc.MustMarshal(pubkey),
    52  		},
    53  		Sequence: accSeq,
    54  	}
    55  
    56  	fee := txtypes.Fee{Amount: sdk.NewCoins(sdk.NewInt64Coin("atom", 150)), GasLimit: 20000}
    57  
    58  	t.Log("verify that authInfo bytes encoded with DefaultTxEncoder and decoded with DefaultTxDecoder can be retrieved from getAuthInfoBytes")
    59  	authInfo := &txtypes.AuthInfo{
    60  		Fee:         &fee,
    61  		SignerInfos: signerInfo,
    62  	}
    63  
    64  	authInfoBytes := marshaler.MustMarshal(authInfo)
    65  
    66  	require.NotEmpty(t, authInfoBytes)
    67  
    68  	t.Log("verify that body bytes encoded with DefaultTxEncoder and decoded with DefaultTxDecoder can be retrieved from getBodyBytes")
    69  	anys := make([]*codectypes.Any, len(msgs))
    70  
    71  	for i, msg := range msgs {
    72  		var err error
    73  		anys[i], err = codectypes.NewAnyWithValue(msg)
    74  		if err != nil {
    75  			panic(err)
    76  		}
    77  	}
    78  
    79  	txBody := &txtypes.TxBody{
    80  		Memo:     memo,
    81  		Messages: anys,
    82  	}
    83  	bodyBytes := marshaler.MustMarshal(txBody)
    84  	require.NotEmpty(t, bodyBytes)
    85  	require.Empty(t, txBuilder.getBodyBytes())
    86  
    87  	t.Log("verify that calling the SetMsgs, SetMemo results in the correct getBodyBytes")
    88  	require.NotEqual(t, bodyBytes, txBuilder.getBodyBytes())
    89  	err = txBuilder.SetMsgs(msgs...)
    90  	require.NoError(t, err)
    91  	require.NotEqual(t, bodyBytes, txBuilder.getBodyBytes())
    92  	txBuilder.SetMemo(memo)
    93  	require.Equal(t, bodyBytes, txBuilder.getBodyBytes())
    94  	require.Equal(t, len(msgs), len(txBuilder.GetMsgs()))
    95  	pks, err := txBuilder.GetPubKeys()
    96  	require.NoError(t, err)
    97  	require.Empty(t, pks)
    98  
    99  	t.Log("verify that updated AuthInfo  results in the correct getAuthInfoBytes and GetPubKeys")
   100  	require.NotEqual(t, authInfoBytes, txBuilder.getAuthInfoBytes())
   101  	txBuilder.SetFeeAmount(fee.Amount)
   102  	require.NotEqual(t, authInfoBytes, txBuilder.getAuthInfoBytes())
   103  	txBuilder.SetGasLimit(fee.GasLimit)
   104  	require.NotEqual(t, authInfoBytes, txBuilder.getAuthInfoBytes())
   105  	err = txBuilder.SetSignatures(sig)
   106  	require.NoError(t, err)
   107  
   108  	// once fee, gas and signerInfos are all set, AuthInfo bytes should match
   109  	require.Equal(t, authInfoBytes, txBuilder.getAuthInfoBytes())
   110  
   111  	require.Equal(t, len(msgs), len(txBuilder.GetMsgs()))
   112  	pks, err = txBuilder.GetPubKeys()
   113  	require.NoError(t, err)
   114  	require.Equal(t, 1, len(pks))
   115  	require.True(t, pubkey.Equals(pks[0]))
   116  
   117  	any, err = codectypes.NewAnyWithValue(testdata.NewTestMsg())
   118  	require.NoError(t, err)
   119  	txBuilder.SetExtensionOptions(any)
   120  	require.Equal(t, []*codectypes.Any{any}, txBuilder.GetExtensionOptions())
   121  	txBuilder.SetNonCriticalExtensionOptions(any)
   122  	require.Equal(t, []*codectypes.Any{any}, txBuilder.GetNonCriticalExtensionOptions())
   123  
   124  	txBuilder = &wrapper{}
   125  	require.NotPanics(t, func() {
   126  		_ = txBuilder.GetMsgs()
   127  	})
   128  }
   129  
   130  func TestSetSignaturesNoPublicKey(t *testing.T) {
   131  	_, pubkey, _ := testdata.KeyTestPubAddr()
   132  	txBuilder := newBuilder(nil)
   133  	sig2 := signing.SignatureV2{
   134  		Data: &signing.SingleSignatureData{
   135  			SignMode:  signing.SignMode_SIGN_MODE_DIRECT,
   136  			Signature: legacy.Cdc.MustMarshal(pubkey),
   137  		},
   138  		Sequence: 1,
   139  	}
   140  	err := txBuilder.SetSignatures(sig2)
   141  	require.NoError(t, err)
   142  }
   143  
   144  func TestBuilderValidateBasic(t *testing.T) {
   145  	// keys and addresses
   146  	_, pubKey1, addr1 := testdata.KeyTestPubAddr()
   147  	_, pubKey2, addr2 := testdata.KeyTestPubAddr()
   148  
   149  	// msg and signatures
   150  	msg1 := testdata.NewTestMsg(addr1, addr2)
   151  	feeAmount := testdata.NewTestFeeAmount()
   152  	msgs := []sdk.Msg{msg1}
   153  
   154  	// require to fail validation upon invalid fee
   155  	badFeeAmount := testdata.NewTestFeeAmount()
   156  	badFeeAmount[0].Amount = sdkmath.NewInt(-5)
   157  	txBuilder := newBuilder(testutil.CodecOptions{}.NewCodec())
   158  
   159  	var sig1, sig2 signing.SignatureV2
   160  	sig1 = signing.SignatureV2{
   161  		PubKey: pubKey1,
   162  		Data: &signing.SingleSignatureData{
   163  			SignMode:  signing.SignMode_SIGN_MODE_DIRECT,
   164  			Signature: legacy.Cdc.MustMarshal(pubKey1),
   165  		},
   166  		Sequence: 0, // Arbitrary account sequence
   167  	}
   168  
   169  	sig2 = signing.SignatureV2{
   170  		PubKey: pubKey2,
   171  		Data: &signing.SingleSignatureData{
   172  			SignMode:  signing.SignMode_SIGN_MODE_DIRECT,
   173  			Signature: legacy.Cdc.MustMarshal(pubKey2),
   174  		},
   175  		Sequence: 0, // Arbitrary account sequence
   176  	}
   177  
   178  	err := txBuilder.SetMsgs(msgs...)
   179  	require.NoError(t, err)
   180  	txBuilder.SetGasLimit(200000)
   181  	err = txBuilder.SetSignatures(sig1, sig2)
   182  	require.NoError(t, err)
   183  	txBuilder.SetFeeAmount(badFeeAmount)
   184  	err = txBuilder.ValidateBasic()
   185  	require.Error(t, err)
   186  	_, code, _ := errorsmod.ABCIInfo(err, false)
   187  	require.Equal(t, sdkerrors.ErrInsufficientFee.ABCICode(), code)
   188  
   189  	// require to fail validation when no signatures exist
   190  	err = txBuilder.SetSignatures()
   191  	require.NoError(t, err)
   192  	txBuilder.SetFeeAmount(feeAmount)
   193  	err = txBuilder.ValidateBasic()
   194  	require.Error(t, err)
   195  	_, code, _ = errorsmod.ABCIInfo(err, false)
   196  	require.Equal(t, sdkerrors.ErrNoSignatures.ABCICode(), code)
   197  
   198  	// require to fail with nil values for tx, authinfo
   199  	err = txBuilder.SetMsgs(msgs...)
   200  	require.NoError(t, err)
   201  	err = txBuilder.ValidateBasic()
   202  	require.Error(t, err)
   203  
   204  	// require to fail validation when signatures do not match expected signers
   205  	err = txBuilder.SetSignatures(sig1)
   206  	require.NoError(t, err)
   207  
   208  	err = txBuilder.ValidateBasic()
   209  	require.Error(t, err)
   210  	_, code, _ = errorsmod.ABCIInfo(err, false)
   211  	require.Equal(t, sdkerrors.ErrUnauthorized.ABCICode(), code)
   212  
   213  	require.Error(t, err)
   214  	txBuilder.SetFeeAmount(feeAmount)
   215  	err = txBuilder.SetSignatures(sig1, sig2)
   216  	require.NoError(t, err)
   217  	err = txBuilder.ValidateBasic()
   218  	require.NoError(t, err)
   219  
   220  	// gas limit too high
   221  	txBuilder.SetGasLimit(txtypes.MaxGasWanted + 1)
   222  	err = txBuilder.ValidateBasic()
   223  	require.Error(t, err)
   224  	txBuilder.SetGasLimit(txtypes.MaxGasWanted - 1)
   225  	err = txBuilder.ValidateBasic()
   226  	require.NoError(t, err)
   227  
   228  	// bad builder structs
   229  
   230  	// missing body
   231  	body := txBuilder.tx.Body
   232  	txBuilder.tx.Body = nil
   233  	err = txBuilder.ValidateBasic()
   234  	require.Error(t, err)
   235  	txBuilder.tx.Body = body
   236  	err = txBuilder.ValidateBasic()
   237  	require.NoError(t, err)
   238  
   239  	// missing fee
   240  	f := txBuilder.tx.AuthInfo.Fee
   241  	txBuilder.tx.AuthInfo.Fee = nil
   242  	err = txBuilder.ValidateBasic()
   243  	require.Error(t, err)
   244  	txBuilder.tx.AuthInfo.Fee = f
   245  	err = txBuilder.ValidateBasic()
   246  	require.NoError(t, err)
   247  
   248  	// missing AuthInfo
   249  	authInfo := txBuilder.tx.AuthInfo
   250  	txBuilder.tx.AuthInfo = nil
   251  	err = txBuilder.ValidateBasic()
   252  	require.Error(t, err)
   253  	txBuilder.tx.AuthInfo = authInfo
   254  	err = txBuilder.ValidateBasic()
   255  	require.NoError(t, err)
   256  
   257  	// missing tx
   258  	txBuilder.tx = nil
   259  	err = txBuilder.ValidateBasic()
   260  	require.Error(t, err)
   261  }
   262  
   263  func TestBuilderFeePayer(t *testing.T) {
   264  	// keys and addresses
   265  	_, _, addr1 := testdata.KeyTestPubAddr()
   266  	_, _, addr2 := testdata.KeyTestPubAddr()
   267  	_, _, addr3 := testdata.KeyTestPubAddr()
   268  
   269  	// msg and signatures
   270  	msg1 := testdata.NewTestMsg(addr1, addr2)
   271  	feeAmount := testdata.NewTestFeeAmount()
   272  	msgs := []sdk.Msg{msg1}
   273  
   274  	cases := map[string]struct {
   275  		txFeePayer      sdk.AccAddress
   276  		expectedSigners [][]byte
   277  		expectedPayer   []byte
   278  	}{
   279  		"no fee payer specified": {
   280  			expectedSigners: [][]byte{addr1, addr2},
   281  			expectedPayer:   addr1,
   282  		},
   283  		"secondary signer set as fee payer": {
   284  			txFeePayer:      addr2,
   285  			expectedSigners: [][]byte{addr1, addr2},
   286  			expectedPayer:   addr2,
   287  		},
   288  		"outside signer set as fee payer": {
   289  			txFeePayer:      addr3,
   290  			expectedSigners: [][]byte{addr1, addr2, addr3},
   291  			expectedPayer:   addr3,
   292  		},
   293  	}
   294  
   295  	for name, tc := range cases {
   296  		t.Run(name, func(t *testing.T) {
   297  			// setup basic tx
   298  			txBuilder := newBuilder(testutil.CodecOptions{}.NewCodec())
   299  			err := txBuilder.SetMsgs(msgs...)
   300  			require.NoError(t, err)
   301  			txBuilder.SetGasLimit(200000)
   302  			txBuilder.SetFeeAmount(feeAmount)
   303  
   304  			// set fee payer
   305  			txBuilder.SetFeePayer(tc.txFeePayer)
   306  			// and check it updates fields properly
   307  			signers, err := txBuilder.GetSigners()
   308  			require.NoError(t, err)
   309  			require.Equal(t, tc.expectedSigners, signers)
   310  			require.Equal(t, tc.expectedPayer, txBuilder.FeePayer())
   311  		})
   312  	}
   313  }
   314  
   315  func TestBuilderFeeGranter(t *testing.T) {
   316  	// keys and addresses
   317  	_, _, addr1 := testdata.KeyTestPubAddr()
   318  
   319  	// msg and signatures
   320  	msg1 := testdata.NewTestMsg(addr1, addr2)
   321  	feeAmount := testdata.NewTestFeeAmount()
   322  	msgs := []sdk.Msg{msg1}
   323  
   324  	txBuilder := newBuilder(testutil.CodecOptions{}.NewCodec())
   325  	err := txBuilder.SetMsgs(msgs...)
   326  	require.NoError(t, err)
   327  	txBuilder.SetGasLimit(200000)
   328  	txBuilder.SetFeeAmount(feeAmount)
   329  
   330  	require.Empty(t, txBuilder.GetTx().FeeGranter())
   331  
   332  	// set fee granter
   333  	txBuilder.SetFeeGranter(addr1)
   334  	require.Equal(t, addr1.String(), sdk.AccAddress(txBuilder.GetTx().FeeGranter()).String())
   335  }