github.com/ari-anchor/sei-tendermint@v0.0.0-20230519144642-dc826b7b56bb/types/tx_test.go (about) 1 package types 2 3 import ( 4 "bytes" 5 "math/rand" 6 "testing" 7 8 "github.com/stretchr/testify/assert" 9 "github.com/stretchr/testify/require" 10 11 abci "github.com/ari-anchor/sei-tendermint/abci/types" 12 ctest "github.com/ari-anchor/sei-tendermint/internal/libs/test" 13 tmrand "github.com/ari-anchor/sei-tendermint/libs/rand" 14 tmproto "github.com/ari-anchor/sei-tendermint/proto/tendermint/types" 15 ) 16 17 func makeTxs(cnt, size int) Txs { 18 txs := make(Txs, cnt) 19 for i := 0; i < cnt; i++ { 20 txs[i] = tmrand.Bytes(size) 21 } 22 return txs 23 } 24 25 func TestTxIndex(t *testing.T) { 26 for i := 0; i < 20; i++ { 27 txs := makeTxs(15, 60) 28 for j := 0; j < len(txs); j++ { 29 tx := txs[j] 30 idx := txs.Index(tx) 31 assert.Equal(t, j, idx) 32 } 33 assert.Equal(t, -1, txs.Index(nil)) 34 assert.Equal(t, -1, txs.Index(Tx("foodnwkf"))) 35 } 36 } 37 38 func TestTxIndexByHash(t *testing.T) { 39 for i := 0; i < 20; i++ { 40 txs := makeTxs(15, 60) 41 for j := 0; j < len(txs); j++ { 42 tx := txs[j] 43 idx := txs.IndexByHash(tx.Hash()) 44 assert.Equal(t, j, idx) 45 } 46 assert.Equal(t, -1, txs.IndexByHash(nil)) 47 assert.Equal(t, -1, txs.IndexByHash(Tx("foodnwkf").Hash())) 48 } 49 } 50 51 func TestValidateTxRecordSet(t *testing.T) { 52 t.Run("should error on total transaction size exceeding max data size", func(t *testing.T) { 53 trs := []*abci.TxRecord{ 54 { 55 Action: abci.TxRecord_ADDED, 56 Tx: Tx([]byte{1, 2, 3, 4, 5}), 57 }, 58 { 59 Action: abci.TxRecord_ADDED, 60 Tx: Tx([]byte{6, 7, 8, 9, 10}), 61 }, 62 } 63 txrSet := NewTxRecordSet(trs) 64 err := txrSet.Validate(9, []Tx{}) 65 require.Error(t, err) 66 }) 67 t.Run("should not error on removed transaction size exceeding max data size", func(t *testing.T) { 68 trs := []*abci.TxRecord{ 69 { 70 Action: abci.TxRecord_ADDED, 71 Tx: Tx([]byte{1, 2, 3, 4, 5}), 72 }, 73 { 74 Action: abci.TxRecord_ADDED, 75 Tx: Tx([]byte{6, 7, 8, 9}), 76 }, 77 { 78 Action: abci.TxRecord_REMOVED, 79 Tx: Tx([]byte{10}), 80 }, 81 } 82 txrSet := NewTxRecordSet(trs) 83 err := txrSet.Validate(9, []Tx{[]byte{10}}) 84 require.NoError(t, err) 85 }) 86 t.Run("should error on duplicate transactions with the same action", func(t *testing.T) { 87 trs := []*abci.TxRecord{ 88 { 89 Action: abci.TxRecord_ADDED, 90 Tx: Tx([]byte{1, 2, 3, 4, 5}), 91 }, 92 { 93 Action: abci.TxRecord_ADDED, 94 Tx: Tx([]byte{100}), 95 }, 96 { 97 Action: abci.TxRecord_ADDED, 98 Tx: Tx([]byte{1, 2, 3, 4, 5}), 99 }, 100 { 101 Action: abci.TxRecord_ADDED, 102 Tx: Tx([]byte{200}), 103 }, 104 } 105 txrSet := NewTxRecordSet(trs) 106 err := txrSet.Validate(100, []Tx{}) 107 require.Error(t, err) 108 }) 109 t.Run("should error on duplicate transactions with mixed actions", func(t *testing.T) { 110 trs := []*abci.TxRecord{ 111 { 112 Action: abci.TxRecord_ADDED, 113 Tx: Tx([]byte{1, 2, 3, 4, 5}), 114 }, 115 { 116 Action: abci.TxRecord_ADDED, 117 Tx: Tx([]byte{100}), 118 }, 119 { 120 Action: abci.TxRecord_REMOVED, 121 Tx: Tx([]byte{1, 2, 3, 4, 5}), 122 }, 123 { 124 Action: abci.TxRecord_ADDED, 125 Tx: Tx([]byte{200}), 126 }, 127 } 128 txrSet := NewTxRecordSet(trs) 129 err := txrSet.Validate(100, []Tx{}) 130 require.Error(t, err) 131 }) 132 t.Run("should error on new transactions marked UNMODIFIED", func(t *testing.T) { 133 trs := []*abci.TxRecord{ 134 { 135 Action: abci.TxRecord_UNMODIFIED, 136 Tx: Tx([]byte{1, 2, 3, 4, 5}), 137 }, 138 } 139 txrSet := NewTxRecordSet(trs) 140 err := txrSet.Validate(100, []Tx{}) 141 require.Error(t, err) 142 }) 143 t.Run("should error on new transactions marked REMOVED", func(t *testing.T) { 144 trs := []*abci.TxRecord{ 145 { 146 Action: abci.TxRecord_REMOVED, 147 Tx: Tx([]byte{1, 2, 3, 4, 5}), 148 }, 149 } 150 txrSet := NewTxRecordSet(trs) 151 err := txrSet.Validate(100, []Tx{}) 152 require.Error(t, err) 153 }) 154 t.Run("should error on existing transaction marked as ADDED", func(t *testing.T) { 155 trs := []*abci.TxRecord{ 156 { 157 Action: abci.TxRecord_ADDED, 158 Tx: Tx([]byte{5, 4, 3, 2, 1}), 159 }, 160 { 161 Action: abci.TxRecord_ADDED, 162 Tx: Tx([]byte{6}), 163 }, 164 { 165 Action: abci.TxRecord_ADDED, 166 Tx: Tx([]byte{1, 2, 3, 4, 5}), 167 }, 168 } 169 txrSet := NewTxRecordSet(trs) 170 err := txrSet.Validate(100, []Tx{{0}, {1, 2, 3, 4, 5}}) 171 require.Error(t, err) 172 }) 173 t.Run("should error if any transaction marked as UNKNOWN", func(t *testing.T) { 174 trs := []*abci.TxRecord{ 175 { 176 Action: abci.TxRecord_UNKNOWN, 177 Tx: Tx([]byte{1, 2, 3, 4, 5}), 178 }, 179 } 180 txrSet := NewTxRecordSet(trs) 181 err := txrSet.Validate(100, []Tx{}) 182 require.Error(t, err) 183 }) 184 t.Run("TxRecordSet preserves order", func(t *testing.T) { 185 trs := []*abci.TxRecord{ 186 { 187 Action: abci.TxRecord_ADDED, 188 Tx: Tx([]byte{100}), 189 }, 190 { 191 Action: abci.TxRecord_ADDED, 192 Tx: Tx([]byte{99}), 193 }, 194 { 195 Action: abci.TxRecord_ADDED, 196 Tx: Tx([]byte{55}), 197 }, 198 { 199 Action: abci.TxRecord_ADDED, 200 Tx: Tx([]byte{12}), 201 }, 202 { 203 Action: abci.TxRecord_ADDED, 204 Tx: Tx([]byte{66}), 205 }, 206 { 207 Action: abci.TxRecord_ADDED, 208 Tx: Tx([]byte{9}), 209 }, 210 { 211 Action: abci.TxRecord_ADDED, 212 Tx: Tx([]byte{17}), 213 }, 214 } 215 txrSet := NewTxRecordSet(trs) 216 err := txrSet.Validate(100, []Tx{}) 217 require.NoError(t, err) 218 for i, tx := range txrSet.IncludedTxs() { 219 require.Equal(t, Tx(trs[i].Tx), tx) 220 } 221 }) 222 } 223 224 func TestValidTxProof(t *testing.T) { 225 cases := []struct { 226 txs Txs 227 }{ 228 {Txs{{1, 4, 34, 87, 163, 1}}}, 229 {Txs{{5, 56, 165, 2}, {4, 77}}}, 230 {Txs{Tx("foo"), Tx("bar"), Tx("baz")}}, 231 {makeTxs(20, 5)}, 232 {makeTxs(7, 81)}, 233 {makeTxs(61, 15)}, 234 } 235 236 for h, tc := range cases { 237 txs := tc.txs 238 root := txs.Hash() 239 // make sure valid proof for every tx 240 for i := range txs { 241 tx := []byte(txs[i]) 242 proof := txs.Proof(i) 243 assert.EqualValues(t, i, proof.Proof.Index, "%d: %d", h, i) 244 assert.EqualValues(t, len(txs), proof.Proof.Total, "%d: %d", h, i) 245 assert.EqualValues(t, root, proof.RootHash, "%d: %d", h, i) 246 assert.EqualValues(t, tx, proof.Data, "%d: %d", h, i) 247 assert.EqualValues(t, txs[i].Hash(), proof.Leaf(), "%d: %d", h, i) 248 assert.Nil(t, proof.Validate(root), "%d: %d", h, i) 249 assert.NotNil(t, proof.Validate([]byte("foobar")), "%d: %d", h, i) 250 251 // read-write must also work 252 var ( 253 p2 TxProof 254 pb2 tmproto.TxProof 255 ) 256 pbProof := proof.ToProto() 257 bin, err := pbProof.Marshal() 258 require.NoError(t, err) 259 260 err = pb2.Unmarshal(bin) 261 require.NoError(t, err) 262 263 p2, err = TxProofFromProto(pb2) 264 if assert.NoError(t, err, "%d: %d: %+v", h, i, err) { 265 assert.Nil(t, p2.Validate(root), "%d: %d", h, i) 266 } 267 } 268 } 269 } 270 271 func TestTxProofUnchangable(t *testing.T) { 272 // run the other test a bunch... 273 for i := 0; i < 40; i++ { 274 testTxProofUnchangable(t) 275 } 276 } 277 278 func testTxProofUnchangable(t *testing.T) { 279 // make some proof 280 txs := makeTxs(randInt(2, 100), randInt(16, 128)) 281 root := txs.Hash() 282 i := randInt(0, len(txs)-1) 283 proof := txs.Proof(i) 284 285 // make sure it is valid to start with 286 assert.Nil(t, proof.Validate(root)) 287 pbProof := proof.ToProto() 288 bin, err := pbProof.Marshal() 289 require.NoError(t, err) 290 291 // try mutating the data and make sure nothing breaks 292 for j := 0; j < 500; j++ { 293 bad := ctest.MutateByteSlice(bin) 294 if !bytes.Equal(bad, bin) { 295 assertBadProof(t, root, bad, proof) 296 } 297 } 298 } 299 300 // This makes sure that the proof doesn't deserialize into something valid. 301 func assertBadProof(t *testing.T, root []byte, bad []byte, good TxProof) { 302 303 var ( 304 proof TxProof 305 pbProof tmproto.TxProof 306 ) 307 err := pbProof.Unmarshal(bad) 308 if err == nil { 309 proof, err = TxProofFromProto(pbProof) 310 if err == nil { 311 err = proof.Validate(root) 312 if err == nil { 313 // XXX Fix simple merkle proofs so the following is *not* OK. 314 // This can happen if we have a slightly different total (where the 315 // path ends up the same). If it is something else, we have a real 316 // problem. 317 assert.NotEqual(t, proof.Proof.Total, good.Proof.Total, "bad: %#v\ngood: %#v", proof, good) 318 } 319 } 320 } 321 } 322 323 func randInt(low, high int) int { 324 return rand.Intn(high-low) + low 325 }