7 "github.com/davecgh/go-spew/spew"
9 "github.com/bytom/bytom/consensus"
10 "github.com/bytom/bytom/database/storage"
11 "github.com/bytom/bytom/event"
12 "github.com/bytom/bytom/protocol/bc"
13 "github.com/bytom/bytom/protocol/bc/types"
14 "github.com/bytom/bytom/protocol/state"
15 "github.com/bytom/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) SaveChainStatus(*state.BlockNode, *state.UtxoViewpoint, *state.ContractViewpoint) error {
103 func (s *mockStore) GetBlockHeader(hash *bc.Hash) (*types.BlockHeader, error) { return nil, nil }
104 func (s *mockStore) GetCheckpoint(hash *bc.Hash) (*state.Checkpoint, error) { return nil, nil }
105 func (s *mockStore) GetCheckpointsByHeight(u uint64) ([]*state.Checkpoint, error) { return nil, nil }
106 func (s *mockStore) BlockExist(hash *bc.Hash) bool { return false }
107 func (s *mockStore) GetBlock(*bc.Hash) (*types.Block, error) { return nil, nil }
108 func (s *mockStore) GetStoreStatus() *BlockStoreState { return nil }
109 func (s *mockStore) GetTransactionStatus(*bc.Hash) (*bc.TransactionStatus, error) { return nil, nil }
110 func (s *mockStore) GetTransactionsUtxo(*state.UtxoViewpoint, []*bc.Tx) error { return nil }
111 func (s *mockStore) GetUtxo(*bc.Hash) (*storage.UtxoEntry, error) { return nil, nil }
112 func (s *mockStore) LoadBlockIndex(uint64) (*state.BlockIndex, error) { return nil, nil }
113 func (s *mockStore) SaveBlock(*types.Block, *bc.TransactionStatus) error { return nil }
115 func TestAddOrphan(t *testing.T) {
120 requireParents []*bc.Hash
124 orphans: map[bc.Hash]*orphanTx{},
125 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
128 orphans: map[bc.Hash]*orphanTx{
135 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
136 testTxs[0].SpentOutputIDs[0]: {
145 addOrphan: &TxDesc{Tx: testTxs[0]},
146 requireParents: []*bc.Hash{&testTxs[0].SpentOutputIDs[0]},
150 orphans: map[bc.Hash]*orphanTx{
157 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
158 testTxs[0].SpentOutputIDs[0]: {
168 orphans: map[bc.Hash]*orphanTx{
180 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
181 testTxs[0].SpentOutputIDs[0]: {
195 addOrphan: &TxDesc{Tx: testTxs[1]},
196 requireParents: []*bc.Hash{&testTxs[1].SpentOutputIDs[0]},
200 orphans: map[bc.Hash]*orphanTx{},
201 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
204 orphans: map[bc.Hash]*orphanTx{
211 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
212 testTxs[2].SpentOutputIDs[1]: {
221 addOrphan: &TxDesc{Tx: testTxs[2]},
222 requireParents: []*bc.Hash{&testTxs[2].SpentOutputIDs[1]},
226 for i, c := range cases {
227 c.before.addOrphan(c.addOrphan, c.requireParents)
228 for _, orphan := range c.before.orphans {
229 orphan.expiration = time.Time{}
231 for _, orphans := range c.before.orphansByPrev {
232 for _, orphan := range orphans {
233 orphan.expiration = time.Time{}
236 if !testutil.DeepEqual(c.before, c.after) {
237 t.Errorf("case %d: got %v want %v", i, c.before, c.after)
242 func TestAddTransaction(t *testing.T) {
243 dispatcher := event.NewDispatcher()
251 pool: map[bc.Hash]*TxDesc{},
252 utxo: map[bc.Hash]*types.Tx{},
253 eventDispatcher: dispatcher,
256 pool: map[bc.Hash]*TxDesc{
262 utxo: map[bc.Hash]*types.Tx{
263 *testTxs[2].ResultIds[0]: testTxs[2],
264 *testTxs[2].ResultIds[1]: testTxs[2],
274 pool: map[bc.Hash]*TxDesc{},
275 utxo: map[bc.Hash]*types.Tx{},
276 eventDispatcher: dispatcher,
279 pool: map[bc.Hash]*TxDesc{
285 utxo: map[bc.Hash]*types.Tx{
286 *testTxs[2].ResultIds[0]: testTxs[2],
296 for i, c := range cases {
297 c.before.addTransaction(c.addTx)
298 for _, txD := range c.before.pool {
299 txD.Added = time.Time{}
301 if !testutil.DeepEqual(c.before.pool, c.after.pool) {
302 t.Errorf("case %d: got %v want %v", i, c.before.pool, c.after.pool)
304 if !testutil.DeepEqual(c.before.utxo, c.after.utxo) {
305 t.Errorf("case %d: got %v want %v", i, c.before.utxo, c.after.utxo)
310 func TestExpireOrphan(t *testing.T) {
312 orphans: map[bc.Hash]*orphanTx{
314 expiration: time.Unix(1533489701, 0),
320 expiration: time.Unix(1633489701, 0),
326 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
327 testTxs[0].SpentOutputIDs[0]: {
329 expiration: time.Unix(1533489701, 0),
335 expiration: time.Unix(1633489701, 0),
345 orphans: map[bc.Hash]*orphanTx{
347 expiration: time.Unix(1633489701, 0),
353 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
354 testTxs[0].SpentOutputIDs[0]: {
356 expiration: time.Unix(1633489701, 0),
365 before.ExpireOrphan(time.Unix(1633479701, 0))
366 if !testutil.DeepEqual(before, want) {
367 t.Errorf("got %v want %v", before, want)
371 func TestProcessOrphans(t *testing.T) {
372 dispatcher := event.NewDispatcher()
380 pool: map[bc.Hash]*TxDesc{},
381 utxo: map[bc.Hash]*types.Tx{},
382 eventDispatcher: dispatcher,
383 orphans: map[bc.Hash]*orphanTx{
390 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
391 testTxs[3].SpentOutputIDs[0]: {
401 pool: map[bc.Hash]*TxDesc{
407 utxo: map[bc.Hash]*types.Tx{
408 *testTxs[3].ResultIds[0]: testTxs[3],
409 *testTxs[3].ResultIds[1]: testTxs[3],
411 eventDispatcher: dispatcher,
412 orphans: map[bc.Hash]*orphanTx{},
413 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
415 processTx: &TxDesc{Tx: testTxs[2]},
419 pool: map[bc.Hash]*TxDesc{},
420 utxo: map[bc.Hash]*types.Tx{},
421 eventDispatcher: dispatcher,
422 orphans: map[bc.Hash]*orphanTx{
434 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
435 testTxs[3].SpentOutputIDs[0]: {
442 testTxs[4].SpentOutputIDs[0]: {
452 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],
465 *testTxs[4].ResultIds[0]: testTxs[4],
466 *testTxs[4].ResultIds[1]: testTxs[4],
468 eventDispatcher: dispatcher,
469 orphans: map[bc.Hash]*orphanTx{},
470 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
472 processTx: &TxDesc{Tx: testTxs[2]},
476 for i, c := range cases {
477 c.before.store = &mockStore{}
478 c.before.addTransaction(c.processTx)
479 c.before.processOrphans(c.processTx)
480 c.before.RemoveTransaction(&c.processTx.Tx.ID)
482 c.before.lastUpdated = 0
483 for _, txD := range c.before.pool {
484 txD.Added = time.Time{}
487 if !testutil.DeepEqual(c.before, c.after) {
488 t.Errorf("case %d: got %v want %v", i, c.before, c.after)
493 func TestRemoveOrphan(t *testing.T) {
497 removeHashes []*bc.Hash
501 orphans: map[bc.Hash]*orphanTx{
503 expiration: time.Unix(1533489701, 0),
509 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
510 testTxs[0].SpentOutputIDs[0]: {
512 expiration: time.Unix(1533489701, 0),
521 orphans: map[bc.Hash]*orphanTx{},
522 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
524 removeHashes: []*bc.Hash{
530 orphans: map[bc.Hash]*orphanTx{
532 expiration: time.Unix(1533489701, 0),
538 expiration: time.Unix(1533489701, 0),
544 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
545 testTxs[0].SpentOutputIDs[0]: {
547 expiration: time.Unix(1533489701, 0),
553 expiration: time.Unix(1533489701, 0),
562 orphans: map[bc.Hash]*orphanTx{
564 expiration: time.Unix(1533489701, 0),
570 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
571 testTxs[0].SpentOutputIDs[0]: {
573 expiration: time.Unix(1533489701, 0),
581 removeHashes: []*bc.Hash{
587 for i, c := range cases {
588 for _, hash := range c.removeHashes {
589 c.before.removeOrphan(hash)
591 if !testutil.DeepEqual(c.before, c.after) {
592 t.Errorf("case %d: got %v want %v", i, c.before, c.after)
597 type mockStore1 struct{}
599 func (s *mockStore1) SaveChainStatus(*state.BlockNode, *state.UtxoViewpoint, *state.ContractViewpoint) error {
602 func (s *mockStore1) GetBlockHeader(hash *bc.Hash) (*types.BlockHeader, error) { return nil, nil }
603 func (s *mockStore1) GetCheckpoint(hash *bc.Hash) (*state.Checkpoint, error) { return nil, nil }
604 func (s *mockStore1) GetCheckpointsByHeight(u uint64) ([]*state.Checkpoint, error) { return nil, nil }
605 func (s *mockStore1) BlockExist(hash *bc.Hash) bool { return false }
606 func (s *mockStore1) GetBlock(*bc.Hash) (*types.Block, error) { return nil, nil }
607 func (s *mockStore1) GetStoreStatus() *BlockStoreState { return nil }
608 func (s *mockStore1) GetTransactionStatus(*bc.Hash) (*bc.TransactionStatus, error) { return nil, nil }
609 func (s *mockStore1) GetTransactionsUtxo(utxoView *state.UtxoViewpoint, tx []*bc.Tx) error {
610 for _, hash := range testTxs[2].SpentOutputIDs {
611 utxoView.Entries[hash] = &storage.UtxoEntry{IsCoinBase: false, Spent: false}
615 func (s *mockStore1) GetUtxo(*bc.Hash) (*storage.UtxoEntry, error) { return nil, nil }
616 func (s *mockStore1) LoadBlockIndex(uint64) (*state.BlockIndex, error) { return nil, nil }
617 func (s *mockStore1) SaveBlock(*types.Block, *bc.TransactionStatus) error { return nil }
619 func TestProcessTransaction(t *testing.T) {
621 pool: make(map[bc.Hash]*TxDesc),
622 utxo: make(map[bc.Hash]*types.Tx),
623 orphans: make(map[bc.Hash]*orphanTx),
624 orphansByPrev: make(map[bc.Hash]map[bc.Hash]*orphanTx),
625 store: &mockStore1{},
626 eventDispatcher: event.NewDispatcher(),
667 pool: map[bc.Hash]*TxDesc{
674 utxo: map[bc.Hash]*types.Tx{
675 *testTxs[2].ResultIds[0]: testTxs[2],
676 *testTxs[2].ResultIds[1]: testTxs[2],
686 for i, c := range cases {
687 txPool.ProcessTransaction(c.addTx.Tx, c.addTx.StatusFail, 0, 0)
688 for _, txD := range txPool.pool {
689 txD.Added = time.Time{}
691 for _, txD := range txPool.orphans {
692 txD.Added = time.Time{}
693 txD.expiration = time.Time{}
696 if !testutil.DeepEqual(txPool.pool, c.want.pool) {
697 t.Errorf("case %d: test ProcessTransaction pool mismatch got %s want %s", i, spew.Sdump(txPool.pool), spew.Sdump(c.want.pool))
699 if !testutil.DeepEqual(txPool.utxo, c.want.utxo) {
700 t.Errorf("case %d: test ProcessTransaction utxo mismatch got %s want %s", i, spew.Sdump(txPool.utxo), spew.Sdump(c.want.utxo))
702 if !testutil.DeepEqual(txPool.orphans, c.want.orphans) {
703 t.Errorf("case %d: test ProcessTransaction orphans mismatch got %s want %s", i, spew.Sdump(txPool.orphans), spew.Sdump(c.want.orphans))
705 if !testutil.DeepEqual(txPool.orphansByPrev, c.want.orphansByPrev) {
706 t.Errorf("case %d: test ProcessTransaction orphansByPrev mismatch got %s want %s", i, spew.Sdump(txPool.orphansByPrev), spew.Sdump(c.want.orphansByPrev))