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 }