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) GetBlockHeader(hash *bc.Hash) (*types.BlockHeader, error) {
101 panic("implement me")
104 func (s *mockStore) GetCheckpoint(hash *bc.Hash) (*state.Checkpoint, error) {
105 panic("implement me")
108 func (s *mockStore) GetCheckpointsByHeight(u uint64) ([]*state.Checkpoint, error) {
109 panic("implement me")
112 func (s *mockStore) BlockExist(hash *bc.Hash) bool { return false }
113 func (s *mockStore) GetBlock(*bc.Hash) (*types.Block, error) { return nil, nil }
114 func (s *mockStore) GetStoreStatus() *BlockStoreState { return nil }
115 func (s *mockStore) GetTransactionStatus(*bc.Hash) (*bc.TransactionStatus, error) { return nil, nil }
116 func (s *mockStore) GetTransactionsUtxo(*state.UtxoViewpoint, []*bc.Tx) error { return nil }
117 func (s *mockStore) GetUtxo(*bc.Hash) (*storage.UtxoEntry, error) { return nil, nil }
118 func (s *mockStore) LoadBlockIndex(uint64) (*state.BlockIndex, error) { return nil, nil }
119 func (s *mockStore) SaveBlock(*types.Block, *bc.TransactionStatus) error { return nil }
120 func (s *mockStore) SaveChainStatus(*state.BlockNode, *state.UtxoViewpoint) error { return nil }
122 func TestAddOrphan(t *testing.T) {
127 requireParents []*bc.Hash
131 orphans: map[bc.Hash]*orphanTx{},
132 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
135 orphans: map[bc.Hash]*orphanTx{
142 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
143 testTxs[0].SpentOutputIDs[0]: {
152 addOrphan: &TxDesc{Tx: testTxs[0]},
153 requireParents: []*bc.Hash{&testTxs[0].SpentOutputIDs[0]},
157 orphans: map[bc.Hash]*orphanTx{
164 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
165 testTxs[0].SpentOutputIDs[0]: {
175 orphans: map[bc.Hash]*orphanTx{
187 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
188 testTxs[0].SpentOutputIDs[0]: {
202 addOrphan: &TxDesc{Tx: testTxs[1]},
203 requireParents: []*bc.Hash{&testTxs[1].SpentOutputIDs[0]},
207 orphans: map[bc.Hash]*orphanTx{},
208 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
211 orphans: map[bc.Hash]*orphanTx{
218 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
219 testTxs[2].SpentOutputIDs[1]: {
228 addOrphan: &TxDesc{Tx: testTxs[2]},
229 requireParents: []*bc.Hash{&testTxs[2].SpentOutputIDs[1]},
233 for i, c := range cases {
234 c.before.addOrphan(c.addOrphan, c.requireParents)
235 for _, orphan := range c.before.orphans {
236 orphan.expiration = time.Time{}
238 for _, orphans := range c.before.orphansByPrev {
239 for _, orphan := range orphans {
240 orphan.expiration = time.Time{}
243 if !testutil.DeepEqual(c.before, c.after) {
244 t.Errorf("case %d: got %v want %v", i, c.before, c.after)
249 func TestAddTransaction(t *testing.T) {
250 dispatcher := event.NewDispatcher()
258 pool: map[bc.Hash]*TxDesc{},
259 utxo: map[bc.Hash]*types.Tx{},
260 eventDispatcher: dispatcher,
263 pool: map[bc.Hash]*TxDesc{
269 utxo: map[bc.Hash]*types.Tx{
270 *testTxs[2].ResultIds[0]: testTxs[2],
271 *testTxs[2].ResultIds[1]: testTxs[2],
281 pool: map[bc.Hash]*TxDesc{},
282 utxo: map[bc.Hash]*types.Tx{},
283 eventDispatcher: dispatcher,
286 pool: map[bc.Hash]*TxDesc{
292 utxo: map[bc.Hash]*types.Tx{
293 *testTxs[2].ResultIds[0]: testTxs[2],
303 for i, c := range cases {
304 c.before.addTransaction(c.addTx)
305 for _, txD := range c.before.pool {
306 txD.Added = time.Time{}
308 if !testutil.DeepEqual(c.before.pool, c.after.pool) {
309 t.Errorf("case %d: got %v want %v", i, c.before.pool, c.after.pool)
311 if !testutil.DeepEqual(c.before.utxo, c.after.utxo) {
312 t.Errorf("case %d: got %v want %v", i, c.before.utxo, c.after.utxo)
317 func TestExpireOrphan(t *testing.T) {
319 orphans: map[bc.Hash]*orphanTx{
321 expiration: time.Unix(1533489701, 0),
327 expiration: time.Unix(1633489701, 0),
333 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
334 testTxs[0].SpentOutputIDs[0]: {
336 expiration: time.Unix(1533489701, 0),
342 expiration: time.Unix(1633489701, 0),
352 orphans: map[bc.Hash]*orphanTx{
354 expiration: time.Unix(1633489701, 0),
360 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
361 testTxs[0].SpentOutputIDs[0]: {
363 expiration: time.Unix(1633489701, 0),
372 before.ExpireOrphan(time.Unix(1633479701, 0))
373 if !testutil.DeepEqual(before, want) {
374 t.Errorf("got %v want %v", before, want)
378 func TestProcessOrphans(t *testing.T) {
379 dispatcher := event.NewDispatcher()
387 pool: map[bc.Hash]*TxDesc{},
388 utxo: map[bc.Hash]*types.Tx{},
389 eventDispatcher: dispatcher,
390 orphans: map[bc.Hash]*orphanTx{
397 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
398 testTxs[3].SpentOutputIDs[0]: {
408 pool: map[bc.Hash]*TxDesc{
414 utxo: map[bc.Hash]*types.Tx{
415 *testTxs[3].ResultIds[0]: testTxs[3],
416 *testTxs[3].ResultIds[1]: testTxs[3],
418 eventDispatcher: dispatcher,
419 orphans: map[bc.Hash]*orphanTx{},
420 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
422 processTx: &TxDesc{Tx: testTxs[2]},
426 pool: map[bc.Hash]*TxDesc{},
427 utxo: map[bc.Hash]*types.Tx{},
428 eventDispatcher: dispatcher,
429 orphans: map[bc.Hash]*orphanTx{
441 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
442 testTxs[3].SpentOutputIDs[0]: {
449 testTxs[4].SpentOutputIDs[0]: {
459 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],
472 *testTxs[4].ResultIds[0]: testTxs[4],
473 *testTxs[4].ResultIds[1]: testTxs[4],
475 eventDispatcher: dispatcher,
476 orphans: map[bc.Hash]*orphanTx{},
477 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
479 processTx: &TxDesc{Tx: testTxs[2]},
483 for i, c := range cases {
484 c.before.store = &mockStore{}
485 c.before.addTransaction(c.processTx)
486 c.before.processOrphans(c.processTx)
487 c.before.RemoveTransaction(&c.processTx.Tx.ID)
489 c.before.lastUpdated = 0
490 for _, txD := range c.before.pool {
491 txD.Added = time.Time{}
494 if !testutil.DeepEqual(c.before, c.after) {
495 t.Errorf("case %d: got %v want %v", i, c.before, c.after)
500 func TestRemoveOrphan(t *testing.T) {
504 removeHashes []*bc.Hash
508 orphans: map[bc.Hash]*orphanTx{
510 expiration: time.Unix(1533489701, 0),
516 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
517 testTxs[0].SpentOutputIDs[0]: {
519 expiration: time.Unix(1533489701, 0),
528 orphans: map[bc.Hash]*orphanTx{},
529 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
531 removeHashes: []*bc.Hash{
537 orphans: map[bc.Hash]*orphanTx{
539 expiration: time.Unix(1533489701, 0),
545 expiration: time.Unix(1533489701, 0),
551 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
552 testTxs[0].SpentOutputIDs[0]: {
554 expiration: time.Unix(1533489701, 0),
560 expiration: time.Unix(1533489701, 0),
569 orphans: map[bc.Hash]*orphanTx{
571 expiration: time.Unix(1533489701, 0),
577 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
578 testTxs[0].SpentOutputIDs[0]: {
580 expiration: time.Unix(1533489701, 0),
588 removeHashes: []*bc.Hash{
594 for i, c := range cases {
595 for _, hash := range c.removeHashes {
596 c.before.removeOrphan(hash)
598 if !testutil.DeepEqual(c.before, c.after) {
599 t.Errorf("case %d: got %v want %v", i, c.before, c.after)
604 type mockStore1 struct{}
606 func (s *mockStore1) GetBlockHeader(hash *bc.Hash) (*types.BlockHeader, error) {
607 panic("implement me")
610 func (s *mockStore1) GetCheckpoint(hash *bc.Hash) (*state.Checkpoint, error) {
611 panic("implement me")
614 func (s *mockStore1) GetCheckpointsByHeight(u uint64) ([]*state.Checkpoint, error) {
615 panic("implement me")
618 func (s *mockStore1) BlockExist(hash *bc.Hash) bool { return false }
619 func (s *mockStore1) GetBlock(*bc.Hash) (*types.Block, error) { return nil, nil }
620 func (s *mockStore1) GetStoreStatus() *BlockStoreState { return nil }
621 func (s *mockStore1) GetTransactionStatus(*bc.Hash) (*bc.TransactionStatus, error) { return nil, nil }
622 func (s *mockStore1) GetTransactionsUtxo(utxoView *state.UtxoViewpoint, tx []*bc.Tx) error {
623 for _, hash := range testTxs[2].SpentOutputIDs {
624 utxoView.Entries[hash] = &storage.UtxoEntry{IsCoinBase: false, Spent: false}
628 func (s *mockStore1) GetUtxo(*bc.Hash) (*storage.UtxoEntry, error) { return nil, nil }
629 func (s *mockStore1) LoadBlockIndex(uint64) (*state.BlockIndex, error) { return nil, nil }
630 func (s *mockStore1) SaveBlock(*types.Block, *bc.TransactionStatus) error { return nil }
631 func (s *mockStore1) SaveChainStatus(*state.BlockNode, *state.UtxoViewpoint) error { return nil }
633 func TestProcessTransaction(t *testing.T) {
635 pool: make(map[bc.Hash]*TxDesc),
636 utxo: make(map[bc.Hash]*types.Tx),
637 orphans: make(map[bc.Hash]*orphanTx),
638 orphansByPrev: make(map[bc.Hash]map[bc.Hash]*orphanTx),
639 store: &mockStore1{},
640 eventDispatcher: event.NewDispatcher(),
681 pool: map[bc.Hash]*TxDesc{
688 utxo: map[bc.Hash]*types.Tx{
689 *testTxs[2].ResultIds[0]: testTxs[2],
690 *testTxs[2].ResultIds[1]: testTxs[2],
700 for i, c := range cases {
701 txPool.ProcessTransaction(c.addTx.Tx, c.addTx.StatusFail, 0, 0)
702 for _, txD := range txPool.pool {
703 txD.Added = time.Time{}
705 for _, txD := range txPool.orphans {
706 txD.Added = time.Time{}
707 txD.expiration = time.Time{}
710 if !testutil.DeepEqual(txPool.pool, c.want.pool) {
711 t.Errorf("case %d: test ProcessTransaction pool mismatch got %s want %s", i, spew.Sdump(txPool.pool), spew.Sdump(c.want.pool))
713 if !testutil.DeepEqual(txPool.utxo, c.want.utxo) {
714 t.Errorf("case %d: test ProcessTransaction utxo mismatch got %s want %s", i, spew.Sdump(txPool.utxo), spew.Sdump(c.want.utxo))
716 if !testutil.DeepEqual(txPool.orphans, c.want.orphans) {
717 t.Errorf("case %d: test ProcessTransaction orphans mismatch got %s want %s", i, spew.Sdump(txPool.orphans), spew.Sdump(c.want.orphans))
719 if !testutil.DeepEqual(txPool.orphansByPrev, c.want.orphansByPrev) {
720 t.Errorf("case %d: test ProcessTransaction orphansByPrev mismatch got %s want %s", i, spew.Sdump(txPool.orphansByPrev), spew.Sdump(c.want.orphansByPrev))