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