github.com/okex/exchain@v1.8.0/libs/tendermint/types/tx_test.go (about)

     1  package types
     2  
     3  import (
     4  	"bytes"
     5  	"math"
     6  	"testing"
     7  
     8  	"github.com/stretchr/testify/require"
     9  
    10  	"github.com/okex/exchain/libs/tendermint/abci/types"
    11  
    12  	"github.com/stretchr/testify/assert"
    13  
    14  	"github.com/okex/exchain/libs/tendermint/crypto/etherhash"
    15  	"github.com/okex/exchain/libs/tendermint/crypto/tmhash"
    16  	tmrand "github.com/okex/exchain/libs/tendermint/libs/rand"
    17  	ctest "github.com/okex/exchain/libs/tendermint/libs/test"
    18  )
    19  
    20  func makeTxs(cnt, size int) Txs {
    21  	txs := make(Txs, cnt)
    22  	for i := 0; i < cnt; i++ {
    23  		txs[i] = tmrand.Bytes(size)
    24  	}
    25  	return txs
    26  }
    27  
    28  func randInt(low, high int) int {
    29  	off := tmrand.Int() % (high - low)
    30  	return low + off
    31  }
    32  
    33  func TestTx_Hash(t *testing.T) {
    34  	tx := Tx("Hello, world!")
    35  	oldHeight := GetMilestoneVenusHeight()
    36  	defer UnittestOnlySetMilestoneVenusHeight(oldHeight)
    37  	for _, c := range []struct {
    38  		curHeight   int64
    39  		venusHeight int64
    40  		expected    []byte
    41  	}{
    42  		{999, 0, tmhash.Sum(tx)},
    43  		{999, 1000, tmhash.Sum(tx)},
    44  		{1000, 1000, etherhash.Sum(tx)},
    45  		{1500, 1000, etherhash.Sum(tx)},
    46  	} {
    47  		UnittestOnlySetMilestoneVenusHeight(c.venusHeight)
    48  		assert.Equal(t, c.expected, tx.Hash(c.curHeight))
    49  	}
    50  }
    51  
    52  func TestTxIndex(t *testing.T) {
    53  	for i := 0; i < 20; i++ {
    54  		txs := makeTxs(15, 60)
    55  		for j := 0; j < len(txs); j++ {
    56  			tx := txs[j]
    57  			idx := txs.Index(tx)
    58  			assert.Equal(t, j, idx)
    59  		}
    60  		assert.Equal(t, -1, txs.Index(nil))
    61  		assert.Equal(t, -1, txs.Index(Tx("foodnwkf")))
    62  	}
    63  }
    64  
    65  func TestTxIndexByHash(t *testing.T) {
    66  	var height int64
    67  	for i := 0; i < 20; i++ {
    68  		txs := makeTxs(15, 60)
    69  		for j := 0; j < len(txs); j++ {
    70  			tx := txs[j]
    71  			idx := txs.IndexByHash(tx.Hash(height), height)
    72  			assert.Equal(t, j, idx)
    73  		}
    74  		assert.Equal(t, -1, txs.IndexByHash(nil, height))
    75  		assert.Equal(t, -1, txs.IndexByHash(Tx("foodnwkf").Hash(height), height))
    76  	}
    77  }
    78  
    79  func TestValidTxProof(t *testing.T) {
    80  	cases := []struct {
    81  		txs Txs
    82  	}{
    83  		{Txs{{1, 4, 34, 87, 163, 1}}},
    84  		{Txs{{5, 56, 165, 2}, {4, 77}}},
    85  		{Txs{Tx("foo"), Tx("bar"), Tx("baz")}},
    86  		{makeTxs(20, 5)},
    87  		{makeTxs(7, 81)},
    88  		{makeTxs(61, 15)},
    89  	}
    90  
    91  	for h, tc := range cases {
    92  		txs := tc.txs
    93  		root := txs.Hash(0)
    94  		// make sure valid proof for every tx
    95  		for i := range txs {
    96  			tx := []byte(txs[i])
    97  			proof := txs.Proof(i, 0)
    98  			assert.Equal(t, i, proof.Proof.Index, "%d: %d", h, i)
    99  			assert.Equal(t, len(txs), proof.Proof.Total, "%d: %d", h, i)
   100  			assert.EqualValues(t, root, proof.RootHash, "%d: %d", h, i)
   101  			assert.EqualValues(t, tx, proof.Data, "%d: %d", h, i)
   102  			assert.EqualValues(t, txs[i].Hash(0), proof.Leaf(0), "%d: %d", h, i)
   103  			assert.Nil(t, proof.Validate(root, 0), "%d: %d", h, i)
   104  			assert.NotNil(t, proof.Validate([]byte("foobar"), 0), "%d: %d", h, i)
   105  
   106  			// read-write must also work
   107  			var p2 TxProof
   108  			bin, err := cdc.MarshalBinaryLengthPrefixed(proof)
   109  			assert.Nil(t, err)
   110  			err = cdc.UnmarshalBinaryLengthPrefixed(bin, &p2)
   111  			if assert.Nil(t, err, "%d: %d: %+v", h, i, err) {
   112  				assert.Nil(t, p2.Validate(root, 0), "%d: %d", h, i)
   113  			}
   114  		}
   115  	}
   116  }
   117  
   118  func TestTxProofUnchangable(t *testing.T) {
   119  	// run the other test a bunch...
   120  	for i := 0; i < 40; i++ {
   121  		testTxProofUnchangable(t)
   122  	}
   123  }
   124  
   125  func TestComputeTxsOverhead(t *testing.T) {
   126  	cases := []struct {
   127  		txs          Txs
   128  		wantOverhead int
   129  	}{
   130  		{Txs{[]byte{6, 6, 6, 6, 6, 6}}, 2},
   131  		// one 21 Mb transaction:
   132  		{Txs{make([]byte, 22020096)}, 5},
   133  		// two 21Mb/2 sized transactions:
   134  		{Txs{make([]byte, 11010048), make([]byte, 11010048)}, 10},
   135  		{Txs{[]byte{1, 2, 3}, []byte{1, 2, 3}, []byte{4, 5, 6}}, 6},
   136  		{Txs{[]byte{100, 5, 64}, []byte{42, 116, 118}, []byte{6, 6, 6}, []byte{6, 6, 6}}, 8},
   137  	}
   138  
   139  	for _, tc := range cases {
   140  		totalBytes := int64(0)
   141  		totalOverhead := int64(0)
   142  		for _, tx := range tc.txs {
   143  			aminoOverhead := ComputeAminoOverhead(tx, 1)
   144  			totalOverhead += aminoOverhead
   145  			totalBytes += aminoOverhead + int64(len(tx))
   146  		}
   147  		bz, err := cdc.MarshalBinaryBare(tc.txs)
   148  		assert.EqualValues(t, tc.wantOverhead, totalOverhead)
   149  		assert.NoError(t, err)
   150  		assert.EqualValues(t, len(bz), totalBytes)
   151  	}
   152  }
   153  
   154  func TestComputeAminoOverhead(t *testing.T) {
   155  	cases := []struct {
   156  		tx       Tx
   157  		fieldNum int
   158  		want     int
   159  	}{
   160  		{[]byte{6, 6, 6}, 1, 2},
   161  		{[]byte{6, 6, 6}, 16, 3},
   162  		{[]byte{6, 6, 6}, 32, 3},
   163  		{[]byte{6, 6, 6}, 64, 3},
   164  		{[]byte{6, 6, 6}, 512, 3},
   165  		{[]byte{6, 6, 6}, 1024, 3},
   166  		{[]byte{6, 6, 6}, 2048, 4},
   167  		{make([]byte, 64), 1, 2},
   168  		{make([]byte, 65), 1, 2},
   169  		{make([]byte, 127), 1, 2},
   170  		{make([]byte, 128), 1, 3},
   171  		{make([]byte, 256), 1, 3},
   172  		{make([]byte, 512), 1, 3},
   173  		{make([]byte, 1024), 1, 3},
   174  		{make([]byte, 128), 16, 4},
   175  	}
   176  	for _, tc := range cases {
   177  		got := ComputeAminoOverhead(tc.tx, tc.fieldNum)
   178  		assert.EqualValues(t, tc.want, got)
   179  	}
   180  }
   181  
   182  func testTxProofUnchangable(t *testing.T) {
   183  	// make some proof
   184  	txs := makeTxs(randInt(2, 100), randInt(16, 128))
   185  	root := txs.Hash(0)
   186  	i := randInt(0, len(txs)-1)
   187  	proof := txs.Proof(i, 0)
   188  
   189  	// make sure it is valid to start with
   190  	assert.Nil(t, proof.Validate(root, 0))
   191  	bin, err := cdc.MarshalBinaryLengthPrefixed(proof)
   192  	assert.Nil(t, err)
   193  
   194  	// try mutating the data and make sure nothing breaks
   195  	for j := 0; j < 500; j++ {
   196  		bad := ctest.MutateByteSlice(bin)
   197  		if !bytes.Equal(bad, bin) {
   198  			assertBadProof(t, root, bad, proof)
   199  		}
   200  	}
   201  }
   202  
   203  // This makes sure that the proof doesn't deserialize into something valid.
   204  func assertBadProof(t *testing.T, root []byte, bad []byte, good TxProof) {
   205  	var proof TxProof
   206  	err := cdc.UnmarshalBinaryLengthPrefixed(bad, &proof)
   207  	if err == nil {
   208  		err = proof.Validate(root, 0)
   209  		if err == nil {
   210  			// XXX Fix simple merkle proofs so the following is *not* OK.
   211  			// This can happen if we have a slightly different total (where the
   212  			// path ends up the same). If it is something else, we have a real
   213  			// problem.
   214  			assert.NotEqual(t, proof.Proof.Total, good.Proof.Total, "bad: %#v\ngood: %#v", proof, good)
   215  		}
   216  	}
   217  }
   218  
   219  var txResultTestCases = []TxResult{
   220  	{},
   221  	{Tx: []byte{}},
   222  	{123, 123, []byte("tx bytes"), types.ResponseDeliverTx{Code: 123, Data: []byte("this is data"), Log: "log123", Info: "123info", GasWanted: 1234445, GasUsed: 98, Events: []types.Event{}, Codespace: "sssdasf"}},
   223  	{Height: math.MaxInt64, Index: math.MaxUint32},
   224  	{Height: math.MinInt64, Index: 0},
   225  	{Height: -1, Index: 0},
   226  }
   227  
   228  func TestTxResultAmino(t *testing.T) {
   229  	for _, txResult := range txResultTestCases {
   230  		expectData, err := cdc.MarshalBinaryBare(txResult)
   231  		require.NoError(t, err)
   232  
   233  		var expectValue TxResult
   234  		err = cdc.UnmarshalBinaryBare(expectData, &expectValue)
   235  		require.NoError(t, err)
   236  
   237  		var actualValue TxResult
   238  		err = actualValue.UnmarshalFromAmino(cdc, expectData)
   239  		require.NoError(t, err)
   240  
   241  		require.EqualValues(t, expectValue, actualValue)
   242  	}
   243  }
   244  
   245  func BenchmarkTxResultAminoUnmarshal(b *testing.B) {
   246  	testData := make([][]byte, len(txResultTestCases))
   247  	for i, res := range txResultTestCases {
   248  		expectData, err := cdc.MarshalBinaryBare(res)
   249  		require.NoError(b, err)
   250  		testData[i] = expectData
   251  	}
   252  	b.ResetTimer()
   253  
   254  	b.Run("amino", func(b *testing.B) {
   255  		b.ReportAllocs()
   256  		for i := 0; i < b.N; i++ {
   257  			for _, data := range testData {
   258  				var res TxResult
   259  				err := cdc.UnmarshalBinaryBare(data, &res)
   260  				if err != nil {
   261  					b.Fatal(err)
   262  				}
   263  			}
   264  		}
   265  	})
   266  	b.Run("unmarshaller", func(b *testing.B) {
   267  		b.ReportAllocs()
   268  		for i := 0; i < b.N; i++ {
   269  			for _, data := range testData {
   270  				var res TxResult
   271  				err := res.UnmarshalFromAmino(cdc, data)
   272  				if err != nil {
   273  					b.Fatal(err)
   274  				}
   275  			}
   276  		}
   277  	})
   278  }