OSDN Git Service

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