7 "github.com/davecgh/go-spew/spew"
9 "github.com/bytom/consensus"
10 "github.com/bytom/database/storage"
11 "github.com/bytom/event"
12 "github.com/bytom/protocol/bc"
13 "github.com/bytom/protocol/bc/types"
14 "github.com/bytom/protocol/state"
15 "github.com/bytom/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.NewTxOutput(*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.NewTxOutput(*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.NewTxOutput(*consensus.BTMAssetID, 1, []byte{0x6b}),
49 types.NewTxOutput(bc.NewAssetID([32]byte{0xa1}), 4, []byte{0x61}),
53 types.NewTx(types.TxData{
55 Inputs: []*types.TxInput{
56 types.NewSpendInput(nil, testutil.MustDecodeHash("dbea684b5c5153ed7729669a53d6c59574f26015a3e1eb2a0e8a1c645425a764"), bc.NewAssetID([32]byte{0xa1}), 4, 1, []byte{0x61}),
58 Outputs: []*types.TxOutput{
59 types.NewTxOutput(bc.NewAssetID([32]byte{0xa1}), 3, []byte{0x62}),
60 types.NewTxOutput(bc.NewAssetID([32]byte{0xa1}), 1, []byte{0x63}),
64 types.NewTx(types.TxData{
66 Inputs: []*types.TxInput{
67 types.NewSpendInput(nil, testutil.MustDecodeHash("d84d0be0fd08e7341f2d127749bb0d0844d4560f53bd54861cee9981fd922cad"), bc.NewAssetID([32]byte{0xa1}), 3, 0, []byte{0x62}),
69 Outputs: []*types.TxOutput{
70 types.NewTxOutput(bc.NewAssetID([32]byte{0xa1}), 2, []byte{0x64}),
71 types.NewTxOutput(bc.NewAssetID([32]byte{0xa1}), 1, []byte{0x65}),
75 types.NewTx(types.TxData{
77 Inputs: []*types.TxInput{
78 types.NewSpendInput(nil, bc.NewHash([32]byte{0x01}), *consensus.BTMAssetID, 1, 1, []byte{0x51}),
80 Outputs: []*types.TxOutput{
81 types.NewTxOutput(*consensus.BTMAssetID, 0, []byte{0x51}),
85 types.NewTx(types.TxData{
87 Inputs: []*types.TxInput{
88 types.NewSpendInput(nil, bc.NewHash([32]byte{0x01}), *consensus.BTMAssetID, 3, 1, []byte{0x51}),
89 types.NewSpendInput(nil, testutil.MustDecodeHash("d84d0be0fd08e7341f2d127749bb0d0844d4560f53bd54861cee9981fd922cad"), bc.NewAssetID([32]byte{0xa1}), 3, 0, []byte{0x62}),
91 Outputs: []*types.TxOutput{
92 types.NewTxOutput(*consensus.BTMAssetID, 2, []byte{0x51}),
93 types.NewTxOutput(bc.NewAssetID([32]byte{0xa1}), 0, []byte{0x65}),
98 type mockStore struct{}
100 func (s *mockStore) BlockExist(hash *bc.Hash) bool { return false }
101 func (s *mockStore) GetBlock(*bc.Hash) (*types.Block, error) { return nil, nil }
102 func (s *mockStore) GetStoreStatus() *BlockStoreState { return nil }
103 func (s *mockStore) GetTransactionStatus(*bc.Hash) (*bc.TransactionStatus, error) { return nil, nil }
104 func (s *mockStore) GetTransactionsUtxo(*state.UtxoViewpoint, []*bc.Tx) error { return nil }
105 func (s *mockStore) GetUtxo(*bc.Hash) (*storage.UtxoEntry, error) { return nil, nil }
106 func (s *mockStore) LoadBlockIndex(uint64) (*state.BlockIndex, error) { return nil, nil }
107 func (s *mockStore) SaveBlock(*types.Block, *bc.TransactionStatus) error { return nil }
108 func (s *mockStore) SaveChainStatus(*state.BlockNode, *state.UtxoViewpoint) error { return nil }
110 func TestAddOrphan(t *testing.T) {
115 requireParents []*bc.Hash
119 orphans: map[bc.Hash]*orphanTx{},
120 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
123 orphans: map[bc.Hash]*orphanTx{
130 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
131 testTxs[0].SpentOutputIDs[0]: {
140 addOrphan: &TxDesc{Tx: testTxs[0]},
141 requireParents: []*bc.Hash{&testTxs[0].SpentOutputIDs[0]},
145 orphans: map[bc.Hash]*orphanTx{
152 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
153 testTxs[0].SpentOutputIDs[0]: {
163 orphans: map[bc.Hash]*orphanTx{
175 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
176 testTxs[0].SpentOutputIDs[0]: {
190 addOrphan: &TxDesc{Tx: testTxs[1]},
191 requireParents: []*bc.Hash{&testTxs[1].SpentOutputIDs[0]},
195 orphans: map[bc.Hash]*orphanTx{},
196 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
199 orphans: map[bc.Hash]*orphanTx{
206 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
207 testTxs[2].SpentOutputIDs[1]: {
216 addOrphan: &TxDesc{Tx: testTxs[2]},
217 requireParents: []*bc.Hash{&testTxs[2].SpentOutputIDs[1]},
221 for i, c := range cases {
222 c.before.addOrphan(c.addOrphan, c.requireParents)
223 for _, orphan := range c.before.orphans {
224 orphan.expiration = time.Time{}
226 for _, orphans := range c.before.orphansByPrev {
227 for _, orphan := range orphans {
228 orphan.expiration = time.Time{}
231 if !testutil.DeepEqual(c.before, c.after) {
232 t.Errorf("case %d: got %v want %v", i, c.before, c.after)
237 func TestAddTransaction(t *testing.T) {
238 dispatcher := event.NewDispatcher()
246 pool: map[bc.Hash]*TxDesc{},
247 utxo: map[bc.Hash]*types.Tx{},
248 eventDispatcher: dispatcher,
251 pool: map[bc.Hash]*TxDesc{
257 utxo: map[bc.Hash]*types.Tx{
258 *testTxs[2].ResultIds[0]: testTxs[2],
259 *testTxs[2].ResultIds[1]: testTxs[2],
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],
291 for i, c := range cases {
292 c.before.addTransaction(c.addTx)
293 for _, txD := range c.before.pool {
294 txD.Added = time.Time{}
296 if !testutil.DeepEqual(c.before.pool, c.after.pool) {
297 t.Errorf("case %d: got %v want %v", i, c.before.pool, c.after.pool)
299 if !testutil.DeepEqual(c.before.utxo, c.after.utxo) {
300 t.Errorf("case %d: got %v want %v", i, c.before.utxo, c.after.utxo)
305 func TestExpireOrphan(t *testing.T) {
307 orphans: map[bc.Hash]*orphanTx{
309 expiration: time.Unix(1533489701, 0),
315 expiration: time.Unix(1633489701, 0),
321 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
322 testTxs[0].SpentOutputIDs[0]: {
324 expiration: time.Unix(1533489701, 0),
330 expiration: time.Unix(1633489701, 0),
340 orphans: map[bc.Hash]*orphanTx{
342 expiration: time.Unix(1633489701, 0),
348 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
349 testTxs[0].SpentOutputIDs[0]: {
351 expiration: time.Unix(1633489701, 0),
360 before.ExpireOrphan(time.Unix(1633479701, 0))
361 if !testutil.DeepEqual(before, want) {
362 t.Errorf("got %v want %v", before, want)
366 func TestProcessOrphans(t *testing.T) {
367 dispatcher := event.NewDispatcher()
375 pool: map[bc.Hash]*TxDesc{},
376 utxo: map[bc.Hash]*types.Tx{},
377 eventDispatcher: dispatcher,
378 orphans: map[bc.Hash]*orphanTx{
385 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
386 testTxs[3].SpentOutputIDs[0]: {
396 pool: map[bc.Hash]*TxDesc{
402 utxo: map[bc.Hash]*types.Tx{
403 *testTxs[3].ResultIds[0]: testTxs[3],
404 *testTxs[3].ResultIds[1]: testTxs[3],
406 eventDispatcher: dispatcher,
407 orphans: map[bc.Hash]*orphanTx{},
408 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
410 processTx: &TxDesc{Tx: testTxs[2]},
414 pool: map[bc.Hash]*TxDesc{},
415 utxo: map[bc.Hash]*types.Tx{},
416 eventDispatcher: dispatcher,
417 orphans: map[bc.Hash]*orphanTx{
429 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
430 testTxs[3].SpentOutputIDs[0]: {
437 testTxs[4].SpentOutputIDs[0]: {
447 pool: map[bc.Hash]*TxDesc{
457 utxo: map[bc.Hash]*types.Tx{
458 *testTxs[3].ResultIds[0]: testTxs[3],
459 *testTxs[3].ResultIds[1]: testTxs[3],
460 *testTxs[4].ResultIds[0]: testTxs[4],
461 *testTxs[4].ResultIds[1]: testTxs[4],
463 eventDispatcher: dispatcher,
464 orphans: map[bc.Hash]*orphanTx{},
465 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
467 processTx: &TxDesc{Tx: testTxs[2]},
471 for i, c := range cases {
472 c.before.store = &mockStore{}
473 c.before.addTransaction(c.processTx)
474 c.before.processOrphans(c.processTx)
475 c.before.RemoveTransaction(&c.processTx.Tx.ID)
477 c.before.lastUpdated = 0
478 for _, txD := range c.before.pool {
479 txD.Added = time.Time{}
482 if !testutil.DeepEqual(c.before, c.after) {
483 t.Errorf("case %d: got %v want %v", i, c.before, c.after)
488 func TestRemoveOrphan(t *testing.T) {
492 removeHashes []*bc.Hash
496 orphans: map[bc.Hash]*orphanTx{
498 expiration: time.Unix(1533489701, 0),
504 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
505 testTxs[0].SpentOutputIDs[0]: {
507 expiration: time.Unix(1533489701, 0),
516 orphans: map[bc.Hash]*orphanTx{},
517 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
519 removeHashes: []*bc.Hash{
525 orphans: map[bc.Hash]*orphanTx{
527 expiration: time.Unix(1533489701, 0),
533 expiration: time.Unix(1533489701, 0),
539 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
540 testTxs[0].SpentOutputIDs[0]: {
542 expiration: time.Unix(1533489701, 0),
548 expiration: time.Unix(1533489701, 0),
557 orphans: map[bc.Hash]*orphanTx{
559 expiration: time.Unix(1533489701, 0),
565 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
566 testTxs[0].SpentOutputIDs[0]: {
568 expiration: time.Unix(1533489701, 0),
576 removeHashes: []*bc.Hash{
582 for i, c := range cases {
583 for _, hash := range c.removeHashes {
584 c.before.removeOrphan(hash)
586 if !testutil.DeepEqual(c.before, c.after) {
587 t.Errorf("case %d: got %v want %v", i, c.before, c.after)
592 type mockStore1 struct{}
594 func (s *mockStore1) BlockExist(hash *bc.Hash) bool { return false }
595 func (s *mockStore1) GetBlock(*bc.Hash) (*types.Block, error) { return nil, nil }
596 func (s *mockStore1) GetStoreStatus() *BlockStoreState { return nil }
597 func (s *mockStore1) GetTransactionStatus(*bc.Hash) (*bc.TransactionStatus, error) { return nil, nil }
598 func (s *mockStore1) GetTransactionsUtxo(utxoView *state.UtxoViewpoint, tx []*bc.Tx) error {
599 for _, hash := range testTxs[2].SpentOutputIDs {
600 utxoView.Entries[hash] = &storage.UtxoEntry{IsCoinBase: false, Spent: false}
604 func (s *mockStore1) GetUtxo(*bc.Hash) (*storage.UtxoEntry, error) { return nil, nil }
605 func (s *mockStore1) LoadBlockIndex(uint64) (*state.BlockIndex, error) { return nil, nil }
606 func (s *mockStore1) SaveBlock(*types.Block, *bc.TransactionStatus) error { return nil }
607 func (s *mockStore1) SaveChainStatus(*state.BlockNode, *state.UtxoViewpoint) error { return nil }
609 func TestProcessTransaction(t *testing.T) {
611 pool: make(map[bc.Hash]*TxDesc),
612 utxo: make(map[bc.Hash]*types.Tx),
613 orphans: make(map[bc.Hash]*orphanTx),
614 orphansByPrev: make(map[bc.Hash]map[bc.Hash]*orphanTx),
615 store: &mockStore1{},
616 eventDispatcher: event.NewDispatcher(),
657 pool: map[bc.Hash]*TxDesc{
664 utxo: map[bc.Hash]*types.Tx{
665 *testTxs[2].ResultIds[0]: testTxs[2],
666 *testTxs[2].ResultIds[1]: testTxs[2],
676 for i, c := range cases {
677 txPool.ProcessTransaction(c.addTx.Tx, c.addTx.StatusFail, 0, 0)
678 for _, txD := range txPool.pool {
679 txD.Added = time.Time{}
681 for _, txD := range txPool.orphans {
682 txD.Added = time.Time{}
683 txD.expiration = time.Time{}
686 if !testutil.DeepEqual(txPool.pool, c.want.pool) {
687 t.Errorf("case %d: test ProcessTransaction pool mismatch got %s want %s", i, spew.Sdump(txPool.pool), spew.Sdump(c.want.pool))
689 if !testutil.DeepEqual(txPool.utxo, c.want.utxo) {
690 t.Errorf("case %d: test ProcessTransaction utxo mismatch got %s want %s", i, spew.Sdump(txPool.utxo), spew.Sdump(c.want.utxo))
692 if !testutil.DeepEqual(txPool.orphans, c.want.orphans) {
693 t.Errorf("case %d: test ProcessTransaction orphans mismatch got %s want %s", i, spew.Sdump(txPool.orphans), spew.Sdump(c.want.orphans))
695 if !testutil.DeepEqual(txPool.orphansByPrev, c.want.orphansByPrev) {
696 t.Errorf("case %d: test ProcessTransaction orphansByPrev mismatch got %s want %s", i, spew.Sdump(txPool.orphansByPrev), spew.Sdump(c.want.orphansByPrev))