@bsv/wallet-toolbox 2.1.8 → 2.1.10

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 (110) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/docs/client.md +305 -156
  3. package/docs/monitor.md +153 -16
  4. package/docs/setup.md +4 -8
  5. package/docs/storage.md +37 -8
  6. package/docs/wallet.md +305 -156
  7. package/out/src/Setup.d.ts.map +1 -1
  8. package/out/src/Setup.js +1 -2
  9. package/out/src/Setup.js.map +1 -1
  10. package/out/src/SetupClient.d.ts.map +1 -1
  11. package/out/src/SetupClient.js +1 -2
  12. package/out/src/SetupClient.js.map +1 -1
  13. package/out/src/index.all.d.ts +1 -2
  14. package/out/src/index.all.d.ts.map +1 -1
  15. package/out/src/index.all.js +1 -2
  16. package/out/src/index.all.js.map +1 -1
  17. package/out/src/monitor/Monitor.d.ts +4 -3
  18. package/out/src/monitor/Monitor.d.ts.map +1 -1
  19. package/out/src/monitor/Monitor.js +39 -11
  20. package/out/src/monitor/Monitor.js.map +1 -1
  21. package/out/src/monitor/MonitorDaemon.d.ts +2 -1
  22. package/out/src/monitor/MonitorDaemon.d.ts.map +1 -1
  23. package/out/src/monitor/MonitorDaemon.js +1 -4
  24. package/out/src/monitor/MonitorDaemon.js.map +1 -1
  25. package/out/src/monitor/index.all.d.ts +4 -0
  26. package/out/src/monitor/index.all.d.ts.map +1 -0
  27. package/out/src/monitor/index.all.js +43 -0
  28. package/out/src/monitor/index.all.js.map +1 -0
  29. package/out/src/monitor/tasks/TaskReviewDoubleSpends.d.ts +26 -0
  30. package/out/src/monitor/tasks/TaskReviewDoubleSpends.d.ts.map +1 -0
  31. package/out/src/monitor/tasks/TaskReviewDoubleSpends.js +124 -0
  32. package/out/src/monitor/tasks/TaskReviewDoubleSpends.js.map +1 -0
  33. package/out/src/monitor/tasks/TaskReviewProvenTxs.d.ts +34 -0
  34. package/out/src/monitor/tasks/TaskReviewProvenTxs.d.ts.map +1 -0
  35. package/out/src/monitor/tasks/TaskReviewProvenTxs.js +131 -0
  36. package/out/src/monitor/tasks/TaskReviewProvenTxs.js.map +1 -0
  37. package/out/src/monitor/tasks/TaskReviewUtxos.d.ts +23 -0
  38. package/out/src/monitor/tasks/TaskReviewUtxos.d.ts.map +1 -0
  39. package/out/src/monitor/tasks/TaskReviewUtxos.js +71 -0
  40. package/out/src/monitor/tasks/TaskReviewUtxos.js.map +1 -0
  41. package/out/src/monitor/tasks/TaskSendWaiting.d.ts +14 -1
  42. package/out/src/monitor/tasks/TaskSendWaiting.d.ts.map +1 -1
  43. package/out/src/monitor/tasks/TaskSendWaiting.js +94 -25
  44. package/out/src/monitor/tasks/TaskSendWaiting.js.map +1 -1
  45. package/out/src/monitor/tasks/__tests/TaskReviewDoubleSpends.test.d.ts +2 -0
  46. package/out/src/monitor/tasks/__tests/TaskReviewDoubleSpends.test.d.ts.map +1 -0
  47. package/out/src/monitor/tasks/__tests/TaskReviewDoubleSpends.test.js +161 -0
  48. package/out/src/monitor/tasks/__tests/TaskReviewDoubleSpends.test.js.map +1 -0
  49. package/out/src/monitor/tasks/__tests/TaskReviewProvenTxs.test.d.ts +2 -0
  50. package/out/src/monitor/tasks/__tests/TaskReviewProvenTxs.test.d.ts.map +1 -0
  51. package/out/src/monitor/tasks/__tests/TaskReviewProvenTxs.test.js +214 -0
  52. package/out/src/monitor/tasks/__tests/TaskReviewProvenTxs.test.js.map +1 -0
  53. package/out/src/monitor/tasks/__tests/TaskReviewUtxos.test.d.ts +2 -0
  54. package/out/src/monitor/tasks/__tests/TaskReviewUtxos.test.d.ts.map +1 -0
  55. package/out/src/monitor/tasks/__tests/TaskReviewUtxos.test.js +92 -0
  56. package/out/src/monitor/tasks/__tests/TaskReviewUtxos.test.js.map +1 -0
  57. package/out/src/monitor/tasks/__tests/TaskSendWaiting.test.d.ts +2 -0
  58. package/out/src/monitor/tasks/__tests/TaskSendWaiting.test.d.ts.map +1 -0
  59. package/out/src/monitor/tasks/__tests/TaskSendWaiting.test.js +139 -0
  60. package/out/src/monitor/tasks/__tests/TaskSendWaiting.test.js.map +1 -0
  61. package/out/src/monitor/tasks/index.all.d.ts +19 -0
  62. package/out/src/monitor/tasks/index.all.d.ts.map +1 -0
  63. package/out/src/monitor/tasks/index.all.js +35 -0
  64. package/out/src/monitor/tasks/index.all.js.map +1 -0
  65. package/out/src/sdk/WalletStorage.interfaces.d.ts +9 -0
  66. package/out/src/sdk/WalletStorage.interfaces.d.ts.map +1 -1
  67. package/out/src/services/Services.d.ts.map +1 -1
  68. package/out/src/services/Services.js +10 -2
  69. package/out/src/services/Services.js.map +1 -1
  70. package/out/src/services/__tests/getFiatExchangeRate.test.d.ts +2 -0
  71. package/out/src/services/__tests/getFiatExchangeRate.test.d.ts.map +1 -0
  72. package/out/src/services/__tests/getFiatExchangeRate.test.js +156 -0
  73. package/out/src/services/__tests/getFiatExchangeRate.test.js.map +1 -0
  74. package/out/src/services/chaintracker/chaintracks/Ingest/BulkIngestorWhatsOnChainCdn.js +1 -1
  75. package/out/src/services/chaintracker/chaintracks/Ingest/BulkIngestorWhatsOnChainCdn.js.map +1 -1
  76. package/out/src/services/createDefaultWalletServicesOptions.js +1 -1
  77. package/out/src/services/createDefaultWalletServicesOptions.js.map +1 -1
  78. package/out/src/services/providers/__tests/exchangeRates.test.js +4 -0
  79. package/out/src/services/providers/__tests/exchangeRates.test.js.map +1 -1
  80. package/out/src/storage/StorageKnex.d.ts +3 -1
  81. package/out/src/storage/StorageKnex.d.ts.map +1 -1
  82. package/out/src/storage/StorageKnex.js +26 -5
  83. package/out/src/storage/StorageKnex.js.map +1 -1
  84. package/out/src/storage/StorageProvider.d.ts +6 -1
  85. package/out/src/storage/StorageProvider.d.ts.map +1 -1
  86. package/out/src/storage/StorageProvider.js +6 -0
  87. package/out/src/storage/StorageProvider.js.map +1 -1
  88. package/out/src/storage/StorageReaderWriter.d.ts +2 -1
  89. package/out/src/storage/StorageReaderWriter.d.ts.map +1 -1
  90. package/out/src/storage/StorageReaderWriter.js.map +1 -1
  91. package/out/src/storage/WalletStorageManager.d.ts +7 -0
  92. package/out/src/storage/WalletStorageManager.d.ts.map +1 -1
  93. package/out/src/storage/WalletStorageManager.js +33 -2
  94. package/out/src/storage/WalletStorageManager.js.map +1 -1
  95. package/out/src/storage/__test/findStaleMerkleRoots.test.d.ts +2 -0
  96. package/out/src/storage/__test/findStaleMerkleRoots.test.d.ts.map +1 -0
  97. package/out/src/storage/__test/findStaleMerkleRoots.test.js +41 -0
  98. package/out/src/storage/__test/findStaleMerkleRoots.test.js.map +1 -0
  99. package/out/src/storage/__test/findStaleMerkleRootsKnex.test.d.ts +2 -0
  100. package/out/src/storage/__test/findStaleMerkleRootsKnex.test.d.ts.map +1 -0
  101. package/out/src/storage/__test/findStaleMerkleRootsKnex.test.js +73 -0
  102. package/out/src/storage/__test/findStaleMerkleRootsKnex.test.js.map +1 -0
  103. package/out/src/utility/Format.d.ts.map +1 -1
  104. package/out/src/utility/Format.js +1 -0
  105. package/out/src/utility/Format.js.map +1 -1
  106. package/out/src/utility/index.all.d.ts +1 -0
  107. package/out/src/utility/index.all.d.ts.map +1 -1
  108. package/out/src/utility/index.all.js +1 -0
  109. package/out/src/utility/index.all.js.map +1 -1
  110. package/package.json +2 -2
