@rosen-bridge/tx-pot 1.0.3 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/README.md +8 -8
  3. package/dist/db/entities/transactionEntity.d.ts +15 -0
  4. package/dist/db/entities/{TransactionEntity.d.ts.map → transactionEntity.d.ts.map} +1 -1
  5. package/dist/db/entities/transactionEntity.js +81 -0
  6. package/dist/db/migrations/index.d.ts +3 -3
  7. package/dist/db/migrations/index.js +3 -3
  8. package/dist/db/migrations/postgres/1706350644686-migration.d.ts +4 -4
  9. package/dist/db/migrations/postgres/1706350644686-migration.d.ts.map +1 -1
  10. package/dist/db/migrations/postgres/1706350644686-migration.js +8 -8
  11. package/dist/db/migrations/sqlite/1706007154531-migration.d.ts +4 -4
  12. package/dist/db/migrations/sqlite/1706007154531-migration.d.ts.map +1 -1
  13. package/dist/db/migrations/sqlite/1706007154531-migration.js +8 -8
  14. package/dist/index.d.ts +4 -4
  15. package/dist/index.js +4 -4
  16. package/dist/network/abstractPotChainManager.d.ts +36 -0
  17. package/dist/network/{AbstractPotChainManager.d.ts.map → abstractPotChainManager.d.ts.map} +1 -1
  18. package/dist/network/{AbstractPotChainManager.js → abstractPotChainManager.js} +3 -2
  19. package/dist/transaction/txPot.d.ts +212 -0
  20. package/dist/transaction/txPot.d.ts.map +1 -0
  21. package/dist/transaction/{TxPot.js → txPot.js} +2 -2
  22. package/dist/transaction/types.d.ts +21 -24
  23. package/dist/transaction/types.d.ts.map +1 -1
  24. package/dist/transaction/types.js +13 -13
  25. package/dist/transaction/utils.d.ts +2 -4
  26. package/dist/transaction/utils.d.ts.map +1 -1
  27. package/dist/transaction/utils.js +48 -43
  28. package/package.json +25 -21
  29. package/.eslintignore +0 -1
  30. package/dist/db/entities/TransactionEntity.d.ts +0 -15
  31. package/dist/db/entities/TransactionEntity.js +0 -125
  32. package/dist/network/AbstractPotChainManager.d.ts +0 -39
  33. package/dist/transaction/TxPot.d.ts +0 -284
  34. package/dist/transaction/TxPot.d.ts.map +0 -1
  35. package/dist/tsconfig.tsbuildinfo +0 -1
  36. package/lib/db/entities/TransactionEntity.ts +0 -44
  37. package/lib/db/migrations/index.ts +0 -7
  38. package/lib/db/migrations/postgres/1706350644686-migration.ts +0 -31
  39. package/lib/db/migrations/sqlite/1706007154531-migration.ts +0 -31
  40. package/lib/index.ts +0 -5
  41. package/lib/network/AbstractPotChainManager.ts +0 -44
  42. package/lib/transaction/TxPot.ts +0 -728
  43. package/lib/transaction/types.ts +0 -46
  44. package/lib/transaction/utils.ts +0 -59
  45. package/tests/.gitkeep +0 -0
  46. package/tests/db/dataSource.mock.ts +0 -18
  47. package/tests/network/TestPotChainManager.ts +0 -23
  48. package/tests/transaction/TestTxPot.ts +0 -32
  49. package/tests/transaction/TxPot.spec.ts +0 -1881
  50. package/tests/transaction/testData.ts +0 -84
  51. package/tsconfig.build.json +0 -8
  52. package/tsconfig.build.tsbuildinfo +0 -1
  53. package/tsconfig.json +0 -9
  54. package/vitest.config.ts +0 -13
