7 "github.com/davecgh/go-spew/spew"
9 "github.com/vapor/consensus"
10 "github.com/vapor/database/storage"
11 "github.com/vapor/event"
12 "github.com/vapor/protocol/bc"
13 "github.com/vapor/protocol/bc/types"
14 "github.com/vapor/protocol/state"
15 "github.com/vapor/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.NewIntraChainOutput(*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.NewIntraChainOutput(*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.NewIntraChainOutput(*consensus.BTMAssetID, 1, []byte{0x6b}),
49 types.NewIntraChainOutput(bc.NewAssetID([32]byte{0xa1}), 4, []byte{0x61}),
53 types.NewTx(types.TxData{
56 Inputs: []*types.TxInput{
57 types.NewSpendInput(nil, testutil.MustDecodeHash("7d3f8e8474775f9fab2a7370529f0569a2199b22a5a83d235a036f50de3e8c84"), bc.NewAssetID([32]byte{0xa1}), 4, 1, []byte{0x61}),
59 Outputs: []*types.TxOutput{
60 types.NewIntraChainOutput(bc.NewAssetID([32]byte{0xa1}), 3, []byte{0x62}),
61 types.NewIntraChainOutput(bc.NewAssetID([32]byte{0xa1}), 1, []byte{0x63}),
65 types.NewTx(types.TxData{
67 Inputs: []*types.TxInput{
68 types.NewSpendInput(nil, testutil.MustDecodeHash("9a26cde504a5d7190dbed119280276f9816d9c2b7d20c768b312be57930fe840"), bc.NewAssetID([32]byte{0xa1}), 3, 0, []byte{0x62}),
70 Outputs: []*types.TxOutput{
71 types.NewIntraChainOutput(bc.NewAssetID([32]byte{0xa1}), 2, []byte{0x64}),
72 types.NewIntraChainOutput(bc.NewAssetID([32]byte{0xa1}), 1, []byte{0x65}),
76 types.NewTx(types.TxData{
78 Inputs: []*types.TxInput{
79 types.NewSpendInput(nil, bc.NewHash([32]byte{0x01}), *consensus.BTMAssetID, 1, 1, []byte{0x51}),
81 Outputs: []*types.TxOutput{
82 types.NewIntraChainOutput(*consensus.BTMAssetID, 0, []byte{0x51}),
86 types.NewTx(types.TxData{
88 Inputs: []*types.TxInput{
89 types.NewSpendInput(nil, bc.NewHash([32]byte{0x01}), *consensus.BTMAssetID, 3, 1, []byte{0x51}),
90 types.NewSpendInput(nil, testutil.MustDecodeHash("9a26cde504a5d7190dbed119280276f9816d9c2b7d20c768b312be57930fe840"), bc.NewAssetID([32]byte{0xa1}), 3, 0, []byte{0x62}),
92 Outputs: []*types.TxOutput{
93 types.NewIntraChainOutput(*consensus.BTMAssetID, 2, []byte{0x51}),
94 types.NewIntraChainOutput(bc.NewAssetID([32]byte{0xa1}), 0, []byte{0x65}),
99 type mockStore struct{}
101 func (s *mockStore) BlockExist(hash *bc.Hash) bool { return false }
102 func (s *mockStore) GetBlock(*bc.Hash) (*types.Block, error) { return nil, nil }
103 func (s *mockStore) GetStoreStatus() *BlockStoreState { return nil }
104 func (s *mockStore) GetTransactionStatus(*bc.Hash) (*bc.TransactionStatus, error) { return nil, nil }
105 func (s *mockStore) GetTransactionsUtxo(*state.UtxoViewpoint, []*bc.Tx) error { return nil }
106 func (s *mockStore) GetUtxo(*bc.Hash) (*storage.UtxoEntry, error) { return nil, nil }
107 func (s *mockStore) LoadBlockIndex(uint64) (*state.BlockIndex, error) { return nil, nil }
108 func (s *mockStore) SaveBlock(*types.Block, *bc.TransactionStatus) error { return nil }
109 func (s *mockStore) SaveChainStatus(*state.BlockNode, *state.UtxoViewpoint) error { return nil }
111 func TestAddOrphan(t *testing.T) {
116 requireParents []*bc.Hash
120 orphans: map[bc.Hash]*orphanTx{},
121 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
124 orphans: map[bc.Hash]*orphanTx{
131 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
132 testTxs[0].SpentOutputIDs[0]: {
141 addOrphan: &TxDesc{Tx: testTxs[0]},
142 requireParents: []*bc.Hash{&testTxs[0].SpentOutputIDs[0]},
146 orphans: map[bc.Hash]*orphanTx{
153 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
154 testTxs[0].SpentOutputIDs[0]: {
164 orphans: map[bc.Hash]*orphanTx{
176 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
177 testTxs[0].SpentOutputIDs[0]: {
191 addOrphan: &TxDesc{Tx: testTxs[1]},
192 requireParents: []*bc.Hash{&testTxs[1].SpentOutputIDs[0]},
196 orphans: map[bc.Hash]*orphanTx{},
197 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
200 orphans: map[bc.Hash]*orphanTx{
207 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
208 testTxs[2].SpentOutputIDs[1]: {
217 addOrphan: &TxDesc{Tx: testTxs[2]},
218 requireParents: []*bc.Hash{&testTxs[2].SpentOutputIDs[1]},
222 for i, c := range cases {
223 c.before.addOrphan(c.addOrphan, c.requireParents)
224 for _, orphan := range c.before.orphans {
225 orphan.expiration = time.Time{}
227 for _, orphans := range c.before.orphansByPrev {
228 for _, orphan := range orphans {
229 orphan.expiration = time.Time{}
232 if !testutil.DeepEqual(c.before, c.after) {
233 t.Errorf("case %d: got %v want %v", i, c.before, c.after)
238 func TestAddTransaction(t *testing.T) {
239 dispatcher := event.NewDispatcher()
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],
260 *testTxs[2].ResultIds[1]: testTxs[2],
270 pool: map[bc.Hash]*TxDesc{},
271 utxo: map[bc.Hash]*types.Tx{},
272 eventDispatcher: dispatcher,
275 pool: map[bc.Hash]*TxDesc{
281 utxo: map[bc.Hash]*types.Tx{
282 *testTxs[2].ResultIds[0]: testTxs[2],
292 for i, c := range cases {
293 c.before.addTransaction(c.addTx)
294 for _, txD := range c.before.pool {
295 txD.Added = time.Time{}
297 if !testutil.DeepEqual(c.before.pool, c.after.pool) {
298 t.Errorf("case %d: got %v want %v", i, c.before.pool, c.after.pool)
300 if !testutil.DeepEqual(c.before.utxo, c.after.utxo) {
301 t.Errorf("case %d: got %v want %v", i, c.before.utxo, c.after.utxo)
306 func TestExpireOrphan(t *testing.T) {
308 orphans: map[bc.Hash]*orphanTx{
310 expiration: time.Unix(1533489701, 0),
316 expiration: time.Unix(1633489701, 0),
322 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
323 testTxs[0].SpentOutputIDs[0]: {
325 expiration: time.Unix(1533489701, 0),
331 expiration: time.Unix(1633489701, 0),
341 orphans: map[bc.Hash]*orphanTx{
343 expiration: time.Unix(1633489701, 0),
349 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
350 testTxs[0].SpentOutputIDs[0]: {
352 expiration: time.Unix(1633489701, 0),
361 before.ExpireOrphan(time.Unix(1633479701, 0))
362 if !testutil.DeepEqual(before, want) {
363 t.Errorf("got %v want %v", before, want)
367 func TestProcessOrphans(t *testing.T) {
368 dispatcher := event.NewDispatcher()
376 pool: map[bc.Hash]*TxDesc{},
377 utxo: map[bc.Hash]*types.Tx{},
378 eventDispatcher: dispatcher,
379 orphans: map[bc.Hash]*orphanTx{
386 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
387 testTxs[3].SpentOutputIDs[0]: {
397 pool: map[bc.Hash]*TxDesc{
403 utxo: map[bc.Hash]*types.Tx{
404 *testTxs[3].ResultIds[0]: testTxs[3],
405 *testTxs[3].ResultIds[1]: testTxs[3],
407 eventDispatcher: dispatcher,
408 orphans: map[bc.Hash]*orphanTx{},
409 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
411 processTx: &TxDesc{Tx: testTxs[2]},
415 pool: map[bc.Hash]*TxDesc{},
416 utxo: map[bc.Hash]*types.Tx{},
417 eventDispatcher: dispatcher,
418 orphans: map[bc.Hash]*orphanTx{
430 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
431 testTxs[3].SpentOutputIDs[0]: {
438 testTxs[4].SpentOutputIDs[0]: {
448 pool: map[bc.Hash]*TxDesc{
458 utxo: map[bc.Hash]*types.Tx{
459 *testTxs[3].ResultIds[0]: testTxs[3],
460 *testTxs[3].ResultIds[1]: testTxs[3],
461 *testTxs[4].ResultIds[0]: testTxs[4],
462 *testTxs[4].ResultIds[1]: testTxs[4],
464 eventDispatcher: dispatcher,
465 orphans: map[bc.Hash]*orphanTx{},
466 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
468 processTx: &TxDesc{Tx: testTxs[2]},
472 for i, c := range cases {
473 c.before.store = &mockStore{}
474 c.before.addTransaction(c.processTx)
475 c.before.processOrphans(c.processTx)
476 c.before.RemoveTransaction(&c.processTx.Tx.ID)
478 c.before.lastUpdated = 0
479 for _, txD := range c.before.pool {
480 txD.Added = time.Time{}
483 if !testutil.DeepEqual(c.before, c.after) {
484 t.Errorf("case %d: got %v want %v", i, c.before, c.after)
489 func TestRemoveOrphan(t *testing.T) {
493 removeHashes []*bc.Hash
497 orphans: map[bc.Hash]*orphanTx{
499 expiration: time.Unix(1533489701, 0),
505 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
506 testTxs[0].SpentOutputIDs[0]: {
508 expiration: time.Unix(1533489701, 0),
517 orphans: map[bc.Hash]*orphanTx{},
518 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
520 removeHashes: []*bc.Hash{
526 orphans: map[bc.Hash]*orphanTx{
528 expiration: time.Unix(1533489701, 0),
534 expiration: time.Unix(1533489701, 0),
540 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
541 testTxs[0].SpentOutputIDs[0]: {
543 expiration: time.Unix(1533489701, 0),
549 expiration: time.Unix(1533489701, 0),
558 orphans: map[bc.Hash]*orphanTx{
560 expiration: time.Unix(1533489701, 0),
566 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
567 testTxs[0].SpentOutputIDs[0]: {
569 expiration: time.Unix(1533489701, 0),
577 removeHashes: []*bc.Hash{
583 for i, c := range cases {
584 for _, hash := range c.removeHashes {
585 c.before.removeOrphan(hash)
587 if !testutil.DeepEqual(c.before, c.after) {
588 t.Errorf("case %d: got %v want %v", i, c.before, c.after)
593 type mockStore1 struct{}
595 func (s *mockStore1) BlockExist(hash *bc.Hash) bool { return false }
596 func (s *mockStore1) GetBlock(*bc.Hash) (*types.Block, error) { return nil, nil }
597 func (s *mockStore1) GetStoreStatus() *BlockStoreState { return nil }
598 func (s *mockStore1) GetTransactionStatus(*bc.Hash) (*bc.TransactionStatus, error) { return nil, nil }
599 func (s *mockStore1) GetTransactionsUtxo(utxoView *state.UtxoViewpoint, tx []*bc.Tx) error {
600 for _, hash := range testTxs[2].SpentOutputIDs {
601 utxoView.Entries[hash] = &storage.UtxoEntry{IsCoinBase: false, Spent: false}
605 func (s *mockStore1) GetUtxo(*bc.Hash) (*storage.UtxoEntry, error) { return nil, nil }
606 func (s *mockStore1) LoadBlockIndex(uint64) (*state.BlockIndex, error) { return nil, nil }
607 func (s *mockStore1) SaveBlock(*types.Block, *bc.TransactionStatus) error { return nil }
608 func (s *mockStore1) SaveChainStatus(*state.BlockNode, *state.UtxoViewpoint) error { return nil }
610 func TestProcessTransaction(t *testing.T) {
612 pool: make(map[bc.Hash]*TxDesc),
613 utxo: make(map[bc.Hash]*types.Tx),
614 orphans: make(map[bc.Hash]*orphanTx),
615 orphansByPrev: make(map[bc.Hash]map[bc.Hash]*orphanTx),
616 store: &mockStore1{},
617 eventDispatcher: event.NewDispatcher(),
658 pool: map[bc.Hash]*TxDesc{
665 utxo: map[bc.Hash]*types.Tx{
666 *testTxs[2].ResultIds[0]: testTxs[2],
667 *testTxs[2].ResultIds[1]: testTxs[2],
677 for i, c := range cases {
678 txPool.ProcessTransaction(c.addTx.Tx, c.addTx.StatusFail, 0, 0)
679 for _, txD := range txPool.pool {
680 txD.Added = time.Time{}
682 for _, txD := range txPool.orphans {
683 txD.Added = time.Time{}
684 txD.expiration = time.Time{}
687 if !testutil.DeepEqual(txPool.pool, c.want.pool) {
688 t.Errorf("case %d: test ProcessTransaction pool mismatch got %s want %s", i, spew.Sdump(txPool.pool), spew.Sdump(c.want.pool))
690 if !testutil.DeepEqual(txPool.utxo, c.want.utxo) {
691 t.Errorf("case %d: test ProcessTransaction utxo mismatch got %s want %s", i, spew.Sdump(txPool.utxo), spew.Sdump(c.want.utxo))
693 if !testutil.DeepEqual(txPool.orphans, c.want.orphans) {
694 t.Errorf("case %d: test ProcessTransaction orphans mismatch got %s want %s", i, spew.Sdump(txPool.orphans), spew.Sdump(c.want.orphans))
696 if !testutil.DeepEqual(txPool.orphansByPrev, c.want.orphansByPrev) {
697 t.Errorf("case %d: test ProcessTransaction orphansByPrev mismatch got %s want %s", i, spew.Sdump(txPool.orphansByPrev), spew.Sdump(c.want.orphansByPrev))