7 "github.com/davecgh/go-spew/spew"
8 log "github.com/sirupsen/logrus"
10 "github.com/bytom/vapor/consensus"
11 "github.com/bytom/vapor/database/storage"
12 "github.com/bytom/vapor/event"
13 "github.com/bytom/vapor/protocol/bc"
14 "github.com/bytom/vapor/protocol/bc/types"
15 "github.com/bytom/vapor/protocol/state"
16 "github.com/bytom/vapor/testutil"
19 var testTxs = []*types.Tx{
21 types.NewTx(types.TxData{
23 Inputs: []*types.TxInput{
24 types.NewSpendInput(nil, bc.NewHash([32]byte{0x01}), *consensus.BTMAssetID, 1, 1, []byte{0x51}),
26 Outputs: []*types.TxOutput{
27 types.NewIntraChainOutput(*consensus.BTMAssetID, 1, []byte{0x6a}),
31 types.NewTx(types.TxData{
33 Inputs: []*types.TxInput{
34 types.NewSpendInput(nil, bc.NewHash([32]byte{0x01}), *consensus.BTMAssetID, 1, 1, []byte{0x51}),
36 Outputs: []*types.TxOutput{
37 types.NewIntraChainOutput(*consensus.BTMAssetID, 1, []byte{0x6b}),
41 types.NewTx(types.TxData{
44 Inputs: []*types.TxInput{
45 types.NewSpendInput(nil, bc.NewHash([32]byte{0x01}), *consensus.BTMAssetID, 1, 1, []byte{0x51}),
46 types.NewSpendInput(nil, bc.NewHash([32]byte{0x02}), bc.NewAssetID([32]byte{0xa1}), 4, 1, []byte{0x51}),
48 Outputs: []*types.TxOutput{
49 types.NewIntraChainOutput(*consensus.BTMAssetID, 1, []byte{0x6b}),
50 types.NewIntraChainOutput(bc.NewAssetID([32]byte{0xa1}), 4, []byte{0x61}),
54 types.NewTx(types.TxData{
57 Inputs: []*types.TxInput{
58 types.NewSpendInput(nil, testutil.MustDecodeHash("7d3f8e8474775f9fab2a7370529f0569a2199b22a5a83d235a036f50de3e8c84"), bc.NewAssetID([32]byte{0xa1}), 4, 1, []byte{0x61}),
60 Outputs: []*types.TxOutput{
61 types.NewIntraChainOutput(bc.NewAssetID([32]byte{0xa1}), 3, []byte{0x62}),
62 types.NewIntraChainOutput(bc.NewAssetID([32]byte{0xa1}), 1, []byte{0x63}),
66 types.NewTx(types.TxData{
68 Inputs: []*types.TxInput{
69 types.NewSpendInput(nil, testutil.MustDecodeHash("9a26cde504a5d7190dbed119280276f9816d9c2b7d20c768b312be57930fe840"), bc.NewAssetID([32]byte{0xa1}), 3, 0, []byte{0x62}),
71 Outputs: []*types.TxOutput{
72 types.NewIntraChainOutput(bc.NewAssetID([32]byte{0xa1}), 2, []byte{0x64}),
73 types.NewIntraChainOutput(bc.NewAssetID([32]byte{0xa1}), 1, []byte{0x65}),
77 types.NewTx(types.TxData{
79 Inputs: []*types.TxInput{
80 types.NewSpendInput(nil, bc.NewHash([32]byte{0x01}), *consensus.BTMAssetID, 1, 1, []byte{0x51}),
82 Outputs: []*types.TxOutput{
83 types.NewIntraChainOutput(*consensus.BTMAssetID, 0, []byte{0x51}),
87 types.NewTx(types.TxData{
89 Inputs: []*types.TxInput{
90 types.NewSpendInput(nil, bc.NewHash([32]byte{0x01}), *consensus.BTMAssetID, 3, 1, []byte{0x51}),
91 types.NewSpendInput(nil, testutil.MustDecodeHash("9a26cde504a5d7190dbed119280276f9816d9c2b7d20c768b312be57930fe840"), bc.NewAssetID([32]byte{0xa1}), 3, 0, []byte{0x62}),
93 Outputs: []*types.TxOutput{
94 types.NewIntraChainOutput(*consensus.BTMAssetID, 2, []byte{0x51}),
95 types.NewIntraChainOutput(bc.NewAssetID([32]byte{0xa1}), 0, []byte{0x65}),
99 types.NewTx(types.TxData{
102 Inputs: []*types.TxInput{
103 types.NewSpendInput(nil, bc.NewHash([32]byte{0x01}), *consensus.BTMAssetID, 1, 1, []byte{0x51}),
104 types.NewSpendInput(nil, bc.NewHash([32]byte{0x02}), bc.NewAssetID([32]byte{0xa1}), 4, 1, []byte{0x51}),
106 Outputs: []*types.TxOutput{
107 types.NewIntraChainOutput(*consensus.BTMAssetID, 1, []byte{0x6b}),
108 types.NewVoteOutput(bc.NewAssetID([32]byte{0xa1}), 4, []byte{0x61}, []byte("a8f410b9f7cd9ce352d215ed17c85559c351dc8d18ed89ad403ca28cfc423f612e04a1c9584f945c286c47ec1e5b8405c65ff56e31f44a2627aca4f77e03936f")),
113 type mockStore struct{}
115 func (s *mockStore) BlockExist(hash *bc.Hash) bool { return false }
116 func (s *mockStore) GetBlock(*bc.Hash) (*types.Block, error) { return nil, nil }
117 func (s *mockStore) GetBlockHeader(*bc.Hash) (*types.BlockHeader, error) { return nil, nil }
118 func (s *mockStore) GetStoreStatus() *BlockStoreState { return nil }
119 func (s *mockStore) GetTransactionStatus(*bc.Hash) (*bc.TransactionStatus, error) { return nil, nil }
120 func (s *mockStore) GetTransactionsUtxo(*state.UtxoViewpoint, []*bc.Tx) error { return nil }
121 func (s *mockStore) GetUtxo(*bc.Hash) (*storage.UtxoEntry, error) { return nil, nil }
122 func (s *mockStore) GetConsensusResult(uint64) (*state.ConsensusResult, error) { return nil, nil }
123 func (s *mockStore) GetMainChainHash(uint64) (*bc.Hash, error) { return nil, nil }
124 func (s *mockStore) GetBlockHashesByHeight(uint64) ([]*bc.Hash, error) { return nil, nil }
125 func (s *mockStore) SaveBlock(*types.Block, *bc.TransactionStatus) error { return nil }
126 func (s *mockStore) DeleteConsensusResult(seq uint64) error { return nil }
127 func (s *mockStore) DeleteBlock(*types.Block) error { return nil }
128 func (s *mockStore) SaveBlockHeader(*types.BlockHeader) error { return nil }
129 func (s *mockStore) SaveChainStatus(*types.BlockHeader, *types.BlockHeader, []*types.BlockHeader, *state.UtxoViewpoint, []*state.ConsensusResult) error {
133 func TestAddOrphan(t *testing.T) {
138 requireParents []*bc.Hash
142 orphans: map[bc.Hash]*orphanTx{},
143 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
146 orphans: map[bc.Hash]*orphanTx{
153 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
154 testTxs[0].SpentOutputIDs[0]: {
163 addOrphan: &TxDesc{Tx: testTxs[0]},
164 requireParents: []*bc.Hash{&testTxs[0].SpentOutputIDs[0]},
168 orphans: map[bc.Hash]*orphanTx{
175 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
176 testTxs[0].SpentOutputIDs[0]: {
186 orphans: map[bc.Hash]*orphanTx{
198 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
199 testTxs[0].SpentOutputIDs[0]: {
213 addOrphan: &TxDesc{Tx: testTxs[1]},
214 requireParents: []*bc.Hash{&testTxs[1].SpentOutputIDs[0]},
218 orphans: map[bc.Hash]*orphanTx{},
219 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
222 orphans: map[bc.Hash]*orphanTx{
229 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
230 testTxs[2].SpentOutputIDs[1]: {
239 addOrphan: &TxDesc{Tx: testTxs[2]},
240 requireParents: []*bc.Hash{&testTxs[2].SpentOutputIDs[1]},
244 for i, c := range cases {
245 c.before.addOrphan(c.addOrphan, c.requireParents)
246 for _, orphan := range c.before.orphans {
247 orphan.expiration = time.Time{}
249 for _, orphans := range c.before.orphansByPrev {
250 for _, orphan := range orphans {
251 orphan.expiration = time.Time{}
254 if !testutil.DeepEqual(c.before, c.after) {
255 t.Errorf("case %d: got %v want %v", i, c.before, c.after)
260 func TestAddTransaction(t *testing.T) {
261 dispatcher := event.NewDispatcher()
269 pool: map[bc.Hash]*TxDesc{},
270 utxo: map[bc.Hash]*types.Tx{},
271 eventDispatcher: dispatcher,
274 pool: map[bc.Hash]*TxDesc{
280 utxo: map[bc.Hash]*types.Tx{
281 *testTxs[2].ResultIds[0]: testTxs[2],
282 *testTxs[2].ResultIds[1]: testTxs[2],
292 pool: map[bc.Hash]*TxDesc{},
293 utxo: map[bc.Hash]*types.Tx{},
294 eventDispatcher: dispatcher,
297 pool: map[bc.Hash]*TxDesc{
303 utxo: map[bc.Hash]*types.Tx{
304 *testTxs[2].ResultIds[0]: testTxs[2],
314 pool: map[bc.Hash]*TxDesc{},
315 utxo: map[bc.Hash]*types.Tx{},
316 eventDispatcher: dispatcher,
319 pool: map[bc.Hash]*TxDesc{
325 utxo: map[bc.Hash]*types.Tx{
326 *testTxs[7].ResultIds[0]: testTxs[7],
327 *testTxs[7].ResultIds[1]: testTxs[7],
337 pool: map[bc.Hash]*TxDesc{},
338 utxo: map[bc.Hash]*types.Tx{},
339 eventDispatcher: dispatcher,
342 pool: map[bc.Hash]*TxDesc{
348 utxo: map[bc.Hash]*types.Tx{
349 *testTxs[7].ResultIds[0]: testTxs[7],
359 for i, c := range cases {
360 c.before.addTransaction(c.addTx)
361 for _, txD := range c.before.pool {
362 txD.Added = time.Time{}
364 if !testutil.DeepEqual(c.before.pool, c.after.pool) {
365 t.Errorf("case %d: got %v want %v", i, c.before.pool, c.after.pool)
367 if !testutil.DeepEqual(c.before.utxo, c.after.utxo) {
368 t.Errorf("case %d: got %v want %v", i, c.before.utxo, c.after.utxo)
373 func TestExpireOrphan(t *testing.T) {
375 orphans: map[bc.Hash]*orphanTx{
377 expiration: time.Unix(1533489701, 0),
383 expiration: time.Unix(1633489701, 0),
389 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
390 testTxs[0].SpentOutputIDs[0]: {
392 expiration: time.Unix(1533489701, 0),
398 expiration: time.Unix(1633489701, 0),
408 orphans: map[bc.Hash]*orphanTx{
410 expiration: time.Unix(1633489701, 0),
416 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
417 testTxs[0].SpentOutputIDs[0]: {
419 expiration: time.Unix(1633489701, 0),
428 before.expireOrphan(time.Unix(1633479701, 0))
429 if !testutil.DeepEqual(before, want) {
430 t.Errorf("got %v want %v", before, want)
434 func TestProcessOrphans(t *testing.T) {
435 dispatcher := event.NewDispatcher()
443 pool: map[bc.Hash]*TxDesc{},
444 utxo: map[bc.Hash]*types.Tx{},
445 eventDispatcher: dispatcher,
446 orphans: map[bc.Hash]*orphanTx{
453 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
454 testTxs[3].SpentOutputIDs[0]: {
464 pool: map[bc.Hash]*TxDesc{
470 utxo: map[bc.Hash]*types.Tx{
471 *testTxs[3].ResultIds[0]: testTxs[3],
472 *testTxs[3].ResultIds[1]: testTxs[3],
474 eventDispatcher: dispatcher,
475 orphans: map[bc.Hash]*orphanTx{},
476 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
478 processTx: &TxDesc{Tx: testTxs[2]},
482 pool: map[bc.Hash]*TxDesc{},
483 utxo: map[bc.Hash]*types.Tx{},
484 eventDispatcher: dispatcher,
485 orphans: map[bc.Hash]*orphanTx{
497 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
498 testTxs[3].SpentOutputIDs[0]: {
505 testTxs[4].SpentOutputIDs[0]: {
515 pool: map[bc.Hash]*TxDesc{
525 utxo: map[bc.Hash]*types.Tx{
526 *testTxs[3].ResultIds[0]: testTxs[3],
527 *testTxs[3].ResultIds[1]: testTxs[3],
528 *testTxs[4].ResultIds[0]: testTxs[4],
529 *testTxs[4].ResultIds[1]: testTxs[4],
531 eventDispatcher: dispatcher,
532 orphans: map[bc.Hash]*orphanTx{},
533 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
535 processTx: &TxDesc{Tx: testTxs[2]},
539 for i, c := range cases {
540 c.before.store = &mockStore{}
541 c.before.addTransaction(c.processTx)
542 c.before.processOrphans(c.processTx)
543 c.before.RemoveTransaction(&c.processTx.Tx.ID)
545 c.before.lastUpdated = 0
546 for _, txD := range c.before.pool {
547 txD.Added = time.Time{}
550 if !testutil.DeepEqual(c.before, c.after) {
551 t.Errorf("case %d: got %v want %v", i, c.before, c.after)
556 func TestRemoveOrphan(t *testing.T) {
560 removeHashes []*bc.Hash
564 orphans: map[bc.Hash]*orphanTx{
566 expiration: time.Unix(1533489701, 0),
572 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
573 testTxs[0].SpentOutputIDs[0]: {
575 expiration: time.Unix(1533489701, 0),
584 orphans: map[bc.Hash]*orphanTx{},
585 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
587 removeHashes: []*bc.Hash{
593 orphans: map[bc.Hash]*orphanTx{
595 expiration: time.Unix(1533489701, 0),
601 expiration: time.Unix(1533489701, 0),
607 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
608 testTxs[0].SpentOutputIDs[0]: {
610 expiration: time.Unix(1533489701, 0),
616 expiration: time.Unix(1533489701, 0),
625 orphans: map[bc.Hash]*orphanTx{
627 expiration: time.Unix(1533489701, 0),
633 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
634 testTxs[0].SpentOutputIDs[0]: {
636 expiration: time.Unix(1533489701, 0),
644 removeHashes: []*bc.Hash{
650 for i, c := range cases {
651 for _, hash := range c.removeHashes {
652 c.before.removeOrphan(hash)
654 if !testutil.DeepEqual(c.before, c.after) {
655 t.Errorf("case %d: got %v want %v", i, c.before, c.after)
660 type mockStore1 struct{}
662 func (s *mockStore1) BlockExist(hash *bc.Hash) bool { return false }
663 func (s *mockStore1) GetBlock(*bc.Hash) (*types.Block, error) { return nil, nil }
664 func (s *mockStore1) GetBlockHeader(*bc.Hash) (*types.BlockHeader, error) { return nil, nil }
665 func (s *mockStore1) GetStoreStatus() *BlockStoreState { return nil }
666 func (s *mockStore1) GetTransactionStatus(*bc.Hash) (*bc.TransactionStatus, error) { return nil, nil }
667 func (s *mockStore1) GetTransactionsUtxo(utxoView *state.UtxoViewpoint, tx []*bc.Tx) error {
669 for _, hash := range testTxs[2].SpentOutputIDs {
670 utxoView.Entries[hash] = &storage.UtxoEntry{Type: storage.NormalUTXOType, Spent: false}
674 func (s *mockStore1) GetUtxo(*bc.Hash) (*storage.UtxoEntry, error) { return nil, nil }
675 func (s *mockStore1) GetConsensusResult(uint64) (*state.ConsensusResult, error) { return nil, nil }
676 func (s *mockStore1) GetMainChainHash(uint64) (*bc.Hash, error) { return nil, nil }
677 func (s *mockStore1) GetBlockHashesByHeight(uint64) ([]*bc.Hash, error) { return nil, nil }
678 func (s *mockStore1) DeleteBlock(*types.Block) error { return nil }
679 func (s *mockStore1) SaveBlock(*types.Block, *bc.TransactionStatus) error { return nil }
680 func (s *mockStore1) DeleteConsensusResult(seq uint64) error { return nil }
681 func (s *mockStore1) SaveBlockHeader(*types.BlockHeader) error { return nil }
682 func (s *mockStore1) SaveChainStatus(*types.BlockHeader, *types.BlockHeader, []*types.BlockHeader, *state.UtxoViewpoint, []*state.ConsensusResult) error {
686 func TestProcessTransaction(t *testing.T) {
688 pool: make(map[bc.Hash]*TxDesc),
689 utxo: make(map[bc.Hash]*types.Tx),
690 orphans: make(map[bc.Hash]*orphanTx),
691 orphansByPrev: make(map[bc.Hash]map[bc.Hash]*orphanTx),
692 store: &mockStore1{},
693 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))
763 log.SetLevel(log.ErrorLevel)