OSDN Git Service

modify ci
[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 func (s *mockStore) IsWithdrawSpent(hash *bc.Hash) bool                           { return true }
80 func (s *mockStore) SetWithdrawSpent(hash *bc.Hash)                               {}
81
82 func TestAddOrphan(t *testing.T) {
83         cases := []struct {
84                 before         *TxPool
85                 after          *TxPool
86                 addOrphan      *TxDesc
87                 requireParents []*bc.Hash
88         }{
89                 {
90                         before: &TxPool{
91                                 orphans:       map[bc.Hash]*orphanTx{},
92                                 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
93                         },
94                         after: &TxPool{
95                                 orphans: map[bc.Hash]*orphanTx{
96                                         testTxs[0].ID: &orphanTx{
97                                                 TxDesc: &TxDesc{
98                                                         Tx: testTxs[0],
99                                                 },
100                                         },
101                                 },
102                                 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
103                                         testTxs[0].SpentOutputIDs[0]: map[bc.Hash]*orphanTx{
104                                                 testTxs[0].ID: &orphanTx{
105                                                         TxDesc: &TxDesc{
106                                                                 Tx: testTxs[0],
107                                                         },
108                                                 },
109                                         },
110                                 },
111                         },
112                         addOrphan:      &TxDesc{Tx: testTxs[0]},
113                         requireParents: []*bc.Hash{&testTxs[0].SpentOutputIDs[0]},
114                 },
115                 {
116                         before: &TxPool{
117                                 orphans: map[bc.Hash]*orphanTx{
118                                         testTxs[0].ID: &orphanTx{
119                                                 TxDesc: &TxDesc{
120                                                         Tx: testTxs[0],
121                                                 },
122                                         },
123                                 },
124                                 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
125                                         testTxs[0].SpentOutputIDs[0]: map[bc.Hash]*orphanTx{
126                                                 testTxs[0].ID: &orphanTx{
127                                                         TxDesc: &TxDesc{
128                                                                 Tx: testTxs[0],
129                                                         },
130                                                 },
131                                         },
132                                 },
133                         },
134                         after: &TxPool{
135                                 orphans: map[bc.Hash]*orphanTx{
136                                         testTxs[0].ID: &orphanTx{
137                                                 TxDesc: &TxDesc{
138                                                         Tx: testTxs[0],
139                                                 },
140                                         },
141                                         testTxs[1].ID: &orphanTx{
142                                                 TxDesc: &TxDesc{
143                                                         Tx: testTxs[1],
144                                                 },
145                                         },
146                                 },
147                                 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
148                                         testTxs[0].SpentOutputIDs[0]: map[bc.Hash]*orphanTx{
149                                                 testTxs[0].ID: &orphanTx{
150                                                         TxDesc: &TxDesc{
151                                                                 Tx: testTxs[0],
152                                                         },
153                                                 },
154                                                 testTxs[1].ID: &orphanTx{
155                                                         TxDesc: &TxDesc{
156                                                                 Tx: testTxs[1],
157                                                         },
158                                                 },
159                                         },
160                                 },
161                         },
162                         addOrphan:      &TxDesc{Tx: testTxs[1]},
163                         requireParents: []*bc.Hash{&testTxs[1].SpentOutputIDs[0]},
164                 },
165                 {
166                         before: &TxPool{
167                                 orphans:       map[bc.Hash]*orphanTx{},
168                                 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
169                         },
170                         after: &TxPool{
171                                 orphans: map[bc.Hash]*orphanTx{
172                                         testTxs[2].ID: &orphanTx{
173                                                 TxDesc: &TxDesc{
174                                                         Tx: testTxs[2],
175                                                 },
176                                         },
177                                 },
178                                 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
179                                         testTxs[2].SpentOutputIDs[1]: map[bc.Hash]*orphanTx{
180                                                 testTxs[2].ID: &orphanTx{
181                                                         TxDesc: &TxDesc{
182                                                                 Tx: testTxs[2],
183                                                         },
184                                                 },
185                                         },
186                                 },
187                         },
188                         addOrphan:      &TxDesc{Tx: testTxs[2]},
189                         requireParents: []*bc.Hash{&testTxs[2].SpentOutputIDs[1]},
190                 },
191         }
192
193         for i, c := range cases {
194                 c.before.addOrphan(c.addOrphan, c.requireParents)
195                 for _, orphan := range c.before.orphans {
196                         orphan.expiration = time.Time{}
197                 }
198                 for _, orphans := range c.before.orphansByPrev {
199                         for _, orphan := range orphans {
200                                 orphan.expiration = time.Time{}
201                         }
202                 }
203                 if !testutil.DeepEqual(c.before, c.after) {
204                         t.Errorf("case %d: got %v want %v", i, c.before, c.after)
205                 }
206         }
207 }
208
209 func TestAddTransaction(t *testing.T) {
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                                 msgCh: make(chan *TxPoolMsg, 1),
220                         },
221                         after: &TxPool{
222                                 pool: map[bc.Hash]*TxDesc{
223                                         testTxs[2].ID: &TxDesc{
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                                 msgCh: make(chan *TxPoolMsg, 1),
243                         },
244                         after: &TxPool{
245                                 pool: map[bc.Hash]*TxDesc{
246                                         testTxs[2].ID: &TxDesc{
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: &orphanTx{
280                                 expiration: time.Unix(1533489701, 0),
281                                 TxDesc: &TxDesc{
282                                         Tx: testTxs[0],
283                                 },
284                         },
285                         testTxs[1].ID: &orphanTx{
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]: map[bc.Hash]*orphanTx{
294                                 testTxs[0].ID: &orphanTx{
295                                         expiration: time.Unix(1533489701, 0),
296                                         TxDesc: &TxDesc{
297                                                 Tx: testTxs[0],
298                                         },
299                                 },
300                                 testTxs[1].ID: &orphanTx{
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: &orphanTx{
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]: map[bc.Hash]*orphanTx{
321                                 testTxs[1].ID: &orphanTx{
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         cases := []struct {
339                 before    *TxPool
340                 after     *TxPool
341                 processTx *TxDesc
342         }{
343                 {
344                         before: &TxPool{
345                                 pool: map[bc.Hash]*TxDesc{},
346                                 utxo: map[bc.Hash]*types.Tx{},
347                                 orphans: map[bc.Hash]*orphanTx{
348                                         testTxs[3].ID: &orphanTx{
349                                                 TxDesc: &TxDesc{
350                                                         Tx: testTxs[3],
351                                                 },
352                                         },
353                                 },
354                                 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
355                                         testTxs[3].SpentOutputIDs[0]: map[bc.Hash]*orphanTx{
356                                                 testTxs[3].ID: &orphanTx{
357                                                         TxDesc: &TxDesc{
358                                                                 Tx: testTxs[3],
359                                                         },
360                                                 },
361                                         },
362                                 },
363                                 msgCh: make(chan *TxPoolMsg, 10),
364                         },
365                         after: &TxPool{
366                                 pool: map[bc.Hash]*TxDesc{
367                                         testTxs[3].ID: &TxDesc{
368                                                 Tx:         testTxs[3],
369                                                 StatusFail: false,
370                                         },
371                                 },
372                                 utxo: map[bc.Hash]*types.Tx{
373                                         *testTxs[3].ResultIds[0]: testTxs[3],
374                                         *testTxs[3].ResultIds[1]: testTxs[3],
375                                 },
376                                 orphans:       map[bc.Hash]*orphanTx{},
377                                 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
378                         },
379                         processTx: &TxDesc{Tx: testTxs[2]},
380                 },
381                 {
382                         before: &TxPool{
383                                 pool: map[bc.Hash]*TxDesc{},
384                                 utxo: map[bc.Hash]*types.Tx{},
385                                 orphans: map[bc.Hash]*orphanTx{
386                                         testTxs[3].ID: &orphanTx{
387                                                 TxDesc: &TxDesc{
388                                                         Tx: testTxs[3],
389                                                 },
390                                         },
391                                         testTxs[4].ID: &orphanTx{
392                                                 TxDesc: &TxDesc{
393                                                         Tx: testTxs[4],
394                                                 },
395                                         },
396                                 },
397                                 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
398                                         testTxs[3].SpentOutputIDs[0]: map[bc.Hash]*orphanTx{
399                                                 testTxs[3].ID: &orphanTx{
400                                                         TxDesc: &TxDesc{
401                                                                 Tx: testTxs[3],
402                                                         },
403                                                 },
404                                         },
405                                         testTxs[4].SpentOutputIDs[0]: map[bc.Hash]*orphanTx{
406                                                 testTxs[4].ID: &orphanTx{
407                                                         TxDesc: &TxDesc{
408                                                                 Tx: testTxs[4],
409                                                         },
410                                                 },
411                                         },
412                                 },
413                                 msgCh: make(chan *TxPoolMsg, 10),
414                         },
415                         after: &TxPool{
416                                 pool: map[bc.Hash]*TxDesc{
417                                         testTxs[3].ID: &TxDesc{
418                                                 Tx:         testTxs[3],
419                                                 StatusFail: false,
420                                         },
421                                         testTxs[4].ID: &TxDesc{
422                                                 Tx:         testTxs[4],
423                                                 StatusFail: false,
424                                         },
425                                 },
426                                 utxo: map[bc.Hash]*types.Tx{
427                                         *testTxs[3].ResultIds[0]: testTxs[3],
428                                         *testTxs[3].ResultIds[1]: testTxs[3],
429                                         *testTxs[4].ResultIds[0]: testTxs[4],
430                                         *testTxs[4].ResultIds[1]: testTxs[4],
431                                 },
432                                 orphans:       map[bc.Hash]*orphanTx{},
433                                 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
434                         },
435                         processTx: &TxDesc{Tx: testTxs[2]},
436                 },
437         }
438
439         for i, c := range cases {
440                 c.before.store = &mockStore{}
441                 c.before.addTransaction(c.processTx)
442                 c.before.processOrphans(c.processTx)
443                 c.before.RemoveTransaction(&c.processTx.Tx.ID)
444                 c.before.store = nil
445                 c.before.msgCh = nil
446                 c.before.lastUpdated = 0
447                 for _, txD := range c.before.pool {
448                         txD.Added = time.Time{}
449                 }
450
451                 if !testutil.DeepEqual(c.before, c.after) {
452                         t.Errorf("case %d: got %v want %v", i, c.before, c.after)
453                 }
454         }
455 }
456
457 func TestRemoveOrphan(t *testing.T) {
458         cases := []struct {
459                 before       *TxPool
460                 after        *TxPool
461                 removeHashes []*bc.Hash
462         }{
463                 {
464                         before: &TxPool{
465                                 orphans: map[bc.Hash]*orphanTx{
466                                         testTxs[0].ID: &orphanTx{
467                                                 expiration: time.Unix(1533489701, 0),
468                                                 TxDesc: &TxDesc{
469                                                         Tx: testTxs[0],
470                                                 },
471                                         },
472                                 },
473                                 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
474                                         testTxs[0].SpentOutputIDs[0]: map[bc.Hash]*orphanTx{
475                                                 testTxs[0].ID: &orphanTx{
476                                                         expiration: time.Unix(1533489701, 0),
477                                                         TxDesc: &TxDesc{
478                                                                 Tx: testTxs[0],
479                                                         },
480                                                 },
481                                         },
482                                 },
483                         },
484                         after: &TxPool{
485                                 orphans:       map[bc.Hash]*orphanTx{},
486                                 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
487                         },
488                         removeHashes: []*bc.Hash{
489                                 &testTxs[0].ID,
490                         },
491                 },
492                 {
493                         before: &TxPool{
494                                 orphans: map[bc.Hash]*orphanTx{
495                                         testTxs[0].ID: &orphanTx{
496                                                 expiration: time.Unix(1533489701, 0),
497                                                 TxDesc: &TxDesc{
498                                                         Tx: testTxs[0],
499                                                 },
500                                         },
501                                         testTxs[1].ID: &orphanTx{
502                                                 expiration: time.Unix(1533489701, 0),
503                                                 TxDesc: &TxDesc{
504                                                         Tx: testTxs[1],
505                                                 },
506                                         },
507                                 },
508                                 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
509                                         testTxs[0].SpentOutputIDs[0]: map[bc.Hash]*orphanTx{
510                                                 testTxs[0].ID: &orphanTx{
511                                                         expiration: time.Unix(1533489701, 0),
512                                                         TxDesc: &TxDesc{
513                                                                 Tx: testTxs[0],
514                                                         },
515                                                 },
516                                                 testTxs[1].ID: &orphanTx{
517                                                         expiration: time.Unix(1533489701, 0),
518                                                         TxDesc: &TxDesc{
519                                                                 Tx: testTxs[1],
520                                                         },
521                                                 },
522                                         },
523                                 },
524                         },
525                         after: &TxPool{
526                                 orphans: map[bc.Hash]*orphanTx{
527                                         testTxs[0].ID: &orphanTx{
528                                                 expiration: time.Unix(1533489701, 0),
529                                                 TxDesc: &TxDesc{
530                                                         Tx: testTxs[0],
531                                                 },
532                                         },
533                                 },
534                                 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
535                                         testTxs[0].SpentOutputIDs[0]: map[bc.Hash]*orphanTx{
536                                                 testTxs[0].ID: &orphanTx{
537                                                         expiration: time.Unix(1533489701, 0),
538                                                         TxDesc: &TxDesc{
539                                                                 Tx: testTxs[0],
540                                                         },
541                                                 },
542                                         },
543                                 },
544                         },
545                         removeHashes: []*bc.Hash{
546                                 &testTxs[1].ID,
547                         },
548                 },
549         }
550
551         for i, c := range cases {
552                 for _, hash := range c.removeHashes {
553                         c.before.removeOrphan(hash)
554                 }
555                 if !testutil.DeepEqual(c.before, c.after) {
556                         t.Errorf("case %d: got %v want %v", i, c.before, c.after)
557                 }
558         }
559 }