OSDN Git Service

338d57fbdfb855c59b712b32422336de79736edc
[bytom/vapor.git] / protocol / txpool_test.go
1 package protocol
2
3 import (
4         "testing"
5         "time"
6
7         "github.com/davecgh/go-spew/spew"
8
9         "github.com/vapor/consensus"
10         "github.com/vapor/database/storage"
11         "github.com/vapor/event"
12         "github.com/vapor/protocol/bc"
13         "github.com/vapor/protocol/bc/types"
14         "github.com/vapor/protocol/state"
15         "github.com/vapor/testutil"
16 )
17
18 var testTxs = []*types.Tx{
19         //tx0
20         types.NewTx(types.TxData{
21                 SerializedSize: 100,
22                 Inputs: []*types.TxInput{
23                         types.NewSpendInput(nil, bc.NewHash([32]byte{0x01}), *consensus.BTMAssetID, 1, 1, []byte{0x51}),
24                 },
25                 Outputs: []*types.TxOutput{
26                         types.NewIntraChainOutput(*consensus.BTMAssetID, 1, []byte{0x6a}),
27                 },
28         }),
29         //tx1
30         types.NewTx(types.TxData{
31                 SerializedSize: 100,
32                 Inputs: []*types.TxInput{
33                         types.NewSpendInput(nil, bc.NewHash([32]byte{0x01}), *consensus.BTMAssetID, 1, 1, []byte{0x51}),
34                 },
35                 Outputs: []*types.TxOutput{
36                         types.NewIntraChainOutput(*consensus.BTMAssetID, 1, []byte{0x6b}),
37                 },
38         }),
39         //tx2
40         types.NewTx(types.TxData{
41                 SerializedSize: 150,
42                 TimeRange:      0,
43                 Inputs: []*types.TxInput{
44                         types.NewSpendInput(nil, bc.NewHash([32]byte{0x01}), *consensus.BTMAssetID, 1, 1, []byte{0x51}),
45                         types.NewSpendInput(nil, bc.NewHash([32]byte{0x02}), bc.NewAssetID([32]byte{0xa1}), 4, 1, []byte{0x51}),
46                 },
47                 Outputs: []*types.TxOutput{
48                         types.NewIntraChainOutput(*consensus.BTMAssetID, 1, []byte{0x6b}),
49                         types.NewIntraChainOutput(bc.NewAssetID([32]byte{0xa1}), 4, []byte{0x61}),
50                 },
51         }),
52         //tx3
53         types.NewTx(types.TxData{
54
55                 SerializedSize: 100,
56                 Inputs: []*types.TxInput{
57                         types.NewSpendInput(nil, testutil.MustDecodeHash("7d3f8e8474775f9fab2a7370529f0569a2199b22a5a83d235a036f50de3e8c84"), bc.NewAssetID([32]byte{0xa1}), 4, 1, []byte{0x61}),
58                 },
59                 Outputs: []*types.TxOutput{
60                         types.NewIntraChainOutput(bc.NewAssetID([32]byte{0xa1}), 3, []byte{0x62}),
61                         types.NewIntraChainOutput(bc.NewAssetID([32]byte{0xa1}), 1, []byte{0x63}),
62                 },
63         }),
64         //tx4
65         types.NewTx(types.TxData{
66                 SerializedSize: 100,
67                 Inputs: []*types.TxInput{
68                         types.NewSpendInput(nil, testutil.MustDecodeHash("9a26cde504a5d7190dbed119280276f9816d9c2b7d20c768b312be57930fe840"), bc.NewAssetID([32]byte{0xa1}), 3, 0, []byte{0x62}),
69                 },
70                 Outputs: []*types.TxOutput{
71                         types.NewIntraChainOutput(bc.NewAssetID([32]byte{0xa1}), 2, []byte{0x64}),
72                         types.NewIntraChainOutput(bc.NewAssetID([32]byte{0xa1}), 1, []byte{0x65}),
73                 },
74         }),
75         //tx5
76         types.NewTx(types.TxData{
77                 SerializedSize: 100,
78                 Inputs: []*types.TxInput{
79                         types.NewSpendInput(nil, bc.NewHash([32]byte{0x01}), *consensus.BTMAssetID, 1, 1, []byte{0x51}),
80                 },
81                 Outputs: []*types.TxOutput{
82                         types.NewIntraChainOutput(*consensus.BTMAssetID, 0, []byte{0x51}),
83                 },
84         }),
85         //tx6
86         types.NewTx(types.TxData{
87                 SerializedSize: 100,
88                 Inputs: []*types.TxInput{
89                         types.NewSpendInput(nil, bc.NewHash([32]byte{0x01}), *consensus.BTMAssetID, 3, 1, []byte{0x51}),
90                         types.NewSpendInput(nil, testutil.MustDecodeHash("9a26cde504a5d7190dbed119280276f9816d9c2b7d20c768b312be57930fe840"), bc.NewAssetID([32]byte{0xa1}), 3, 0, []byte{0x62}),
91                 },
92                 Outputs: []*types.TxOutput{
93                         types.NewIntraChainOutput(*consensus.BTMAssetID, 2, []byte{0x51}),
94                         types.NewIntraChainOutput(bc.NewAssetID([32]byte{0xa1}), 0, []byte{0x65}),
95                 },
96         }),
97         //tx7
98         types.NewTx(types.TxData{
99                 SerializedSize: 150,
100                 TimeRange:      0,
101                 Inputs: []*types.TxInput{
102                         types.NewSpendInput(nil, bc.NewHash([32]byte{0x01}), *consensus.BTMAssetID, 1, 1, []byte{0x51}),
103                         types.NewSpendInput(nil, bc.NewHash([32]byte{0x02}), bc.NewAssetID([32]byte{0xa1}), 4, 1, []byte{0x51}),
104                 },
105                 Outputs: []*types.TxOutput{
106                         types.NewIntraChainOutput(*consensus.BTMAssetID, 1, []byte{0x6b}),
107                         types.NewVoteOutput(bc.NewAssetID([32]byte{0xa1}), 4, []byte{0x61}, []byte("a8f410b9f7cd9ce352d215ed17c85559c351dc8d18ed89ad403ca28cfc423f612e04a1c9584f945c286c47ec1e5b8405c65ff56e31f44a2627aca4f77e03936f")),
108                 },
109         }),
110 }
111
112 type mockStore struct{}
113
114 func (s *mockStore) BlockExist(hash *bc.Hash, height uint64) bool                 { return false }
115 func (s *mockStore) GetBlock(*bc.Hash, uint64) (*types.Block, error)              { return nil, nil }
116 func (s *mockStore) GetBlockHeader(*bc.Hash, uint64) (*types.BlockHeader, error)  { return nil, nil }
117 func (s *mockStore) GetStoreStatus() *BlockStoreState                             { return nil }
118 func (s *mockStore) GetTransactionStatus(*bc.Hash) (*bc.TransactionStatus, error) { return nil, nil }
119 func (s *mockStore) GetTransactionsUtxo(*state.UtxoViewpoint, []*bc.Tx) error     { return nil }
120 func (s *mockStore) GetUtxo(*bc.Hash) (*storage.UtxoEntry, error)                 { return nil, nil }
121 func (s *mockStore) GetVoteResult(uint64) (*state.VoteResult, error)              { return nil, nil }
122 func (s *mockStore) LoadBlockIndex(uint64) (*state.BlockIndex, error)             { return nil, nil }
123 func (s *mockStore) SaveBlock(*types.Block, *bc.TransactionStatus) error          { return nil }
124 func (s *mockStore) SaveBlockHeader(*types.BlockHeader) error                     { return nil }
125 func (s *mockStore) SaveChainStatus(*state.BlockNode, *state.BlockNode, *state.UtxoViewpoint, []*state.VoteResult) error {
126         return nil
127 }
128
129 func TestAddOrphan(t *testing.T) {
130         cases := []struct {
131                 before         *TxPool
132                 after          *TxPool
133                 addOrphan      *TxDesc
134                 requireParents []*bc.Hash
135         }{
136                 {
137                         before: &TxPool{
138                                 orphans:       map[bc.Hash]*orphanTx{},
139                                 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
140                         },
141                         after: &TxPool{
142                                 orphans: map[bc.Hash]*orphanTx{
143                                         testTxs[0].ID: {
144                                                 TxDesc: &TxDesc{
145                                                         Tx: testTxs[0],
146                                                 },
147                                         },
148                                 },
149                                 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
150                                         testTxs[0].SpentOutputIDs[0]: {
151                                                 testTxs[0].ID: {
152                                                         TxDesc: &TxDesc{
153                                                                 Tx: testTxs[0],
154                                                         },
155                                                 },
156                                         },
157                                 },
158                         },
159                         addOrphan:      &TxDesc{Tx: testTxs[0]},
160                         requireParents: []*bc.Hash{&testTxs[0].SpentOutputIDs[0]},
161                 },
162                 {
163                         before: &TxPool{
164                                 orphans: map[bc.Hash]*orphanTx{
165                                         testTxs[0].ID: {
166                                                 TxDesc: &TxDesc{
167                                                         Tx: testTxs[0],
168                                                 },
169                                         },
170                                 },
171                                 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
172                                         testTxs[0].SpentOutputIDs[0]: {
173                                                 testTxs[0].ID: {
174                                                         TxDesc: &TxDesc{
175                                                                 Tx: testTxs[0],
176                                                         },
177                                                 },
178                                         },
179                                 },
180                         },
181                         after: &TxPool{
182                                 orphans: map[bc.Hash]*orphanTx{
183                                         testTxs[0].ID: {
184                                                 TxDesc: &TxDesc{
185                                                         Tx: testTxs[0],
186                                                 },
187                                         },
188                                         testTxs[1].ID: {
189                                                 TxDesc: &TxDesc{
190                                                         Tx: testTxs[1],
191                                                 },
192                                         },
193                                 },
194                                 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
195                                         testTxs[0].SpentOutputIDs[0]: {
196                                                 testTxs[0].ID: {
197                                                         TxDesc: &TxDesc{
198                                                                 Tx: testTxs[0],
199                                                         },
200                                                 },
201                                                 testTxs[1].ID: {
202                                                         TxDesc: &TxDesc{
203                                                                 Tx: testTxs[1],
204                                                         },
205                                                 },
206                                         },
207                                 },
208                         },
209                         addOrphan:      &TxDesc{Tx: testTxs[1]},
210                         requireParents: []*bc.Hash{&testTxs[1].SpentOutputIDs[0]},
211                 },
212                 {
213                         before: &TxPool{
214                                 orphans:       map[bc.Hash]*orphanTx{},
215                                 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
216                         },
217                         after: &TxPool{
218                                 orphans: map[bc.Hash]*orphanTx{
219                                         testTxs[2].ID: {
220                                                 TxDesc: &TxDesc{
221                                                         Tx: testTxs[2],
222                                                 },
223                                         },
224                                 },
225                                 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
226                                         testTxs[2].SpentOutputIDs[1]: {
227                                                 testTxs[2].ID: {
228                                                         TxDesc: &TxDesc{
229                                                                 Tx: testTxs[2],
230                                                         },
231                                                 },
232                                         },
233                                 },
234                         },
235                         addOrphan:      &TxDesc{Tx: testTxs[2]},
236                         requireParents: []*bc.Hash{&testTxs[2].SpentOutputIDs[1]},
237                 },
238         }
239
240         for i, c := range cases {
241                 c.before.addOrphan(c.addOrphan, c.requireParents)
242                 for _, orphan := range c.before.orphans {
243                         orphan.expiration = time.Time{}
244                 }
245                 for _, orphans := range c.before.orphansByPrev {
246                         for _, orphan := range orphans {
247                                 orphan.expiration = time.Time{}
248                         }
249                 }
250                 if !testutil.DeepEqual(c.before, c.after) {
251                         t.Errorf("case %d: got %v want %v", i, c.before, c.after)
252                 }
253         }
254 }
255
256 func TestAddTransaction(t *testing.T) {
257         dispatcher := event.NewDispatcher()
258         cases := []struct {
259                 before *TxPool
260                 after  *TxPool
261                 addTx  *TxDesc
262         }{
263                 {
264                         before: &TxPool{
265                                 pool:            map[bc.Hash]*TxDesc{},
266                                 utxo:            map[bc.Hash]*types.Tx{},
267                                 eventDispatcher: dispatcher,
268                         },
269                         after: &TxPool{
270                                 pool: map[bc.Hash]*TxDesc{
271                                         testTxs[2].ID: {
272                                                 Tx:         testTxs[2],
273                                                 StatusFail: false,
274                                         },
275                                 },
276                                 utxo: map[bc.Hash]*types.Tx{
277                                         *testTxs[2].ResultIds[0]: testTxs[2],
278                                         *testTxs[2].ResultIds[1]: testTxs[2],
279                                 },
280                         },
281                         addTx: &TxDesc{
282                                 Tx:         testTxs[2],
283                                 StatusFail: false,
284                         },
285                 },
286                 {
287                         before: &TxPool{
288                                 pool:            map[bc.Hash]*TxDesc{},
289                                 utxo:            map[bc.Hash]*types.Tx{},
290                                 eventDispatcher: dispatcher,
291                         },
292                         after: &TxPool{
293                                 pool: map[bc.Hash]*TxDesc{
294                                         testTxs[2].ID: {
295                                                 Tx:         testTxs[2],
296                                                 StatusFail: true,
297                                         },
298                                 },
299                                 utxo: map[bc.Hash]*types.Tx{
300                                         *testTxs[2].ResultIds[0]: testTxs[2],
301                                 },
302                         },
303                         addTx: &TxDesc{
304                                 Tx:         testTxs[2],
305                                 StatusFail: true,
306                         },
307                 },
308                 {
309                         before: &TxPool{
310                                 pool:            map[bc.Hash]*TxDesc{},
311                                 utxo:            map[bc.Hash]*types.Tx{},
312                                 eventDispatcher: dispatcher,
313                         },
314                         after: &TxPool{
315                                 pool: map[bc.Hash]*TxDesc{
316                                         testTxs[7].ID: {
317                                                 Tx:         testTxs[7],
318                                                 StatusFail: false,
319                                         },
320                                 },
321                                 utxo: map[bc.Hash]*types.Tx{
322                                         *testTxs[7].ResultIds[0]: testTxs[7],
323                                         *testTxs[7].ResultIds[1]: testTxs[7],
324                                 },
325                         },
326                         addTx: &TxDesc{
327                                 Tx:         testTxs[7],
328                                 StatusFail: false,
329                         },
330                 },
331                 {
332                         before: &TxPool{
333                                 pool:            map[bc.Hash]*TxDesc{},
334                                 utxo:            map[bc.Hash]*types.Tx{},
335                                 eventDispatcher: dispatcher,
336                         },
337                         after: &TxPool{
338                                 pool: map[bc.Hash]*TxDesc{
339                                         testTxs[7].ID: {
340                                                 Tx:         testTxs[7],
341                                                 StatusFail: true,
342                                         },
343                                 },
344                                 utxo: map[bc.Hash]*types.Tx{
345                                         *testTxs[7].ResultIds[0]: testTxs[7],
346                                 },
347                         },
348                         addTx: &TxDesc{
349                                 Tx:         testTxs[7],
350                                 StatusFail: true,
351                         },
352                 },
353         }
354
355         for i, c := range cases {
356                 c.before.addTransaction(c.addTx)
357                 for _, txD := range c.before.pool {
358                         txD.Added = time.Time{}
359                 }
360                 if !testutil.DeepEqual(c.before.pool, c.after.pool) {
361                         t.Errorf("case %d: got %v want %v", i, c.before.pool, c.after.pool)
362                 }
363                 if !testutil.DeepEqual(c.before.utxo, c.after.utxo) {
364                         t.Errorf("case %d: got %v want %v", i, c.before.utxo, c.after.utxo)
365                 }
366         }
367 }
368
369 func TestExpireOrphan(t *testing.T) {
370         before := &TxPool{
371                 orphans: map[bc.Hash]*orphanTx{
372                         testTxs[0].ID: {
373                                 expiration: time.Unix(1533489701, 0),
374                                 TxDesc: &TxDesc{
375                                         Tx: testTxs[0],
376                                 },
377                         },
378                         testTxs[1].ID: {
379                                 expiration: time.Unix(1633489701, 0),
380                                 TxDesc: &TxDesc{
381                                         Tx: testTxs[1],
382                                 },
383                         },
384                 },
385                 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
386                         testTxs[0].SpentOutputIDs[0]: {
387                                 testTxs[0].ID: {
388                                         expiration: time.Unix(1533489701, 0),
389                                         TxDesc: &TxDesc{
390                                                 Tx: testTxs[0],
391                                         },
392                                 },
393                                 testTxs[1].ID: {
394                                         expiration: time.Unix(1633489701, 0),
395                                         TxDesc: &TxDesc{
396                                                 Tx: testTxs[1],
397                                         },
398                                 },
399                         },
400                 },
401         }
402
403         want := &TxPool{
404                 orphans: map[bc.Hash]*orphanTx{
405                         testTxs[1].ID: {
406                                 expiration: time.Unix(1633489701, 0),
407                                 TxDesc: &TxDesc{
408                                         Tx: testTxs[1],
409                                 },
410                         },
411                 },
412                 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
413                         testTxs[0].SpentOutputIDs[0]: {
414                                 testTxs[1].ID: {
415                                         expiration: time.Unix(1633489701, 0),
416                                         TxDesc: &TxDesc{
417                                                 Tx: testTxs[1],
418                                         },
419                                 },
420                         },
421                 },
422         }
423
424         before.ExpireOrphan(time.Unix(1633479701, 0))
425         if !testutil.DeepEqual(before, want) {
426                 t.Errorf("got %v want %v", before, want)
427         }
428 }
429
430 func TestProcessOrphans(t *testing.T) {
431         dispatcher := event.NewDispatcher()
432         cases := []struct {
433                 before    *TxPool
434                 after     *TxPool
435                 processTx *TxDesc
436         }{
437                 {
438                         before: &TxPool{
439                                 pool:            map[bc.Hash]*TxDesc{},
440                                 utxo:            map[bc.Hash]*types.Tx{},
441                                 eventDispatcher: dispatcher,
442                                 orphans: map[bc.Hash]*orphanTx{
443                                         testTxs[3].ID: {
444                                                 TxDesc: &TxDesc{
445                                                         Tx: testTxs[3],
446                                                 },
447                                         },
448                                 },
449                                 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
450                                         testTxs[3].SpentOutputIDs[0]: {
451                                                 testTxs[3].ID: {
452                                                         TxDesc: &TxDesc{
453                                                                 Tx: testTxs[3],
454                                                         },
455                                                 },
456                                         },
457                                 },
458                         },
459                         after: &TxPool{
460                                 pool: map[bc.Hash]*TxDesc{
461                                         testTxs[3].ID: {
462                                                 Tx:         testTxs[3],
463                                                 StatusFail: false,
464                                         },
465                                 },
466                                 utxo: map[bc.Hash]*types.Tx{
467                                         *testTxs[3].ResultIds[0]: testTxs[3],
468                                         *testTxs[3].ResultIds[1]: testTxs[3],
469                                 },
470                                 eventDispatcher: dispatcher,
471                                 orphans:         map[bc.Hash]*orphanTx{},
472                                 orphansByPrev:   map[bc.Hash]map[bc.Hash]*orphanTx{},
473                         },
474                         processTx: &TxDesc{Tx: testTxs[2]},
475                 },
476                 {
477                         before: &TxPool{
478                                 pool:            map[bc.Hash]*TxDesc{},
479                                 utxo:            map[bc.Hash]*types.Tx{},
480                                 eventDispatcher: dispatcher,
481                                 orphans: map[bc.Hash]*orphanTx{
482                                         testTxs[3].ID: {
483                                                 TxDesc: &TxDesc{
484                                                         Tx: testTxs[3],
485                                                 },
486                                         },
487                                         testTxs[4].ID: {
488                                                 TxDesc: &TxDesc{
489                                                         Tx: testTxs[4],
490                                                 },
491                                         },
492                                 },
493                                 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
494                                         testTxs[3].SpentOutputIDs[0]: {
495                                                 testTxs[3].ID: {
496                                                         TxDesc: &TxDesc{
497                                                                 Tx: testTxs[3],
498                                                         },
499                                                 },
500                                         },
501                                         testTxs[4].SpentOutputIDs[0]: {
502                                                 testTxs[4].ID: {
503                                                         TxDesc: &TxDesc{
504                                                                 Tx: testTxs[4],
505                                                         },
506                                                 },
507                                         },
508                                 },
509                         },
510                         after: &TxPool{
511                                 pool: map[bc.Hash]*TxDesc{
512                                         testTxs[3].ID: {
513                                                 Tx:         testTxs[3],
514                                                 StatusFail: false,
515                                         },
516                                         testTxs[4].ID: {
517                                                 Tx:         testTxs[4],
518                                                 StatusFail: false,
519                                         },
520                                 },
521                                 utxo: map[bc.Hash]*types.Tx{
522                                         *testTxs[3].ResultIds[0]: testTxs[3],
523                                         *testTxs[3].ResultIds[1]: testTxs[3],
524                                         *testTxs[4].ResultIds[0]: testTxs[4],
525                                         *testTxs[4].ResultIds[1]: testTxs[4],
526                                 },
527                                 eventDispatcher: dispatcher,
528                                 orphans:         map[bc.Hash]*orphanTx{},
529                                 orphansByPrev:   map[bc.Hash]map[bc.Hash]*orphanTx{},
530                         },
531                         processTx: &TxDesc{Tx: testTxs[2]},
532                 },
533         }
534
535         for i, c := range cases {
536                 c.before.store = &mockStore{}
537                 c.before.addTransaction(c.processTx)
538                 c.before.processOrphans(c.processTx)
539                 c.before.RemoveTransaction(&c.processTx.Tx.ID)
540                 c.before.store = nil
541                 c.before.lastUpdated = 0
542                 for _, txD := range c.before.pool {
543                         txD.Added = time.Time{}
544                 }
545
546                 if !testutil.DeepEqual(c.before, c.after) {
547                         t.Errorf("case %d: got %v want %v", i, c.before, c.after)
548                 }
549         }
550 }
551
552 func TestRemoveOrphan(t *testing.T) {
553         cases := []struct {
554                 before       *TxPool
555                 after        *TxPool
556                 removeHashes []*bc.Hash
557         }{
558                 {
559                         before: &TxPool{
560                                 orphans: map[bc.Hash]*orphanTx{
561                                         testTxs[0].ID: {
562                                                 expiration: time.Unix(1533489701, 0),
563                                                 TxDesc: &TxDesc{
564                                                         Tx: testTxs[0],
565                                                 },
566                                         },
567                                 },
568                                 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
569                                         testTxs[0].SpentOutputIDs[0]: {
570                                                 testTxs[0].ID: {
571                                                         expiration: time.Unix(1533489701, 0),
572                                                         TxDesc: &TxDesc{
573                                                                 Tx: testTxs[0],
574                                                         },
575                                                 },
576                                         },
577                                 },
578                         },
579                         after: &TxPool{
580                                 orphans:       map[bc.Hash]*orphanTx{},
581                                 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
582                         },
583                         removeHashes: []*bc.Hash{
584                                 &testTxs[0].ID,
585                         },
586                 },
587                 {
588                         before: &TxPool{
589                                 orphans: map[bc.Hash]*orphanTx{
590                                         testTxs[0].ID: {
591                                                 expiration: time.Unix(1533489701, 0),
592                                                 TxDesc: &TxDesc{
593                                                         Tx: testTxs[0],
594                                                 },
595                                         },
596                                         testTxs[1].ID: {
597                                                 expiration: time.Unix(1533489701, 0),
598                                                 TxDesc: &TxDesc{
599                                                         Tx: testTxs[1],
600                                                 },
601                                         },
602                                 },
603                                 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
604                                         testTxs[0].SpentOutputIDs[0]: {
605                                                 testTxs[0].ID: {
606                                                         expiration: time.Unix(1533489701, 0),
607                                                         TxDesc: &TxDesc{
608                                                                 Tx: testTxs[0],
609                                                         },
610                                                 },
611                                                 testTxs[1].ID: {
612                                                         expiration: time.Unix(1533489701, 0),
613                                                         TxDesc: &TxDesc{
614                                                                 Tx: testTxs[1],
615                                                         },
616                                                 },
617                                         },
618                                 },
619                         },
620                         after: &TxPool{
621                                 orphans: map[bc.Hash]*orphanTx{
622                                         testTxs[0].ID: {
623                                                 expiration: time.Unix(1533489701, 0),
624                                                 TxDesc: &TxDesc{
625                                                         Tx: testTxs[0],
626                                                 },
627                                         },
628                                 },
629                                 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
630                                         testTxs[0].SpentOutputIDs[0]: {
631                                                 testTxs[0].ID: {
632                                                         expiration: time.Unix(1533489701, 0),
633                                                         TxDesc: &TxDesc{
634                                                                 Tx: testTxs[0],
635                                                         },
636                                                 },
637                                         },
638                                 },
639                         },
640                         removeHashes: []*bc.Hash{
641                                 &testTxs[1].ID,
642                         },
643                 },
644         }
645
646         for i, c := range cases {
647                 for _, hash := range c.removeHashes {
648                         c.before.removeOrphan(hash)
649                 }
650                 if !testutil.DeepEqual(c.before, c.after) {
651                         t.Errorf("case %d: got %v want %v", i, c.before, c.after)
652                 }
653         }
654 }
655
656 type mockStore1 struct{}
657
658 func (s *mockStore1) BlockExist(hash *bc.Hash, height uint64) bool                 { return false }
659 func (s *mockStore1) GetBlock(*bc.Hash, uint64) (*types.Block, error)              { return nil, nil }
660 func (s *mockStore1) GetBlockHeader(*bc.Hash, uint64) (*types.BlockHeader, error)  { return nil, nil }
661 func (s *mockStore1) GetStoreStatus() *BlockStoreState                             { return nil }
662 func (s *mockStore1) GetTransactionStatus(*bc.Hash) (*bc.TransactionStatus, error) { return nil, nil }
663 func (s *mockStore1) GetTransactionsUtxo(utxoView *state.UtxoViewpoint, tx []*bc.Tx) error {
664         // TODO:
665         for _, hash := range testTxs[2].SpentOutputIDs {
666                 utxoView.Entries[hash] = &storage.UtxoEntry{Type: storage.NormalUTXOType, Spent: false}
667         }
668         return nil
669 }
670 func (s *mockStore1) GetUtxo(*bc.Hash) (*storage.UtxoEntry, error)        { return nil, nil }
671 func (s *mockStore1) GetVoteResult(uint64) (*state.VoteResult, error)     { return nil, nil }
672 func (s *mockStore1) LoadBlockIndex(uint64) (*state.BlockIndex, error)    { return nil, nil }
673 func (s *mockStore1) SaveBlock(*types.Block, *bc.TransactionStatus) error { return nil }
674 func (s *mockStore1) SaveBlockHeader(*types.BlockHeader) error            { return nil }
675 func (s *mockStore1) SaveChainStatus(*state.BlockNode, *state.BlockNode, *state.UtxoViewpoint, []*state.VoteResult) error {
676         return nil
677 }
678
679 func TestProcessTransaction(t *testing.T) {
680         txPool := &TxPool{
681                 pool:            make(map[bc.Hash]*TxDesc),
682                 utxo:            make(map[bc.Hash]*types.Tx),
683                 orphans:         make(map[bc.Hash]*orphanTx),
684                 orphansByPrev:   make(map[bc.Hash]map[bc.Hash]*orphanTx),
685                 store:           &mockStore1{},
686                 eventDispatcher: event.NewDispatcher(),
687         }
688         cases := []struct {
689                 want  *TxPool
690                 addTx *TxDesc
691         }{
692                 //Dust tx
693                 {
694                         want: &TxPool{},
695                         addTx: &TxDesc{
696                                 Tx:         testTxs[3],
697                                 StatusFail: false,
698                         },
699                 },
700                 //Dust tx
701                 {
702                         want: &TxPool{},
703                         addTx: &TxDesc{
704                                 Tx:         testTxs[4],
705                                 StatusFail: false,
706                         },
707                 },
708                 //Dust tx
709                 {
710                         want: &TxPool{},
711                         addTx: &TxDesc{
712                                 Tx:         testTxs[5],
713                                 StatusFail: false,
714                         },
715                 },
716                 //Dust tx
717                 {
718                         want: &TxPool{},
719                         addTx: &TxDesc{
720                                 Tx:         testTxs[6],
721                                 StatusFail: false,
722                         },
723                 },
724                 //normal tx
725                 {
726                         want: &TxPool{
727                                 pool: map[bc.Hash]*TxDesc{
728                                         testTxs[2].ID: {
729                                                 Tx:         testTxs[2],
730                                                 StatusFail: false,
731                                                 Weight:     150,
732                                         },
733                                 },
734                                 utxo: map[bc.Hash]*types.Tx{
735                                         *testTxs[2].ResultIds[0]: testTxs[2],
736                                         *testTxs[2].ResultIds[1]: testTxs[2],
737                                 },
738                         },
739                         addTx: &TxDesc{
740                                 Tx:         testTxs[2],
741                                 StatusFail: false,
742                         },
743                 },
744         }
745
746         for i, c := range cases {
747                 txPool.ProcessTransaction(c.addTx.Tx, c.addTx.StatusFail, 0, 0)
748                 for _, txD := range txPool.pool {
749                         txD.Added = time.Time{}
750                 }
751                 for _, txD := range txPool.orphans {
752                         txD.Added = time.Time{}
753                         txD.expiration = time.Time{}
754                 }
755
756                 if !testutil.DeepEqual(txPool.pool, c.want.pool) {
757                         t.Errorf("case %d: test ProcessTransaction pool mismatch got %s want %s", i, spew.Sdump(txPool.pool), spew.Sdump(c.want.pool))
758                 }
759                 if !testutil.DeepEqual(txPool.utxo, c.want.utxo) {
760                         t.Errorf("case %d: test ProcessTransaction utxo mismatch got %s want %s", i, spew.Sdump(txPool.utxo), spew.Sdump(c.want.utxo))
761                 }
762                 if !testutil.DeepEqual(txPool.orphans, c.want.orphans) {
763                         t.Errorf("case %d: test ProcessTransaction orphans mismatch got %s want %s", i, spew.Sdump(txPool.orphans), spew.Sdump(c.want.orphans))
764                 }
765                 if !testutil.DeepEqual(txPool.orphansByPrev, c.want.orphansByPrev) {
766                         t.Errorf("case %d: test ProcessTransaction orphansByPrev mismatch got %s want %s", i, spew.Sdump(txPool.orphansByPrev), spew.Sdump(c.want.orphansByPrev))
767                 }
768         }
769 }