7 "github.com/davecgh/go-spew/spew"
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"
18 var testTxs = []*types.Tx{
20 types.NewTx(types.TxData{
22 Inputs: []*types.TxInput{
23 types.NewSpendInput(nil, bc.NewHash([32]byte{0x01}), *consensus.BTMAssetID, 1, 1, []byte{0x51}),
25 Outputs: []*types.TxOutput{
26 types.NewIntraChainOutput(*consensus.BTMAssetID, 1, []byte{0x6a}),
30 types.NewTx(types.TxData{
32 Inputs: []*types.TxInput{
33 types.NewSpendInput(nil, bc.NewHash([32]byte{0x01}), *consensus.BTMAssetID, 1, 1, []byte{0x51}),
35 Outputs: []*types.TxOutput{
36 types.NewIntraChainOutput(*consensus.BTMAssetID, 1, []byte{0x6b}),
40 types.NewTx(types.TxData{
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}),
47 Outputs: []*types.TxOutput{
48 types.NewIntraChainOutput(*consensus.BTMAssetID, 1, []byte{0x6b}),
49 types.NewIntraChainOutput(bc.NewAssetID([32]byte{0xa1}), 4, []byte{0x61}),
53 types.NewTx(types.TxData{
56 Inputs: []*types.TxInput{
57 types.NewSpendInput(nil, testutil.MustDecodeHash("7d3f8e8474775f9fab2a7370529f0569a2199b22a5a83d235a036f50de3e8c84"), bc.NewAssetID([32]byte{0xa1}), 4, 1, []byte{0x61}),
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}),
65 types.NewTx(types.TxData{
67 Inputs: []*types.TxInput{
68 types.NewSpendInput(nil, testutil.MustDecodeHash("9a26cde504a5d7190dbed119280276f9816d9c2b7d20c768b312be57930fe840"), bc.NewAssetID([32]byte{0xa1}), 3, 0, []byte{0x62}),
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}),
76 types.NewTx(types.TxData{
78 Inputs: []*types.TxInput{
79 types.NewSpendInput(nil, bc.NewHash([32]byte{0x01}), *consensus.BTMAssetID, 1, 1, []byte{0x51}),
81 Outputs: []*types.TxOutput{
82 types.NewIntraChainOutput(*consensus.BTMAssetID, 0, []byte{0x51}),
86 types.NewTx(types.TxData{
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}),
92 Outputs: []*types.TxOutput{
93 types.NewIntraChainOutput(*consensus.BTMAssetID, 2, []byte{0x51}),
94 types.NewIntraChainOutput(bc.NewAssetID([32]byte{0xa1}), 0, []byte{0x65}),
98 types.NewTx(types.TxData{
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}),
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")),
112 type mockStore struct{}
114 func (s *mockStore) BlockExist(hash *bc.Hash) bool { return false }
115 func (s *mockStore) GetBlock(*bc.Hash) (*types.Block, error) { return nil, nil }
116 func (s *mockStore) GetStoreStatus() *BlockStoreState { return nil }
117 func (s *mockStore) GetTransactionStatus(*bc.Hash) (*bc.TransactionStatus, error) { return nil, nil }
118 func (s *mockStore) GetTransactionsUtxo(*state.UtxoViewpoint, []*bc.Tx) error { return nil }
119 func (s *mockStore) GetUtxo(*bc.Hash) (*storage.UtxoEntry, error) { return nil, nil }
120 func (s *mockStore) GetVoteResult(uint64) (*state.VoteResult, error) { return nil, nil }
121 func (s *mockStore) LoadBlockIndex(uint64) (*state.BlockIndex, error) { return nil, nil }
122 func (s *mockStore) SaveBlock(*types.Block, *bc.TransactionStatus) error { return nil }
123 func (s *mockStore) SaveChainStatus(*state.BlockNode, *state.BlockNode, *state.UtxoViewpoint, map[uint64]*state.VoteResult) error { return nil }
125 func TestAddOrphan(t *testing.T) {
130 requireParents []*bc.Hash
134 orphans: map[bc.Hash]*orphanTx{},
135 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
138 orphans: map[bc.Hash]*orphanTx{
145 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
146 testTxs[0].SpentOutputIDs[0]: {
155 addOrphan: &TxDesc{Tx: testTxs[0]},
156 requireParents: []*bc.Hash{&testTxs[0].SpentOutputIDs[0]},
160 orphans: map[bc.Hash]*orphanTx{
167 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
168 testTxs[0].SpentOutputIDs[0]: {
178 orphans: map[bc.Hash]*orphanTx{
190 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
191 testTxs[0].SpentOutputIDs[0]: {
205 addOrphan: &TxDesc{Tx: testTxs[1]},
206 requireParents: []*bc.Hash{&testTxs[1].SpentOutputIDs[0]},
210 orphans: map[bc.Hash]*orphanTx{},
211 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
214 orphans: map[bc.Hash]*orphanTx{
221 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
222 testTxs[2].SpentOutputIDs[1]: {
231 addOrphan: &TxDesc{Tx: testTxs[2]},
232 requireParents: []*bc.Hash{&testTxs[2].SpentOutputIDs[1]},
236 for i, c := range cases {
237 c.before.addOrphan(c.addOrphan, c.requireParents)
238 for _, orphan := range c.before.orphans {
239 orphan.expiration = time.Time{}
241 for _, orphans := range c.before.orphansByPrev {
242 for _, orphan := range orphans {
243 orphan.expiration = time.Time{}
246 if !testutil.DeepEqual(c.before, c.after) {
247 t.Errorf("case %d: got %v want %v", i, c.before, c.after)
252 func TestAddTransaction(t *testing.T) {
253 dispatcher := event.NewDispatcher()
261 pool: map[bc.Hash]*TxDesc{},
262 utxo: map[bc.Hash]*types.Tx{},
263 eventDispatcher: dispatcher,
266 pool: map[bc.Hash]*TxDesc{
272 utxo: map[bc.Hash]*types.Tx{
273 *testTxs[2].ResultIds[0]: testTxs[2],
274 *testTxs[2].ResultIds[1]: testTxs[2],
284 pool: map[bc.Hash]*TxDesc{},
285 utxo: map[bc.Hash]*types.Tx{},
286 eventDispatcher: dispatcher,
289 pool: map[bc.Hash]*TxDesc{
295 utxo: map[bc.Hash]*types.Tx{
296 *testTxs[2].ResultIds[0]: testTxs[2],
306 pool: map[bc.Hash]*TxDesc{},
307 utxo: map[bc.Hash]*types.Tx{},
308 eventDispatcher: dispatcher,
311 pool: map[bc.Hash]*TxDesc{
317 utxo: map[bc.Hash]*types.Tx{
318 *testTxs[7].ResultIds[0]: testTxs[7],
319 *testTxs[7].ResultIds[1]: testTxs[7],
329 pool: map[bc.Hash]*TxDesc{},
330 utxo: map[bc.Hash]*types.Tx{},
331 eventDispatcher: dispatcher,
334 pool: map[bc.Hash]*TxDesc{
340 utxo: map[bc.Hash]*types.Tx{
341 *testTxs[7].ResultIds[0]: testTxs[7],
351 for i, c := range cases {
352 c.before.addTransaction(c.addTx)
353 for _, txD := range c.before.pool {
354 txD.Added = time.Time{}
356 if !testutil.DeepEqual(c.before.pool, c.after.pool) {
357 t.Errorf("case %d: got %v want %v", i, c.before.pool, c.after.pool)
359 if !testutil.DeepEqual(c.before.utxo, c.after.utxo) {
360 t.Errorf("case %d: got %v want %v", i, c.before.utxo, c.after.utxo)
365 func TestExpireOrphan(t *testing.T) {
367 orphans: map[bc.Hash]*orphanTx{
369 expiration: time.Unix(1533489701, 0),
375 expiration: time.Unix(1633489701, 0),
381 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
382 testTxs[0].SpentOutputIDs[0]: {
384 expiration: time.Unix(1533489701, 0),
390 expiration: time.Unix(1633489701, 0),
400 orphans: map[bc.Hash]*orphanTx{
402 expiration: time.Unix(1633489701, 0),
408 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
409 testTxs[0].SpentOutputIDs[0]: {
411 expiration: time.Unix(1633489701, 0),
420 before.ExpireOrphan(time.Unix(1633479701, 0))
421 if !testutil.DeepEqual(before, want) {
422 t.Errorf("got %v want %v", before, want)
426 func TestProcessOrphans(t *testing.T) {
427 dispatcher := event.NewDispatcher()
435 pool: map[bc.Hash]*TxDesc{},
436 utxo: map[bc.Hash]*types.Tx{},
437 eventDispatcher: dispatcher,
438 orphans: map[bc.Hash]*orphanTx{
445 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
446 testTxs[3].SpentOutputIDs[0]: {
456 pool: map[bc.Hash]*TxDesc{
462 utxo: map[bc.Hash]*types.Tx{
463 *testTxs[3].ResultIds[0]: testTxs[3],
464 *testTxs[3].ResultIds[1]: testTxs[3],
466 eventDispatcher: dispatcher,
467 orphans: map[bc.Hash]*orphanTx{},
468 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
470 processTx: &TxDesc{Tx: testTxs[2]},
474 pool: map[bc.Hash]*TxDesc{},
475 utxo: map[bc.Hash]*types.Tx{},
476 eventDispatcher: dispatcher,
477 orphans: map[bc.Hash]*orphanTx{
489 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
490 testTxs[3].SpentOutputIDs[0]: {
497 testTxs[4].SpentOutputIDs[0]: {
507 pool: map[bc.Hash]*TxDesc{
517 utxo: map[bc.Hash]*types.Tx{
518 *testTxs[3].ResultIds[0]: testTxs[3],
519 *testTxs[3].ResultIds[1]: testTxs[3],
520 *testTxs[4].ResultIds[0]: testTxs[4],
521 *testTxs[4].ResultIds[1]: testTxs[4],
523 eventDispatcher: dispatcher,
524 orphans: map[bc.Hash]*orphanTx{},
525 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
527 processTx: &TxDesc{Tx: testTxs[2]},
531 for i, c := range cases {
532 c.before.store = &mockStore{}
533 c.before.addTransaction(c.processTx)
534 c.before.processOrphans(c.processTx)
535 c.before.RemoveTransaction(&c.processTx.Tx.ID)
537 c.before.lastUpdated = 0
538 for _, txD := range c.before.pool {
539 txD.Added = time.Time{}
542 if !testutil.DeepEqual(c.before, c.after) {
543 t.Errorf("case %d: got %v want %v", i, c.before, c.after)
548 func TestRemoveOrphan(t *testing.T) {
552 removeHashes []*bc.Hash
556 orphans: map[bc.Hash]*orphanTx{
558 expiration: time.Unix(1533489701, 0),
564 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
565 testTxs[0].SpentOutputIDs[0]: {
567 expiration: time.Unix(1533489701, 0),
576 orphans: map[bc.Hash]*orphanTx{},
577 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
579 removeHashes: []*bc.Hash{
585 orphans: map[bc.Hash]*orphanTx{
587 expiration: time.Unix(1533489701, 0),
593 expiration: time.Unix(1533489701, 0),
599 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
600 testTxs[0].SpentOutputIDs[0]: {
602 expiration: time.Unix(1533489701, 0),
608 expiration: time.Unix(1533489701, 0),
617 orphans: map[bc.Hash]*orphanTx{
619 expiration: time.Unix(1533489701, 0),
625 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
626 testTxs[0].SpentOutputIDs[0]: {
628 expiration: time.Unix(1533489701, 0),
636 removeHashes: []*bc.Hash{
642 for i, c := range cases {
643 for _, hash := range c.removeHashes {
644 c.before.removeOrphan(hash)
646 if !testutil.DeepEqual(c.before, c.after) {
647 t.Errorf("case %d: got %v want %v", i, c.before, c.after)
652 type mockStore1 struct{}
654 func (s *mockStore1) BlockExist(hash *bc.Hash) bool { return false }
655 func (s *mockStore1) GetBlock(*bc.Hash) (*types.Block, error) { return nil, nil }
656 func (s *mockStore1) GetStoreStatus() *BlockStoreState { return nil }
657 func (s *mockStore1) GetTransactionStatus(*bc.Hash) (*bc.TransactionStatus, error) { return nil, nil }
658 func (s *mockStore1) GetTransactionsUtxo(utxoView *state.UtxoViewpoint, tx []*bc.Tx) error {
659 for _, hash := range testTxs[2].SpentOutputIDs {
660 utxoView.Entries[hash] = &storage.UtxoEntry{IsCoinBase: false, Spent: false}
664 func (s *mockStore1) GetUtxo(*bc.Hash) (*storage.UtxoEntry, error) { return nil, nil }
665 func (s *mockStore1) GetVoteResult(uint64) (*state.VoteResult, error) { return nil, nil }
666 func (s *mockStore1) LoadBlockIndex(uint64) (*state.BlockIndex, error) { return nil, nil }
667 func (s *mockStore1) SaveBlock(*types.Block, *bc.TransactionStatus) error { return nil }
668 func (s *mockStore1) SaveChainStatus(*state.BlockNode, *state.BlockNode, *state.UtxoViewpoint, map[uint64]*state.VoteResult) error { return nil }
670 func TestProcessTransaction(t *testing.T) {
672 pool: make(map[bc.Hash]*TxDesc),
673 utxo: make(map[bc.Hash]*types.Tx),
674 orphans: make(map[bc.Hash]*orphanTx),
675 orphansByPrev: make(map[bc.Hash]map[bc.Hash]*orphanTx),
676 store: &mockStore1{},
677 eventDispatcher: event.NewDispatcher(),
718 pool: map[bc.Hash]*TxDesc{
725 utxo: map[bc.Hash]*types.Tx{
726 *testTxs[2].ResultIds[0]: testTxs[2],
727 *testTxs[2].ResultIds[1]: testTxs[2],
737 for i, c := range cases {
738 txPool.ProcessTransaction(c.addTx.Tx, c.addTx.StatusFail, 0, 0)
739 for _, txD := range txPool.pool {
740 txD.Added = time.Time{}
742 for _, txD := range txPool.orphans {
743 txD.Added = time.Time{}
744 txD.expiration = time.Time{}
747 if !testutil.DeepEqual(txPool.pool, c.want.pool) {
748 t.Errorf("case %d: test ProcessTransaction pool mismatch got %s want %s", i, spew.Sdump(txPool.pool), spew.Sdump(c.want.pool))
750 if !testutil.DeepEqual(txPool.utxo, c.want.utxo) {
751 t.Errorf("case %d: test ProcessTransaction utxo mismatch got %s want %s", i, spew.Sdump(txPool.utxo), spew.Sdump(c.want.utxo))
753 if !testutil.DeepEqual(txPool.orphans, c.want.orphans) {
754 t.Errorf("case %d: test ProcessTransaction orphans mismatch got %s want %s", i, spew.Sdump(txPool.orphans), spew.Sdump(c.want.orphans))
756 if !testutil.DeepEqual(txPool.orphansByPrev, c.want.orphansByPrev) {
757 t.Errorf("case %d: test ProcessTransaction orphansByPrev mismatch got %s want %s", i, spew.Sdump(txPool.orphansByPrev), spew.Sdump(c.want.orphansByPrev))