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"
15 var testTxs = []*types.Tx{
16 types.NewTx(types.TxData{
18 Inputs: []*types.TxInput{
19 types.NewSpendInput(nil, bc.NewHash([32]byte{0x01}), *consensus.BTMAssetID, 1, 1, []byte{0x51}),
21 Outputs: []*types.TxOutput{
22 types.NewTxOutput(*consensus.BTMAssetID, 1, []byte{0x6a}),
25 types.NewTx(types.TxData{
27 Inputs: []*types.TxInput{
28 types.NewSpendInput(nil, bc.NewHash([32]byte{0x01}), *consensus.BTMAssetID, 1, 1, []byte{0x51}),
30 Outputs: []*types.TxOutput{
31 types.NewTxOutput(*consensus.BTMAssetID, 1, []byte{0x6b}),
34 types.NewTx(types.TxData{
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}),
41 Outputs: []*types.TxOutput{
42 types.NewTxOutput(*consensus.BTMAssetID, 1, []byte{0x6b}),
43 types.NewTxOutput(bc.NewAssetID([32]byte{0xa1}), 4, []byte{0x61}),
46 types.NewTx(types.TxData{
48 Inputs: []*types.TxInput{
49 types.NewSpendInput(nil, testutil.MustDecodeHash("dbea684b5c5153ed7729669a53d6c59574f26015a3e1eb2a0e8a1c645425a764"), bc.NewAssetID([32]byte{0xa1}), 4, 1, []byte{0x61}),
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}),
56 types.NewTx(types.TxData{
58 Inputs: []*types.TxInput{
59 types.NewSpendInput(nil, testutil.MustDecodeHash("d84d0be0fd08e7341f2d127749bb0d0844d4560f53bd54861cee9981fd922cad"), bc.NewAssetID([32]byte{0xa1}), 3, 0, []byte{0x62}),
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}),
68 type mockStore struct{}
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 }
80 func TestAddOrphan(t *testing.T) {
85 requireParents []*bc.Hash
89 orphans: map[bc.Hash]*orphanTx{},
90 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
93 orphans: map[bc.Hash]*orphanTx{
94 testTxs[0].ID: &orphanTx{
100 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
101 testTxs[0].SpentOutputIDs[0]: map[bc.Hash]*orphanTx{
102 testTxs[0].ID: &orphanTx{
110 addOrphan: &TxDesc{Tx: testTxs[0]},
111 requireParents: []*bc.Hash{&testTxs[0].SpentOutputIDs[0]},
115 orphans: map[bc.Hash]*orphanTx{
116 testTxs[0].ID: &orphanTx{
122 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
123 testTxs[0].SpentOutputIDs[0]: map[bc.Hash]*orphanTx{
124 testTxs[0].ID: &orphanTx{
133 orphans: map[bc.Hash]*orphanTx{
134 testTxs[0].ID: &orphanTx{
139 testTxs[1].ID: &orphanTx{
145 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
146 testTxs[0].SpentOutputIDs[0]: map[bc.Hash]*orphanTx{
147 testTxs[0].ID: &orphanTx{
152 testTxs[1].ID: &orphanTx{
160 addOrphan: &TxDesc{Tx: testTxs[1]},
161 requireParents: []*bc.Hash{&testTxs[1].SpentOutputIDs[0]},
165 orphans: map[bc.Hash]*orphanTx{},
166 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
169 orphans: map[bc.Hash]*orphanTx{
170 testTxs[2].ID: &orphanTx{
176 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
177 testTxs[2].SpentOutputIDs[1]: map[bc.Hash]*orphanTx{
178 testTxs[2].ID: &orphanTx{
186 addOrphan: &TxDesc{Tx: testTxs[2]},
187 requireParents: []*bc.Hash{&testTxs[2].SpentOutputIDs[1]},
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{}
196 for _, orphans := range c.before.orphansByPrev {
197 for _, orphan := range orphans {
198 orphan.expiration = time.Time{}
201 if !testutil.DeepEqual(c.before, c.after) {
202 t.Errorf("case %d: got %v want %v", i, c.before, c.after)
207 func TestAddTransaction(t *testing.T) {
215 pool: map[bc.Hash]*TxDesc{},
216 utxo: map[bc.Hash]*types.Tx{},
217 msgCh: make(chan *TxPoolMsg, 1),
220 pool: map[bc.Hash]*TxDesc{
221 testTxs[2].ID: &TxDesc{
226 utxo: map[bc.Hash]*types.Tx{
227 *testTxs[2].ResultIds[0]: testTxs[2],
228 *testTxs[2].ResultIds[1]: testTxs[2],
238 pool: map[bc.Hash]*TxDesc{},
239 utxo: map[bc.Hash]*types.Tx{},
240 msgCh: make(chan *TxPoolMsg, 1),
243 pool: map[bc.Hash]*TxDesc{
244 testTxs[2].ID: &TxDesc{
249 utxo: map[bc.Hash]*types.Tx{
250 *testTxs[2].ResultIds[0]: testTxs[2],
260 for i, c := range cases {
261 c.before.addTransaction(c.addTx)
262 for _, txD := range c.before.pool {
263 txD.Added = time.Time{}
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)
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)
274 func TestExpireOrphan(t *testing.T) {
276 orphans: map[bc.Hash]*orphanTx{
277 testTxs[0].ID: &orphanTx{
278 expiration: time.Unix(1533489701, 0),
283 testTxs[1].ID: &orphanTx{
284 expiration: time.Unix(1633489701, 0),
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),
298 testTxs[1].ID: &orphanTx{
299 expiration: time.Unix(1633489701, 0),
309 orphans: map[bc.Hash]*orphanTx{
310 testTxs[1].ID: &orphanTx{
311 expiration: time.Unix(1633489701, 0),
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),
329 before.ExpireOrphan(time.Unix(1633479701, 0))
330 if !testutil.DeepEqual(before, want) {
331 t.Errorf("got %v want %v", before, want)
335 func TestProcessOrphans(t *testing.T) {
343 pool: map[bc.Hash]*TxDesc{},
344 utxo: map[bc.Hash]*types.Tx{},
345 orphans: map[bc.Hash]*orphanTx{
346 testTxs[3].ID: &orphanTx{
352 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
353 testTxs[3].SpentOutputIDs[0]: map[bc.Hash]*orphanTx{
354 testTxs[3].ID: &orphanTx{
361 msgCh: make(chan *TxPoolMsg, 10),
364 pool: map[bc.Hash]*TxDesc{
365 testTxs[3].ID: &TxDesc{
370 utxo: map[bc.Hash]*types.Tx{
371 *testTxs[3].ResultIds[0]: testTxs[3],
372 *testTxs[3].ResultIds[1]: testTxs[3],
374 orphans: map[bc.Hash]*orphanTx{},
375 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
377 processTx: &TxDesc{Tx: testTxs[2]},
381 pool: map[bc.Hash]*TxDesc{},
382 utxo: map[bc.Hash]*types.Tx{},
383 orphans: map[bc.Hash]*orphanTx{
384 testTxs[3].ID: &orphanTx{
389 testTxs[4].ID: &orphanTx{
395 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
396 testTxs[3].SpentOutputIDs[0]: map[bc.Hash]*orphanTx{
397 testTxs[3].ID: &orphanTx{
403 testTxs[4].SpentOutputIDs[0]: map[bc.Hash]*orphanTx{
404 testTxs[4].ID: &orphanTx{
411 msgCh: make(chan *TxPoolMsg, 10),
414 pool: map[bc.Hash]*TxDesc{
415 testTxs[3].ID: &TxDesc{
419 testTxs[4].ID: &TxDesc{
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],
430 orphans: map[bc.Hash]*orphanTx{},
431 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
433 processTx: &TxDesc{Tx: testTxs[2]},
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)
444 c.before.lastUpdated = 0
445 for _, txD := range c.before.pool {
446 txD.Added = time.Time{}
449 if !testutil.DeepEqual(c.before, c.after) {
450 t.Errorf("case %d: got %v want %v", i, c.before, c.after)
455 func TestRemoveOrphan(t *testing.T) {
459 removeHashes []*bc.Hash
463 orphans: map[bc.Hash]*orphanTx{
464 testTxs[0].ID: &orphanTx{
465 expiration: time.Unix(1533489701, 0),
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),
483 orphans: map[bc.Hash]*orphanTx{},
484 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
486 removeHashes: []*bc.Hash{
492 orphans: map[bc.Hash]*orphanTx{
493 testTxs[0].ID: &orphanTx{
494 expiration: time.Unix(1533489701, 0),
499 testTxs[1].ID: &orphanTx{
500 expiration: time.Unix(1533489701, 0),
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),
514 testTxs[1].ID: &orphanTx{
515 expiration: time.Unix(1533489701, 0),
524 orphans: map[bc.Hash]*orphanTx{
525 testTxs[0].ID: &orphanTx{
526 expiration: time.Unix(1533489701, 0),
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),
543 removeHashes: []*bc.Hash{
549 for i, c := range cases {
550 for _, hash := range c.removeHashes {
551 c.before.removeOrphan(hash)
553 if !testutil.DeepEqual(c.before, c.after) {
554 t.Errorf("case %d: got %v want %v", i, c.before, c.after)