@@ -1,1881 +0,0 @@
1
- import { Repository } from 'typeorm';
2
- import { mockDataSource } from '../db/dataSource.mock';
3
- import {
4
- CallbackFunction,
5
- TransactionEntity,
6
- TransactionStatus,
7
- ValidatorFunction,
8
- } from '../../lib';
9
- import { TestTxPot } from './TestTxPot';
10
- import * as testData from './testData';
11
- import { TestPotChainManager } from '../network/TestPotChainManager';
12
-
13
- describe('TxPot', () => {
14
- let txRepository: Repository<TransactionEntity>;
15
- let txPot: TestTxPot;
16
-
17
- beforeAll(() => {
18
- vi.useFakeTimers();
19
- vi.setSystemTime(new Date(testData.currentTimeStamp));
20
- });
21
-
22
- beforeEach(async () => {
23
- // init TxPot
24
- const dataSource = await mockDataSource();
25
- txPot = TestTxPot.setup(dataSource);
26
- txRepository = dataSource.getRepository(TransactionEntity);
27
- });
28
-
29
- afterAll(() => {
30
- vi.useRealTimers();
31
- });
32
-
33
- describe('unregisterValidator', () => {
34
- /**
35
- * @target TxPot.unregisterValidator should remove registered validator successfully
36
- * @dependencies
37
- * @scenario
38
- * - register a validator function
39
- * - run test
40
- * - check registered validators
41
- * @expected
42
- * - there should be no validator
43
- */
44
- it('should remove registered validator successfully', async () => {
45
- const mockedValidator = async (tx: TransactionEntity) => true;
46
- txPot.registerValidator('chain', 'txType', 'id', mockedValidator);
47
-
48
- txPot.unregisterValidator('chain', 'txType', 'id');
49
-
50
- const validatorsMap: Map<
51
- string,
52
- Map<string, Map<string, ValidatorFunction>>
53
- > = (txPot as any).validators;
54
- expect(validatorsMap.get('chain')?.get('txType')?.size).toEqual(0);
55
- });
56
- });
57
-
58
- describe('unregisterSubmitValidator', () => {
59
- /**
60
- * @target TxPot.unregisterSubmitValidator should remove registered submit validator successfully
61
- * @dependencies
62
- * @scenario
63
- * - register a validator function
64
- * - run test
65
- * - check registered submit validators
66
- * @expected
67
- * - there should be no validator
68
- */
69
- it('should remove registered submit validator successfully', async () => {
70
- const mockedValidator = async (tx: TransactionEntity) => true;
71
- txPot.registerSubmitValidator('chain', 'id', mockedValidator);
72
-
73
- txPot.unregisterSubmitValidator('chain', 'id');
74
-
75
- const validatorsMap: Map<string, Map<string, ValidatorFunction>> = (
76
- txPot as any
77
- ).submissionAllowance;
78
- expect(validatorsMap.get('chain')?.size).toEqual(0);
79
- });
80
- });
81
-
82
- describe('unregisterCallback', () => {
83
- /**
84
- * @target TxPot.unregisterCallback should remove registered submit validator successfully
85
- * @dependencies
86
- * @scenario
87
- * - register a validator function
88
- * - run test
89
- * - check registered submit validators
90
- * @expected
91
- * - there should be no validator
92
- */
93
- it('should remove registered submit validator successfully', async () => {
94
- const mockedCallback = vi.fn();
95
- txPot.registerCallback(
96
- 'txType',
97
- TransactionStatus.SIGNED,
98
- 'id',
99
- mockedCallback
100
- );
101
-
102
- txPot.unregisterCallback('txType', TransactionStatus.SIGNED, 'id');
103
-
104
- const callbacksMap: Map<
105
- string,
106
- Map<TransactionStatus, Map<string, CallbackFunction>>
107
- > = (txPot as any).txTypeCallbacks;
108
- expect(
109
- callbacksMap.get('txType')?.get(TransactionStatus.SIGNED)?.size
110
- ).toEqual(0);
111
- });
112
- });
113
-
114
- describe('setTransactionAsInvalid', () => {
115
- /**
116
- * @target TxPot.setTransactionAsInvalid should update status when enough blocks is passed
117
- * @dependencies
118
- * - Date
119
- * - database
120
- * @scenario
121
- * - insert tx
122
- * - mock PotChainManager and register to TxPot
123
- * - mock `getHeight`
124
- * - mock `getTxRequiredConfirmation` to return -1
125
- * - run test
126
- * - check db records
127
- * @expected
128
- * - columns of the tx should be updated
129
- * - status should be updated to invalid
130
- * - lastStatusUpdate should be updated to currentTimeStamp in seconds
131
- */
132
- it('should update status when enough blocks is passed', async () => {
133
- // insert tx
134
- await txRepository.insert(testData.tx1);
135
-
136
- // mock PotChainManager and register to TxPot
137
- const mockedManager = new TestPotChainManager();
138
- txPot.registerChain(testData.tx1.chain, mockedManager);
139
- // mock `getHeight`
140
- const requiredConfirmation = 5;
141
- const currentHeight = testData.tx1.lastCheck + requiredConfirmation;
142
- vi.spyOn(mockedManager, 'getHeight').mockResolvedValue(currentHeight);
143
- // mock `getTxRequiredConfirmation`
144
- vi.spyOn(mockedManager, 'getTxRequiredConfirmation').mockReturnValue(
145
- requiredConfirmation
146
- );
147
-
148
- // run test
149
- await txPot.callSetTransactionAsInvalid(testData.tx1);
150
-
151
- // check db records
152
- const txs = (await txRepository.find()).map((tx) => [
153
- tx.txId,
154
- tx.status,
155
- tx.lastStatusUpdate,
156
- ]);
157
- expect(txs).toEqual([
158
- [
159
- testData.tx1.txId,
160
- TransactionStatus.INVALID,
161
- String(testData.currentTimeStampAsSeconds),
162
- ],
163
- ]);
164
- });
165
-
166
- /**
167
- * @target TxPot.setTransactionAsInvalid should NOT update when enough blocks is NOT passed
168
- * @dependencies
169
- * - Date
170
- * - database
171
- * @scenario
172
- * - insert tx
173
- * - mock PotChainManager and register to TxPot
174
- * - mock `getHeight`
175
- * - mock `getTxRequiredConfirmation` to return -1
176
- * - run test
177
- * - check db records
178
- * @expected
179
- * - columns of the tx should remain unchanged
180
- */
181
- it('should NOT update when enough blocks is NOT passed', async () => {
182
- // insert tx
183
- await txRepository.insert(testData.tx1);
184
-
185
- // mock PotChainManager and register to TxPot
186
- const mockedManager = new TestPotChainManager();
187
- txPot.registerChain(testData.tx1.chain, mockedManager);
188
- // mock `getHeight`
189
- const requiredConfirmation = 5;
190
- const currentHeight = testData.tx1.lastCheck + requiredConfirmation - 1;
191
- vi.spyOn(mockedManager, 'getHeight').mockResolvedValue(currentHeight);
192
- // mock `getTxRequiredConfirmation`
193
- vi.spyOn(mockedManager, 'getTxRequiredConfirmation').mockReturnValue(
194
- requiredConfirmation
195
- );
196
-
197
- // run test
198
- await txPot.callSetTransactionAsInvalid(testData.tx1);
199
-
200
- // check db records
201
- const txs = (await txRepository.find()).map((tx) => [
202
- tx.txId,
203
- tx.status,
204
- tx.lastStatusUpdate,
205
- ]);
206
- expect(txs).toEqual([
207
- [testData.tx1.txId, testData.tx1.status, testData.tx1.lastStatusUpdate],
208
- ]);
209
- });
210
- });
211
-
212
- describe('validateTx', () => {
213
- /**
214
- * @target TxPot.validateTx should return true when no validator function is set
215
- * @dependencies
216
- * @scenario
217
- * - run test
218
- * - check returned value
219
- * @expected
220
- * - should return true
221
- */
222
- it('should return true when no validator function is set', async () => {
223
- const res = await txPot.callValidateTx(testData.tx1);
224
- expect(res).toEqual(true);
225
- });
226
-
227
- /**
228
- * @target TxPot.validateTx should return true when tx is valid
229
- * @dependencies
230
- * @scenario
231
- * - register a validator function to return true
232
- * - run test
233
- * - check returned value
234
- * @expected
235
- * - should return true
236
- */
237
- it('should return true when tx is valid', async () => {
238
- const mockedValidator = async (tx: TransactionEntity) => true;
239
- txPot.registerValidator(
240
- testData.tx1.chain,
241
- testData.tx1.txType,
242
- 'id',
243
- mockedValidator
244
- );
245
-
246
- const res = await txPot.callValidateTx(testData.tx1);
247
- expect(res).toEqual(true);
248
- });
249
-
250
- /**
251
- * @target TxPot.validateTx should return false and set tx as invalid
252
- * @dependencies
253
- * - database
254
- * @scenario
255
- * - insert tx into db
256
- * - register a validator function to return false
257
- * - mock TxPot.setTransactionAsInvalid
258
- * - run test
259
- * - check returned value
260
- * - check if function got called
261
- * @expected
262
- * - should return false
263
- * - `setTransactionAsInvalid` should got called
264
- */
265
- it('should return false and set tx as invalid', async () => {
266
- await txRepository.insert(testData.tx1);
267
-
268
- const mockedValidator = async (tx: TransactionEntity) => false;
269
- txPot.registerValidator(
270
- testData.tx1.chain,
271
- testData.tx1.txType,
272
- 'id',
273
- mockedValidator
274
- );
275
-
276
- const mockedSetTransactionAsInvalid = vi.fn();
277
- vi.spyOn(txPot as any, 'setTransactionAsInvalid').mockImplementation(
278
- mockedSetTransactionAsInvalid
279
- );
280
-
281
- const res = await txPot.callValidateTx(testData.tx1);
282
- expect(res).toEqual(false);
283
- expect(mockedSetTransactionAsInvalid).toHaveBeenCalled();
284
- });
285
-
286
- /**
287
- * @target TxPot.validateTx should return false and set tx as invalid
288
- * when at least one validator returns false
289
- * @dependencies
290
- * - database
291
- * @scenario
292
- * - insert tx into db
293
- * - register 3 validator functions (1st and 3rd ones returns true, 2nd one returns false)
294
- * - mock TxPot.setTransactionAsInvalid
295
- * - run test
296
- * - check returned value
297
- * - check if function got called
298
- * @expected
299
- * - should return false
300
- * - `setTransactionAsInvalid` should got called
301
- */
302
- it('should return false and set tx as invalid when at least one validator returns false', async () => {
303
- await txRepository.insert(testData.tx1);
304
-
305
- const mockedValidators = [
306
- { id: 'validator-1', validator: async (tx: TransactionEntity) => true },
307
- {
308
- id: 'validator-2',
309
- validator: async (tx: TransactionEntity) => false,
310
- },
311
- { id: 'validator-3', validator: async (tx: TransactionEntity) => true },
312
- ];
313
- mockedValidators.forEach((mockedValidator) =>
314
- txPot.registerValidator(
315
- testData.tx1.chain,
316
- testData.tx1.txType,
317
- mockedValidator.id,
318
- mockedValidator.validator
319
- )
320
- );
321
-
322
- const mockedSetTransactionAsInvalid = vi.fn();
323
- vi.spyOn(txPot as any, 'setTransactionAsInvalid').mockImplementation(
324
- mockedSetTransactionAsInvalid
325
- );
326
-
327
- const res = await txPot.callValidateTx(testData.tx1);
328
- expect(res).toEqual(false);
329
- expect(mockedSetTransactionAsInvalid).toHaveBeenCalled();
330
- });
331
- });
332
-
333
- describe('setTxStatus', () => {
334
- /**
335
- * @target TxPot.setTxStatus should update status and lastStatusUpdate successfully
336
- * @dependencies
337
- * - Date
338
- * - database
339
- * @scenario
340
- * - insert 2 txs
341
- * - register a callback function
342
- * - run test
343
- * - check db records
344
- * @expected
345
- * - columns of target tx should be updated as expected
346
- * - status should be updated to new status
347
- * - lastStatusUpdate should be updated to currentTimeStamp in seconds
348
- * - columns of other txs should remain unchanged
349
- */
350
- it('should update status and lastStatusUpdate successfully', async () => {
351
- await txRepository.insert(testData.tx1);
352
- await txRepository.insert(testData.tx5);
353
-
354
- const newStatus = TransactionStatus.IN_SIGN;
355
- await txPot.callSetTxStatus(testData.tx1, newStatus);
356
-
357
- const txs = (await txRepository.find()).map((tx) => [
358
- tx.txId,
359
- tx.status,
360
- tx.lastStatusUpdate,
361
- ]);
362
- expect(txs).toEqual([
363
- [
364
- testData.tx1.txId,
365
- newStatus,
366
- String(testData.currentTimeStampAsSeconds),
367
- ],
368
- [testData.tx5.txId, testData.tx5.status, testData.tx5.lastStatusUpdate],
369
- ]);
370
- });
371
-
372
- /**
373
- * @target TxPot.setTxStatus should also call tx status callback if is provided
374
- * @dependencies
375
- * - Date
376
- * - database
377
- * @scenario
378
- * - insert 2 txs
379
- * - register a callback function for new status
380
- * - run test
381
- * - check db records
382
- * - check if function got called
383
- * @expected
384
- * - columns of target tx should be updated as expected
385
- * - status should be updated to new status
386
- * - lastStatusUpdate should be updated to currentTimeStamp in seconds
387
- * - columns of other txs should remain unchanged
388
- * - mocked callback should got called
389
- */
390
- it('should also call tx status callback if is provided', async () => {
391
- // insert 2 txs
392
- await txRepository.insert(testData.tx1);
393
- await txRepository.insert(testData.tx5);
394
-
395
- // register a callback function
396
- const newStatus = TransactionStatus.IN_SIGN;
397
- const mockedCallback = vi.fn();
398
- mockedCallback.mockResolvedValue(undefined);
399
- txPot.registerCallback(
400
- testData.tx1.txType,
401
- newStatus,
402
- 'id',
403
- mockedCallback
404
- );
405
-
406
- // run test
407
- await txPot.callSetTxStatus(testData.tx1, newStatus);
408
-
409
- // check db records
410
- const txs = (await txRepository.find()).map((tx) => [
411
- tx.txId,
412
- tx.status,
413
- tx.lastStatusUpdate,
414
- ]);
415
- expect(txs).toEqual([
416
- [
417
- testData.tx1.txId,
418
- newStatus,
419
- String(testData.currentTimeStampAsSeconds),
420
- ],
421
- [testData.tx5.txId, testData.tx5.status, testData.tx5.lastStatusUpdate],
422
- ]);
423
-
424
- // check if function got called
425
- expect(mockedCallback).toHaveBeenCalled();
426
- });
427
- });
428
-
429
- describe('processSignedTx', () => {
430
- /**
431
- * @target TxPot.processSignedTx should submit the tx and update the status
432
- * @dependencies
433
- * - database
434
- * @scenario
435
- * - insert tx with signed status
436
- * - mock PotChainManager and register to TxPot
437
- * - mock `submitTransaction`
438
- * - run test (call `update`)
439
- * - check if function got called
440
- * - check db records
441
- * @expected
442
- * - `submitTransaction` should got called
443
- * - columns of the tx should be updated
444
- * - status should be updated to sent
445
- * - lastStatusUpdate should be updated to currentTimeStamp in seconds
446
- */
447
- it('should submit the tx and update the status', async () => {
448
- // insert tx with signed status
449
- await txRepository.insert(testData.tx4);
450
-
451
- // mock PotChainManager and register to TxPot
452
- const mockedManager = new TestPotChainManager();
453
- txPot.registerChain(testData.tx4.chain, mockedManager);
454
- // mock `submitTransaction`
455
- const mockedSubmitTransaction = vi.fn();
456
- mockedSubmitTransaction.mockResolvedValue(undefined);
457
- vi.spyOn(mockedManager, 'submitTransaction').mockImplementation(
458
- mockedSubmitTransaction
459
- );
460
-
461
- // run test
462
- await txPot.update();
463
-
464
- // check if function got called
465
- expect(mockedSubmitTransaction).toHaveBeenCalled();
466
-
467
- // check db records
468
- const txs = (await txRepository.find()).map((tx) => [
469
- tx.txId,
470
- tx.status,
471
- tx.lastStatusUpdate,
472
- ]);
473
- expect(txs).toEqual([
474
- [
475
- testData.tx4.txId,
476
- TransactionStatus.SENT,
477
- String(testData.currentTimeStampAsSeconds),
478
- ],
479
- ]);
480
- });
481
-
482
- /**
483
- * @target TxPot.processSignedTx should update the status regardless of submit response
484
- * @dependencies
485
- * - database
486
- * @scenario
487
- * - insert tx with signed status
488
- * - mock PotChainManager and register to TxPot
489
- * - mock `submitTransaction` to throw error
490
- * - register submit validator function
491
- * - run test (call `update`)
492
- * - check if function got called
493
- * - check db records
494
- * @expected
495
- * - `submitTransaction` should got called
496
- * - columns of the tx should be updated
497
- * - status should be updated to sent
498
- * - lastStatusUpdate should be updated to currentTimeStamp in seconds
499
- */
500
- it('should update the status regardless of submit response', async () => {
501
- // insert tx with signed status
502
- await txRepository.insert(testData.tx4);
503
-
504
- // mock PotChainManager and register to TxPot
505
- const mockedManager = new TestPotChainManager();
506
- txPot.registerChain(testData.tx4.chain, mockedManager);
507
- // mock `submitTransaction`
508
- const mockedSubmitTransaction = vi.fn();
509
- mockedSubmitTransaction.mockRejectedValue(
510
- Error(`TestError: submit failed`)
511
- );
512
- vi.spyOn(mockedManager, 'submitTransaction').mockImplementation(
513
- mockedSubmitTransaction
514
- );
515
-
516
- // register submit validator function
517
- txPot.registerSubmitValidator(
518
- testData.tx1.chain,
519
- 'validator-1',
520
- async (tx: TransactionEntity) => true
521
- );
522
-
523
- // run test
524
- await txPot.update();
525
-
526
- // check if function got called
527
- expect(mockedSubmitTransaction).toHaveBeenCalled();
528
-
529
- // check db records
530
- const txs = (await txRepository.find()).map((tx) => [
531
- tx.txId,
532
- tx.status,
533
- tx.lastStatusUpdate,
534
- ]);
535
- expect(txs).toEqual([
536
- [
537
- testData.tx4.txId,
538
- TransactionStatus.SENT,
539
- String(testData.currentTimeStampAsSeconds),
540
- ],
541
- ]);
542
- });
543
-
544
- /**
545
- * @target TxPot.processSignedTx should not submit the tx nor update the status
546
- * when at least one submit validator does not allow submission
547
- * @dependencies
548
- * - database
549
- * @scenario
550
- * - insert tx with signed status
551
- * - mock PotChainManager and register to TxPot
552
- * - mock `submitTransaction`
553
- * - register 3 submit validator functions
554
- * - 1st and 3rd ones returns true
555
- * - 2nd one returns false
556
- * - run test (call `update`)
557
- * - check if function got called
558
- * - check db records
559
- * @expected
560
- * - `submitTransaction` should NOT got called
561
- * - columns of the tx should remain unchanged
562
- */
563
- it('should not submit the tx nor update the status when at least one submit validator does not allow submission', async () => {
564
- // insert tx with signed status
565
- await txRepository.insert(testData.tx4);
566
-
567
- // mock PotChainManager and register to TxPot
568
- const mockedManager = new TestPotChainManager();
569
- txPot.registerChain(testData.tx4.chain, mockedManager);
570
- // mock `submitTransaction`
571
- const mockedSubmitTransaction = vi.fn();
572
- mockedSubmitTransaction.mockResolvedValue(undefined);
573
- vi.spyOn(mockedManager, 'submitTransaction').mockImplementation(
574
- mockedSubmitTransaction
575
- );
576
-
577
- // register 3 submit validator functions
578
- const mockedValidators = [
579
- { id: 'validator-1', validator: async (tx: TransactionEntity) => true },
580
- {
581
- id: 'validator-2',
582
- validator: async (tx: TransactionEntity) => false,
583
- },
584
- { id: 'validator-3', validator: async (tx: TransactionEntity) => true },
585
- ];
586
- mockedValidators.forEach((mockedValidator) =>
587
- txPot.registerSubmitValidator(
588
- testData.tx1.chain,
589
- mockedValidator.id,
590
- mockedValidator.validator
591
- )
592
- );
593
-
594
- // run test
595
- await txPot.update();
596
-
597
- // check if function got called
598
- expect(mockedSubmitTransaction).not.toHaveBeenCalled();
599
-
600
- // check db records
601
- const txs = (await txRepository.find()).map((tx) => [
602
- tx.txId,
603
- tx.status,
604
- tx.lastStatusUpdate,
605
- ]);
606
- expect(txs).toEqual([
607
- [testData.tx4.txId, testData.tx4.status, testData.tx4.lastStatusUpdate],
608
- ]);
609
- });
610
- });
611
-
612
- describe('processesSentTx', () => {
613
- /**
614
- * @target TxPot.processesSentTx should update tx status to completed when
615
- * transaction is confirmed enough
616
- * @dependencies
617
- * - Date
618
- * - database
619
- * @scenario
620
- * - insert tx with sent status
621
- * - mock PotChainManager and register to TxPot
622
- * - mock `getTxConfirmation`
623
- * - mock `getTxRequiredConfirmation`
624
- * - run test (call `update`)
625
- * - check db records
626
- * @expected
627
- * - columns of the tx should be updated
628
- * - status should be updated to completed
629
- * - lastStatusUpdate should be updated to currentTimeStamp in seconds
630
- */
631
- it('should update tx status to completed when transaction is confirmed enough', async () => {
632
- // insert tx with sent status
633
- await txRepository.insert(testData.tx6);
634
-
635
- // mock PotChainManager and register to TxPot
636
- const mockedManager = new TestPotChainManager();
637
- txPot.registerChain(testData.tx6.chain, mockedManager);
638
- // mock `getTxConfirmation`
639
- vi.spyOn(mockedManager, 'getTxConfirmation').mockResolvedValue(5);
640
- // mock `getTxRequiredConfirmation`
641
- vi.spyOn(mockedManager, 'getTxRequiredConfirmation').mockReturnValue(5);
642
-
643
- // run test
644
- await txPot.update();
645
-
646
- // check db records
647
- const txs = (await txRepository.find()).flatMap((tx) => [
648
- tx.txId,
649
- tx.status,
650
- tx.lastStatusUpdate,
651
- ]);
652
- expect(txs).toEqual([
653
- testData.tx6.txId,
654
- TransactionStatus.COMPLETED,
655
- String(testData.currentTimeStampAsSeconds),
656
- ]);
657
- });
658
-
659
- /**
660
- * @target TxPot.processesSentTx should only update tx lastCheck when transaction
661
- * is NOT confirmed enough
662
- * @dependencies
663
- * - database
664
- * @scenario
665
- * - insert tx with sent status
666
- * - mock PotChainManager and register to TxPot
667
- * - mock `getTxConfirmation`
668
- * - mock `getTxRequiredConfirmation`
669
- * - mock `getHeight`
670
- * - run test (call `update`)
671
- * - check db records
672
- * @expected
673
- * - columns of the tx should be as expected
674
- * - lastCheck should be updated to current height
675
- * - status and lastStatusUpdate should remain unchanged
676
- */
677
- it('should only update tx lastCheck when transaction is NOT confirmed enough', async () => {
678
- // insert tx with sent status
679
- await txRepository.insert(testData.tx6);
680
-
681
- // mock PotChainManager and register to TxPot
682
- const mockedManager = new TestPotChainManager();
683
- txPot.registerChain(testData.tx6.chain, mockedManager);
684
- // mock `getTxConfirmation`
685
- vi.spyOn(mockedManager, 'getTxConfirmation').mockResolvedValue(5);
686
- // mock `getTxRequiredConfirmation`
687
- vi.spyOn(mockedManager, 'getTxRequiredConfirmation').mockReturnValue(10);
688
- // mock `getHeight`
689
- const mockedHeight = 100110;
690
- vi.spyOn(mockedManager, 'getHeight').mockResolvedValue(mockedHeight);
691
-
692
- // run test
693
- await txPot.update();
694
-
695
- // check db records
696
- const txs = (await txRepository.find()).flatMap((tx) => [
697
- tx.txId,
698
- tx.status,
699
- tx.lastCheck,
700
- tx.lastStatusUpdate,
701
- ]);
702
- expect(txs).toEqual([
703
- testData.tx6.txId,
704
- testData.tx6.status,
705
- mockedHeight,
706
- testData.tx6.lastStatusUpdate,
707
- ]);
708
- });
709
-
710
- /**
711
- * @target TxPot.processesSentTx should update tx lastCheck when transaction
712
- * is found in mempool
713
- * @dependencies
714
- * - database
715
- * @scenario
716
- * - insert tx with sent status
717
- * - mock PotChainManager and register to TxPot
718
- * - mock `getTxConfirmation`
719
- * - mock `getTxRequiredConfirmation` to return -1
720
- * - mock `isTxInMempool` to return true
721
- * - mock `getHeight`
722
- * - run test (call `update`)
723
- * - check db records
724
- * @expected
725
- * - columns of the tx should be as expected
726
- * - lastCheck should be updated to current height
727
- * - status and lastStatusUpdate should remain unchanged
728
- */
729
- it('should update tx lastCheck when transaction is found in mempool', async () => {
730
- // insert tx with sent status
731
- await txRepository.insert(testData.tx6);
732
-
733
- // mock PotChainManager and register to TxPot
734
- const mockedManager = new TestPotChainManager();
735
- txPot.registerChain(testData.tx6.chain, mockedManager);
736
- // mock `getTxConfirmation`
737
- vi.spyOn(mockedManager, 'getTxConfirmation').mockResolvedValue(-1);
738
- // mock `getTxRequiredConfirmation`
739
- vi.spyOn(mockedManager, 'getTxRequiredConfirmation').mockReturnValue(10);
740
- // mock `isTxInMempool`
741
- vi.spyOn(mockedManager, 'isTxInMempool').mockResolvedValue(true);
742
- // mock `getHeight`
743
- const mockedHeight = 100110;
744
- vi.spyOn(mockedManager, 'getHeight').mockResolvedValue(mockedHeight);
745
-
746
- // run test
747
- await txPot.update();
748
-
749
- // check db records
750
- const txs = (await txRepository.find()).flatMap((tx) => [
751
- tx.txId,
752
- tx.status,
753
- tx.lastCheck,
754
- tx.lastStatusUpdate,
755
- ]);
756
- expect(txs).toEqual([
757
- testData.tx6.txId,
758
- testData.tx6.status,
759
- mockedHeight,
760
- testData.tx6.lastStatusUpdate,
761
- ]);
762
- });
763
-
764
- /**
765
- * @target TxPot.processesSentTx should resubmit if tx is not found but still valid
766
- * @dependencies
767
- * - database
768
- * @scenario
769
- * - insert tx with sent status
770
- * - mock PotChainManager and register to TxPot
771
- * - mock `getTxConfirmation`
772
- * - mock `getTxRequiredConfirmation` to return -1
773
- * - mock `isTxInMempool` to return false
774
- * - mock `isTxValid` to return true
775
- * - mock `submitTransaction`
776
- * - run test (call `update`)
777
- * - check if function got called
778
- * @expected
779
- * - `submitTransaction` should got called
780
- */
781
- it('should resubmit if tx is not found but still valid', async () => {
782
- // insert tx with sent status
783
- await txRepository.insert(testData.tx6);
784
-
785
- // mock PotChainManager and register to TxPot
786
- const mockedManager = new TestPotChainManager();
787
- txPot.registerChain(testData.tx6.chain, mockedManager);
788
- // mock `getTxConfirmation`
789
- vi.spyOn(mockedManager, 'getTxConfirmation').mockResolvedValue(-1);
790
- // mock `getTxRequiredConfirmation`
791
- vi.spyOn(mockedManager, 'getTxRequiredConfirmation').mockReturnValue(10);
792
- // mock `isTxInMempool`
793
- vi.spyOn(mockedManager, 'isTxInMempool').mockResolvedValue(false);
794
- // mock `isTxValid`
795
- vi.spyOn(mockedManager, 'isTxValid').mockResolvedValue(true);
796
- // mock `submitTransaction`
797
- const mockedSubmitTransaction = vi.fn();
798
- mockedSubmitTransaction.mockResolvedValue(undefined);
799
- vi.spyOn(mockedManager, 'submitTransaction').mockImplementation(
800
- mockedSubmitTransaction
801
- );
802
-
803
- // run test
804
- await txPot.update();
805
-
806
- // check if function got called
807
- expect(mockedSubmitTransaction).toHaveBeenCalled();
808
- });
809
-
810
- /**
811
- * @target TxPot.processesSentTx should not resubmit if submit validator does not allow
812
- * @dependencies
813
- * - database
814
- * @scenario
815
- * - insert tx with sent status
816
- * - mock PotChainManager and register to TxPot
817
- * - mock `getTxConfirmation`
818
- * - mock `getTxRequiredConfirmation` to return -1
819
- * - mock `isTxInMempool` to return false
820
- * - mock `isTxValid` to return true
821
- * - mock `submitTransaction`
822
- * - register a submit validator function to return false
823
- * - run test (call `update`)
824
- * - check if function got called
825
- * @expected
826
- * - `submitTransaction` should NOT got called
827
- */
828
- it('should not resubmit if submit validator does not allow', async () => {
829
- // insert tx with sent status
830
- await txRepository.insert(testData.tx6);
831
-
832
- // mock PotChainManager and register to TxPot
833
- const mockedManager = new TestPotChainManager();
834
- txPot.registerChain(testData.tx6.chain, mockedManager);
835
- // mock `getTxConfirmation`
836
- vi.spyOn(mockedManager, 'getTxConfirmation').mockResolvedValue(-1);
837
- // mock `getTxRequiredConfirmation`
838
- vi.spyOn(mockedManager, 'getTxRequiredConfirmation').mockReturnValue(10);
839
- // mock `isTxInMempool`
840
- vi.spyOn(mockedManager, 'isTxInMempool').mockResolvedValue(false);
841
- // mock `isTxValid`
842
- vi.spyOn(mockedManager, 'isTxValid').mockResolvedValue(true);
843
- // mock `submitTransaction`
844
- const mockedSubmitTransaction = vi.fn();
845
- mockedSubmitTransaction.mockResolvedValue(undefined);
846
- vi.spyOn(mockedManager, 'submitTransaction').mockImplementation(
847
- mockedSubmitTransaction
848
- );
849
-
850
- // register a submit validator function to return false
851
- txPot.registerSubmitValidator(
852
- testData.tx6.chain,
853
- 'validator-2',
854
- async (tx: TransactionEntity) => false
855
- );
856
-
857
- // run test
858
- await txPot.update();
859
-
860
- // check if function got called
861
- expect(mockedSubmitTransaction).not.toHaveBeenCalled();
862
- });
863
-
864
- /**
865
- * @target TxPot.processesSentTx should set transaction as invalid if tx is not valid anymore
866
- * @dependencies
867
- * - database
868
- * @scenario
869
- * - insert tx with sent status
870
- * - mock PotChainManager and register to TxPot
871
- * - mock `getTxConfirmation`
872
- * - mock `getTxRequiredConfirmation` to return -1
873
- * - mock `isTxInMempool` to return false
874
- * - mock `isTxValid` to return false
875
- * - mock `getHeight`
876
- * - mock TxPot.setTransactionAsInvalid
877
- * - run test (call `update`)
878
- * - check if function got called
879
- * @expected
880
- * - `setTransactionAsInvalid` should got called
881
- */
882
- it('should set transaction as invalid if tx is not valid anymore', async () => {
883
- // insert tx with sent status
884
- await txRepository.insert(testData.tx6);
885
-
886
- // mock PotChainManager and register to TxPot
887
- const mockedManager = new TestPotChainManager();
888
- txPot.registerChain(testData.tx6.chain, mockedManager);
889
- // mock `getTxConfirmation`
890
- vi.spyOn(mockedManager, 'getTxConfirmation').mockResolvedValue(-1);
891
- // mock `getTxRequiredConfirmation`
892
- vi.spyOn(mockedManager, 'getTxRequiredConfirmation').mockReturnValue(10);
893
- // mock `isTxInMempool`
894
- vi.spyOn(mockedManager, 'isTxInMempool').mockResolvedValue(false);
895
- // mock `isTxValid`
896
- vi.spyOn(mockedManager, 'isTxValid').mockResolvedValue(false);
897
-
898
- // mock TxPot.setTransactionAsInvalid
899
- const mockedSetTransactionAsInvalid = vi.fn();
900
- vi.spyOn(txPot as any, 'setTransactionAsInvalid').mockImplementation(
901
- mockedSetTransactionAsInvalid
902
- );
903
-
904
- // run test
905
- await txPot.update();
906
-
907
- // check if function got called
908
- expect(mockedSetTransactionAsInvalid).toHaveBeenCalled();
909
- });
910
-
911
- /**
912
- * @target TxPot.processesSentTx should set transaction as invalid when registered
913
- * validator recognizes the tx as invalid
914
- * @dependencies
915
- * - database
916
- * @scenario
917
- * - insert tx with sent status
918
- * - register a validator function to return false
919
- * - mock PotChainManager and register to TxPot
920
- * - mock `getTxConfirmation`
921
- * - mock `getTxRequiredConfirmation` to return -1
922
- * - mock `isTxInMempool` to return false
923
- * - mock `isTxValid` to return true
924
- * - mock `getHeight`
925
- * - mock TxPot.setTransactionAsInvalid
926
- * - run test (call `update`)
927
- * - check if function got called
928
- * @expected
929
- * - `setTransactionAsInvalid` should got called
930
- */
931
- it('should set transaction as invalid when registered validator recognizes the tx as invalid', async () => {
932
- // insert tx with sent status
933
- await txRepository.insert(testData.tx6);
934
-
935
- // register a validator function
936
- const mockedValidator = async (tx: TransactionEntity) => false;
937
- txPot.registerValidator(
938
- testData.tx6.chain,
939
- testData.tx6.txType,
940
- 'id',
941
- mockedValidator
942
- );
943
-
944
- // mock PotChainManager and register to TxPot
945
- const mockedManager = new TestPotChainManager();
946
- txPot.registerChain(testData.tx6.chain, mockedManager);
947
- // mock `getTxConfirmation`
948
- vi.spyOn(mockedManager, 'getTxConfirmation').mockResolvedValue(-1);
949
- // mock `getTxRequiredConfirmation`
950
- vi.spyOn(mockedManager, 'getTxRequiredConfirmation').mockReturnValue(10);
951
- // mock `isTxInMempool`
952
- vi.spyOn(mockedManager, 'isTxInMempool').mockResolvedValue(false);
953
- // mock `isTxValid`
954
- vi.spyOn(mockedManager, 'isTxValid').mockResolvedValue(true);
955
-
956
- // mock TxPot.setTransactionAsInvalid
957
- const mockedSetTransactionAsInvalid = vi.fn();
958
- vi.spyOn(txPot as any, 'setTransactionAsInvalid').mockImplementation(
959
- mockedSetTransactionAsInvalid
960
- );
961
-
962
- // run test
963
- await txPot.update();
964
-
965
- // check if function got called
966
- expect(mockedSetTransactionAsInvalid).toHaveBeenCalled();
967
- });
968
- });
969
-
970
- describe('getTxsByStatus', () => {
971
- /**
972
- * @target TxPot.getTxsByStatus should return txs filtered by status
973
- * @dependencies
974
- * - database
975
- * @scenario
976
- * - insert 3 txs with different status
977
- * - run test
978
- * - check returned value
979
- * @expected
980
- * - should return 2 filtered txs
981
- */
982
- it('should return txs filtered by status', async () => {
983
- await txRepository.insert(testData.tx1); // different status
984
- await txRepository.insert(testData.tx3);
985
- await txRepository.insert(testData.tx5);
986
-
987
- const txs = await txPot.getTxsByStatus(
988
- testData.tx3.status as TransactionStatus
989
- );
990
- expect(txs.length).toEqual(2);
991
- expect(txs[0].txId).toEqual(testData.tx3.txId);
992
- expect(txs[1].txId).toEqual(testData.tx5.txId);
993
- });
994
-
995
- /**
996
- * @target TxPot.getTxsByStatus should only return valid txs when
997
- * validate key is passed
998
- * @dependencies
999
- * - database
1000
- * @scenario
1001
- * - insert 2 txs with same status
1002
- * - register a validator function
1003
- * - should return true for first tx
1004
- * - should return false for second tx
1005
- * - mock TxPot.setTransactionAsInvalid
1006
- * - run test
1007
- * - check returned value
1008
- * @expected
1009
- * - should return the valid tx
1010
- */
1011
- it('should only return valid txs when validate key is passed', async () => {
1012
- // insert 2 txs with same status
1013
- await txRepository.insert(testData.tx3);
1014
- await txRepository.insert(testData.tx5);
1015
-
1016
- // register a validator function
1017
- const mockedValidator = async (tx: TransactionEntity) => {
1018
- if (tx.txId === testData.tx3.txId) return true;
1019
- return false;
1020
- };
1021
- txPot.registerValidator(
1022
- testData.tx3.chain,
1023
- testData.tx3.txType,
1024
- 'tx3-validator',
1025
- mockedValidator
1026
- );
1027
- txPot.registerValidator(
1028
- testData.tx5.chain,
1029
- testData.tx5.txType,
1030
- 'tx5-validator',
1031
- mockedValidator
1032
- );
1033
-
1034
- // mock TxPot.setTransactionAsInvalid
1035
- vi.spyOn(txPot as any, 'setTransactionAsInvalid').mockResolvedValue(
1036
- undefined
1037
- );
1038
-
1039
- // run test
1040
- const txs = await txPot.getTxsByStatus(
1041
- testData.tx3.status as TransactionStatus,
1042
- true
1043
- );
1044
- expect(txs.length).toEqual(1);
1045
- expect(txs[0].txId).toEqual(testData.tx3.txId);
1046
- });
1047
- });
1048
-
1049
- describe('addTx', () => {
1050
- /**
1051
- * @target TxPot.addTx should insert new tx successfully
1052
- * @dependencies
1053
- * - Date
1054
- * - database
1055
- * @scenario
1056
- * - run test
1057
- * - check db records
1058
- * @expected
1059
- * - new tx should be inserted
1060
- */
1061
- it('should insert new tx successfully', async () => {
1062
- await txPot.addTx(
1063
- testData.tx1.txId,
1064
- testData.tx1.chain,
1065
- testData.tx1.txType,
1066
- testData.tx1.requiredSign,
1067
- testData.tx1.serializedTx,
1068
- testData.tx1.status as TransactionStatus,
1069
- testData.tx1.lastCheck
1070
- );
1071
-
1072
- const txs = await txRepository.find();
1073
- expect(txs.length).toEqual(1);
1074
- expect(txs[0]).toEqual({
1075
- ...testData.tx1,
1076
- lastStatusUpdate: String(testData.currentTimeStampAsSeconds),
1077
- extra: null,
1078
- extra2: null,
1079
- });
1080
- });
1081
-
1082
- /**
1083
- * @target TxPot.addTx should insert new tx with extra fields successfully
1084
- * @dependencies
1085
- * - Date
1086
- * - database
1087
- * @scenario
1088
- * - run test
1089
- * - check db records
1090
- * @expected
1091
- * - new tx should be inserted
1092
- */
1093
- it('should insert new tx with extra fields successfully', async () => {
1094
- await txPot.addTx(
1095
- testData.tx3.txId,
1096
- testData.tx3.chain,
1097
- testData.tx3.txType,
1098
- testData.tx3.requiredSign,
1099
- testData.tx3.serializedTx,
1100
- testData.tx3.status as TransactionStatus,
1101
- testData.tx3.lastCheck,
1102
- testData.tx3.extra,
1103
- testData.tx3.extra2
1104
- );
1105
-
1106
- const txs = await txRepository.find();
1107
- expect(txs.length).toEqual(1);
1108
- expect(txs[0]).toEqual({
1109
- ...testData.tx3,
1110
- failedInSign: false,
1111
- signFailedCount: 0,
1112
- lastStatusUpdate: String(testData.currentTimeStampAsSeconds),
1113
- extra: testData.tx3.extra,
1114
- extra2: null,
1115
- });
1116
- });
1117
- });
1118
-
1119
- describe('setTxStatusById', () => {
1120
- /**
1121
- * @target TxPot.setTxStatusById should throw error when tx is not found
1122
- * @dependencies
1123
- * - Date
1124
- * - database
1125
- * @scenario
1126
- * - run test & expect exception thrown
1127
- * @expected
1128
- * - it should throw Error
1129
- */
1130
- it('should throw error when tx is not found', async () => {
1131
- await expect(async () => {
1132
- await txPot.setTxStatusById(
1133
- testData.tx1.txId,
1134
- testData.tx1.chain,
1135
- TransactionStatus.IN_SIGN
1136
- );
1137
- }).rejects.toThrow(Error);
1138
- });
1139
-
1140
- /**
1141
- * @target TxPot.setTxStatusById should update status and lastStatusUpdate successfully
1142
- * @dependencies
1143
- * - Date
1144
- * - database
1145
- * @scenario
1146
- * - insert 2 txs
1147
- * - run test
1148
- * - check db records
1149
- * @expected
1150
- * - columns of target tx should be updated
1151
- * - status should be updated to new status
1152
- * - lastStatusUpdate should be updated to currentTimeStamp in seconds
1153
- * - columns of other txs should remain unchanged
1154
- */
1155
- it('should update status and lastStatusUpdate successfully', async () => {
1156
- await txRepository.insert(testData.tx1);
1157
- await txRepository.insert(testData.tx2);
1158
-
1159
- const newStatus = TransactionStatus.IN_SIGN;
1160
- await txPot.setTxStatusById(
1161
- testData.tx1.txId,
1162
- testData.tx1.chain,
1163
- newStatus
1164
- );
1165
-
1166
- const txs = (await txRepository.find()).map((tx) => [
1167
- tx.txId,
1168
- tx.status,
1169
- tx.lastStatusUpdate,
1170
- ]);
1171
- expect(txs).toEqual([
1172
- [
1173
- testData.tx1.txId,
1174
- newStatus,
1175
- String(testData.currentTimeStampAsSeconds),
1176
- ],
1177
- [testData.tx2.txId, testData.tx2.status, testData.tx2.lastStatusUpdate],
1178
- ]);
1179
- });
1180
- });
1181
-
1182
- describe('setTxAsSignFailed', () => {
1183
- /**
1184
- * @target TxPot.setTxAsSignFailed should set tx as sign-failed and update required fields successfully
1185
- * @dependencies
1186
- * - Date
1187
- * - database
1188
- * @scenario
1189
- * - insert 2 txs
1190
- * - run test
1191
- * - check db records
1192
- * @expected
1193
- * - columns of target tx should be updated as expected
1194
- * - status should be sign-failed
1195
- * - lastStatusUpdate should be updated to currentTimeStamp in seconds
1196
- * - failedInSign should be true
1197
- * - signFailedCount should be incremented
1198
- * - columns of other txs should remain unchanged
1199
- */
1200
- it('should set tx as sign-failed and update required fields successfully', async () => {
1201
- await txRepository.insert(testData.tx3);
1202
- await txRepository.insert(testData.tx5);
1203
-
1204
- await txPot.setTxAsSignFailed(testData.tx5.txId, testData.tx5.chain);
1205
-
1206
- const txs = (await txRepository.find()).map((tx) => [
1207
- tx.txId,
1208
- tx.status,
1209
- tx.lastStatusUpdate,
1210
- tx.failedInSign,
1211
- tx.signFailedCount,
1212
- ]);
1213
- expect(txs).toEqual([
1214
- [
1215
- testData.tx3.txId,
1216
- testData.tx3.status,
1217
- testData.tx3.lastStatusUpdate,
1218
- testData.tx3.failedInSign,
1219
- testData.tx3.signFailedCount,
1220
- ],
1221
- [
1222
- testData.tx5.txId,
1223
- TransactionStatus.SIGN_FAILED,
1224
- String(testData.currentTimeStampAsSeconds),
1225
- true,
1226
- testData.tx5.signFailedCount + 1,
1227
- ],
1228
- ]);
1229
- });
1230
- });
1231
-
1232
- describe('setTxAsSigned', () => {
1233
- /**
1234
- * @target TxPot.setTxAsSigned should set tx as signed and update required fields successfully
1235
- * @dependencies
1236
- * - Date
1237
- * - database
1238
- * @scenario
1239
- * - insert 2 txs
1240
- * - run test
1241
- * - check db records
1242
- * @expected
1243
- * - columns of target tx should be updated as expected
1244
- * - status should be signed
1245
- * - lastCheck should be updated to currentHeight
1246
- * - lastStatusUpdate should be updated to currentTimeStamp in seconds
1247
- * - serializedTx should be updated
1248
- * - columns of other txs should remain unchanged
1249
- */
1250
- it('should set tx as signed and update required fields successfully', async () => {
1251
- await txRepository.insert(testData.tx3);
1252
- await txRepository.insert(testData.tx5);
1253
-
1254
- const currentHeight = testData.tx3.lastCheck + 10;
1255
- const serializedSignedTx = 'serialized-signed-tx';
1256
- await txPot.setTxAsSigned(
1257
- testData.tx3.txId,
1258
- testData.tx3.chain,
1259
- serializedSignedTx,
1260
- currentHeight
1261
- );
1262
-
1263
- const txs = (await txRepository.find()).map((tx) => [
1264
- tx.txId,
1265
- tx.status,
1266
- tx.lastCheck,
1267
- tx.lastStatusUpdate,
1268
- tx.serializedTx,
1269
- ]);
1270
- expect(txs).toEqual([
1271
- [
1272
- testData.tx3.txId,
1273
- TransactionStatus.SIGNED,
1274
- currentHeight,
1275
- String(testData.currentTimeStampAsSeconds),
1276
- serializedSignedTx,
1277
- ],
1278
- [
1279
- testData.tx5.txId,
1280
- testData.tx5.status,
1281
- testData.tx5.lastCheck,
1282
- testData.tx5.lastStatusUpdate,
1283
- testData.tx5.serializedTx,
1284
- ],
1285
- ]);
1286
- });
1287
-
1288
- /**
1289
- * @target TxPot.setTxAsSigned should also update extra fields if are provided
1290
- * @dependencies
1291
- * - Date
1292
- * - database
1293
- * @scenario
1294
- * - insert 2 txs
1295
- * - run test
1296
- * - check db records
1297
- * @expected
1298
- * - columns of target tx should be updated as expected
1299
- * - status should be signed
1300
- * - lastCheck should be updated to currentHeight
1301
- * - lastStatusUpdate should be updated to currentTimeStamp in seconds
1302
- * - serializedTx should be updated
1303
- * - extra should be updated
1304
- * - extra2 should be updated
1305
- * - columns of other txs should remain unchanged
1306
- */
1307
- it('should also update extra fields if are provided', async () => {
1308
- await txRepository.insert(testData.tx3);
1309
- await txRepository.insert(testData.tx5);
1310
-
1311
- const currentHeight = testData.tx3.lastCheck + 10;
1312
- const serializedSignedTx = 'serialized-signed-tx';
1313
- const updatedExtra = 'updated-extra';
1314
- const updatedExtra2 = 'updated-extra-2';
1315
- await txPot.setTxAsSigned(
1316
- testData.tx3.txId,
1317
- testData.tx3.chain,
1318
- serializedSignedTx,
1319
- currentHeight,
1320
- updatedExtra,
1321
- updatedExtra2
1322
- );
1323
-
1324
- const txs = (await txRepository.find()).map((tx) => [
1325
- tx.txId,
1326
- tx.status,
1327
- tx.lastCheck,
1328
- tx.lastStatusUpdate,
1329
- tx.serializedTx,
1330
- tx.extra,
1331
- tx.extra2,
1332
- ]);
1333
- expect(txs).toEqual([
1334
- [
1335
- testData.tx3.txId,
1336
- TransactionStatus.SIGNED,
1337
- currentHeight,
1338
- String(testData.currentTimeStampAsSeconds),
1339
- serializedSignedTx,
1340
- updatedExtra,
1341
- updatedExtra2,
1342
- ],
1343
- [
1344
- testData.tx5.txId,
1345
- testData.tx5.status,
1346
- testData.tx5.lastCheck,
1347
- testData.tx5.lastStatusUpdate,
1348
- testData.tx5.serializedTx,
1349
- testData.tx5.extra ?? null,
1350
- testData.tx5.extra2 ?? null,
1351
- ],
1352
- ]);
1353
- });
1354
- });
1355
-
1356
- describe('updateTxLastCheck', () => {
1357
- /**
1358
- * @target TxPot.updateTxLastCheck should update lastCheck column successfully
1359
- * @dependencies
1360
- * - database
1361
- * @scenario
1362
- * - insert 2 txs
1363
- * - run test
1364
- * - check db records
1365
- * @expected
1366
- * - lastCheck of target tx should be updated
1367
- * - lastCheck of other txs should remain unchanged
1368
- */
1369
- it('should update lastCheck column successfully', async () => {
1370
- await txRepository.insert(testData.tx1);
1371
- await txRepository.insert(testData.tx2);
1372
-
1373
- const updatedLastCheck = testData.tx1.lastCheck + 100;
1374
- await txPot.updateTxLastCheck(
1375
- testData.tx1.txId,
1376
- testData.tx1.chain,
1377
- updatedLastCheck
1378
- );
1379
-
1380
- const txs = (await txRepository.find()).map((tx) => [
1381
- tx.txId,
1382
- tx.lastCheck,
1383
- ]);
1384
- expect(txs).toEqual([
1385
- [testData.tx1.txId, updatedLastCheck],
1386
- [testData.tx2.txId, testData.tx2.lastCheck],
1387
- ]);
1388
- });
1389
- });
1390
-
1391
- describe('resetFailedInSign', () => {
1392
- /**
1393
- * @target TxPot.resetFailedInSign should set failedInSign column to false successfully
1394
- * @dependencies
1395
- * - database
1396
- * @scenario
1397
- * - insert 3 txs
1398
- * - 2 with failedInSign column as true
1399
- * - 1 with failedInSign column as false
1400
- * - run test
1401
- * - check db records
1402
- * @expected
1403
- * - failedInSign of target tx should be false
1404
- * - failedInSign of other txs should remain unchanged
1405
- */
1406
- it('should set failedInSign column to false successfully', async () => {
1407
- await txRepository.insert(testData.tx1); // failedInSign is false
1408
- await txRepository.insert(testData.tx3);
1409
- await txRepository.insert(testData.tx4);
1410
-
1411
- await txPot.resetFailedInSign(testData.tx3.txId, testData.tx3.chain);
1412
-
1413
- const txs = (await txRepository.find()).map((tx) => [
1414
- tx.txId,
1415
- tx.failedInSign,
1416
- ]);
1417
- expect(txs).toEqual([
1418
- [testData.tx1.txId, testData.tx1.failedInSign],
1419
- [testData.tx3.txId, false],
1420
- [testData.tx4.txId, testData.tx4.failedInSign],
1421
- ]);
1422
- });
1423
- });
1424
-
1425
- describe('updateRequiredSign', () => {
1426
- /**
1427
- * @target TxPot.updateRequiredSign should update requiredSign column successfully
1428
- * @dependencies
1429
- * - database
1430
- * @scenario
1431
- * - insert 2 txs
1432
- * - run test
1433
- * - check db records
1434
- * @expected
1435
- * - requiredSign of target tx should be updated
1436
- * - requiredSign of other txs should remain unchanged
1437
- */
1438
- it('should update requiredSign column successfully', async () => {
1439
- await txRepository.insert(testData.tx1);
1440
- await txRepository.insert(testData.tx2);
1441
-
1442
- const updatedRequiredSign = testData.tx1.requiredSign + 2;
1443
- await txPot.updateRequiredSign(
1444
- testData.tx1.txId,
1445
- testData.tx1.chain,
1446
- updatedRequiredSign
1447
- );
1448
-
1449
- const txs = (await txRepository.find()).map((tx) => [
1450
- tx.txId,
1451
- tx.requiredSign,
1452
- ]);
1453
- expect(txs).toEqual([
1454
- [testData.tx1.txId, updatedRequiredSign],
1455
- [testData.tx2.txId, testData.tx2.requiredSign],
1456
- ]);
1457
- });
1458
- });
1459
-
1460
- describe('getTxByKey', () => {
1461
- /**
1462
- * @target TxPot.getTxByKey should return the tx successfully
1463
- * @dependencies
1464
- * - database
1465
- * @scenario
1466
- * - insert 2 txs
1467
- * - run test
1468
- * - check returned value
1469
- * @expected
1470
- * - should return the expected tx
1471
- */
1472
- it('should return the tx successfully', async () => {
1473
- await txRepository.insert(testData.tx1);
1474
- await txRepository.insert(testData.tx2);
1475
-
1476
- const tx = await txPot.getTxByKey(testData.tx1.txId, testData.tx1.chain);
1477
- expect(tx?.txId).toEqual(testData.tx1.txId);
1478
- });
1479
-
1480
- /**
1481
- * @target TxPot.getTxByKey should return null when tx is not found
1482
- * @dependencies
1483
- * - database
1484
- * @scenario
1485
- * - insert 2 txs
1486
- * - run test
1487
- * - check returned value
1488
- * @expected
1489
- * - should return null
1490
- */
1491
- it('should return null when tx is not found', async () => {
1492
- await txRepository.insert(testData.tx1);
1493
- await txRepository.insert(testData.tx2);
1494
-
1495
- const tx = await txPot.getTxByKey(testData.tx3.txId, testData.tx3.chain);
1496
- expect(tx).toBeNull();
1497
- });
1498
- });
1499
-
1500
- describe('getTxsQuery', () => {
1501
- /**
1502
- * @target TxPot.getTxsQuery should return all txs when no option is passed
1503
- * @dependencies
1504
- * - database
1505
- * @scenario
1506
- * - insert 2 txs
1507
- * - run test
1508
- * - check returned value
1509
- * @expected
1510
- * - should return 2 txs
1511
- */
1512
- it('should return all txs when no option is passed', async () => {
1513
- await txRepository.insert(testData.tx1);
1514
- await txRepository.insert(testData.tx2);
1515
-
1516
- const txs = await txPot.getTxsQuery();
1517
- expect(txs.length).toEqual(2);
1518
- });
1519
-
1520
- /**
1521
- * @target TxPot.getTxsQuery should return txs filtered by txId
1522
- * @dependencies
1523
- * - database
1524
- * @scenario
1525
- * - insert 2 txs with different txIds
1526
- * - run test
1527
- * - check returned value
1528
- * @expected
1529
- * - should return filtered tx
1530
- */
1531
- it('should return txs filtered by txId', async () => {
1532
- await txRepository.insert(testData.tx1);
1533
- await txRepository.insert(testData.tx2);
1534
-
1535
- const txs = await txPot.getTxsQuery([{ txId: testData.tx1.txId }]);
1536
- expect(txs.length).toEqual(1);
1537
- expect(txs[0].txId).toEqual(testData.tx1.txId);
1538
- });
1539
-
1540
- /**
1541
- * @target TxPot.getTxsQuery should return txs filtered by list of txId
1542
- * @dependencies
1543
- * - database
1544
- * @scenario
1545
- * - insert 3 txs with different txIds
1546
- * - run test
1547
- * - check returned value
1548
- * @expected
1549
- * - should return 2 filtered txs
1550
- */
1551
- it('should return txs filtered by list of txId', async () => {
1552
- await txRepository.insert(testData.tx1);
1553
- await txRepository.insert(testData.tx2);
1554
- await txRepository.insert(testData.tx3); // txId not on the list
1555
-
1556
- const txs = await txPot.getTxsQuery([
1557
- { txId: [testData.tx1.txId, testData.tx2.txId] },
1558
- ]);
1559
- expect(txs.length).toEqual(2);
1560
- expect(txs[0].txId).toEqual(testData.tx1.txId);
1561
- expect(txs[1].txId).toEqual(testData.tx2.txId);
1562
- });
1563
-
1564
- /**
1565
- * @target TxPot.getTxsQuery should return txs filtered by chain
1566
- * @dependencies
1567
- * - database
1568
- * @scenario
1569
- * - insert 3 txs with different chains
1570
- * - run test
1571
- * - check returned value
1572
- * @expected
1573
- * - should return 2 filtered txs
1574
- */
1575
- it('should return txs filtered by chain', async () => {
1576
- await txRepository.insert(testData.tx1);
1577
- await txRepository.insert(testData.tx2);
1578
- await txRepository.insert(testData.tx3); // different chain
1579
-
1580
- const txs = await txPot.getTxsQuery([{ chain: testData.tx1.chain }]);
1581
- expect(txs.length).toEqual(2);
1582
- expect(txs[0].txId).toEqual(testData.tx1.txId);
1583
- expect(txs[1].txId).toEqual(testData.tx2.txId);
1584
- });
1585
-
1586
- /**
1587
- * @target TxPot.getTxsQuery should return txs filtered by txType
1588
- * @dependencies
1589
- * - database
1590
- * @scenario
1591
- * - insert 3 txs with different txTypes
1592
- * - run test
1593
- * - check returned value
1594
- * @expected
1595
- * - should return 2 filtered txs
1596
- */
1597
- it('should return txs filtered by txType', async () => {
1598
- await txRepository.insert(testData.tx1);
1599
- await txRepository.insert(testData.tx3);
1600
- await txRepository.insert(testData.tx4); // different txType
1601
-
1602
- const txs = await txPot.getTxsQuery([{ txType: testData.tx1.txType }]);
1603
- expect(txs.length).toEqual(2);
1604
- expect(txs[0].txId).toEqual(testData.tx1.txId);
1605
- expect(txs[1].txId).toEqual(testData.tx3.txId);
1606
- });
1607
-
1608
- /**
1609
- * @target TxPot.getTxsQuery should return txs filtered by status
1610
- * @dependencies
1611
- * - database
1612
- * @scenario
1613
- * - insert 3 txs with different status
1614
- * - run test
1615
- * - check returned value
1616
- * @expected
1617
- * - should return 2 filtered txs
1618
- */
1619
- it('should return txs filtered by status', async () => {
1620
- await txRepository.insert(testData.tx1); // different status
1621
- await txRepository.insert(testData.tx3);
1622
- await txRepository.insert(testData.tx5);
1623
-
1624
- const txs = await txPot.getTxsQuery([
1625
- {
1626
- status: {
1627
- not: false,
1628
- value: testData.tx3.status as TransactionStatus,
1629
- },
1630
- },
1631
- ]);
1632
- expect(txs.length).toEqual(2);
1633
- expect(txs[0].txId).toEqual(testData.tx3.txId);
1634
- expect(txs[1].txId).toEqual(testData.tx5.txId);
1635
- });
1636
-
1637
- /**
1638
- * @target TxPot.getTxsQuery should return txs filtered by list of statuses
1639
- * @dependencies
1640
- * - database
1641
- * @scenario
1642
- * - insert 3 txs with different status
1643
- * - run test
1644
- * - check returned value
1645
- * @expected
1646
- * - should return 2 filtered txs
1647
- */
1648
- it('should return txs filtered by list of statuses', async () => {
1649
- await txRepository.insert(testData.tx1);
1650
- await txRepository.insert(testData.tx2);
1651
- await txRepository.insert(testData.tx3); // status not on the list
1652
-
1653
- const txs = await txPot.getTxsQuery([
1654
- {
1655
- status: {
1656
- not: false,
1657
- value: [
1658
- testData.tx1.status as TransactionStatus,
1659
- testData.tx2.status as TransactionStatus,
1660
- ],
1661
- },
1662
- },
1663
- ]);
1664
- expect(txs.length).toEqual(2);
1665
- expect(txs[0].txId).toEqual(testData.tx1.txId);
1666
- expect(txs[1].txId).toEqual(testData.tx2.txId);
1667
- });
1668
-
1669
- /**
1670
- * @target TxPot.getTxsQuery should return txs that their status are not
1671
- * equal to given status
1672
- * @dependencies
1673
- * - database
1674
- * @scenario
1675
- * - insert 3 txs with different status
1676
- * - run test
1677
- * - check returned value
1678
- * @expected
1679
- * - should return 2 filtered txs
1680
- */
1681
- it('should return txs that their status are not equal to given status', async () => {
1682
- await txRepository.insert(testData.tx1);
1683
- await txRepository.insert(testData.tx2);
1684
- await txRepository.insert(testData.tx3);
1685
-
1686
- const txs = await txPot.getTxsQuery([
1687
- {
1688
- status: {
1689
- not: true,
1690
- value: testData.tx1.status as TransactionStatus,
1691
- },
1692
- },
1693
- ]);
1694
- expect(txs.length).toEqual(2);
1695
- expect(txs[0].txId).toEqual(testData.tx2.txId);
1696
- expect(txs[1].txId).toEqual(testData.tx3.txId);
1697
- });
1698
-
1699
- /**
1700
- * @target TxPot.getTxsQuery should return txs that their status are not
1701
- * on given list of statuses
1702
- * @dependencies
1703
- * - database
1704
- * @scenario
1705
- * - insert 3 txs with different status
1706
- * - run test
1707
- * - check returned value
1708
- * @expected
1709
- * - should return filtered tx
1710
- */
1711
- it('should return txs that their status are not on given list of statuses', async () => {
1712
- await txRepository.insert(testData.tx1);
1713
- await txRepository.insert(testData.tx2);
1714
- await txRepository.insert(testData.tx3); // status not on the list
1715
-
1716
- const txs = await txPot.getTxsQuery([
1717
- {
1718
- status: {
1719
- not: true,
1720
- value: [
1721
- testData.tx1.status as TransactionStatus,
1722
- testData.tx2.status as TransactionStatus,
1723
- ],
1724
- },
1725
- },
1726
- ]);
1727
- expect(txs.length).toEqual(1);
1728
- expect(txs[0].txId).toEqual(testData.tx3.txId);
1729
- });
1730
-
1731
- /**
1732
- * @target TxPot.getTxsQuery should return txs filtered by failedInSign
1733
- * @dependencies
1734
- * - database
1735
- * @scenario
1736
- * - insert 3 txs with different failedInSign
1737
- * - run test
1738
- * - check returned value
1739
- * @expected
1740
- * - should return 2 filtered txs
1741
- */
1742
- it('should return txs filtered by failedInSign', async () => {
1743
- await txRepository.insert(testData.tx1);
1744
- await txRepository.insert(testData.tx2);
1745
- await txRepository.insert(testData.tx3); // different failedInSign
1746
-
1747
- const txs = await txPot.getTxsQuery([
1748
- { failedInSign: testData.tx1.failedInSign },
1749
- ]);
1750
- expect(txs.length).toEqual(2);
1751
- expect(txs[0].txId).toEqual(testData.tx1.txId);
1752
- expect(txs[1].txId).toEqual(testData.tx2.txId);
1753
- });
1754
-
1755
- /**
1756
- * @target TxPot.getTxsQuery should return txs filtered by extra
1757
- * @dependencies
1758
- * - database
1759
- * @scenario
1760
- * - insert 2 txs with different extra
1761
- * - run test
1762
- * - check returned value
1763
- * @expected
1764
- * - should return filtered tx
1765
- */
1766
- it('should return txs filtered by extra', async () => {
1767
- await txRepository.insert(testData.tx1); // different extra
1768
- await txRepository.insert(testData.tx3);
1769
-
1770
- const txs = await txPot.getTxsQuery([{ extra: testData.tx3.extra }]);
1771
- expect(txs.length).toEqual(1);
1772
- expect(txs[0].txId).toEqual(testData.tx3.txId);
1773
- });
1774
-
1775
- /**
1776
- * @target TxPot.getTxsQuery should return txs filtered by list of extra
1777
- * @dependencies
1778
- * - database
1779
- * @scenario
1780
- * - insert 3 txs with different list of extra
1781
- * - run test
1782
- * - check returned value
1783
- * @expected
1784
- * - should return 2 filtered txs
1785
- */
1786
- it('should return txs filtered by list of extra', async () => {
1787
- await txRepository.insert(testData.tx1); // extra not on the list
1788
- await txRepository.insert(testData.tx3);
1789
- await txRepository.insert(testData.tx4);
1790
-
1791
- const txs = await txPot.getTxsQuery([
1792
- { extra: [testData.tx3.extra!, testData.tx4.extra!] },
1793
- ]);
1794
- expect(txs.length).toEqual(2);
1795
- expect(txs[0].txId).toEqual(testData.tx3.txId);
1796
- expect(txs[1].txId).toEqual(testData.tx4.txId);
1797
- });
1798
-
1799
- /**
1800
- * @target TxPot.getTxsQuery should combine two filter options successfully
1801
- * @dependencies
1802
- * - database
1803
- * @scenario
1804
- * - insert 3 txs with different txIds and chains
1805
- * - run test
1806
- * - check returned value
1807
- * @expected
1808
- * - should return 2 filtered txs
1809
- */
1810
- it('should combine two filter options successfully', async () => {
1811
- await txRepository.insert(testData.tx1);
1812
- await txRepository.insert(testData.tx2);
1813
- await txRepository.insert(testData.tx3);
1814
-
1815
- const txs = await txPot.getTxsQuery([
1816
- { txId: testData.tx1.txId },
1817
- { chain: testData.tx1.chain },
1818
- ]);
1819
- expect(txs.length).toEqual(2);
1820
- expect(txs[0].txId).toEqual(testData.tx1.txId);
1821
- expect(txs[1].txId).toEqual(testData.tx2.txId);
1822
- });
1823
- });
1824
-
1825
- describe('updateExtra', () => {
1826
- /**
1827
- * @target TxPot.updateExtra should update extra columns successfully
1828
- * @dependencies
1829
- * - database
1830
- * @scenario
1831
- * - insert 2 txs
1832
- * - run test
1833
- * - check db records
1834
- * @expected
1835
- * - extra of target tx should be updated
1836
- * - extra of other txs should remain unchanged
1837
- */
1838
- it('should update extra columns successfully', async () => {
1839
- await txRepository.insert(testData.tx3);
1840
- await txRepository.insert(testData.tx4);
1841
-
1842
- const updatedExtra = 'new-extra';
1843
- await txPot.updateExtra(
1844
- testData.tx3.txId,
1845
- testData.tx3.chain,
1846
- updatedExtra
1847
- );
1848
-
1849
- const txs = (await txRepository.find()).map((tx) => [tx.txId, tx.extra]);
1850
- expect(txs).toEqual([
1851
- [testData.tx3.txId, updatedExtra],
1852
- [testData.tx4.txId, testData.tx4.extra],
1853
- ]);
1854
- });
1855
-
1856
- /**
1857
- * @target TxPot.updateExtra should set null successfully
1858
- * @dependencies
1859
- * - database
1860
- * @scenario
1861
- * - insert a tx with extra
1862
- * - run test
1863
- * - check db records
1864
- * @expected
1865
- * - extra of target tx should be updated
1866
- */
1867
- it('should set null successfully', async () => {
1868
- await txRepository.insert(testData.tx3);
1869
-
1870
- const updatedExtra = null;
1871
- await txPot.updateExtra(
1872
- testData.tx3.txId,
1873
- testData.tx3.chain,
1874
- updatedExtra
1875
- );
1876
-
1877
- const txs = (await txRepository.find()).map((tx) => [tx.txId, tx.extra]);
1878
- expect(txs).toEqual([[testData.tx3.txId, updatedExtra]]);
1879
- });
1880
- });
1881
- });