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}, nil),
25 Outputs: []*types.TxOutput{
26 types.NewOriginalTxOutput(*consensus.BTMAssetID, 1, []byte{0x6a}, nil),
30 types.NewTx(types.TxData{
32 Inputs: []*types.TxInput{
33 types.NewSpendInput(nil, bc.NewHash([32]byte{0x01}), *consensus.BTMAssetID, 1, 1, []byte{0x51}, nil),
35 Outputs: []*types.TxOutput{
36 types.NewOriginalTxOutput(*consensus.BTMAssetID, 1, []byte{0x6b}, nil),
40 types.NewTx(types.TxData{
43 Inputs: []*types.TxInput{
44 types.NewSpendInput(nil, bc.NewHash([32]byte{0x01}), *consensus.BTMAssetID, 1, 1, []byte{0x51}, nil),
45 types.NewSpendInput(nil, bc.NewHash([32]byte{0x02}), bc.NewAssetID([32]byte{0xa1}), 4, 1, []byte{0x51}, nil),
47 Outputs: []*types.TxOutput{
48 types.NewOriginalTxOutput(*consensus.BTMAssetID, 1, []byte{0x6b}, nil),
49 types.NewOriginalTxOutput(bc.NewAssetID([32]byte{0xa1}), 4, []byte{0x61}, nil),
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}, nil),
58 Outputs: []*types.TxOutput{
59 types.NewOriginalTxOutput(bc.NewAssetID([32]byte{0xa1}), 3, []byte{0x62}, nil),
60 types.NewOriginalTxOutput(bc.NewAssetID([32]byte{0xa1}), 1, []byte{0x63}, nil),
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}, nil),
69 Outputs: []*types.TxOutput{
70 types.NewOriginalTxOutput(bc.NewAssetID([32]byte{0xa1}), 2, []byte{0x64}, nil),
71 types.NewOriginalTxOutput(bc.NewAssetID([32]byte{0xa1}), 1, []byte{0x65}, nil),
75 types.NewTx(types.TxData{
77 Inputs: []*types.TxInput{
78 types.NewSpendInput(nil, bc.NewHash([32]byte{0x01}), *consensus.BTMAssetID, 1, 1, []byte{0x51}, nil),
80 Outputs: []*types.TxOutput{
81 types.NewOriginalTxOutput(*consensus.BTMAssetID, 0, []byte{0x51}, nil),
85 types.NewTx(types.TxData{
87 Inputs: []*types.TxInput{
88 types.NewSpendInput(nil, bc.NewHash([32]byte{0x01}), *consensus.BTMAssetID, 3, 1, []byte{0x51}, nil),
89 types.NewSpendInput(nil, testutil.MustDecodeHash("d84d0be0fd08e7341f2d127749bb0d0844d4560f53bd54861cee9981fd922cad"), bc.NewAssetID([32]byte{0xa1}), 3, 0, []byte{0x62}, nil),
91 Outputs: []*types.TxOutput{
92 types.NewOriginalTxOutput(*consensus.BTMAssetID, 2, []byte{0x51}, nil),
93 types.NewOriginalTxOutput(bc.NewAssetID([32]byte{0xa1}), 0, []byte{0x65}, nil),
98 type mockStore struct{}
100 func (s *mockStore) GetBlockHeader(hash *bc.Hash) (*types.BlockHeader, error) { return nil, nil }
101 func (s *mockStore) GetCheckpoint(hash *bc.Hash) (*state.Checkpoint, error) { return nil, nil }
102 func (s *mockStore) GetCheckpointsByHeight(u uint64) ([]*state.Checkpoint, error) { return nil, nil }
103 func (s *mockStore) SaveCheckpoints([]*state.Checkpoint) error { return nil }
104 func (s *mockStore) CheckpointsFromNode(height uint64, hash *bc.Hash) ([]*state.Checkpoint, error) { return nil, nil }
105 func (s *mockStore) BlockExist(hash *bc.Hash) bool { return false }
106 func (s *mockStore) GetBlock(*bc.Hash) (*types.Block, error) { return nil, nil }
107 func (s *mockStore) GetStoreStatus() *BlockStoreState { return nil }
108 func (s *mockStore) GetTransactionsUtxo(*state.UtxoViewpoint, []*bc.Tx) error { return nil }
109 func (s *mockStore) GetUtxo(*bc.Hash) (*storage.UtxoEntry, error) { return nil, nil }
110 func (s *mockStore) GetContract(hash [32]byte) ([]byte, error) { return nil, nil }
111 func (s *mockStore) LoadBlockIndex(uint64) (*state.BlockIndex, error) { return nil, nil }
112 func (s *mockStore) SaveBlock(*types.Block) error { return nil }
113 func (s *mockStore) SaveBlockHeader(*types.BlockHeader) error { return nil }
114 func (s *mockStore) SaveChainStatus(*state.BlockNode, *state.UtxoViewpoint, *state.ContractViewpoint, uint64, *bc.Hash) error {
118 func TestAddOrphan(t *testing.T) {
123 requireParents []*bc.Hash
127 orphans: map[bc.Hash]*orphanTx{},
128 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
131 orphans: map[bc.Hash]*orphanTx{
138 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
139 testTxs[0].SpentOutputIDs[0]: {
148 addOrphan: &TxDesc{Tx: testTxs[0]},
149 requireParents: []*bc.Hash{&testTxs[0].SpentOutputIDs[0]},
153 orphans: map[bc.Hash]*orphanTx{
160 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
161 testTxs[0].SpentOutputIDs[0]: {
171 orphans: map[bc.Hash]*orphanTx{
183 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
184 testTxs[0].SpentOutputIDs[0]: {
198 addOrphan: &TxDesc{Tx: testTxs[1]},
199 requireParents: []*bc.Hash{&testTxs[1].SpentOutputIDs[0]},
203 orphans: map[bc.Hash]*orphanTx{},
204 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
207 orphans: map[bc.Hash]*orphanTx{
214 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
215 testTxs[2].SpentOutputIDs[1]: {
224 addOrphan: &TxDesc{Tx: testTxs[2]},
225 requireParents: []*bc.Hash{&testTxs[2].SpentOutputIDs[1]},
229 for i, c := range cases {
230 c.before.addOrphan(c.addOrphan, c.requireParents)
231 for _, orphan := range c.before.orphans {
232 orphan.expiration = time.Time{}
234 for _, orphans := range c.before.orphansByPrev {
235 for _, orphan := range orphans {
236 orphan.expiration = time.Time{}
239 if !testutil.DeepEqual(c.before, c.after) {
240 t.Errorf("case %d: got %v want %v", i, c.before, c.after)
245 func TestAddTransaction(t *testing.T) {
246 dispatcher := event.NewDispatcher()
254 pool: map[bc.Hash]*TxDesc{},
255 utxo: map[bc.Hash]*types.Tx{},
256 eventDispatcher: dispatcher,
259 pool: map[bc.Hash]*TxDesc{
264 utxo: map[bc.Hash]*types.Tx{
265 *testTxs[2].ResultIds[0]: testTxs[2],
266 *testTxs[2].ResultIds[1]: testTxs[2],
275 pool: map[bc.Hash]*TxDesc{},
276 utxo: map[bc.Hash]*types.Tx{},
277 eventDispatcher: dispatcher,
280 pool: map[bc.Hash]*TxDesc{
285 utxo: map[bc.Hash]*types.Tx{
286 *testTxs[2].ResultIds[0]: testTxs[2],
287 *testTxs[2].ResultIds[1]: 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: pool: 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: utxo: 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 t.Skip("Skipping testing in CI environment temp")
373 dispatcher := event.NewDispatcher()
381 pool: map[bc.Hash]*TxDesc{},
382 utxo: map[bc.Hash]*types.Tx{},
383 eventDispatcher: dispatcher,
384 orphans: map[bc.Hash]*orphanTx{
391 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
392 testTxs[3].SpentOutputIDs[0]: {
402 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{
460 utxo: map[bc.Hash]*types.Tx{
461 *testTxs[3].ResultIds[0]: testTxs[3],
462 *testTxs[3].ResultIds[1]: testTxs[3],
463 *testTxs[4].ResultIds[0]: testTxs[4],
464 *testTxs[4].ResultIds[1]: testTxs[4],
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 for i, c := range cases {
475 c.before.store = &mockStore{}
476 c.before.addTransaction(c.processTx)
477 c.before.processOrphans(c.processTx)
478 c.before.RemoveTransaction(&c.processTx.Tx.ID)
480 c.before.lastUpdated = 0
481 for _, txD := range c.before.pool {
482 txD.Added = time.Time{}
485 if !testutil.DeepEqual(c.before, c.after) {
486 t.Errorf("case %d: got %v want %v", i, c.before, c.after)
491 func TestRemoveOrphan(t *testing.T) {
495 removeHashes []*bc.Hash
499 orphans: map[bc.Hash]*orphanTx{
501 expiration: time.Unix(1533489701, 0),
507 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
508 testTxs[0].SpentOutputIDs[0]: {
510 expiration: time.Unix(1533489701, 0),
519 orphans: map[bc.Hash]*orphanTx{},
520 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
522 removeHashes: []*bc.Hash{
528 orphans: map[bc.Hash]*orphanTx{
530 expiration: time.Unix(1533489701, 0),
536 expiration: time.Unix(1533489701, 0),
542 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
543 testTxs[0].SpentOutputIDs[0]: {
545 expiration: time.Unix(1533489701, 0),
551 expiration: time.Unix(1533489701, 0),
560 orphans: map[bc.Hash]*orphanTx{
562 expiration: time.Unix(1533489701, 0),
568 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
569 testTxs[0].SpentOutputIDs[0]: {
571 expiration: time.Unix(1533489701, 0),
579 removeHashes: []*bc.Hash{
585 for i, c := range cases {
586 for _, hash := range c.removeHashes {
587 c.before.removeOrphan(hash)
589 if !testutil.DeepEqual(c.before, c.after) {
590 t.Errorf("case %d: got %v want %v", i, c.before, c.after)
595 type mockStore1 struct{}
597 func (s *mockStore1) GetBlockHeader(hash *bc.Hash) (*types.BlockHeader, error) { return nil, nil }
598 func (s *mockStore1) GetCheckpoint(hash *bc.Hash) (*state.Checkpoint, error) { return nil, nil }
599 func (s *mockStore1) GetCheckpointsByHeight(u uint64) ([]*state.Checkpoint, error) { return nil, nil }
600 func (s *mockStore1) SaveCheckpoints([]*state.Checkpoint) error { return nil }
601 func (s *mockStore1) CheckpointsFromNode(height uint64, hash *bc.Hash) ([]*state.Checkpoint, error) { return nil, nil }
602 func (s *mockStore1) BlockExist(hash *bc.Hash) bool { return false }
603 func (s *mockStore1) GetBlock(*bc.Hash) (*types.Block, error) { return nil, nil }
604 func (s *mockStore1) GetStoreStatus() *BlockStoreState { return nil }
605 func (s *mockStore1) GetTransactionStatus(*bc.Hash) (*bc.TransactionStatus, error) { return nil, nil }
606 func (s *mockStore1) GetTransactionsUtxo(utxoView *state.UtxoViewpoint, tx []*bc.Tx) error {
607 for _, hash := range testTxs[2].SpentOutputIDs {
608 utxoView.Entries[hash] = &storage.UtxoEntry{IsCoinBase: false, Spent: false}
612 func (s *mockStore1) GetUtxo(*bc.Hash) (*storage.UtxoEntry, error) { return nil, nil }
613 func (s *mockStore1) GetContract(hash [32]byte) ([]byte, error) { return nil, nil }
614 func (s *mockStore1) LoadBlockIndex(uint64) (*state.BlockIndex, error) { return nil, nil }
615 func (s *mockStore1) SaveBlock(*types.Block) error { return nil }
616 func (s *mockStore1) SaveBlockHeader(*types.BlockHeader) error { return nil }
617 func (s *mockStore1) SaveChainStatus(*state.BlockNode, *state.UtxoViewpoint, *state.ContractViewpoint, uint64, *bc.Hash) 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(),
663 pool: map[bc.Hash]*TxDesc{
669 utxo: map[bc.Hash]*types.Tx{
670 *testTxs[2].ResultIds[0]: testTxs[2],
671 *testTxs[2].ResultIds[1]: testTxs[2],
680 for i, c := range cases {
681 txPool.ProcessTransaction(c.addTx.Tx, 0, 0)
682 for _, txD := range txPool.pool {
683 txD.Added = time.Time{}
685 for _, txD := range txPool.orphans {
686 txD.Added = time.Time{}
687 txD.expiration = time.Time{}
690 if !testutil.DeepEqual(txPool.pool, c.want.pool) {
691 t.Errorf("case %d: test ProcessTransaction pool mismatch got %s want %s", i, spew.Sdump(txPool.pool), spew.Sdump(c.want.pool))
693 if !testutil.DeepEqual(txPool.utxo, c.want.utxo) {
694 t.Errorf("case %d: test ProcessTransaction utxo mismatch got %s want %s", i, spew.Sdump(txPool.utxo), spew.Sdump(c.want.utxo))
696 if !testutil.DeepEqual(txPool.orphans, c.want.orphans) {
697 t.Errorf("case %d: test ProcessTransaction orphans mismatch got %s want %s", i, spew.Sdump(txPool.orphans), spew.Sdump(c.want.orphans))
699 if !testutil.DeepEqual(txPool.orphansByPrev, c.want.orphansByPrev) {
700 t.Errorf("case %d: test ProcessTransaction orphansByPrev mismatch got %s want %s", i, spew.Sdump(txPool.orphansByPrev), spew.Sdump(c.want.orphansByPrev))