OSDN Git Service

Add mempool new tx subscription support (#1578)
[bytom/bytom.git] / protocol / txpool_test.go
1 package protocol
2
3 import (
4         "testing"
5         "time"
6
7         "github.com/bytom/consensus"
8         "github.com/bytom/database/storage"
9         "github.com/bytom/event"
10         "github.com/bytom/protocol/bc"
11         "github.com/bytom/protocol/bc/types"
12         "github.com/bytom/protocol/state"
13         "github.com/bytom/testutil"
14 )
15
16 var testTxs = []*types.Tx{
17         types.NewTx(types.TxData{
18                 SerializedSize: 100,
19                 Inputs: []*types.TxInput{
20                         types.NewSpendInput(nil, bc.NewHash([32]byte{0x01}), *consensus.BTMAssetID, 1, 1, []byte{0x51}),
21                 },
22                 Outputs: []*types.TxOutput{
23                         types.NewTxOutput(*consensus.BTMAssetID, 1, []byte{0x6a}),
24                 },
25         }),
26         types.NewTx(types.TxData{
27                 SerializedSize: 100,
28                 Inputs: []*types.TxInput{
29                         types.NewSpendInput(nil, bc.NewHash([32]byte{0x01}), *consensus.BTMAssetID, 1, 1, []byte{0x51}),
30                 },
31                 Outputs: []*types.TxOutput{
32                         types.NewTxOutput(*consensus.BTMAssetID, 1, []byte{0x6b}),
33                 },
34         }),
35         types.NewTx(types.TxData{
36                 SerializedSize: 150,
37                 TimeRange:      0,
38                 Inputs: []*types.TxInput{
39                         types.NewSpendInput(nil, bc.NewHash([32]byte{0x01}), *consensus.BTMAssetID, 1, 1, []byte{0x51}),
40                         types.NewSpendInput(nil, bc.NewHash([32]byte{0x02}), bc.NewAssetID([32]byte{0xa1}), 4, 1, []byte{0x51}),
41                 },
42                 Outputs: []*types.TxOutput{
43                         types.NewTxOutput(*consensus.BTMAssetID, 1, []byte{0x6b}),
44                         types.NewTxOutput(bc.NewAssetID([32]byte{0xa1}), 4, []byte{0x61}),
45                 },
46         }),
47         types.NewTx(types.TxData{
48                 SerializedSize: 100,
49                 Inputs: []*types.TxInput{
50                         types.NewSpendInput(nil, testutil.MustDecodeHash("dbea684b5c5153ed7729669a53d6c59574f26015a3e1eb2a0e8a1c645425a764"), bc.NewAssetID([32]byte{0xa1}), 4, 1, []byte{0x61}),
51                 },
52                 Outputs: []*types.TxOutput{
53                         types.NewTxOutput(bc.NewAssetID([32]byte{0xa1}), 3, []byte{0x62}),
54                         types.NewTxOutput(bc.NewAssetID([32]byte{0xa1}), 1, []byte{0x63}),
55                 },
56         }),
57         types.NewTx(types.TxData{
58                 SerializedSize: 100,
59                 Inputs: []*types.TxInput{
60                         types.NewSpendInput(nil, testutil.MustDecodeHash("d84d0be0fd08e7341f2d127749bb0d0844d4560f53bd54861cee9981fd922cad"), bc.NewAssetID([32]byte{0xa1}), 3, 0, []byte{0x62}),
61                 },
62                 Outputs: []*types.TxOutput{
63                         types.NewTxOutput(bc.NewAssetID([32]byte{0xa1}), 2, []byte{0x64}),
64                         types.NewTxOutput(bc.NewAssetID([32]byte{0xa1}), 1, []byte{0x65}),
65                 },
66         }),
67 }
68
69 type mockStore struct{}
70
71 func (s *mockStore) BlockExist(hash *bc.Hash) bool                                { return false }
72 func (s *mockStore) GetBlock(*bc.Hash) (*types.Block, error)                      { return nil, nil }
73 func (s *mockStore) GetStoreStatus() *BlockStoreState                             { return nil }
74 func (s *mockStore) GetTransactionStatus(*bc.Hash) (*bc.TransactionStatus, error) { return nil, nil }
75 func (s *mockStore) GetTransactionsUtxo(*state.UtxoViewpoint, []*bc.Tx) error     { return nil }
76 func (s *mockStore) GetUtxo(*bc.Hash) (*storage.UtxoEntry, error)                 { return nil, nil }
77 func (s *mockStore) LoadBlockIndex(uint64) (*state.BlockIndex, error)             { return nil, nil }
78 func (s *mockStore) SaveBlock(*types.Block, *bc.TransactionStatus) error          { return nil }
79 func (s *mockStore) SaveChainStatus(*state.BlockNode, *state.UtxoViewpoint) error { return nil }
80
81 func TestAddOrphan(t *testing.T) {
82         cases := []struct {
83                 before         *TxPool
84                 after          *TxPool
85                 addOrphan      *TxDesc
86                 requireParents []*bc.Hash
87         }{
88                 {
89                         before: &TxPool{
90                                 orphans:       map[bc.Hash]*orphanTx{},
91                                 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
92                         },
93                         after: &TxPool{
94                                 orphans: map[bc.Hash]*orphanTx{
95                                         testTxs[0].ID: {
96                                                 TxDesc: &TxDesc{
97                                                         Tx: testTxs[0],
98                                                 },
99                                         },
100                                 },
101                                 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
102                                         testTxs[0].SpentOutputIDs[0]: {
103                                                 testTxs[0].ID: {
104                                                         TxDesc: &TxDesc{
105                                                                 Tx: testTxs[0],
106                                                         },
107                                                 },
108                                         },
109                                 },
110                         },
111                         addOrphan:      &TxDesc{Tx: testTxs[0]},
112                         requireParents: []*bc.Hash{&testTxs[0].SpentOutputIDs[0]},
113                 },
114                 {
115                         before: &TxPool{
116                                 orphans: map[bc.Hash]*orphanTx{
117                                         testTxs[0].ID: {
118                                                 TxDesc: &TxDesc{
119                                                         Tx: testTxs[0],
120                                                 },
121                                         },
122                                 },
123                                 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
124                                         testTxs[0].SpentOutputIDs[0]: {
125                                                 testTxs[0].ID: {
126                                                         TxDesc: &TxDesc{
127                                                                 Tx: testTxs[0],
128                                                         },
129                                                 },
130                                         },
131                                 },
132                         },
133                         after: &TxPool{
134                                 orphans: map[bc.Hash]*orphanTx{
135                                         testTxs[0].ID: {
136                                                 TxDesc: &TxDesc{
137                                                         Tx: testTxs[0],
138                                                 },
139                                         },
140                                         testTxs[1].ID: {
141                                                 TxDesc: &TxDesc{
142                                                         Tx: testTxs[1],
143                                                 },
144                                         },
145                                 },
146                                 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
147                                         testTxs[0].SpentOutputIDs[0]: {
148                                                 testTxs[0].ID: {
149                                                         TxDesc: &TxDesc{
150                                                                 Tx: testTxs[0],
151                                                         },
152                                                 },
153                                                 testTxs[1].ID: {
154                                                         TxDesc: &TxDesc{
155                                                                 Tx: testTxs[1],
156                                                         },
157                                                 },
158                                         },
159                                 },
160                         },
161                         addOrphan:      &TxDesc{Tx: testTxs[1]},
162                         requireParents: []*bc.Hash{&testTxs[1].SpentOutputIDs[0]},
163                 },
164                 {
165                         before: &TxPool{
166                                 orphans:       map[bc.Hash]*orphanTx{},
167                                 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
168                         },
169                         after: &TxPool{
170                                 orphans: map[bc.Hash]*orphanTx{
171                                         testTxs[2].ID: {
172                                                 TxDesc: &TxDesc{
173                                                         Tx: testTxs[2],
174                                                 },
175                                         },
176                                 },
177                                 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
178                                         testTxs[2].SpentOutputIDs[1]: {
179                                                 testTxs[2].ID: {
180                                                         TxDesc: &TxDesc{
181                                                                 Tx: testTxs[2],
182                                                         },
183                                                 },
184                                         },
185                                 },
186                         },
187                         addOrphan:      &TxDesc{Tx: testTxs[2]},
188                         requireParents: []*bc.Hash{&testTxs[2].SpentOutputIDs[1]},
189                 },
190         }
191
192         for i, c := range cases {
193                 c.before.addOrphan(c.addOrphan, c.requireParents)
194                 for _, orphan := range c.before.orphans {
195                         orphan.expiration = time.Time{}
196                 }
197                 for _, orphans := range c.before.orphansByPrev {
198                         for _, orphan := range orphans {
199                                 orphan.expiration = time.Time{}
200                         }
201                 }
202                 if !testutil.DeepEqual(c.before, c.after) {
203                         t.Errorf("case %d: got %v want %v", i, c.before, c.after)
204                 }
205         }
206 }
207
208 func TestAddTransaction(t *testing.T) {
209         dispatcher := event.NewDispatcher()
210         cases := []struct {
211                 before *TxPool
212                 after  *TxPool
213                 addTx  *TxDesc
214         }{
215                 {
216                         before: &TxPool{
217                                 pool:            map[bc.Hash]*TxDesc{},
218                                 utxo:            map[bc.Hash]*types.Tx{},
219                                 eventDispatcher: dispatcher,
220                         },
221                         after: &TxPool{
222                                 pool: map[bc.Hash]*TxDesc{
223                                         testTxs[2].ID: {
224                                                 Tx:         testTxs[2],
225                                                 StatusFail: false,
226                                         },
227                                 },
228                                 utxo: map[bc.Hash]*types.Tx{
229                                         *testTxs[2].ResultIds[0]: testTxs[2],
230                                         *testTxs[2].ResultIds[1]: testTxs[2],
231                                 },
232                         },
233                         addTx: &TxDesc{
234                                 Tx:         testTxs[2],
235                                 StatusFail: false,
236                         },
237                 },
238                 {
239                         before: &TxPool{
240                                 pool:            map[bc.Hash]*TxDesc{},
241                                 utxo:            map[bc.Hash]*types.Tx{},
242                                 eventDispatcher: dispatcher,
243                         },
244                         after: &TxPool{
245                                 pool: map[bc.Hash]*TxDesc{
246                                         testTxs[2].ID: {
247                                                 Tx:         testTxs[2],
248                                                 StatusFail: true,
249                                         },
250                                 },
251                                 utxo: map[bc.Hash]*types.Tx{
252                                         *testTxs[2].ResultIds[0]: testTxs[2],
253                                 },
254                         },
255                         addTx: &TxDesc{
256                                 Tx:         testTxs[2],
257                                 StatusFail: true,
258                         },
259                 },
260         }
261
262         for i, c := range cases {
263                 c.before.addTransaction(c.addTx)
264                 for _, txD := range c.before.pool {
265                         txD.Added = time.Time{}
266                 }
267                 if !testutil.DeepEqual(c.before.pool, c.after.pool) {
268                         t.Errorf("case %d: got %v want %v", i, c.before.pool, c.after.pool)
269                 }
270                 if !testutil.DeepEqual(c.before.utxo, c.after.utxo) {
271                         t.Errorf("case %d: got %v want %v", i, c.before.utxo, c.after.utxo)
272                 }
273         }
274 }
275
276 func TestExpireOrphan(t *testing.T) {
277         before := &TxPool{
278                 orphans: map[bc.Hash]*orphanTx{
279                         testTxs[0].ID: {
280                                 expiration: time.Unix(1533489701, 0),
281                                 TxDesc: &TxDesc{
282                                         Tx: testTxs[0],
283                                 },
284                         },
285                         testTxs[1].ID: {
286                                 expiration: time.Unix(1633489701, 0),
287                                 TxDesc: &TxDesc{
288                                         Tx: testTxs[1],
289                                 },
290                         },
291                 },
292                 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
293                         testTxs[0].SpentOutputIDs[0]: {
294                                 testTxs[0].ID: {
295                                         expiration: time.Unix(1533489701, 0),
296                                         TxDesc: &TxDesc{
297                                                 Tx: testTxs[0],
298                                         },
299                                 },
300                                 testTxs[1].ID: {
301                                         expiration: time.Unix(1633489701, 0),
302                                         TxDesc: &TxDesc{
303                                                 Tx: testTxs[1],
304                                         },
305                                 },
306                         },
307                 },
308         }
309
310         want := &TxPool{
311                 orphans: map[bc.Hash]*orphanTx{
312                         testTxs[1].ID: {
313                                 expiration: time.Unix(1633489701, 0),
314                                 TxDesc: &TxDesc{
315                                         Tx: testTxs[1],
316                                 },
317                         },
318                 },
319                 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
320                         testTxs[0].SpentOutputIDs[0]: {
321                                 testTxs[1].ID: {
322                                         expiration: time.Unix(1633489701, 0),
323                                         TxDesc: &TxDesc{
324                                                 Tx: testTxs[1],
325                                         },
326                                 },
327                         },
328                 },
329         }
330
331         before.ExpireOrphan(time.Unix(1633479701, 0))
332         if !testutil.DeepEqual(before, want) {
333                 t.Errorf("got %v want %v", before, want)
334         }
335 }
336
337 func TestProcessOrphans(t *testing.T) {
338         dispatcher := event.NewDispatcher()
339         cases := []struct {
340                 before    *TxPool
341                 after     *TxPool
342                 processTx *TxDesc
343         }{
344                 {
345                         before: &TxPool{
346                                 pool:            map[bc.Hash]*TxDesc{},
347                                 utxo:            map[bc.Hash]*types.Tx{},
348                                 eventDispatcher: dispatcher,
349                                 orphans: map[bc.Hash]*orphanTx{
350                                         testTxs[3].ID: {
351                                                 TxDesc: &TxDesc{
352                                                         Tx: testTxs[3],
353                                                 },
354                                         },
355                                 },
356                                 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
357                                         testTxs[3].SpentOutputIDs[0]: {
358                                                 testTxs[3].ID: {
359                                                         TxDesc: &TxDesc{
360                                                                 Tx: testTxs[3],
361                                                         },
362                                                 },
363                                         },
364                                 },
365                         },
366                         after: &TxPool{
367                                 pool: map[bc.Hash]*TxDesc{
368                                         testTxs[3].ID: {
369                                                 Tx:         testTxs[3],
370                                                 StatusFail: false,
371                                         },
372                                 },
373                                 utxo: map[bc.Hash]*types.Tx{
374                                         *testTxs[3].ResultIds[0]: testTxs[3],
375                                         *testTxs[3].ResultIds[1]: testTxs[3],
376                                 },
377                                 eventDispatcher: dispatcher,
378                                 orphans:         map[bc.Hash]*orphanTx{},
379                                 orphansByPrev:   map[bc.Hash]map[bc.Hash]*orphanTx{},
380                         },
381                         processTx: &TxDesc{Tx: testTxs[2]},
382                 },
383                 {
384                         before: &TxPool{
385                                 pool:            map[bc.Hash]*TxDesc{},
386                                 utxo:            map[bc.Hash]*types.Tx{},
387                                 eventDispatcher: dispatcher,
388                                 orphans: map[bc.Hash]*orphanTx{
389                                         testTxs[3].ID: {
390                                                 TxDesc: &TxDesc{
391                                                         Tx: testTxs[3],
392                                                 },
393                                         },
394                                         testTxs[4].ID: {
395                                                 TxDesc: &TxDesc{
396                                                         Tx: testTxs[4],
397                                                 },
398                                         },
399                                 },
400                                 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
401                                         testTxs[3].SpentOutputIDs[0]: {
402                                                 testTxs[3].ID: {
403                                                         TxDesc: &TxDesc{
404                                                                 Tx: testTxs[3],
405                                                         },
406                                                 },
407                                         },
408                                         testTxs[4].SpentOutputIDs[0]: {
409                                                 testTxs[4].ID: {
410                                                         TxDesc: &TxDesc{
411                                                                 Tx: testTxs[4],
412                                                         },
413                                                 },
414                                         },
415                                 },
416                         },
417                         after: &TxPool{
418                                 pool: map[bc.Hash]*TxDesc{
419                                         testTxs[3].ID: {
420                                                 Tx:         testTxs[3],
421                                                 StatusFail: false,
422                                         },
423                                         testTxs[4].ID: {
424                                                 Tx:         testTxs[4],
425                                                 StatusFail: false,
426                                         },
427                                 },
428                                 utxo: map[bc.Hash]*types.Tx{
429                                         *testTxs[3].ResultIds[0]: testTxs[3],
430                                         *testTxs[3].ResultIds[1]: testTxs[3],
431                                         *testTxs[4].ResultIds[0]: testTxs[4],
432                                         *testTxs[4].ResultIds[1]: testTxs[4],
433                                 },
434                                 eventDispatcher: dispatcher,
435                                 orphans:         map[bc.Hash]*orphanTx{},
436                                 orphansByPrev:   map[bc.Hash]map[bc.Hash]*orphanTx{},
437                         },
438                         processTx: &TxDesc{Tx: testTxs[2]},
439                 },
440         }
441
442         for i, c := range cases {
443                 c.before.store = &mockStore{}
444                 c.before.addTransaction(c.processTx)
445                 c.before.processOrphans(c.processTx)
446                 c.before.RemoveTransaction(&c.processTx.Tx.ID)
447                 c.before.store = nil
448                 c.before.lastUpdated = 0
449                 for _, txD := range c.before.pool {
450                         txD.Added = time.Time{}
451                 }
452
453                 if !testutil.DeepEqual(c.before, c.after) {
454                         t.Errorf("case %d: got %v want %v", i, c.before, c.after)
455                 }
456         }
457 }
458
459 func TestRemoveOrphan(t *testing.T) {
460         cases := []struct {
461                 before       *TxPool
462                 after        *TxPool
463                 removeHashes []*bc.Hash
464         }{
465                 {
466                         before: &TxPool{
467                                 orphans: map[bc.Hash]*orphanTx{
468                                         testTxs[0].ID: {
469                                                 expiration: time.Unix(1533489701, 0),
470                                                 TxDesc: &TxDesc{
471                                                         Tx: testTxs[0],
472                                                 },
473                                         },
474                                 },
475                                 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
476                                         testTxs[0].SpentOutputIDs[0]: {
477                                                 testTxs[0].ID: {
478                                                         expiration: time.Unix(1533489701, 0),
479                                                         TxDesc: &TxDesc{
480                                                                 Tx: testTxs[0],
481                                                         },
482                                                 },
483                                         },
484                                 },
485                         },
486                         after: &TxPool{
487                                 orphans:       map[bc.Hash]*orphanTx{},
488                                 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
489                         },
490                         removeHashes: []*bc.Hash{
491                                 &testTxs[0].ID,
492                         },
493                 },
494                 {
495                         before: &TxPool{
496                                 orphans: map[bc.Hash]*orphanTx{
497                                         testTxs[0].ID: {
498                                                 expiration: time.Unix(1533489701, 0),
499                                                 TxDesc: &TxDesc{
500                                                         Tx: testTxs[0],
501                                                 },
502                                         },
503                                         testTxs[1].ID: {
504                                                 expiration: time.Unix(1533489701, 0),
505                                                 TxDesc: &TxDesc{
506                                                         Tx: testTxs[1],
507                                                 },
508                                         },
509                                 },
510                                 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
511                                         testTxs[0].SpentOutputIDs[0]: {
512                                                 testTxs[0].ID: {
513                                                         expiration: time.Unix(1533489701, 0),
514                                                         TxDesc: &TxDesc{
515                                                                 Tx: testTxs[0],
516                                                         },
517                                                 },
518                                                 testTxs[1].ID: {
519                                                         expiration: time.Unix(1533489701, 0),
520                                                         TxDesc: &TxDesc{
521                                                                 Tx: testTxs[1],
522                                                         },
523                                                 },
524                                         },
525                                 },
526                         },
527                         after: &TxPool{
528                                 orphans: map[bc.Hash]*orphanTx{
529                                         testTxs[0].ID: {
530                                                 expiration: time.Unix(1533489701, 0),
531                                                 TxDesc: &TxDesc{
532                                                         Tx: testTxs[0],
533                                                 },
534                                         },
535                                 },
536                                 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
537                                         testTxs[0].SpentOutputIDs[0]: {
538                                                 testTxs[0].ID: {
539                                                         expiration: time.Unix(1533489701, 0),
540                                                         TxDesc: &TxDesc{
541                                                                 Tx: testTxs[0],
542                                                         },
543                                                 },
544                                         },
545                                 },
546                         },
547                         removeHashes: []*bc.Hash{
548                                 &testTxs[1].ID,
549                         },
550                 },
551         }
552
553         for i, c := range cases {
554                 for _, hash := range c.removeHashes {
555                         c.before.removeOrphan(hash)
556                 }
557                 if !testutil.DeepEqual(c.before, c.after) {
558                         t.Errorf("case %d: got %v want %v", i, c.before, c.after)
559                 }
560         }
561 }