7 "github.com/vapor/consensus"
8 "github.com/vapor/database/storage"
9 "github.com/vapor/protocol/bc"
10 "github.com/vapor/protocol/bc/types"
11 "github.com/vapor/protocol/state"
12 "github.com/vapor/testutil"
15 var testTxs = []*types.Tx{
16 types.NewTx(types.TxData{
18 Inputs: []*types.TxInput{
19 types.NewSpendInput(nil, bc.NewHash([32]byte{0x01}), *consensus.BTMAssetID, 1, 1, []byte{0x51}),
21 Outputs: []*types.TxOutput{
22 types.NewTxOutput(*consensus.BTMAssetID, 1, []byte{0x6a}),
25 types.NewTx(types.TxData{
27 Inputs: []*types.TxInput{
28 types.NewSpendInput(nil, bc.NewHash([32]byte{0x01}), *consensus.BTMAssetID, 1, 1, []byte{0x51}),
30 Outputs: []*types.TxOutput{
31 types.NewTxOutput(*consensus.BTMAssetID, 1, []byte{0x6b}),
34 types.NewTx(types.TxData{
37 Inputs: []*types.TxInput{
38 types.NewSpendInput(nil, bc.NewHash([32]byte{0x01}), *consensus.BTMAssetID, 1, 1, []byte{0x51}),
39 types.NewSpendInput(nil, bc.NewHash([32]byte{0x02}), bc.NewAssetID([32]byte{0xa1}), 4, 1, []byte{0x51}),
41 Outputs: []*types.TxOutput{
42 types.NewTxOutput(*consensus.BTMAssetID, 1, []byte{0x6b}),
43 types.NewTxOutput(bc.NewAssetID([32]byte{0xa1}), 4, []byte{0x61}),
46 types.NewTx(types.TxData{
48 Inputs: []*types.TxInput{
49 types.NewSpendInput(nil, testutil.MustDecodeHash("dbea684b5c5153ed7729669a53d6c59574f26015a3e1eb2a0e8a1c645425a764"), bc.NewAssetID([32]byte{0xa1}), 4, 1, []byte{0x61}),
51 Outputs: []*types.TxOutput{
52 types.NewTxOutput(bc.NewAssetID([32]byte{0xa1}), 3, []byte{0x62}),
53 types.NewTxOutput(bc.NewAssetID([32]byte{0xa1}), 1, []byte{0x63}),
56 types.NewTx(types.TxData{
58 Inputs: []*types.TxInput{
59 types.NewSpendInput(nil, testutil.MustDecodeHash("d84d0be0fd08e7341f2d127749bb0d0844d4560f53bd54861cee9981fd922cad"), bc.NewAssetID([32]byte{0xa1}), 3, 0, []byte{0x62}),
61 Outputs: []*types.TxOutput{
62 types.NewTxOutput(bc.NewAssetID([32]byte{0xa1}), 2, []byte{0x64}),
63 types.NewTxOutput(bc.NewAssetID([32]byte{0xa1}), 1, []byte{0x65}),
68 type mockStore struct{}
70 func (s *mockStore) BlockExist(hash *bc.Hash) bool { return false }
71 func (s *mockStore) GetBlock(*bc.Hash) (*types.Block, error) { return nil, nil }
72 func (s *mockStore) GetStoreStatus() *BlockStoreState { return nil }
73 func (s *mockStore) GetTransactionStatus(*bc.Hash) (*bc.TransactionStatus, error) { return nil, nil }
74 func (s *mockStore) GetTransactionsUtxo(*state.UtxoViewpoint, []*bc.Tx) error { return nil }
75 func (s *mockStore) GetUtxo(*bc.Hash) (*storage.UtxoEntry, error) { return nil, nil }
76 func (s *mockStore) LoadBlockIndex(uint64) (*state.BlockIndex, error) { return nil, nil }
77 func (s *mockStore) SaveBlock(*types.Block, *bc.TransactionStatus) error { return nil }
78 func (s *mockStore) SaveChainStatus(*state.BlockNode, *state.UtxoViewpoint) error { return nil }
79 func (s *mockStore) IsWithdrawSpent(hash *bc.Hash) bool { return true }
80 func (s *mockStore) SetWithdrawSpent(hash *bc.Hash) {}
82 func TestAddOrphan(t *testing.T) {
87 requireParents []*bc.Hash
91 orphans: map[bc.Hash]*orphanTx{},
92 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
95 orphans: map[bc.Hash]*orphanTx{
96 testTxs[0].ID: &orphanTx{
102 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
103 testTxs[0].SpentOutputIDs[0]: map[bc.Hash]*orphanTx{
104 testTxs[0].ID: &orphanTx{
112 addOrphan: &TxDesc{Tx: testTxs[0]},
113 requireParents: []*bc.Hash{&testTxs[0].SpentOutputIDs[0]},
117 orphans: map[bc.Hash]*orphanTx{
118 testTxs[0].ID: &orphanTx{
124 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
125 testTxs[0].SpentOutputIDs[0]: map[bc.Hash]*orphanTx{
126 testTxs[0].ID: &orphanTx{
135 orphans: map[bc.Hash]*orphanTx{
136 testTxs[0].ID: &orphanTx{
141 testTxs[1].ID: &orphanTx{
147 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
148 testTxs[0].SpentOutputIDs[0]: map[bc.Hash]*orphanTx{
149 testTxs[0].ID: &orphanTx{
154 testTxs[1].ID: &orphanTx{
162 addOrphan: &TxDesc{Tx: testTxs[1]},
163 requireParents: []*bc.Hash{&testTxs[1].SpentOutputIDs[0]},
167 orphans: map[bc.Hash]*orphanTx{},
168 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
171 orphans: map[bc.Hash]*orphanTx{
172 testTxs[2].ID: &orphanTx{
178 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
179 testTxs[2].SpentOutputIDs[1]: map[bc.Hash]*orphanTx{
180 testTxs[2].ID: &orphanTx{
188 addOrphan: &TxDesc{Tx: testTxs[2]},
189 requireParents: []*bc.Hash{&testTxs[2].SpentOutputIDs[1]},
193 for i, c := range cases {
194 c.before.addOrphan(c.addOrphan, c.requireParents)
195 for _, orphan := range c.before.orphans {
196 orphan.expiration = time.Time{}
198 for _, orphans := range c.before.orphansByPrev {
199 for _, orphan := range orphans {
200 orphan.expiration = time.Time{}
203 if !testutil.DeepEqual(c.before, c.after) {
204 t.Errorf("case %d: got %v want %v", i, c.before, c.after)
209 func TestAddTransaction(t *testing.T) {
217 pool: map[bc.Hash]*TxDesc{},
218 utxo: map[bc.Hash]*types.Tx{},
219 msgCh: make(chan *TxPoolMsg, 1),
222 pool: map[bc.Hash]*TxDesc{
223 testTxs[2].ID: &TxDesc{
228 utxo: map[bc.Hash]*types.Tx{
229 *testTxs[2].ResultIds[0]: testTxs[2],
230 *testTxs[2].ResultIds[1]: testTxs[2],
240 pool: map[bc.Hash]*TxDesc{},
241 utxo: map[bc.Hash]*types.Tx{},
242 msgCh: make(chan *TxPoolMsg, 1),
245 pool: map[bc.Hash]*TxDesc{
246 testTxs[2].ID: &TxDesc{
251 utxo: map[bc.Hash]*types.Tx{
252 *testTxs[2].ResultIds[0]: testTxs[2],
262 for i, c := range cases {
263 c.before.addTransaction(c.addTx)
264 for _, txD := range c.before.pool {
265 txD.Added = time.Time{}
267 if !testutil.DeepEqual(c.before.pool, c.after.pool) {
268 t.Errorf("case %d: got %v want %v", i, c.before.pool, c.after.pool)
270 if !testutil.DeepEqual(c.before.utxo, c.after.utxo) {
271 t.Errorf("case %d: got %v want %v", i, c.before.utxo, c.after.utxo)
276 func TestExpireOrphan(t *testing.T) {
278 orphans: map[bc.Hash]*orphanTx{
279 testTxs[0].ID: &orphanTx{
280 expiration: time.Unix(1533489701, 0),
285 testTxs[1].ID: &orphanTx{
286 expiration: time.Unix(1633489701, 0),
292 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
293 testTxs[0].SpentOutputIDs[0]: map[bc.Hash]*orphanTx{
294 testTxs[0].ID: &orphanTx{
295 expiration: time.Unix(1533489701, 0),
300 testTxs[1].ID: &orphanTx{
301 expiration: time.Unix(1633489701, 0),
311 orphans: map[bc.Hash]*orphanTx{
312 testTxs[1].ID: &orphanTx{
313 expiration: time.Unix(1633489701, 0),
319 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
320 testTxs[0].SpentOutputIDs[0]: map[bc.Hash]*orphanTx{
321 testTxs[1].ID: &orphanTx{
322 expiration: time.Unix(1633489701, 0),
331 before.ExpireOrphan(time.Unix(1633479701, 0))
332 if !testutil.DeepEqual(before, want) {
333 t.Errorf("got %v want %v", before, want)
337 func TestProcessOrphans(t *testing.T) {
345 pool: map[bc.Hash]*TxDesc{},
346 utxo: map[bc.Hash]*types.Tx{},
347 orphans: map[bc.Hash]*orphanTx{
348 testTxs[3].ID: &orphanTx{
354 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
355 testTxs[3].SpentOutputIDs[0]: map[bc.Hash]*orphanTx{
356 testTxs[3].ID: &orphanTx{
363 msgCh: make(chan *TxPoolMsg, 10),
366 pool: map[bc.Hash]*TxDesc{
367 testTxs[3].ID: &TxDesc{
372 utxo: map[bc.Hash]*types.Tx{
373 *testTxs[3].ResultIds[0]: testTxs[3],
374 *testTxs[3].ResultIds[1]: testTxs[3],
376 orphans: map[bc.Hash]*orphanTx{},
377 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
379 processTx: &TxDesc{Tx: testTxs[2]},
383 pool: map[bc.Hash]*TxDesc{},
384 utxo: map[bc.Hash]*types.Tx{},
385 orphans: map[bc.Hash]*orphanTx{
386 testTxs[3].ID: &orphanTx{
391 testTxs[4].ID: &orphanTx{
397 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
398 testTxs[3].SpentOutputIDs[0]: map[bc.Hash]*orphanTx{
399 testTxs[3].ID: &orphanTx{
405 testTxs[4].SpentOutputIDs[0]: map[bc.Hash]*orphanTx{
406 testTxs[4].ID: &orphanTx{
413 msgCh: make(chan *TxPoolMsg, 10),
416 pool: map[bc.Hash]*TxDesc{
417 testTxs[3].ID: &TxDesc{
421 testTxs[4].ID: &TxDesc{
426 utxo: map[bc.Hash]*types.Tx{
427 *testTxs[3].ResultIds[0]: testTxs[3],
428 *testTxs[3].ResultIds[1]: testTxs[3],
429 *testTxs[4].ResultIds[0]: testTxs[4],
430 *testTxs[4].ResultIds[1]: testTxs[4],
432 orphans: map[bc.Hash]*orphanTx{},
433 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
435 processTx: &TxDesc{Tx: testTxs[2]},
439 for i, c := range cases {
440 c.before.store = &mockStore{}
441 c.before.addTransaction(c.processTx)
442 c.before.processOrphans(c.processTx)
443 c.before.RemoveTransaction(&c.processTx.Tx.ID)
446 c.before.lastUpdated = 0
447 for _, txD := range c.before.pool {
448 txD.Added = time.Time{}
451 if !testutil.DeepEqual(c.before, c.after) {
452 t.Errorf("case %d: got %v want %v", i, c.before, c.after)
457 func TestRemoveOrphan(t *testing.T) {
461 removeHashes []*bc.Hash
465 orphans: map[bc.Hash]*orphanTx{
466 testTxs[0].ID: &orphanTx{
467 expiration: time.Unix(1533489701, 0),
473 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
474 testTxs[0].SpentOutputIDs[0]: map[bc.Hash]*orphanTx{
475 testTxs[0].ID: &orphanTx{
476 expiration: time.Unix(1533489701, 0),
485 orphans: map[bc.Hash]*orphanTx{},
486 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{},
488 removeHashes: []*bc.Hash{
494 orphans: map[bc.Hash]*orphanTx{
495 testTxs[0].ID: &orphanTx{
496 expiration: time.Unix(1533489701, 0),
501 testTxs[1].ID: &orphanTx{
502 expiration: time.Unix(1533489701, 0),
508 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
509 testTxs[0].SpentOutputIDs[0]: map[bc.Hash]*orphanTx{
510 testTxs[0].ID: &orphanTx{
511 expiration: time.Unix(1533489701, 0),
516 testTxs[1].ID: &orphanTx{
517 expiration: time.Unix(1533489701, 0),
526 orphans: map[bc.Hash]*orphanTx{
527 testTxs[0].ID: &orphanTx{
528 expiration: time.Unix(1533489701, 0),
534 orphansByPrev: map[bc.Hash]map[bc.Hash]*orphanTx{
535 testTxs[0].SpentOutputIDs[0]: map[bc.Hash]*orphanTx{
536 testTxs[0].ID: &orphanTx{
537 expiration: time.Unix(1533489701, 0),
545 removeHashes: []*bc.Hash{
551 for i, c := range cases {
552 for _, hash := range c.removeHashes {
553 c.before.removeOrphan(hash)
555 if !testutil.DeepEqual(c.before, c.after) {
556 t.Errorf("case %d: got %v want %v", i, c.before, c.after)