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}),
76 type mockStore struct{}
78 func (s *mockStore) BlockExist(hash *bc.Hash) bool { return false }
79 func (s *mockStore) GetBlock(*bc.Hash) (*types.Block, error) { return nil, nil }
80 func (s *mockStore) GetStoreStatus() *BlockStoreState { return nil }
81 func (s *mockStore) GetTransactionStatus(*bc.Hash) (*bc.TransactionStatus, error) { return nil, nil }
82 func (s *mockStore) GetTransactionsUtxo(*state.UtxoViewpoint, []*bc.Tx) error { return nil }
83 func (s *mockStore) GetUtxo(*bc.Hash) (*storage.UtxoEntry, error) { return nil, nil }
84 func (s *mockStore) LoadBlockIndex(uint64) (*state.BlockIndex, error) { return nil, nil }
85 func (s *mockStore) SaveBlock(*types.Block, *bc.TransactionStatus) error { return nil }
86 func (s *mockStore) SaveChainStatus(*state.BlockNode, *state.UtxoViewpoint) error { return nil }
88 func TestAddOrphan(t *testing.T) {
93 requireParents []*bc.Hash
97 orphans: map[bc.Hash]*orphanTx{},
98 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
101 orphans: map[bc.Hash]*orphanTx{
108 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
109 testTxs[0].SpentOutputIDs[0]: {
118 addOrphan: &TxDesc{Tx: testTxs[0]},
119 requireParents: []*bc.Hash{&testTxs[0].SpentOutputIDs[0]},
123 orphans: map[bc.Hash]*orphanTx{
130 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
131 testTxs[0].SpentOutputIDs[0]: {
141 orphans: map[bc.Hash]*orphanTx{
153 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
154 testTxs[0].SpentOutputIDs[0]: {
168 addOrphan: &TxDesc{Tx: testTxs[1]},
169 requireParents: []*bc.Hash{&testTxs[1].SpentOutputIDs[0]},
173 orphans: map[bc.Hash]*orphanTx{},
174 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
177 orphans: map[bc.Hash]*orphanTx{
184 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
185 testTxs[2].SpentOutputIDs[1]: {
194 addOrphan: &TxDesc{Tx: testTxs[2]},
195 requireParents: []*bc.Hash{&testTxs[2].SpentOutputIDs[1]},
199 for i, c := range cases {
200 c.before.addOrphan(c.addOrphan, c.requireParents)
201 for _, orphan := range c.before.orphans {
202 orphan.expiration = time.Time{}
204 for _, orphans := range c.before.orphansByPrev {
205 for _, orphan := range orphans {
206 orphan.expiration = time.Time{}
209 if !testutil.DeepEqual(c.before, c.after) {
210 t.Errorf("case %d: got %v want %v", i, c.before, c.after)
215 func TestAddTransaction(t *testing.T) {
216 dispatcher := event.NewDispatcher()
224 pool: map[bc.Hash]*TxDesc{},
225 utxo: map[bc.Hash]*types.Tx{},
226 eventDispatcher: dispatcher,
229 pool: map[bc.Hash]*TxDesc{
235 utxo: map[bc.Hash]*types.Tx{
236 *testTxs[2].ResultIds[0]: testTxs[2],
237 *testTxs[2].ResultIds[1]: testTxs[2],
247 pool: map[bc.Hash]*TxDesc{},
248 utxo: map[bc.Hash]*types.Tx{},
249 eventDispatcher: dispatcher,
252 pool: map[bc.Hash]*TxDesc{
258 utxo: map[bc.Hash]*types.Tx{
259 *testTxs[2].ResultIds[0]: testTxs[2],
269 for i, c := range cases {
270 c.before.addTransaction(c.addTx)
271 for _, txD := range c.before.pool {
272 txD.Added = time.Time{}
274 if !testutil.DeepEqual(c.before.pool, c.after.pool) {
275 t.Errorf("case %d: got %v want %v", i, c.before.pool, c.after.pool)
277 if !testutil.DeepEqual(c.before.utxo, c.after.utxo) {
278 t.Errorf("case %d: got %v want %v", i, c.before.utxo, c.after.utxo)
283 func TestExpireOrphan(t *testing.T) {
285 orphans: map[bc.Hash]*orphanTx{
287 expiration: time.Unix(1533489701, 0),
293 expiration: time.Unix(1633489701, 0),
299 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
300 testTxs[0].SpentOutputIDs[0]: {
302 expiration: time.Unix(1533489701, 0),
308 expiration: time.Unix(1633489701, 0),
318 orphans: map[bc.Hash]*orphanTx{
320 expiration: time.Unix(1633489701, 0),
326 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
327 testTxs[0].SpentOutputIDs[0]: {
329 expiration: time.Unix(1633489701, 0),
338 before.ExpireOrphan(time.Unix(1633479701, 0))
339 if !testutil.DeepEqual(before, want) {
340 t.Errorf("got %v want %v", before, want)
344 func TestProcessOrphans(t *testing.T) {
345 dispatcher := event.NewDispatcher()
353 pool: map[bc.Hash]*TxDesc{},
354 utxo: map[bc.Hash]*types.Tx{},
355 eventDispatcher: dispatcher,
356 orphans: map[bc.Hash]*orphanTx{
363 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
364 testTxs[3].SpentOutputIDs[0]: {
374 pool: map[bc.Hash]*TxDesc{
380 utxo: map[bc.Hash]*types.Tx{
381 *testTxs[3].ResultIds[0]: testTxs[3],
382 *testTxs[3].ResultIds[1]: testTxs[3],
384 eventDispatcher: dispatcher,
385 orphans: map[bc.Hash]*orphanTx{},
386 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
388 processTx: &TxDesc{Tx: testTxs[2]},
392 pool: map[bc.Hash]*TxDesc{},
393 utxo: map[bc.Hash]*types.Tx{},
394 eventDispatcher: dispatcher,
395 orphans: map[bc.Hash]*orphanTx{
407 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
408 testTxs[3].SpentOutputIDs[0]: {
415 testTxs[4].SpentOutputIDs[0]: {
425 pool: map[bc.Hash]*TxDesc{
435 utxo: map[bc.Hash]*types.Tx{
436 *testTxs[3].ResultIds[0]: testTxs[3],
437 *testTxs[3].ResultIds[1]: testTxs[3],
438 *testTxs[4].ResultIds[0]: testTxs[4],
439 *testTxs[4].ResultIds[1]: testTxs[4],
441 eventDispatcher: dispatcher,
442 orphans: map[bc.Hash]*orphanTx{},
443 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
445 processTx: &TxDesc{Tx: testTxs[2]},
449 for i, c := range cases {
450 c.before.store = &mockStore{}
451 c.before.addTransaction(c.processTx)
452 c.before.processOrphans(c.processTx)
453 c.before.RemoveTransaction(&c.processTx.Tx.ID)
455 c.before.lastUpdated = 0
456 for _, txD := range c.before.pool {
457 txD.Added = time.Time{}
460 if !testutil.DeepEqual(c.before, c.after) {
461 t.Errorf("case %d: got %v want %v", i, c.before, c.after)
466 func TestRemoveOrphan(t *testing.T) {
470 removeHashes []*bc.Hash
474 orphans: map[bc.Hash]*orphanTx{
476 expiration: time.Unix(1533489701, 0),
482 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
483 testTxs[0].SpentOutputIDs[0]: {
485 expiration: time.Unix(1533489701, 0),
494 orphans: map[bc.Hash]*orphanTx{},
495 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
497 removeHashes: []*bc.Hash{
503 orphans: map[bc.Hash]*orphanTx{
505 expiration: time.Unix(1533489701, 0),
511 expiration: time.Unix(1533489701, 0),
517 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
518 testTxs[0].SpentOutputIDs[0]: {
520 expiration: time.Unix(1533489701, 0),
526 expiration: time.Unix(1533489701, 0),
535 orphans: map[bc.Hash]*orphanTx{
537 expiration: time.Unix(1533489701, 0),
543 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
544 testTxs[0].SpentOutputIDs[0]: {
546 expiration: time.Unix(1533489701, 0),
554 removeHashes: []*bc.Hash{
560 for i, c := range cases {
561 for _, hash := range c.removeHashes {
562 c.before.removeOrphan(hash)
564 if !testutil.DeepEqual(c.before, c.after) {
565 t.Errorf("case %d: got %v want %v", i, c.before, c.after)
570 type mockStore1 struct{}
572 func (s *mockStore1) BlockExist(hash *bc.Hash) bool { return false }
573 func (s *mockStore1) GetBlock(*bc.Hash) (*types.Block, error) { return nil, nil }
574 func (s *mockStore1) GetStoreStatus() *BlockStoreState { return nil }
575 func (s *mockStore1) GetTransactionStatus(*bc.Hash) (*bc.TransactionStatus, error) { return nil, nil }
576 func (s *mockStore1) GetTransactionsUtxo(utxoView *state.UtxoViewpoint, tx []*bc.Tx) error {
577 for _, hash := range testTxs[2].SpentOutputIDs {
578 utxoView.Entries[hash] = &storage.UtxoEntry{IsCoinBase: false, Spent: false}
582 func (s *mockStore1) GetUtxo(*bc.Hash) (*storage.UtxoEntry, error) { return nil, nil }
583 func (s *mockStore1) LoadBlockIndex(uint64) (*state.BlockIndex, error) { return nil, nil }
584 func (s *mockStore1) SaveBlock(*types.Block, *bc.TransactionStatus) error { return nil }
585 func (s *mockStore1) SaveChainStatus(*state.BlockNode, *state.UtxoViewpoint) error { return nil }
587 func TestProcessTransaction(t *testing.T) {
589 pool: make(map[bc.Hash]*TxDesc),
590 utxo: make(map[bc.Hash]*types.Tx),
591 orphans: make(map[bc.Hash]*orphanTx),
592 orphansByPrev: make(map[bc.Hash]map[bc.Hash]*orphanTx),
593 store: &mockStore1{},
594 eventDispatcher: event.NewDispatcher(),
611 pool: map[bc.Hash]*TxDesc{
618 utxo: map[bc.Hash]*types.Tx{
619 *testTxs[2].ResultIds[0]: testTxs[2],
620 *testTxs[2].ResultIds[1]: testTxs[2],
630 for i, c := range cases {
631 txPool.ProcessTransaction(c.addTx.Tx, c.addTx.StatusFail, 0, 0)
632 for _, txD := range txPool.pool {
633 txD.Added = time.Time{}
635 for _, txD := range txPool.orphans {
636 txD.Added = time.Time{}
637 txD.expiration = time.Time{}
640 if !testutil.DeepEqual(txPool.pool, c.want.pool) {
641 t.Errorf("case %d: test ProcessTransaction pool mismatch got %s want %s", i, spew.Sdump(txPool.pool), spew.Sdump(c.want.pool))
643 if !testutil.DeepEqual(txPool.utxo, c.want.utxo) {
644 t.Errorf("case %d: test ProcessTransaction utxo mismatch got %s want %s", i, spew.Sdump(txPool.utxo), spew.Sdump(c.want.utxo))
646 if !testutil.DeepEqual(txPool.orphans, c.want.orphans) {
647 t.Errorf("case %d: test ProcessTransaction orphans mismatch got %s want %s", i, spew.Sdump(txPool.orphans), spew.Sdump(c.want.orphans))
649 if !testutil.DeepEqual(txPool.orphansByPrev, c.want.orphansByPrev) {
650 t.Errorf("case %d: test ProcessTransaction orphansByPrev mismatch got %s want %s", i, spew.Sdump(txPool.orphansByPrev), spew.Sdump(c.want.orphansByPrev))