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 }