@@ -0,0 +1,124 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TaskReviewDoubleSpends = void 0;
4
+ const Monitor_1 = require("../Monitor");
5
+ const WalletMonitorTask_1 = require("./WalletMonitorTask");
6
+ /**
7
+ * Review recent reqs in terminal 'doubleSpend' state and move any false positives
8
+ * back to 'unfail' so existing recovery handling can re-process them.
9
+ */
10
+ class TaskReviewDoubleSpends extends WalletMonitorTask_1.WalletMonitorTask {
11
+ constructor(monitor, triggerMsecs = Monitor_1.Monitor.oneMinute * 12, reviewLimit = 100, minAgeMinutes = 60, triggerQuickMsecs = Monitor_1.Monitor.oneMinute * 1) {
12
+ super(monitor, TaskReviewDoubleSpends.taskName);
13
+ this.triggerMsecs = triggerMsecs;
14
+ this.reviewLimit = reviewLimit;
15
+ this.minAgeMinutes = minAgeMinutes;
16
+ this.triggerQuickMsecs = triggerQuickMsecs;
17
+ this.triggerNextMsecs = this.triggerQuickMsecs;
18
+ }
19
+ trigger(nowMsecsSinceEpoch) {
20
+ return {
21
+ run: TaskReviewDoubleSpends.checkNow ||
22
+ (this.triggerNextMsecs > 0 && nowMsecsSinceEpoch - this.lastRunMsecsSinceEpoch > this.triggerNextMsecs)
23
+ };
24
+ }
25
+ async getLastReviewedCheckpoint() {
26
+ let events = [];
27
+ await this.storage.runAsStorageProvider(async (sp) => {
28
+ events = await sp.findMonitorEvents({
29
+ partial: { event: TaskReviewDoubleSpends.taskName },
30
+ orderDescending: true,
31
+ paged: { limit: 5 }
32
+ });
33
+ });
34
+ for (const event of events) {
35
+ if (!event.details)
36
+ continue;
37
+ try {
38
+ const parsed = JSON.parse(event.details);
39
+ if (typeof parsed.resumeOffset === 'number') {
40
+ return {
41
+ resumeOffset: parsed.resumeOffset,
42
+ expectedProvenTxReqId: parsed.expectedProvenTxReqId
43
+ };
44
+ }
45
+ }
46
+ catch (_a) {
47
+ continue;
48
+ }
49
+ }
50
+ return undefined;
51
+ }
52
+ async runTask() {
53
+ var _a;
54
+ TaskReviewDoubleSpends.checkNow = false;
55
+ const checkpoint = await this.getLastReviewedCheckpoint();
56
+ const updatedBefore = new Date(Date.now() - this.minAgeMinutes * 60 * 1000);
57
+ const reqs = await this.findReqsToReview(checkpoint, updatedBefore);
58
+ if (reqs.length === 0) {
59
+ this.triggerNextMsecs = this.triggerMsecs;
60
+ return '';
61
+ }
62
+ this.triggerNextMsecs = reqs.length >= this.reviewLimit ? this.triggerQuickMsecs : this.triggerMsecs;
63
+ const reviewed = [];
64
+ const unfails = [];
65
+ let log = ``;
66
+ let lastRetainedDoubleSpendIndex = -1;
67
+ let retainedDoubleSpendCount = 0;
68
+ for (const req of reqs) {
69
+ const gsr = await this.monitor.services.getStatusForTxids([req.txid]);
70
+ const status = (_a = gsr.results[0]) === null || _a === void 0 ? void 0 : _a.status;
71
+ reviewed.push(req);
72
+ if (status !== 'unknown') {
73
+ unfails.push(req.provenTxReqId);
74
+ log += `unfail ${req.provenTxReqId} ${req.txid} status:${status}\n`;
75
+ }
76
+ else {
77
+ lastRetainedDoubleSpendIndex = reviewed.length - 1;
78
+ retainedDoubleSpendCount += 1;
79
+ }
80
+ }
81
+ if (unfails.length > 0) {
82
+ await this.storage.runAsStorageProvider(async (sp) => {
83
+ await sp.updateProvenTxReq(unfails, { status: 'unfail' });
84
+ });
85
+ }
86
+ return JSON.stringify({
87
+ minAgeMinutes: this.minAgeMinutes,
88
+ reviewed: reviewed.length,
89
+ unfails: unfails.length,
90
+ reviewLimit: this.reviewLimit,
91
+ provenTxReqIds: unfails,
92
+ resumeOffset: lastRetainedDoubleSpendIndex >= 0 ? reqs.sourceOffset + retainedDoubleSpendCount - 1 : undefined,
93
+ expectedProvenTxReqId: lastRetainedDoubleSpendIndex >= 0 ? reviewed[lastRetainedDoubleSpendIndex].provenTxReqId : undefined,
94
+ reviewLog: `${reviewed.length} reqs with status 'doubleSpend'\n${log}`
95
+ });
96
+ }
97
+ async findReqsToReview(checkpoint, updatedBefore) {
98
+ var _a;
99
+ let offset = (checkpoint === null || checkpoint === void 0 ? void 0 : checkpoint.resumeOffset) || 0;
100
+ if (checkpoint && checkpoint.expectedProvenTxReqId !== undefined) {
101
+ const verify = await this.storage.findProvenTxReqs({
102
+ partial: { status: 'doubleSpend' },
103
+ paged: { limit: 1, offset: checkpoint.resumeOffset }
104
+ });
105
+ if (((_a = verify[0]) === null || _a === void 0 ? void 0 : _a.provenTxReqId) !== checkpoint.expectedProvenTxReqId) {
106
+ offset = 0;
107
+ }
108
+ else {
109
+ offset += 1;
110
+ }
111
+ }
112
+ const batch = await this.storage.findProvenTxReqs({
113
+ partial: { status: 'doubleSpend' },
114
+ paged: { limit: this.reviewLimit, offset }
115
+ });
116
+ const reqs = batch.filter(req => req.updated_at <= updatedBefore);
117
+ reqs.sourceOffset = offset;
118
+ return reqs;
119
+ }
120
+ }
121
+ exports.TaskReviewDoubleSpends = TaskReviewDoubleSpends;
122
+ TaskReviewDoubleSpends.taskName = 'ReviewDoubleSpends';
123
+ TaskReviewDoubleSpends.checkNow = false;
124
+ //# sourceMappingURL=TaskReviewDoubleSpends.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TaskReviewDoubleSpends.js","sourceRoot":"","sources":["../../../../src/monitor/tasks/TaskReviewDoubleSpends.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ import { HeightRange } from '../../services/chaintracker/chaintracks/util/HeightRange';
2
+ import { Monitor } from '../Monitor';
3
+ import { WalletMonitorTask } from './WalletMonitorTask';
4
+ export interface ReviewHeightRangeResult {
5
+ log: string;
6
+ reviewedHeights: number;
7
+ mismatchedHeights: number;
8
+ affectedTransactions: number;
9
+ updatedTransactions: number;
10
+ }
11
+ /**
12
+ * Backup verification task for recent proven_txs records.
13
+ *
14
+ * Reorg handling should normally be driven by TaskReorg via deactivated-header events.
15
+ * This task runs a lagged audit over recent heights and only reproves transactions when
16
+ * the currently canonical merkleRoot at a height no longer matches stored proven_txs roots.
17
+ */
18
+ export declare class TaskReviewProvenTxs extends WalletMonitorTask {
19
+ triggerMsecs: number;
20
+ maxHeightsPerRun: number;
21
+ minBlockAge: number;
22
+ triggerQuickMsecs: number;
23
+ static taskName: string;
24
+ static checkNow: boolean;
25
+ triggerNextMsecs: number;
26
+ constructor(monitor: Monitor, triggerMsecs?: number, maxHeightsPerRun?: number, minBlockAge?: number, triggerQuickMsecs?: number);
27
+ trigger(nowMsecsSinceEpoch: number): {
28
+ run: boolean;
29
+ };
30
+ runTask(): Promise<string>;
31
+ reviewHeightRange(range: HeightRange): Promise<ReviewHeightRangeResult>;
32
+ getLastReviewedHeight(): Promise<number | undefined>;
33
+ }
34
+ //# sourceMappingURL=TaskReviewProvenTxs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TaskReviewProvenTxs.d.ts","sourceRoot":"","sources":["../../../../src/monitor/tasks/TaskReviewProvenTxs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,0DAA0D,CAAA;AACtF,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AACpC,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAEvD,MAAM,WAAW,uBAAuB;IACtC,GAAG,EAAE,MAAM,CAAA;IACX,eAAe,EAAE,MAAM,CAAA;IACvB,iBAAiB,EAAE,MAAM,CAAA;IACzB,oBAAoB,EAAE,MAAM,CAAA;IAC5B,mBAAmB,EAAE,MAAM,CAAA;CAC5B;AAeD;;;;;;GAMG;AACH,qBAAa,mBAAoB,SAAQ,iBAAiB;IAS/C,YAAY;IACZ,gBAAgB;IAChB,WAAW;IACX,iBAAiB;IAX1B,MAAM,CAAC,QAAQ,SAAoB;IAEnC,MAAM,CAAC,QAAQ,UAAQ;IAEvB,gBAAgB,EAAE,MAAM,CAAA;gBAGtB,OAAO,EAAE,OAAO,EACT,YAAY,SAAyB,EACrC,gBAAgB,SAAM,EACtB,WAAW,SAAM,EACjB,iBAAiB,SAAwB;IAMlD,OAAO,CAAC,kBAAkB,EAAE,MAAM,GAAG;QAAE,GAAG,EAAE,OAAO,CAAA;KAAE;IAQ/C,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC;IA8B1B,iBAAiB,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,uBAAuB,CAAC;IAiDvE,qBAAqB,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;CAiC3D"}
@@ -0,0 +1,131 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TaskReviewProvenTxs = void 0;
4
+ const HeightRange_1 = require("../../services/chaintracker/chaintracks/util/HeightRange");
5
+ const Monitor_1 = require("../Monitor");
6
+ const WalletMonitorTask_1 = require("./WalletMonitorTask");
7
+ /**
8
+ * Backup verification task for recent proven_txs records.
9
+ *
10
+ * Reorg handling should normally be driven by TaskReorg via deactivated-header events.
11
+ * This task runs a lagged audit over recent heights and only reproves transactions when
12
+ * the currently canonical merkleRoot at a height no longer matches stored proven_txs roots.
13
+ */
14
+ class TaskReviewProvenTxs extends WalletMonitorTask_1.WalletMonitorTask {
15
+ constructor(monitor, triggerMsecs = Monitor_1.Monitor.oneMinute * 10, maxHeightsPerRun = 100, minBlockAge = 100, triggerQuickMsecs = Monitor_1.Monitor.oneMinute * 1) {
16
+ super(monitor, TaskReviewProvenTxs.taskName);
17
+ this.triggerMsecs = triggerMsecs;
18
+ this.maxHeightsPerRun = maxHeightsPerRun;
19
+ this.minBlockAge = minBlockAge;
20
+ this.triggerQuickMsecs = triggerQuickMsecs;
21
+ this.triggerNextMsecs = this.triggerQuickMsecs;
22
+ }
23
+ trigger(nowMsecsSinceEpoch) {
24
+ return {
25
+ run: TaskReviewProvenTxs.checkNow ||
26
+ (this.triggerNextMsecs > 0 && nowMsecsSinceEpoch - this.lastRunMsecsSinceEpoch > this.triggerNextMsecs)
27
+ };
28
+ }
29
+ async runTask() {
30
+ TaskReviewProvenTxs.checkNow = false;
31
+ const chaintracks = this.monitor.chaintracksWithEvents || this.monitor.chaintracks;
32
+ const tipHeight = await chaintracks.currentHeight();
33
+ const maxEligibleHeight = tipHeight - this.minBlockAge;
34
+ const lastReviewedHeight = await this.getLastReviewedHeight();
35
+ const startHeight = lastReviewedHeight === undefined ? 0 : lastReviewedHeight + 1;
36
+ const endHeight = Math.min(startHeight + this.maxHeightsPerRun - 1, maxEligibleHeight);
37
+ const range = new HeightRange_1.HeightRange(startHeight, endHeight);
38
+ if (range.isEmpty)
39
+ return '';
40
+ let log = `reviewing heights ${range.minHeight}..${range.maxHeight} tip=${tipHeight} minAge=${this.minBlockAge} maxPerRun=${this.maxHeightsPerRun}\n`;
41
+ const review = await this.reviewHeightRange(range);
42
+ log += review.log;
43
+ return JSON.stringify({
44
+ tipHeight,
45
+ minBlockAge: this.minBlockAge,
46
+ maxHeightsPerRun: this.maxHeightsPerRun,
47
+ startHeight,
48
+ reviewedThroughHeight: range.maxHeight,
49
+ reviewedHeights: review.reviewedHeights,
50
+ mismatchedHeights: review.mismatchedHeights,
51
+ affectedTransactions: review.affectedTransactions,
52
+ updatedTransactions: review.updatedTransactions,
53
+ reviewLog: log
54
+ });
55
+ }
56
+ async reviewHeightRange(range) {
57
+ const result = {
58
+ log: '',
59
+ reviewedHeights: 0,
60
+ mismatchedHeights: 0,
61
+ affectedTransactions: 0,
62
+ updatedTransactions: 0
63
+ };
64
+ if (range.isEmpty) {
65
+ this.triggerNextMsecs = this.triggerMsecs;
66
+ return result;
67
+ }
68
+ // If there is work to do, trigger a quick follow-up to continue processing the next range.
69
+ this.triggerNextMsecs = this.triggerQuickMsecs;
70
+ const chaintracks = this.monitor.chaintracksWithEvents || this.monitor.chaintracks;
71
+ for (let height = range.minHeight; height <= range.maxHeight; height++) {
72
+ result.reviewedHeights++;
73
+ const header = await chaintracks.findHeaderForHeight(height);
74
+ if (!header) {
75
+ result.log += ` height ${height} canonical header unavailable\n`;
76
+ continue;
77
+ }
78
+ let staleRoots = [];
79
+ await this.storage.runAsStorageProvider(async (sp) => {
80
+ staleRoots = await sp.findStaleMerkleRoots({ height, merkleRoot: header.merkleRoot });
81
+ });
82
+ if (staleRoots.length === 0)
83
+ continue;
84
+ result.mismatchedHeights++;
85
+ result.log += ` height ${height} canonical ${header.merkleRoot} stale ${staleRoots.join(',')}\n`;
86
+ for (const staleRoot of staleRoots) {
87
+ const reprove = await this.storage.reproveHeightMerkleRoot(height, staleRoot);
88
+ result.affectedTransactions += reprove.updated.length + reprove.unchanged.length + reprove.unavailable.length;
89
+ result.updatedTransactions += reprove.updated.length;
90
+ result.log += reprove.log;
91
+ }
92
+ }
93
+ return result;
94
+ }
95
+ async getLastReviewedHeight() {
96
+ let events = [];
97
+ await this.storage.runAsStorageProvider(async (sp) => {
98
+ events = await sp.findMonitorEvents({
99
+ partial: { event: TaskReviewProvenTxs.taskName },
100
+ orderDescending: true,
101
+ paged: { limit: 5 }
102
+ });
103
+ });
104
+ for (const event of events) {
105
+ if (!event.details)
106
+ continue;
107
+ try {
108
+ const parsed = JSON.parse(event.details);
109
+ if (typeof parsed.reviewedThroughHeight === 'number') {
110
+ return parsed.reviewedThroughHeight;
111
+ }
112
+ }
113
+ catch (_a) {
114
+ continue;
115
+ }
116
+ }
117
+ let lastReviewedHeight = undefined;
118
+ await this.storage.runAsStorageProvider(async (sp) => {
119
+ // Start at height of first proven tx when it appears...
120
+ const ptxs = await sp.findProvenTxs({ partial: {}, paged: { limit: 1, offset: 0 }, orderDescending: false });
121
+ if (ptxs.length > 0) {
122
+ lastReviewedHeight = ptxs[0].height - 1;
123
+ }
124
+ });
125
+ return lastReviewedHeight;
126
+ }
127
+ }
128
+ exports.TaskReviewProvenTxs = TaskReviewProvenTxs;
129
+ TaskReviewProvenTxs.taskName = 'ReviewProvenTxs';
130
+ TaskReviewProvenTxs.checkNow = false;
131
+ //# sourceMappingURL=TaskReviewProvenTxs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TaskReviewProvenTxs.js","sourceRoot":"","sources":["../../../../src/monitor/tasks/TaskReviewProvenTxs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import { Monitor } from '../Monitor';
2
+ import { WalletMonitorTask } from './WalletMonitorTask';
3
+ /**
4
+ * Use the reviewByIdentityKey method to review the utxos of a specific user by their identityKey.
5
+ *
6
+ * The task itself is disabled and will not run on a schedule; review must be triggered manually by calling reviewByIdentityKey.
7
+ */
8
+ export declare class TaskReviewUtxos extends WalletMonitorTask {
9
+ triggerMsecs: number;
10
+ userLimit: number;
11
+ userOffset: number;
12
+ tags: string[];
13
+ static taskName: string;
14
+ static checkNow: boolean;
15
+ constructor(monitor: Monitor, triggerMsecs?: number, userLimit?: number, userOffset?: number, tags?: string[]);
16
+ trigger(_nowMsecsSinceEpoch: number): {
17
+ run: boolean;
18
+ };
19
+ runTask(): Promise<string>;
20
+ reviewByIdentityKey(identityKey: string, mode?: 'all' | 'change'): Promise<string>;
21
+ private toUserLog;
22
+ }
23
+ //# sourceMappingURL=TaskReviewUtxos.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TaskReviewUtxos.d.ts","sourceRoot":"","sources":["../../../../src/monitor/tasks/TaskReviewUtxos.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AACpC,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAEvD;;;;GAIG;AACH,qBAAa,eAAgB,SAAQ,iBAAiB;IAO3C,YAAY;IACZ,SAAS;IACT,UAAU;IACV,IAAI,EAAE,MAAM,EAAE;IATvB,MAAM,CAAC,QAAQ,SAAgB;IAE/B,MAAM,CAAC,QAAQ,UAAQ;gBAGrB,OAAO,EAAE,OAAO,EACT,YAAY,SAAI,EAChB,SAAS,SAAK,EACd,UAAU,SAAI,EACd,IAAI,GAAE,MAAM,EAAuB;IAK5C,OAAO,CAAC,mBAAmB,EAAE,MAAM,GAAG;QAAE,GAAG,EAAE,OAAO,CAAA;KAAE;IAMhD,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC;IAK1B,mBAAmB,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,GAAE,KAAK,GAAG,QAAgB,GAAG,OAAO,CAAC,MAAM,CAAC;IAkC/F,OAAO,CAAC,SAAS;CAelB"}
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TaskReviewUtxos = void 0;
4
+ const sdk_1 = require("../../sdk");
5
+ const WalletMonitorTask_1 = require("./WalletMonitorTask");
6
+ /**
7
+ * Use the reviewByIdentityKey method to review the utxos of a specific user by their identityKey.
8
+ *
9
+ * The task itself is disabled and will not run on a schedule; review must be triggered manually by calling reviewByIdentityKey.
10
+ */
11
+ class TaskReviewUtxos extends WalletMonitorTask_1.WalletMonitorTask {
12
+ constructor(monitor, triggerMsecs = 0, userLimit = 10, userOffset = 0, tags = ['release', 'all']) {
13
+ super(monitor, TaskReviewUtxos.taskName);
14
+ this.triggerMsecs = triggerMsecs;
15
+ this.userLimit = userLimit;
16
+ this.userOffset = userOffset;
17
+ this.tags = tags;
18
+ }
19
+ trigger(_nowMsecsSinceEpoch) {
20
+ return {
21
+ run: false
22
+ };
23
+ }
24
+ async runTask() {
25
+ TaskReviewUtxos.checkNow = false;
26
+ return 'TaskReviewUtxos is disabled; use reviewByIdentityKey instead.\n';
27
+ }
28
+ async reviewByIdentityKey(identityKey, mode = 'all') {
29
+ const tags = ['release', ...(mode === 'all' ? ['all'] : [])];
30
+ const vargs = {
31
+ basket: sdk_1.specOpInvalidChange,
32
+ tags,
33
+ tagQueryMode: 'all',
34
+ includeLockingScripts: false,
35
+ includeTransactions: false,
36
+ includeCustomInstructions: false,
37
+ includeTags: false,
38
+ includeLabels: false,
39
+ limit: 0,
40
+ offset: 0,
41
+ seekPermission: false,
42
+ knownTxids: []
43
+ };
44
+ return await this.storage.runAsStorageProvider(async (sp) => {
45
+ const user = (await sp.findUsers({ partial: { identityKey } }))[0];
46
+ if (!user) {
47
+ return `identityKey ${identityKey} was not found\n`;
48
+ }
49
+ const auth = { userId: user.userId, identityKey: user.identityKey };
50
+ const result = await sp.listOutputs(auth, vargs);
51
+ if (result.totalOutputs === 0) {
52
+ return `userId ${user.userId}: no invalid utxos found, ${user.identityKey}\n`;
53
+ }
54
+ const total = result.outputs.reduce((sum, output) => sum + output.satoshis, 0);
55
+ return this.toUserLog(user, result.outputs, result.totalOutputs, total, tags);
56
+ });
57
+ }
58
+ toUserLog(user, outputs, totalOutputs, total, tags) {
59
+ const action = tags.includes('release') ? 'updated to unspendable' : 'found';
60
+ const target = tags.includes('all') ? 'spendable utxos' : 'spendable change utxos';
61
+ let log = `userId ${user.userId}: ${totalOutputs} ${target} ${action}, total ${total}, ${user.identityKey}\n`;
62
+ for (const output of outputs) {
63
+ log += ` ${output.outpoint} ${output.satoshis} now ${output.spendable ? 'spendable' : 'spent'}\n`;
64
+ }
65
+ return log;
66
+ }
67
+ }
68
+ exports.TaskReviewUtxos = TaskReviewUtxos;
69
+ TaskReviewUtxos.taskName = 'ReviewUtxos';
70
+ TaskReviewUtxos.checkNow = false;
71
+ //# sourceMappingURL=TaskReviewUtxos.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TaskReviewUtxos.js","sourceRoot":"","sources":["../../../../src/monitor/tasks/TaskReviewUtxos.ts"],"names":[],"mappings":";;;AACA,mCAA+C;AAG/C,2DAAuD;AAEvD;;;;GAIG;AACH,MAAa,eAAgB,SAAQ,qCAAiB;IAKpD,YACE,OAAgB,EACT,eAAe,CAAC,EAChB,YAAY,EAAE,EACd,aAAa,CAAC,EACd,OAAiB,CAAC,SAAS,EAAE,KAAK,CAAC;QAE1C,KAAK,CAAC,OAAO,EAAE,eAAe,CAAC,QAAQ,CAAC,CAAA;QALjC,iBAAY,GAAZ,YAAY,CAAI;QAChB,cAAS,GAAT,SAAS,CAAK;QACd,eAAU,GAAV,UAAU,CAAI;QACd,SAAI,GAAJ,IAAI,CAA+B;IAG5C,CAAC;IAED,OAAO,CAAC,mBAA2B;QACjC,OAAO;YACL,GAAG,EAAE,KAAK;SACX,CAAA;IACH,CAAC;IAED,KAAK,CAAC,OAAO;QACX,eAAe,CAAC,QAAQ,GAAG,KAAK,CAAA;QAChC,OAAO,iEAAiE,CAAA;IAC1E,CAAC;IAED,KAAK,CAAC,mBAAmB,CAAC,WAAmB,EAAE,OAAyB,KAAK;QAC3E,MAAM,IAAI,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;QAC5D,MAAM,KAAK,GAAoC;YAC7C,MAAM,EAAE,yBAAmB;YAC3B,IAAI;YACJ,YAAY,EAAE,KAAK;YACnB,qBAAqB,EAAE,KAAK;YAC5B,mBAAmB,EAAE,KAAK;YAC1B,yBAAyB,EAAE,KAAK;YAChC,WAAW,EAAE,KAAK;YAClB,aAAa,EAAE,KAAK;YACpB,KAAK,EAAE,CAAC;YACR,MAAM,EAAE,CAAC;YACT,cAAc,EAAE,KAAK;YACrB,UAAU,EAAE,EAAE;SACf,CAAA;QAED,OAAO,MAAM,IAAI,CAAC,OAAO,CAAC,oBAAoB,CAAC,KAAK,EAAC,EAAE,EAAC,EAAE;YACxD,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,EAAE,WAAW,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;YAClE,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,OAAO,eAAe,WAAW,kBAAkB,CAAA;YACrD,CAAC;YAED,MAAM,IAAI,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,CAAA;YACnE,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;YAChD,IAAI,MAAM,CAAC,YAAY,KAAK,CAAC,EAAE,CAAC;gBAC9B,OAAO,UAAU,IAAI,CAAC,MAAM,6BAA6B,IAAI,CAAC,WAAW,IAAI,CAAA;YAC/E,CAAC;YAED,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,CAAC,GAAG,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAA;YAC9E,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,YAAY,EAAE,KAAK,EAAE,IAAI,CAAC,CAAA;QAC/E,CAAC,CAAC,CAAA;IACJ,CAAC;IAEO,SAAS,CACf,IAAe,EACf,OAAuB,EACvB,YAAoB,EACpB,KAAa,EACb,IAAc;QAEd,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,wBAAwB,CAAC,CAAC,CAAC,OAAO,CAAA;QAC5E,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,wBAAwB,CAAA;QAClF,IAAI,GAAG,GAAG,UAAU,IAAI,CAAC,MAAM,KAAK,YAAY,IAAI,MAAM,IAAI,MAAM,WAAW,KAAK,KAAK,IAAI,CAAC,WAAW,IAAI,CAAA;QAC7G,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,GAAG,IAAI,KAAK,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,QAAQ,QAAQ,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,IAAI,CAAA;QACpG,CAAC;QACD,OAAO,GAAG,CAAA;IACZ,CAAC;;AA1EH,0CA2EC;AA1EQ,wBAAQ,GAAG,aAAa,CAAA;AAExB,wBAAQ,GAAG,KAAK,CAAA"}
@@ -5,14 +5,27 @@ export declare class TaskSendWaiting extends WalletMonitorTask {
5
5
  triggerMsecs: number;
6
6
  agedMsecs: number;
7
7
  sendingMsecs: number;
8
+ triggerQuickMsecs: number;
9
+ chunkLimit: number;
8
10
  static taskName: string;
9
11
  lastSendingRunMsecsSinceEpoch: number | undefined;
10
12
  includeSending: boolean;
11
- constructor(monitor: Monitor, triggerMsecs?: number, agedMsecs?: number, sendingMsecs?: number);
13
+ triggerNextMsecs: number;
14
+ /**
15
+ * @param monitor Wallet monitor owning this task.
16
+ * @param triggerMsecs Normal interval between SendWaiting runs when no backlog remains.
17
+ * @param agedMsecs Minimum age a request must reach before this task will attempt to send it.
18
+ * @param sendingMsecs Minimum interval before stale `sending` requests are included again.
19
+ * @param triggerQuickMsecs Follow-up interval used when a full chunk was consumed and more work may remain.
20
+ * @param chunkLimit Maximum number of waiting requests to fetch and inspect in a single run.
21
+ */
22
+ constructor(monitor: Monitor, triggerMsecs?: number, agedMsecs?: number, sendingMsecs?: number, triggerQuickMsecs?: number, chunkLimit?: number);
12
23
  trigger(nowMsecsSinceEpoch: number): {
13
24
  run: boolean;
14
25
  };
15
26
  runTask(): Promise<string>;
27
+ private expandBatches;
28
+ private filterAgedReqs;
16
29
  /**
17
30
  * Process an array of 'unsent' status table.ProvenTxReq
18
31
  *
@@ -1 +1 @@
1
- {"version":3,"file":"TaskSendWaiting.d.ts","sourceRoot":"","sources":["../../../../src/monitor/tasks/TaskSendWaiting.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AACpC,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAKvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,8CAA8C,CAAA;AAG/E,qBAAa,eAAgB,SAAQ,iBAAiB;IAQ3C,YAAY;IACZ,SAAS;IACT,YAAY;IATrB,MAAM,CAAC,QAAQ,SAAgB;IAE/B,6BAA6B,EAAE,MAAM,GAAG,SAAS,CAAA;IACjD,cAAc,EAAE,OAAO,CAAO;gBAG5B,OAAO,EAAE,OAAO,EACT,YAAY,SAAwB,EACpC,SAAS,SAAwB,EACjC,YAAY,SAAwB;IAK7C,OAAO,CAAC,kBAAkB,EAAE,MAAM,GAAG;QAAE,GAAG,EAAE,OAAO,CAAA;KAAE;IAS/C,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC;IAwBhC;;;;;;;;;;;;;;;;OAgBG;IACG,aAAa,CAAC,OAAO,EAAE,gBAAgB,EAAE,EAAE,MAAM,SAAI,GAAG,OAAO,CAAC,MAAM,CAAC;CAyD9E"}
1
+ {"version":3,"file":"TaskSendWaiting.d.ts","sourceRoot":"","sources":["../../../../src/monitor/tasks/TaskSendWaiting.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AACpC,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAKvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,8CAA8C,CAAA;AAG/E,qBAAa,eAAgB,SAAQ,iBAAiB;IAiB3C,YAAY;IACZ,SAAS;IACT,YAAY;IACZ,iBAAiB;IACjB,UAAU;IApBnB,MAAM,CAAC,QAAQ,SAAgB;IAE/B,6BAA6B,EAAE,MAAM,GAAG,SAAS,CAAA;IACjD,cAAc,EAAE,OAAO,CAAO;IAC9B,gBAAgB,EAAE,MAAM,CAAA;IAExB;;;;;;;OAOG;gBAED,OAAO,EAAE,OAAO,EACT,YAAY,SAAwB,EACpC,SAAS,SAAwB,EACjC,YAAY,SAAwB,EACpC,iBAAiB,SAAwB,EACzC,UAAU,SAAM;IAMzB,OAAO,CAAC,kBAAkB,EAAE,MAAM,GAAG;QAAE,GAAG,EAAE,OAAO,CAAA;KAAE;IAS/C,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC;YAqClB,aAAa;IA8B3B,OAAO,CAAC,cAAc;IAuBtB;;;;;;;;;;;;;;;;OAgBG;IACG,aAAa,CAAC,OAAO,EAAE,gBAAgB,EAAE,EAAE,MAAM,SAAI,GAAG,OAAO,CAAC,MAAM,CAAC;CA6D9E"}
@@ -8,12 +8,23 @@ const aggregateResults_1 = require("../../utility/aggregateResults");
8
8
  const utilityHelpers_1 = require("../../utility/utilityHelpers");
9
9
  const EntityProvenTxReq_1 = require("../../storage/schema/entities/EntityProvenTxReq");
10
10
  class TaskSendWaiting extends WalletMonitorTask_1.WalletMonitorTask {
11
- constructor(monitor, triggerMsecs = Monitor_1.Monitor.oneSecond * 8, agedMsecs = Monitor_1.Monitor.oneSecond * 7, sendingMsecs = Monitor_1.Monitor.oneMinute * 5) {
11
+ /**
12
+ * @param monitor Wallet monitor owning this task.
13
+ * @param triggerMsecs Normal interval between SendWaiting runs when no backlog remains.
14
+ * @param agedMsecs Minimum age a request must reach before this task will attempt to send it.
15
+ * @param sendingMsecs Minimum interval before stale `sending` requests are included again.
16
+ * @param triggerQuickMsecs Follow-up interval used when a full chunk was consumed and more work may remain.
17
+ * @param chunkLimit Maximum number of waiting requests to fetch and inspect in a single run.
18
+ */
19
+ constructor(monitor, triggerMsecs = Monitor_1.Monitor.oneSecond * 8, agedMsecs = Monitor_1.Monitor.oneSecond * 7, sendingMsecs = Monitor_1.Monitor.oneMinute * 5, triggerQuickMsecs = Monitor_1.Monitor.oneSecond * 1, chunkLimit = 100) {
12
20
  super(monitor, TaskSendWaiting.taskName);
13
21
  this.triggerMsecs = triggerMsecs;
14
22
  this.agedMsecs = agedMsecs;
15
23
  this.sendingMsecs = sendingMsecs;
24
+ this.triggerQuickMsecs = triggerQuickMsecs;
25
+ this.chunkLimit = chunkLimit;
16
26
  this.includeSending = true;
27
+ this.triggerNextMsecs = this.triggerQuickMsecs;
17
28
  }
18
29
  trigger(nowMsecsSinceEpoch) {
19
30
  this.includeSending =
@@ -21,34 +32,88 @@ class TaskSendWaiting extends WalletMonitorTask_1.WalletMonitorTask {
21
32
  if (this.includeSending)
22
33
  this.lastSendingRunMsecsSinceEpoch = nowMsecsSinceEpoch;
23
34
  return {
24
- run: nowMsecsSinceEpoch > this.lastRunMsecsSinceEpoch + this.triggerMsecs
35
+ run: nowMsecsSinceEpoch > this.lastRunMsecsSinceEpoch + this.triggerNextMsecs
25
36
  };
26
37
  }
27
38
  async runTask() {
28
39
  let log = '';
29
- const limit = 100;
30
- let offset = 0;
31
- const agedLimit = new Date(Date.now() - this.agedMsecs);
40
+ const nowMsecsSinceEpoch = Date.now();
41
+ const agedLimit = new Date(nowMsecsSinceEpoch - this.agedMsecs);
32
42
  const status = this.includeSending ? ['unsent', 'sending'] : ['unsent'];
33
- for (;;) {
34
- let reqs = await this.storage.findProvenTxReqs({
35
- partial: {},
36
- status,
37
- paged: { limit, offset }
38
- });
39
- const count = reqs.length;
40
- if (reqs.length === 0)
41
- break;
42
- log += `${reqs.length} reqs with status ${status.join(' or ')}\n`;
43
- const agedReqs = reqs.filter(req => (0, utilityHelpers_1.verifyTruthy)(req.updated_at) < agedLimit);
43
+ const reqs = await this.storage.findProvenTxReqs({
44
+ partial: {},
45
+ status,
46
+ paged: { limit: this.chunkLimit, offset: 0 }
47
+ });
48
+ const count = reqs.length;
49
+ if (count > 0) {
50
+ log += `${count} reqs with status ${status.join(' or ')}\n`;
51
+ const filteredReqs = await this.expandBatches(reqs, status);
52
+ const agedReqs = this.filterAgedReqs(filteredReqs, agedLimit);
44
53
  log += ` Of those reqs, ${agedReqs.length} where last updated before ${agedLimit.toISOString()}.\n`;
45
54
  log += await this.processUnsent(agedReqs, 2);
46
- if (count < limit)
47
- break;
48
- offset += limit;
55
+ if (count >= this.chunkLimit) {
56
+ this.triggerNextMsecs = this.triggerQuickMsecs;
57
+ }
58
+ else if (agedReqs.length < filteredReqs.length) {
59
+ const ageAllMsecs = Math.max(...filteredReqs.map(req => (0, utilityHelpers_1.verifyTruthy)(req.updated_at).getTime() + this.agedMsecs - nowMsecsSinceEpoch), 0);
60
+ this.triggerNextMsecs = ageAllMsecs;
61
+ }
62
+ else {
63
+ this.triggerNextMsecs = this.triggerMsecs;
64
+ }
65
+ }
66
+ else {
67
+ this.triggerNextMsecs = this.triggerMsecs;
49
68
  }
50
69
  return log;
51
70
  }
71
+ async expandBatches(reqs, status) {
72
+ const expanded = [];
73
+ const seenReqIds = new Set();
74
+ const seenBatches = new Set();
75
+ for (const req of reqs) {
76
+ if (seenReqIds.has(req.provenTxReqId))
77
+ continue;
78
+ if (!req.batch || seenBatches.has(req.batch)) {
79
+ seenReqIds.add(req.provenTxReqId);
80
+ expanded.push(req);
81
+ continue;
82
+ }
83
+ seenBatches.add(req.batch);
84
+ const batchReqs = await this.storage.findProvenTxReqs({
85
+ partial: { batch: req.batch },
86
+ status
87
+ });
88
+ for (const batchReq of batchReqs) {
89
+ if (seenReqIds.has(batchReq.provenTxReqId))
90
+ continue;
91
+ seenReqIds.add(batchReq.provenTxReqId);
92
+ expanded.push(batchReq);
93
+ }
94
+ }
95
+ return expanded;
96
+ }
97
+ filterAgedReqs(reqs, agedLimit) {
98
+ const agedReqs = [];
99
+ const seenBatches = new Set();
100
+ for (const req of reqs) {
101
+ if (!req.batch) {
102
+ if ((0, utilityHelpers_1.verifyTruthy)(req.updated_at) < agedLimit)
103
+ agedReqs.push(req);
104
+ continue;
105
+ }
106
+ if (seenBatches.has(req.batch))
107
+ continue;
108
+ seenBatches.add(req.batch);
109
+ const batchReqs = reqs.filter(candidate => candidate.batch === req.batch);
110
+ const youngestUpdatedAt = Math.max(...batchReqs.map(batchReq => (0, utilityHelpers_1.verifyTruthy)(batchReq.updated_at).getTime()));
111
+ if (youngestUpdatedAt < agedLimit.getTime()) {
112
+ agedReqs.push(...batchReqs);
113
+ }
114
+ }
115
+ return agedReqs;
116
+ }
52
117
  /**
53
118
  * Process an array of 'unsent' status table.ProvenTxReq
54
119
  *
@@ -69,12 +134,18 @@ class TaskSendWaiting extends WalletMonitorTask_1.WalletMonitorTask {
69
134
  async processUnsent(reqApis, indent = 0) {
70
135
  const txids = reqApis.map(r => r.txid);
71
136
  const logs = {};
137
+ const reqApiIds = new Set(reqApis.map(r => r.provenTxReqId));
138
+ const groupedReqIds = new Set();
72
139
  for (let i = 0; i < reqApis.length; i++) {
73
140
  const reqApi = reqApis[i];
74
141
  logs[reqApi.txid] = `${i} reqId=${reqApi.provenTxReqId} attempts=${reqApi.attempts} txid=${reqApi.txid}:`;
75
142
  }
76
143
  for (let i = 0; i < reqApis.length; i++) {
77
144
  const reqApi = reqApis[i];
145
+ if (groupedReqIds.has(reqApi.provenTxReqId)) {
146
+ logs[reqApi.txid] += ` processed with batch`;
147
+ continue;
148
+ }
78
149
  if (reqApi.status !== 'unsent' && reqApi.status !== 'sending') {
79
150
  logs[reqApi.txid] += ` status now ${reqApi.status}`;
80
151
  continue;
@@ -85,14 +156,12 @@ class TaskSendWaiting extends WalletMonitorTask_1.WalletMonitorTask {
85
156
  logs[reqApi.txid] += ` batch ${req.batch}`;
86
157
  // Make sure wew process entire batch together for efficient beef generation
87
158
  const batchReqApis = await this.storage.findProvenTxReqs({
88
- partial: { batch: req.batch, status: 'unsent' }
159
+ partial: { batch: req.batch },
160
+ status: this.includeSending ? ['unsent', 'sending'] : ['unsent']
89
161
  });
90
162
  for (const bra of batchReqApis) {
91
- // Remove any matching batchReqApis from reqApis
92
- const index = reqApis.findIndex(ra => ra.provenTxReqId === bra.provenTxReqId);
93
- if (index > -1)
94
- reqApis.slice(index, index + 1);
95
- // And add to reqs being processed now:
163
+ if (reqApiIds.has(bra.provenTxReqId))
164
+ groupedReqIds.add(bra.provenTxReqId);
96
165
  reqs.push(new EntityProvenTxReq_1.EntityProvenTxReq(bra));
97
166
  }
98
167
  }