github.com/ari-anchor/sei-tendermint@v0.0.0-20230519144642-dc826b7b56bb/types/tx_test.go (about)

     1  package types
     2  
     3  import (
     4  	"bytes"
     5  	"math/rand"
     6  	"testing"
     7  
     8  	"github.com/stretchr/testify/assert"
     9  	"github.com/stretchr/testify/require"
    10  
    11  	abci "github.com/ari-anchor/sei-tendermint/abci/types"
    12  	ctest "github.com/ari-anchor/sei-tendermint/internal/libs/test"
    13  	tmrand "github.com/ari-anchor/sei-tendermint/libs/rand"
    14  	tmproto "github.com/ari-anchor/sei-tendermint/proto/tendermint/types"
    15  )
    16  
    17  func makeTxs(cnt, size int) Txs {
    18  	txs := make(Txs, cnt)
    19  	for i := 0; i < cnt; i++ {
    20  		txs[i] = tmrand.Bytes(size)
    21  	}
    22  	return txs
    23  }
    24  
    25  func TestTxIndex(t *testing.T) {
    26  	for i := 0; i < 20; i++ {
    27  		txs := makeTxs(15, 60)
    28  		for j := 0; j < len(txs); j++ {
    29  			tx := txs[j]
    30  			idx := txs.Index(tx)
    31  			assert.Equal(t, j, idx)
    32  		}
    33  		assert.Equal(t, -1, txs.Index(nil))
    34  		assert.Equal(t, -1, txs.Index(Tx("foodnwkf")))
    35  	}
    36  }
    37  
    38  func TestTxIndexByHash(t *testing.T) {
    39  	for i := 0; i < 20; i++ {
    40  		txs := makeTxs(15, 60)
    41  		for j := 0; j < len(txs); j++ {
    42  			tx := txs[j]
    43  			idx := txs.IndexByHash(tx.Hash())
    44  			assert.Equal(t, j, idx)
    45  		}
    46  		assert.Equal(t, -1, txs.IndexByHash(nil))
    47  		assert.Equal(t, -1, txs.IndexByHash(Tx("foodnwkf").Hash()))
    48  	}
    49  }
    50  
    51  func TestValidateTxRecordSet(t *testing.T) {
    52  	t.Run("should error on total transaction size exceeding max data size", func(t *testing.T) {
    53  		trs := []*abci.TxRecord{
    54  			{
    55  				Action: abci.TxRecord_ADDED,
    56  				Tx:     Tx([]byte{1, 2, 3, 4, 5}),
    57  			},
    58  			{
    59  				Action: abci.TxRecord_ADDED,
    60  				Tx:     Tx([]byte{6, 7, 8, 9, 10}),
    61  			},
    62  		}
    63  		txrSet := NewTxRecordSet(trs)
    64  		err := txrSet.Validate(9, []Tx{})
    65  		require.Error(t, err)
    66  	})
    67  	t.Run("should not error on removed transaction size exceeding max data size", func(t *testing.T) {
    68  		trs := []*abci.TxRecord{
    69  			{
    70  				Action: abci.TxRecord_ADDED,
    71  				Tx:     Tx([]byte{1, 2, 3, 4, 5}),
    72  			},
    73  			{
    74  				Action: abci.TxRecord_ADDED,
    75  				Tx:     Tx([]byte{6, 7, 8, 9}),
    76  			},
    77  			{
    78  				Action: abci.TxRecord_REMOVED,
    79  				Tx:     Tx([]byte{10}),
    80  			},
    81  		}
    82  		txrSet := NewTxRecordSet(trs)
    83  		err := txrSet.Validate(9, []Tx{[]byte{10}})
    84  		require.NoError(t, err)
    85  	})
    86  	t.Run("should error on duplicate transactions with the same action", func(t *testing.T) {
    87  		trs := []*abci.TxRecord{
    88  			{
    89  				Action: abci.TxRecord_ADDED,
    90  				Tx:     Tx([]byte{1, 2, 3, 4, 5}),
    91  			},
    92  			{
    93  				Action: abci.TxRecord_ADDED,
    94  				Tx:     Tx([]byte{100}),
    95  			},
    96  			{
    97  				Action: abci.TxRecord_ADDED,
    98  				Tx:     Tx([]byte{1, 2, 3, 4, 5}),
    99  			},
   100  			{
   101  				Action: abci.TxRecord_ADDED,
   102  				Tx:     Tx([]byte{200}),
   103  			},
   104  		}
   105  		txrSet := NewTxRecordSet(trs)
   106  		err := txrSet.Validate(100, []Tx{})
   107  		require.Error(t, err)
   108  	})
   109  	t.Run("should error on duplicate transactions with mixed actions", func(t *testing.T) {
   110  		trs := []*abci.TxRecord{
   111  			{
   112  				Action: abci.TxRecord_ADDED,
   113  				Tx:     Tx([]byte{1, 2, 3, 4, 5}),
   114  			},
   115  			{
   116  				Action: abci.TxRecord_ADDED,
   117  				Tx:     Tx([]byte{100}),
   118  			},
   119  			{
   120  				Action: abci.TxRecord_REMOVED,
   121  				Tx:     Tx([]byte{1, 2, 3, 4, 5}),
   122  			},
   123  			{
   124  				Action: abci.TxRecord_ADDED,
   125  				Tx:     Tx([]byte{200}),
   126  			},
   127  		}
   128  		txrSet := NewTxRecordSet(trs)
   129  		err := txrSet.Validate(100, []Tx{})
   130  		require.Error(t, err)
   131  	})
   132  	t.Run("should error on new transactions marked UNMODIFIED", func(t *testing.T) {
   133  		trs := []*abci.TxRecord{
   134  			{
   135  				Action: abci.TxRecord_UNMODIFIED,
   136  				Tx:     Tx([]byte{1, 2, 3, 4, 5}),
   137  			},
   138  		}
   139  		txrSet := NewTxRecordSet(trs)
   140  		err := txrSet.Validate(100, []Tx{})
   141  		require.Error(t, err)
   142  	})
   143  	t.Run("should error on new transactions marked REMOVED", func(t *testing.T) {
   144  		trs := []*abci.TxRecord{
   145  			{
   146  				Action: abci.TxRecord_REMOVED,
   147  				Tx:     Tx([]byte{1, 2, 3, 4, 5}),
   148  			},
   149  		}
   150  		txrSet := NewTxRecordSet(trs)
   151  		err := txrSet.Validate(100, []Tx{})
   152  		require.Error(t, err)
   153  	})
   154  	t.Run("should error on existing transaction marked as ADDED", func(t *testing.T) {
   155  		trs := []*abci.TxRecord{
   156  			{
   157  				Action: abci.TxRecord_ADDED,
   158  				Tx:     Tx([]byte{5, 4, 3, 2, 1}),
   159  			},
   160  			{
   161  				Action: abci.TxRecord_ADDED,
   162  				Tx:     Tx([]byte{6}),
   163  			},
   164  			{
   165  				Action: abci.TxRecord_ADDED,
   166  				Tx:     Tx([]byte{1, 2, 3, 4, 5}),
   167  			},
   168  		}
   169  		txrSet := NewTxRecordSet(trs)
   170  		err := txrSet.Validate(100, []Tx{{0}, {1, 2, 3, 4, 5}})
   171  		require.Error(t, err)
   172  	})
   173  	t.Run("should error if any transaction marked as UNKNOWN", func(t *testing.T) {
   174  		trs := []*abci.TxRecord{
   175  			{
   176  				Action: abci.TxRecord_UNKNOWN,
   177  				Tx:     Tx([]byte{1, 2, 3, 4, 5}),
   178  			},
   179  		}
   180  		txrSet := NewTxRecordSet(trs)
   181  		err := txrSet.Validate(100, []Tx{})
   182  		require.Error(t, err)
   183  	})
   184  	t.Run("TxRecordSet preserves order", func(t *testing.T) {
   185  		trs := []*abci.TxRecord{
   186  			{
   187  				Action: abci.TxRecord_ADDED,
   188  				Tx:     Tx([]byte{100}),
   189  			},
   190  			{
   191  				Action: abci.TxRecord_ADDED,
   192  				Tx:     Tx([]byte{99}),
   193  			},
   194  			{
   195  				Action: abci.TxRecord_ADDED,
   196  				Tx:     Tx([]byte{55}),
   197  			},
   198  			{
   199  				Action: abci.TxRecord_ADDED,
   200  				Tx:     Tx([]byte{12}),
   201  			},
   202  			{
   203  				Action: abci.TxRecord_ADDED,
   204  				Tx:     Tx([]byte{66}),
   205  			},
   206  			{
   207  				Action: abci.TxRecord_ADDED,
   208  				Tx:     Tx([]byte{9}),
   209  			},
   210  			{
   211  				Action: abci.TxRecord_ADDED,
   212  				Tx:     Tx([]byte{17}),
   213  			},
   214  		}
   215  		txrSet := NewTxRecordSet(trs)
   216  		err := txrSet.Validate(100, []Tx{})
   217  		require.NoError(t, err)
   218  		for i, tx := range txrSet.IncludedTxs() {
   219  			require.Equal(t, Tx(trs[i].Tx), tx)
   220  		}
   221  	})
   222  }
   223  
   224  func TestValidTxProof(t *testing.T) {
   225  	cases := []struct {
   226  		txs Txs
   227  	}{
   228  		{Txs{{1, 4, 34, 87, 163, 1}}},
   229  		{Txs{{5, 56, 165, 2}, {4, 77}}},
   230  		{Txs{Tx("foo"), Tx("bar"), Tx("baz")}},
   231  		{makeTxs(20, 5)},
   232  		{makeTxs(7, 81)},
   233  		{makeTxs(61, 15)},
   234  	}
   235  
   236  	for h, tc := range cases {
   237  		txs := tc.txs
   238  		root := txs.Hash()
   239  		// make sure valid proof for every tx
   240  		for i := range txs {
   241  			tx := []byte(txs[i])
   242  			proof := txs.Proof(i)
   243  			assert.EqualValues(t, i, proof.Proof.Index, "%d: %d", h, i)
   244  			assert.EqualValues(t, len(txs), proof.Proof.Total, "%d: %d", h, i)
   245  			assert.EqualValues(t, root, proof.RootHash, "%d: %d", h, i)
   246  			assert.EqualValues(t, tx, proof.Data, "%d: %d", h, i)
   247  			assert.EqualValues(t, txs[i].Hash(), proof.Leaf(), "%d: %d", h, i)
   248  			assert.Nil(t, proof.Validate(root), "%d: %d", h, i)
   249  			assert.NotNil(t, proof.Validate([]byte("foobar")), "%d: %d", h, i)
   250  
   251  			// read-write must also work
   252  			var (
   253  				p2  TxProof
   254  				pb2 tmproto.TxProof
   255  			)
   256  			pbProof := proof.ToProto()
   257  			bin, err := pbProof.Marshal()
   258  			require.NoError(t, err)
   259  
   260  			err = pb2.Unmarshal(bin)
   261  			require.NoError(t, err)
   262  
   263  			p2, err = TxProofFromProto(pb2)
   264  			if assert.NoError(t, err, "%d: %d: %+v", h, i, err) {
   265  				assert.Nil(t, p2.Validate(root), "%d: %d", h, i)
   266  			}
   267  		}
   268  	}
   269  }
   270  
   271  func TestTxProofUnchangable(t *testing.T) {
   272  	// run the other test a bunch...
   273  	for i := 0; i < 40; i++ {
   274  		testTxProofUnchangable(t)
   275  	}
   276  }
   277  
   278  func testTxProofUnchangable(t *testing.T) {
   279  	// make some proof
   280  	txs := makeTxs(randInt(2, 100), randInt(16, 128))
   281  	root := txs.Hash()
   282  	i := randInt(0, len(txs)-1)
   283  	proof := txs.Proof(i)
   284  
   285  	// make sure it is valid to start with
   286  	assert.Nil(t, proof.Validate(root))
   287  	pbProof := proof.ToProto()
   288  	bin, err := pbProof.Marshal()
   289  	require.NoError(t, err)
   290  
   291  	// try mutating the data and make sure nothing breaks
   292  	for j := 0; j < 500; j++ {
   293  		bad := ctest.MutateByteSlice(bin)
   294  		if !bytes.Equal(bad, bin) {
   295  			assertBadProof(t, root, bad, proof)
   296  		}
   297  	}
   298  }
   299  
   300  // This makes sure that the proof doesn't deserialize into something valid.
   301  func assertBadProof(t *testing.T, root []byte, bad []byte, good TxProof) {
   302  
   303  	var (
   304  		proof   TxProof
   305  		pbProof tmproto.TxProof
   306  	)
   307  	err := pbProof.Unmarshal(bad)
   308  	if err == nil {
   309  		proof, err = TxProofFromProto(pbProof)
   310  		if err == nil {
   311  			err = proof.Validate(root)
   312  			if err == nil {
   313  				// XXX Fix simple merkle proofs so the following is *not* OK.
   314  				// This can happen if we have a slightly different total (where the
   315  				// path ends up the same). If it is something else, we have a real
   316  				// problem.
   317  				assert.NotEqual(t, proof.Proof.Total, good.Proof.Total, "bad: %#v\ngood: %#v", proof, good)
   318  			}
   319  		}
   320  	}
   321  }
   322  
   323  func randInt(low, high int) int {
   324  	return rand.Intn(high-low) + low
   325  }