7 "github.com/davecgh/go-spew/spew"
9 "github.com/bytom/vapor/consensus"
10 "github.com/bytom/vapor/database/storage"
11 "github.com/bytom/vapor/event"
12 "github.com/bytom/vapor/protocol/bc"
13 "github.com/bytom/vapor/protocol/bc/types"
14 "github.com/bytom/vapor/protocol/state"
15 "github.com/bytom/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) GetBlockHeader(*bc.Hash) (*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) GetConsensusResult(uint64) (*state.ConsensusResult, error) { return nil, nil }
122 func (s *mockStore) GetMainChainHash(uint64) (*bc.Hash, error) { return nil, nil }
123 func (s *mockStore) GetBlockHashesByHeight(uint64) ([]*bc.Hash, error) { return nil, nil }
124 func (s *mockStore) SaveBlock(*types.Block, *bc.TransactionStatus) error { return nil }
125 func (s *mockStore) DeleteConsensusResult(seq uint64) error { return nil }
126 func (s *mockStore) DeleteBlock(*types.Block) error { return nil }
127 func (s *mockStore) SaveBlockHeader(*types.BlockHeader) error { return nil }
128 func (s *mockStore) SaveChainStatus(*types.BlockHeader, *types.BlockHeader, []*types.BlockHeader, *state.UtxoViewpoint, []*state.ConsensusResult) error {
132 func TestAddOrphan(t *testing.T) {
137 requireParents []*bc.Hash
141 orphans: map[bc.Hash]*orphanTx{},
142 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
145 orphans: map[bc.Hash]*orphanTx{
152 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
153 testTxs[0].SpentOutputIDs[0]: {
162 addOrphan: &TxDesc{Tx: testTxs[0]},
163 requireParents: []*bc.Hash{&testTxs[0].SpentOutputIDs[0]},
167 orphans: map[bc.Hash]*orphanTx{
174 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
175 testTxs[0].SpentOutputIDs[0]: {
185 orphans: map[bc.Hash]*orphanTx{
197 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
198 testTxs[0].SpentOutputIDs[0]: {
212 addOrphan: &TxDesc{Tx: testTxs[1]},
213 requireParents: []*bc.Hash{&testTxs[1].SpentOutputIDs[0]},
217 orphans: map[bc.Hash]*orphanTx{},
218 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
221 orphans: map[bc.Hash]*orphanTx{
228 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
229 testTxs[2].SpentOutputIDs[1]: {
238 addOrphan: &TxDesc{Tx: testTxs[2]},
239 requireParents: []*bc.Hash{&testTxs[2].SpentOutputIDs[1]},
243 for i, c := range cases {
244 c.before.addOrphan(c.addOrphan, c.requireParents)
245 for _, orphan := range c.before.orphans {
246 orphan.expiration = time.Time{}
248 for _, orphans := range c.before.orphansByPrev {
249 for _, orphan := range orphans {
250 orphan.expiration = time.Time{}
253 if !testutil.DeepEqual(c.before, c.after) {
254 t.Errorf("case %d: got %v want %v", i, c.before, c.after)
259 func TestAddTransaction(t *testing.T) {
260 dispatcher := event.NewDispatcher()
268 pool: map[bc.Hash]*TxDesc{},
269 utxo: map[bc.Hash]*types.Tx{},
270 eventDispatcher: dispatcher,
273 pool: map[bc.Hash]*TxDesc{
279 utxo: map[bc.Hash]*types.Tx{
280 *testTxs[2].ResultIds[0]: testTxs[2],
281 *testTxs[2].ResultIds[1]: testTxs[2],
291 pool: map[bc.Hash]*TxDesc{},
292 utxo: map[bc.Hash]*types.Tx{},
293 eventDispatcher: dispatcher,
296 pool: map[bc.Hash]*TxDesc{
302 utxo: map[bc.Hash]*types.Tx{
303 *testTxs[2].ResultIds[0]: testTxs[2],
313 pool: map[bc.Hash]*TxDesc{},
314 utxo: map[bc.Hash]*types.Tx{},
315 eventDispatcher: dispatcher,
318 pool: map[bc.Hash]*TxDesc{
324 utxo: map[bc.Hash]*types.Tx{
325 *testTxs[7].ResultIds[0]: testTxs[7],
326 *testTxs[7].ResultIds[1]: testTxs[7],
336 pool: map[bc.Hash]*TxDesc{},
337 utxo: map[bc.Hash]*types.Tx{},
338 eventDispatcher: dispatcher,
341 pool: map[bc.Hash]*TxDesc{
347 utxo: map[bc.Hash]*types.Tx{
348 *testTxs[7].ResultIds[0]: testTxs[7],
358 for i, c := range cases {
359 c.before.addTransaction(c.addTx)
360 for _, txD := range c.before.pool {
361 txD.Added = time.Time{}
363 if !testutil.DeepEqual(c.before.pool, c.after.pool) {
364 t.Errorf("case %d: got %v want %v", i, c.before.pool, c.after.pool)
366 if !testutil.DeepEqual(c.before.utxo, c.after.utxo) {
367 t.Errorf("case %d: got %v want %v", i, c.before.utxo, c.after.utxo)
372 func TestExpireOrphan(t *testing.T) {
374 orphans: map[bc.Hash]*orphanTx{
376 expiration: time.Unix(1533489701, 0),
382 expiration: time.Unix(1633489701, 0),
388 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
389 testTxs[0].SpentOutputIDs[0]: {
391 expiration: time.Unix(1533489701, 0),
397 expiration: time.Unix(1633489701, 0),
407 orphans: map[bc.Hash]*orphanTx{
409 expiration: time.Unix(1633489701, 0),
415 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
416 testTxs[0].SpentOutputIDs[0]: {
418 expiration: time.Unix(1633489701, 0),
427 before.expireOrphan(time.Unix(1633479701, 0))
428 if !testutil.DeepEqual(before, want) {
429 t.Errorf("got %v want %v", before, want)
433 func TestProcessOrphans(t *testing.T) {
434 dispatcher := event.NewDispatcher()
442 pool: map[bc.Hash]*TxDesc{},
443 utxo: map[bc.Hash]*types.Tx{},
444 eventDispatcher: dispatcher,
445 orphans: map[bc.Hash]*orphanTx{
452 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
453 testTxs[3].SpentOutputIDs[0]: {
463 pool: map[bc.Hash]*TxDesc{
469 utxo: map[bc.Hash]*types.Tx{
470 *testTxs[3].ResultIds[0]: testTxs[3],
471 *testTxs[3].ResultIds[1]: testTxs[3],
473 eventDispatcher: dispatcher,
474 orphans: map[bc.Hash]*orphanTx{},
475 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
477 processTx: &TxDesc{Tx: testTxs[2]},
481 pool: map[bc.Hash]*TxDesc{},
482 utxo: map[bc.Hash]*types.Tx{},
483 eventDispatcher: dispatcher,
484 orphans: map[bc.Hash]*orphanTx{
496 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
497 testTxs[3].SpentOutputIDs[0]: {
504 testTxs[4].SpentOutputIDs[0]: {
514 pool: map[bc.Hash]*TxDesc{
524 utxo: map[bc.Hash]*types.Tx{
525 *testTxs[3].ResultIds[0]: testTxs[3],
526 *testTxs[3].ResultIds[1]: testTxs[3],
527 *testTxs[4].ResultIds[0]: testTxs[4],
528 *testTxs[4].ResultIds[1]: testTxs[4],
530 eventDispatcher: dispatcher,
531 orphans: map[bc.Hash]*orphanTx{},
532 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
534 processTx: &TxDesc{Tx: testTxs[2]},
538 for i, c := range cases {
539 c.before.store = &mockStore{}
540 c.before.addTransaction(c.processTx)
541 c.before.processOrphans(c.processTx)
542 c.before.RemoveTransaction(&c.processTx.Tx.ID)
544 c.before.lastUpdated = 0
545 for _, txD := range c.before.pool {
546 txD.Added = time.Time{}
549 if !testutil.DeepEqual(c.before, c.after) {
550 t.Errorf("case %d: got %v want %v", i, c.before, c.after)
555 func TestRemoveOrphan(t *testing.T) {
559 removeHashes []*bc.Hash
563 orphans: map[bc.Hash]*orphanTx{
565 expiration: time.Unix(1533489701, 0),
571 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
572 testTxs[0].SpentOutputIDs[0]: {
574 expiration: time.Unix(1533489701, 0),
583 orphans: map[bc.Hash]*orphanTx{},
584 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
586 removeHashes: []*bc.Hash{
592 orphans: map[bc.Hash]*orphanTx{
594 expiration: time.Unix(1533489701, 0),
600 expiration: time.Unix(1533489701, 0),
606 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
607 testTxs[0].SpentOutputIDs[0]: {
609 expiration: time.Unix(1533489701, 0),
615 expiration: time.Unix(1533489701, 0),
624 orphans: map[bc.Hash]*orphanTx{
626 expiration: time.Unix(1533489701, 0),
632 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
633 testTxs[0].SpentOutputIDs[0]: {
635 expiration: time.Unix(1533489701, 0),
643 removeHashes: []*bc.Hash{
649 for i, c := range cases {
650 for _, hash := range c.removeHashes {
651 c.before.removeOrphan(hash)
653 if !testutil.DeepEqual(c.before, c.after) {
654 t.Errorf("case %d: got %v want %v", i, c.before, c.after)
659 type mockStore1 struct{}
661 func (s *mockStore1) BlockExist(hash *bc.Hash) bool { return false }
662 func (s *mockStore1) GetBlock(*bc.Hash) (*types.Block, error) { return nil, nil }
663 func (s *mockStore1) GetBlockHeader(*bc.Hash) (*types.BlockHeader, error) { return nil, nil }
664 func (s *mockStore1) GetStoreStatus() *BlockStoreState { return nil }
665 func (s *mockStore1) GetTransactionStatus(*bc.Hash) (*bc.TransactionStatus, error) { return nil, nil }
666 func (s *mockStore1) GetTransactionsUtxo(utxoView *state.UtxoViewpoint, tx []*bc.Tx) error {
668 for _, hash := range testTxs[2].SpentOutputIDs {
669 utxoView.Entries[hash] = &storage.UtxoEntry{Type: storage.NormalUTXOType, Spent: false}
673 func (s *mockStore1) GetUtxo(*bc.Hash) (*storage.UtxoEntry, error) { return nil, nil }
674 func (s *mockStore1) GetConsensusResult(uint64) (*state.ConsensusResult, error) { return nil, nil }
675 func (s *mockStore1) GetMainChainHash(uint64) (*bc.Hash, error) { return nil, nil }
676 func (s *mockStore1) GetBlockHashesByHeight(uint64) ([]*bc.Hash, error) { return nil, nil }
677 func (s *mockStore1) DeleteBlock(*types.Block) error { return nil }
678 func (s *mockStore1) SaveBlock(*types.Block, *bc.TransactionStatus) error { return nil }
679 func (s *mockStore1) DeleteConsensusResult(seq uint64) error { return nil }
680 func (s *mockStore1) SaveBlockHeader(*types.BlockHeader) error { return nil }
681 func (s *mockStore1) SaveChainStatus(*types.BlockHeader, *types.BlockHeader, []*types.BlockHeader, *state.UtxoViewpoint, []*state.ConsensusResult) error {
685 func TestProcessTransaction(t *testing.T) {
687 pool: make(map[bc.Hash]*TxDesc),
688 utxo: make(map[bc.Hash]*types.Tx),
689 orphans: make(map[bc.Hash]*orphanTx),
690 orphansByPrev: make(map[bc.Hash]map[bc.Hash]*orphanTx),
691 store: &mockStore1{},
692 eventDispatcher: event.NewDispatcher(),
717 pool: map[bc.Hash]*TxDesc{
724 utxo: map[bc.Hash]*types.Tx{
725 *testTxs[2].ResultIds[0]: testTxs[2],
726 *testTxs[2].ResultIds[1]: testTxs[2],
736 for i, c := range cases {
737 txPool.ProcessTransaction(c.addTx.Tx, c.addTx.StatusFail, 0, 0)
738 for _, txD := range txPool.pool {
739 txD.Added = time.Time{}
741 for _, txD := range txPool.orphans {
742 txD.Added = time.Time{}
743 txD.expiration = time.Time{}
746 if !testutil.DeepEqual(txPool.pool, c.want.pool) {
747 t.Errorf("case %d: test ProcessTransaction pool mismatch got %s want %s", i, spew.Sdump(txPool.pool), spew.Sdump(c.want.pool))
749 if !testutil.DeepEqual(txPool.utxo, c.want.utxo) {
750 t.Errorf("case %d: test ProcessTransaction utxo mismatch got %s want %s", i, spew.Sdump(txPool.utxo), spew.Sdump(c.want.utxo))
752 if !testutil.DeepEqual(txPool.orphans, c.want.orphans) {
753 t.Errorf("case %d: test ProcessTransaction orphans mismatch got %s want %s", i, spew.Sdump(txPool.orphans), spew.Sdump(c.want.orphans))
755 if !testutil.DeepEqual(txPool.orphansByPrev, c.want.orphansByPrev) {
756 t.Errorf("case %d: test ProcessTransaction orphansByPrev mismatch got %s want %s", i, spew.Sdump(txPool.orphansByPrev), spew.Sdump(c.want.orphansByPrev))