github.com/Finschia/ostracon@v1.1.5/types/tx_test.go (about)

     1  package types
     2  
     3  import (
     4  	"bytes"
     5  	"testing"
     6  
     7  	"github.com/stretchr/testify/assert"
     8  	"github.com/stretchr/testify/require"
     9  
    10  	tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
    11  
    12  	tmrand "github.com/Finschia/ostracon/libs/rand"
    13  	ctest "github.com/Finschia/ostracon/libs/test"
    14  )
    15  
    16  func makeTxs(cnt, size int) Txs {
    17  	txs := make(Txs, cnt)
    18  	for i := 0; i < cnt; i++ {
    19  		txs[i] = tmrand.Bytes(size)
    20  	}
    21  	return txs
    22  }
    23  
    24  func randInt(low, high int) int {
    25  	off := tmrand.Int() % (high - low)
    26  	return low + off
    27  }
    28  
    29  func TestTxIndex(t *testing.T) {
    30  	for i := 0; i < 20; i++ {
    31  		txs := makeTxs(15, 60)
    32  		for j := 0; j < len(txs); j++ {
    33  			tx := txs[j]
    34  			idx := txs.Index(tx)
    35  			assert.Equal(t, j, idx)
    36  		}
    37  		assert.Equal(t, -1, txs.Index(nil))
    38  		assert.Equal(t, -1, txs.Index(Tx("foodnwkf")))
    39  	}
    40  }
    41  
    42  func TestTxIndexByHash(t *testing.T) {
    43  	for i := 0; i < 20; i++ {
    44  		txs := makeTxs(15, 60)
    45  		for j := 0; j < len(txs); j++ {
    46  			tx := txs[j]
    47  			idx := txs.IndexByHash(tx.Hash())
    48  			assert.Equal(t, j, idx)
    49  		}
    50  		assert.Equal(t, -1, txs.IndexByHash(nil))
    51  		assert.Equal(t, -1, txs.IndexByHash(Tx("foodnwkf").Hash()))
    52  	}
    53  }
    54  
    55  func TestValidTxProof(t *testing.T) {
    56  	cases := []struct {
    57  		txs Txs
    58  	}{
    59  		{Txs{{1, 4, 34, 87, 163, 1}}},
    60  		{Txs{{5, 56, 165, 2}, {4, 77}}},
    61  		{Txs{Tx("foo"), Tx("bar"), Tx("baz")}},
    62  		{makeTxs(20, 5)},
    63  		{makeTxs(7, 81)},
    64  		{makeTxs(61, 15)},
    65  	}
    66  
    67  	for h, tc := range cases {
    68  		txs := tc.txs
    69  		root := txs.Hash()
    70  		// make sure valid proof for every tx
    71  		for i := range txs {
    72  			tx := []byte(txs[i])
    73  			proof := txs.Proof(i)
    74  			assert.EqualValues(t, i, proof.Proof.Index, "%d: %d", h, i)
    75  			assert.EqualValues(t, len(txs), proof.Proof.Total, "%d: %d", h, i)
    76  			assert.EqualValues(t, root, proof.RootHash, "%d: %d", h, i)
    77  			assert.EqualValues(t, tx, proof.Data, "%d: %d", h, i)
    78  			assert.EqualValues(t, txs[i].Hash(), proof.Leaf(), "%d: %d", h, i)
    79  			assert.Nil(t, proof.Validate(root), "%d: %d", h, i)
    80  			assert.NotNil(t, proof.Validate([]byte("foobar")), "%d: %d", h, i)
    81  
    82  			// read-write must also work
    83  			var (
    84  				p2  TxProof
    85  				pb2 tmproto.TxProof
    86  			)
    87  			pbProof := proof.ToProto()
    88  			bin, err := pbProof.Marshal()
    89  			require.NoError(t, err)
    90  
    91  			err = pb2.Unmarshal(bin)
    92  			require.NoError(t, err)
    93  
    94  			p2, err = TxProofFromProto(pb2)
    95  			if assert.Nil(t, err, "%d: %d: %+v", h, i, err) {
    96  				assert.Nil(t, p2.Validate(root), "%d: %d", h, i)
    97  			}
    98  		}
    99  	}
   100  }
   101  
   102  func TestTxProofUnchangable(t *testing.T) {
   103  	// run the other test a bunch...
   104  	for i := 0; i < 40; i++ {
   105  		testTxProofUnchangable(t)
   106  	}
   107  }
   108  
   109  func testTxProofUnchangable(t *testing.T) {
   110  	// make some proof
   111  	txs := makeTxs(randInt(2, 100), randInt(16, 128))
   112  	root := txs.Hash()
   113  	i := randInt(0, len(txs)-1)
   114  	proof := txs.Proof(i)
   115  
   116  	// make sure it is valid to start with
   117  	assert.Nil(t, proof.Validate(root))
   118  	pbProof := proof.ToProto()
   119  	bin, err := pbProof.Marshal()
   120  	require.NoError(t, err)
   121  
   122  	// try mutating the data and make sure nothing breaks
   123  	for j := 0; j < 500; j++ {
   124  		bad := ctest.MutateByteSlice(bin)
   125  		if !bytes.Equal(bad, bin) {
   126  			assertBadProof(t, root, bad, proof)
   127  		}
   128  	}
   129  }
   130  
   131  // This makes sure that the proof doesn't deserialize into something valid.
   132  func assertBadProof(t *testing.T, root []byte, bad []byte, good TxProof) {
   133  
   134  	var (
   135  		proof   TxProof
   136  		pbProof tmproto.TxProof
   137  	)
   138  	err := pbProof.Unmarshal(bad)
   139  	if err == nil {
   140  		proof, err = TxProofFromProto(pbProof)
   141  		if err == nil {
   142  			err = proof.Validate(root)
   143  			if err == nil {
   144  				// XXX Fix simple merkle proofs so the following is *not* OK.
   145  				// This can happen if we have a slightly different total (where the
   146  				// path ends up the same). If it is something else, we have a real
   147  				// problem.
   148  				assert.NotEqual(t, proof.Proof.Total, good.Proof.Total, "bad: %#v\ngood: %#v", proof, good)
   149  			}
   150  		}
   151  	}
   152  }
   153  
   154  func TestComputeProtoSizeForTxs(t *testing.T) {
   155  	tests := []struct {
   156  		count int
   157  	}{
   158  		{1},
   159  		{2},
   160  		{30},
   161  		{450},
   162  		{1352},
   163  		{2543},
   164  		{4000},
   165  	}
   166  
   167  	for _, tt := range tests {
   168  		allTxs := make(Txs, tt.count)
   169  		for i := 0; i < tt.count; i++ {
   170  			size := tmrand.Intn(500)
   171  			allTxs[i] = tmrand.Bytes(size)
   172  		}
   173  
   174  		txs := make([]Tx, 0, len(allTxs))
   175  		protoTxs := tmproto.Data{}
   176  		for _, tx := range allTxs {
   177  			protoTxs.Txs = append(protoTxs.Txs, tx)
   178  			txs = append(txs, tx)
   179  			require.Equal(t, int64(protoTxs.Size()), ComputeProtoSizeForTxs(txs))
   180  		}
   181  	}
   182  }