github.com/Finschia/finschia-sdk@v0.49.1/x/auth/tx/builder_test.go (about)

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