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

     1  package tx
     2  
     3  import (
     4  	"encoding/binary"
     5  	"fmt"
     6  	"math"
     7  	"testing"
     8  
     9  	"github.com/stretchr/testify/require"
    10  	"google.golang.org/protobuf/encoding/protowire"
    11  
    12  	"github.com/cosmos/cosmos-sdk/codec"
    13  	codectypes "github.com/cosmos/cosmos-sdk/codec/types"
    14  	"github.com/cosmos/cosmos-sdk/testutil/testdata"
    15  	sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
    16  	"github.com/cosmos/cosmos-sdk/types/tx"
    17  	signingtypes "github.com/cosmos/cosmos-sdk/types/tx/signing"
    18  	"github.com/cosmos/cosmos-sdk/x/auth/signing"
    19  )
    20  
    21  func TestDefaultTxDecoderError(t *testing.T) {
    22  	registry := codectypes.NewInterfaceRegistry()
    23  	cdc := codec.NewProtoCodec(registry)
    24  	encoder := DefaultTxEncoder()
    25  	decoder := DefaultTxDecoder(cdc)
    26  
    27  	builder := newBuilder(nil)
    28  	err := builder.SetMsgs(testdata.NewTestMsg())
    29  	require.NoError(t, err)
    30  
    31  	txBz, err := encoder(builder.GetTx())
    32  	require.NoError(t, err)
    33  
    34  	_, err = decoder(txBz)
    35  	require.EqualError(t, err, "unable to resolve type URL /testpb.TestMsg: tx parse error")
    36  
    37  	testdata.RegisterInterfaces(registry)
    38  	_, err = decoder(txBz)
    39  	require.NoError(t, err)
    40  }
    41  
    42  func TestUnknownFields(t *testing.T) {
    43  	registry := codectypes.NewInterfaceRegistry()
    44  	cdc := codec.NewProtoCodec(registry)
    45  	decoder := DefaultTxDecoder(cdc)
    46  
    47  	tests := []struct {
    48  		name           string
    49  		body           *testdata.TestUpdatedTxBody
    50  		authInfo       *testdata.TestUpdatedAuthInfo
    51  		shouldErr      bool
    52  		shouldAminoErr string
    53  	}{
    54  		{
    55  			name: "no new fields should pass",
    56  			body: &testdata.TestUpdatedTxBody{
    57  				Memo: "foo",
    58  			},
    59  			authInfo:  &testdata.TestUpdatedAuthInfo{},
    60  			shouldErr: false,
    61  		},
    62  		{
    63  			name: "non-critical fields in TxBody should not error on decode, but should error with amino",
    64  			body: &testdata.TestUpdatedTxBody{
    65  				Memo:                         "foo",
    66  				SomeNewFieldNonCriticalField: "blah",
    67  			},
    68  			authInfo:       &testdata.TestUpdatedAuthInfo{},
    69  			shouldErr:      false,
    70  			shouldAminoErr: fmt.Sprintf("%s: %s", aminoNonCriticalFieldsError, sdkerrors.ErrInvalidRequest.Error()),
    71  		},
    72  		{
    73  			name: "critical fields in TxBody should error on decode",
    74  			body: &testdata.TestUpdatedTxBody{
    75  				Memo:         "foo",
    76  				SomeNewField: 10,
    77  			},
    78  			authInfo:  &testdata.TestUpdatedAuthInfo{},
    79  			shouldErr: true,
    80  		},
    81  		{
    82  			name: "critical fields in AuthInfo should error on decode",
    83  			body: &testdata.TestUpdatedTxBody{
    84  				Memo: "foo",
    85  			},
    86  			authInfo: &testdata.TestUpdatedAuthInfo{
    87  				NewField_3: []byte("xyz"),
    88  			},
    89  			shouldErr: true,
    90  		},
    91  		{
    92  			name: "non-critical fields in AuthInfo should error on decode",
    93  			body: &testdata.TestUpdatedTxBody{
    94  				Memo: "foo",
    95  			},
    96  			authInfo: &testdata.TestUpdatedAuthInfo{
    97  				NewField_1024: []byte("xyz"),
    98  			},
    99  			shouldErr: true,
   100  		},
   101  	}
   102  
   103  	for _, tt := range tests {
   104  		tt := tt
   105  		t.Run(tt.name, func(t *testing.T) {
   106  			bodyBz, err := tt.body.Marshal()
   107  			require.NoError(t, err)
   108  
   109  			authInfoBz, err := tt.authInfo.Marshal()
   110  			require.NoError(t, err)
   111  
   112  			txRaw := &tx.TxRaw{
   113  				BodyBytes:     bodyBz,
   114  				AuthInfoBytes: authInfoBz,
   115  			}
   116  			txBz, err := txRaw.Marshal()
   117  			require.NoError(t, err)
   118  
   119  			_, err = decoder(txBz)
   120  			if tt.shouldErr {
   121  				require.Error(t, err)
   122  			} else {
   123  				require.NoError(t, err)
   124  			}
   125  
   126  			if tt.shouldAminoErr != "" {
   127  				handler := signModeLegacyAminoJSONHandler{}
   128  				decoder := DefaultTxDecoder(codec.NewProtoCodec(codectypes.NewInterfaceRegistry()))
   129  				theTx, err := decoder(txBz)
   130  				require.NoError(t, err)
   131  				_, err = handler.GetSignBytes(signingtypes.SignMode_SIGN_MODE_LEGACY_AMINO_JSON, signing.SignerData{}, theTx)
   132  				require.EqualError(t, err, tt.shouldAminoErr)
   133  			}
   134  		})
   135  	}
   136  
   137  	t.Log("test TxRaw no new fields, should succeed")
   138  	txRaw := &testdata.TestUpdatedTxRaw{}
   139  	txBz, err := txRaw.Marshal()
   140  	require.NoError(t, err)
   141  	_, err = decoder(txBz)
   142  	require.NoError(t, err)
   143  
   144  	t.Log("new field in TxRaw should fail")
   145  	txRaw = &testdata.TestUpdatedTxRaw{
   146  		NewField_5: []byte("abc"),
   147  	}
   148  	txBz, err = txRaw.Marshal()
   149  	require.NoError(t, err)
   150  	_, err = decoder(txBz)
   151  	require.Error(t, err)
   152  
   153  	//
   154  	t.Log("new \"non-critical\" field in TxRaw should fail")
   155  	txRaw = &testdata.TestUpdatedTxRaw{
   156  		NewField_1024: []byte("abc"),
   157  	}
   158  	txBz, err = txRaw.Marshal()
   159  	require.NoError(t, err)
   160  	_, err = decoder(txBz)
   161  	require.Error(t, err)
   162  }
   163  
   164  func TestRejectNonADR027(t *testing.T) {
   165  	registry := codectypes.NewInterfaceRegistry()
   166  	cdc := codec.NewProtoCodec(registry)
   167  	decoder := DefaultTxDecoder(cdc)
   168  
   169  	body := &testdata.TestUpdatedTxBody{Memo: "AAA"} // Look for "65 65 65" when debugging the bytes stream.
   170  	bodyBz, err := body.Marshal()
   171  	require.NoError(t, err)
   172  	authInfo := &testdata.TestUpdatedAuthInfo{Fee: &tx.Fee{GasLimit: 127}} // Look for "127" when debugging the bytes stream.
   173  	authInfoBz, err := authInfo.Marshal()
   174  	require.NoError(t, err)
   175  	txRaw := &tx.TxRaw{
   176  		BodyBytes:     bodyBz,
   177  		AuthInfoBytes: authInfoBz,
   178  		Signatures:    [][]byte{{41}, {42}, {43}}, // Look for "42" when debugging the bytes stream.
   179  	}
   180  
   181  	// We know these bytes are ADR-027-compliant.
   182  	txBz, err := txRaw.Marshal()
   183  
   184  	// From the `txBz`, we extract the 3 components:
   185  	// bodyBz, authInfoBz, sigsBz.
   186  	// In our tests, we will try to decode txs with those 3 components in all
   187  	// possible orders.
   188  	//
   189  	// Consume "BodyBytes" field.
   190  	_, _, m := protowire.ConsumeField(txBz)
   191  	bodyBz = append([]byte{}, txBz[:m]...)
   192  	txBz = txBz[m:] // Skip over "BodyBytes" bytes.
   193  	// Consume "AuthInfoBytes" field.
   194  	_, _, m = protowire.ConsumeField(txBz)
   195  	authInfoBz = append([]byte{}, txBz[:m]...)
   196  	txBz = txBz[m:] // Skip over "AuthInfoBytes" bytes.
   197  	// Consume "Signature" field, it's the remaining bytes.
   198  	sigsBz := append([]byte{}, txBz...)
   199  
   200  	// bodyBz's length prefix is 5, with `5` as varint encoding. We also try a
   201  	// longer varint encoding for 5: `133 00`.
   202  	longVarintBodyBz := append(append([]byte{bodyBz[0]}, byte(133), byte(0o0)), bodyBz[2:]...)
   203  
   204  	tests := []struct {
   205  		name      string
   206  		txBz      []byte
   207  		shouldErr bool
   208  	}{
   209  		{
   210  			"authInfo, body, sigs",
   211  			append(append(authInfoBz, bodyBz...), sigsBz...),
   212  			true,
   213  		},
   214  		{
   215  			"authInfo, sigs, body",
   216  			append(append(authInfoBz, sigsBz...), bodyBz...),
   217  			true,
   218  		},
   219  		{
   220  			"sigs, body, authInfo",
   221  			append(append(sigsBz, bodyBz...), authInfoBz...),
   222  			true,
   223  		},
   224  		{
   225  			"sigs, authInfo, body",
   226  			append(append(sigsBz, authInfoBz...), bodyBz...),
   227  			true,
   228  		},
   229  		{
   230  			"body, sigs, authInfo",
   231  			append(append(bodyBz, sigsBz...), authInfoBz...),
   232  			true,
   233  		},
   234  		{
   235  			"body, authInfo, sigs (valid txRaw)",
   236  			append(append(bodyBz, authInfoBz...), sigsBz...),
   237  			false,
   238  		},
   239  		{
   240  			"longer varint than needed",
   241  			append(append(longVarintBodyBz, authInfoBz...), sigsBz...),
   242  			true,
   243  		},
   244  	}
   245  
   246  	for _, tt := range tests {
   247  		tt := tt
   248  		t.Run(tt.name, func(t *testing.T) {
   249  			_, err = decoder(tt.txBz)
   250  			if tt.shouldErr {
   251  				require.Error(t, err)
   252  			} else {
   253  				require.NoError(t, err)
   254  			}
   255  		})
   256  	}
   257  }
   258  
   259  func TestVarintMinLength(t *testing.T) {
   260  	tests := []struct {
   261  		n uint64
   262  	}{
   263  		{1<<7 - 1},
   264  		{1 << 7},
   265  		{1<<14 - 1},
   266  		{1 << 14},
   267  		{1<<21 - 1},
   268  		{1 << 21},
   269  		{1<<28 - 1},
   270  		{1 << 28},
   271  		{1<<35 - 1},
   272  		{1 << 35},
   273  		{1<<42 - 1},
   274  		{1 << 42},
   275  		{1<<49 - 1},
   276  		{1 << 49},
   277  		{1<<56 - 1},
   278  		{1 << 56},
   279  		{1<<63 - 1},
   280  		{1 << 63},
   281  		{math.MaxUint64},
   282  	}
   283  
   284  	for _, tt := range tests {
   285  		tt := tt
   286  		t.Run(fmt.Sprintf("test %d", tt.n), func(t *testing.T) {
   287  			l1 := varintMinLength(tt.n)
   288  			buf := make([]byte, binary.MaxVarintLen64)
   289  			l2 := binary.PutUvarint(buf, tt.n)
   290  			require.Equal(t, l2, l1)
   291  		})
   292  	}
   293  }