@bsv/wallet-toolbox 2.1.9 → 2.1.11
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.
- package/CHANGELOG.md +22 -0
- package/docs/client.md +447 -170
- package/docs/monitor.md +153 -16
- package/docs/setup.md +4 -8
- package/docs/storage.md +37 -8
- package/docs/wallet.md +447 -170
- package/out/src/CWIStyleWalletManager.d.ts +57 -5
- package/out/src/CWIStyleWalletManager.d.ts.map +1 -1
- package/out/src/CWIStyleWalletManager.js +282 -46
- package/out/src/CWIStyleWalletManager.js.map +1 -1
- package/out/src/Setup.d.ts.map +1 -1
- package/out/src/Setup.js +1 -2
- package/out/src/Setup.js.map +1 -1
- package/out/src/SetupClient.d.ts.map +1 -1
- package/out/src/SetupClient.js +1 -2
- package/out/src/SetupClient.js.map +1 -1
- package/out/src/WalletAuthenticationManager.d.ts +1 -1
- package/out/src/WalletAuthenticationManager.d.ts.map +1 -1
- package/out/src/WalletAuthenticationManager.js +41 -31
- package/out/src/WalletAuthenticationManager.js.map +1 -1
- package/out/src/__tests/CWIStyleWalletManager.test.js +219 -10
- package/out/src/__tests/CWIStyleWalletManager.test.js.map +1 -1
- package/out/src/index.all.d.ts +1 -2
- package/out/src/index.all.d.ts.map +1 -1
- package/out/src/index.all.js +1 -2
- package/out/src/index.all.js.map +1 -1
- package/out/src/monitor/Monitor.d.ts +4 -3
- package/out/src/monitor/Monitor.d.ts.map +1 -1
- package/out/src/monitor/Monitor.js +39 -11
- package/out/src/monitor/Monitor.js.map +1 -1
- package/out/src/monitor/MonitorDaemon.d.ts +2 -1
- package/out/src/monitor/MonitorDaemon.d.ts.map +1 -1
- package/out/src/monitor/MonitorDaemon.js +1 -4
- package/out/src/monitor/MonitorDaemon.js.map +1 -1
- package/out/src/monitor/index.all.d.ts +4 -0
- package/out/src/monitor/index.all.d.ts.map +1 -0
- package/out/src/monitor/index.all.js +43 -0
- package/out/src/monitor/index.all.js.map +1 -0
- package/out/src/monitor/tasks/TaskReviewDoubleSpends.d.ts +26 -0
- package/out/src/monitor/tasks/TaskReviewDoubleSpends.d.ts.map +1 -0
- package/out/src/monitor/tasks/TaskReviewDoubleSpends.js +124 -0
- package/out/src/monitor/tasks/TaskReviewDoubleSpends.js.map +1 -0
- package/out/src/monitor/tasks/TaskReviewProvenTxs.d.ts +34 -0
- package/out/src/monitor/tasks/TaskReviewProvenTxs.d.ts.map +1 -0
- package/out/src/monitor/tasks/TaskReviewProvenTxs.js +131 -0
- package/out/src/monitor/tasks/TaskReviewProvenTxs.js.map +1 -0
- package/out/src/monitor/tasks/TaskReviewUtxos.d.ts +23 -0
- package/out/src/monitor/tasks/TaskReviewUtxos.d.ts.map +1 -0
- package/out/src/monitor/tasks/TaskReviewUtxos.js +71 -0
- package/out/src/monitor/tasks/TaskReviewUtxos.js.map +1 -0
- package/out/src/monitor/tasks/TaskSendWaiting.d.ts +14 -1
- package/out/src/monitor/tasks/TaskSendWaiting.d.ts.map +1 -1
- package/out/src/monitor/tasks/TaskSendWaiting.js +86 -20
- package/out/src/monitor/tasks/TaskSendWaiting.js.map +1 -1
- package/out/src/monitor/tasks/__tests/TaskReviewDoubleSpends.test.d.ts +2 -0
- package/out/src/monitor/tasks/__tests/TaskReviewDoubleSpends.test.d.ts.map +1 -0
- package/out/src/monitor/tasks/__tests/TaskReviewDoubleSpends.test.js +161 -0
- package/out/src/monitor/tasks/__tests/TaskReviewDoubleSpends.test.js.map +1 -0
- package/out/src/monitor/tasks/__tests/TaskReviewProvenTxs.test.d.ts +2 -0
- package/out/src/monitor/tasks/__tests/TaskReviewProvenTxs.test.d.ts.map +1 -0
- package/out/src/monitor/tasks/__tests/TaskReviewProvenTxs.test.js +214 -0
- package/out/src/monitor/tasks/__tests/TaskReviewProvenTxs.test.js.map +1 -0
- package/out/src/monitor/tasks/__tests/TaskReviewUtxos.test.d.ts +2 -0
- package/out/src/monitor/tasks/__tests/TaskReviewUtxos.test.d.ts.map +1 -0
- package/out/src/monitor/tasks/__tests/TaskReviewUtxos.test.js +92 -0
- package/out/src/monitor/tasks/__tests/TaskReviewUtxos.test.js.map +1 -0
- package/out/src/monitor/tasks/__tests/TaskSendWaiting.test.d.ts +2 -0
- package/out/src/monitor/tasks/__tests/TaskSendWaiting.test.d.ts.map +1 -0
- package/out/src/monitor/tasks/__tests/TaskSendWaiting.test.js +139 -0
- package/out/src/monitor/tasks/__tests/TaskSendWaiting.test.js.map +1 -0
- package/out/src/monitor/tasks/index.all.d.ts +19 -0
- package/out/src/monitor/tasks/index.all.d.ts.map +1 -0
- package/out/src/monitor/tasks/index.all.js +35 -0
- package/out/src/monitor/tasks/index.all.js.map +1 -0
- package/out/src/sdk/WalletStorage.interfaces.d.ts +9 -0
- package/out/src/sdk/WalletStorage.interfaces.d.ts.map +1 -1
- package/out/src/services/Services.d.ts.map +1 -1
- package/out/src/services/Services.js +10 -2
- package/out/src/services/Services.js.map +1 -1
- package/out/src/services/__tests/getFiatExchangeRate.test.d.ts +2 -0
- package/out/src/services/__tests/getFiatExchangeRate.test.d.ts.map +1 -0
- package/out/src/services/__tests/getFiatExchangeRate.test.js +156 -0
- package/out/src/services/__tests/getFiatExchangeRate.test.js.map +1 -0
- package/out/src/services/chaintracker/chaintracks/Ingest/BulkIngestorWhatsOnChainCdn.js +1 -1
- package/out/src/services/chaintracker/chaintracks/Ingest/BulkIngestorWhatsOnChainCdn.js.map +1 -1
- package/out/src/services/createDefaultWalletServicesOptions.js +1 -1
- package/out/src/services/createDefaultWalletServicesOptions.js.map +1 -1
- package/out/src/services/providers/__tests/exchangeRates.test.js +4 -0
- package/out/src/services/providers/__tests/exchangeRates.test.js.map +1 -1
- package/out/src/storage/StorageKnex.d.ts +3 -1
- package/out/src/storage/StorageKnex.d.ts.map +1 -1
- package/out/src/storage/StorageKnex.js +26 -5
- package/out/src/storage/StorageKnex.js.map +1 -1
- package/out/src/storage/StorageProvider.d.ts +6 -1
- package/out/src/storage/StorageProvider.d.ts.map +1 -1
- package/out/src/storage/StorageProvider.js +6 -0
- package/out/src/storage/StorageProvider.js.map +1 -1
- package/out/src/storage/StorageReaderWriter.d.ts +2 -1
- package/out/src/storage/StorageReaderWriter.d.ts.map +1 -1
- package/out/src/storage/StorageReaderWriter.js.map +1 -1
- package/out/src/storage/WalletStorageManager.d.ts +7 -0
- package/out/src/storage/WalletStorageManager.d.ts.map +1 -1
- package/out/src/storage/WalletStorageManager.js +33 -2
- package/out/src/storage/WalletStorageManager.js.map +1 -1
- package/out/src/storage/__test/findStaleMerkleRoots.test.d.ts +2 -0
- package/out/src/storage/__test/findStaleMerkleRoots.test.d.ts.map +1 -0
- package/out/src/storage/__test/findStaleMerkleRoots.test.js +41 -0
- package/out/src/storage/__test/findStaleMerkleRoots.test.js.map +1 -0
- package/out/src/storage/__test/findStaleMerkleRootsKnex.test.d.ts +2 -0
- package/out/src/storage/__test/findStaleMerkleRootsKnex.test.d.ts.map +1 -0
- package/out/src/storage/__test/findStaleMerkleRootsKnex.test.js +73 -0
- package/out/src/storage/__test/findStaleMerkleRootsKnex.test.js.map +1 -0
- package/out/src/utility/Format.d.ts.map +1 -1
- package/out/src/utility/Format.js +1 -0
- package/out/src/utility/Format.js.map +1 -1
- package/out/src/utility/index.all.d.ts +1 -0
- package/out/src/utility/index.all.d.ts.map +1 -1
- package/out/src/utility/index.all.js +1 -0
- package/out/src/utility/index.all.js.map +1 -1
- package/package.json +3 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TaskReviewUtxos.js","sourceRoot":"","sources":["../../../../src/monitor/tasks/TaskReviewUtxos.ts"],"names":[],"mappings":"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"}
|
|
@@ -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
|
-
|
|
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;
|
|
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
|
-
|
|
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.
|
|
35
|
+
run: nowMsecsSinceEpoch > this.lastRunMsecsSinceEpoch + this.triggerNextMsecs
|
|
25
36
|
};
|
|
26
37
|
}
|
|
27
38
|
async runTask() {
|
|
28
39
|
let log = '';
|
|
29
|
-
const
|
|
30
|
-
|
|
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
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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
|
|
47
|
-
|
|
48
|
-
|
|
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
|
*
|
|
@@ -91,7 +156,8 @@ class TaskSendWaiting extends WalletMonitorTask_1.WalletMonitorTask {
|
|
|
91
156
|
logs[reqApi.txid] += ` batch ${req.batch}`;
|
|
92
157
|
// Make sure wew process entire batch together for efficient beef generation
|
|
93
158
|
const batchReqApis = await this.storage.findProvenTxReqs({
|
|
94
|
-
partial: { batch: req.batch
|
|
159
|
+
partial: { batch: req.batch },
|
|
160
|
+
status: this.includeSending ? ['unsent', 'sending'] : ['unsent']
|
|
95
161
|
});
|
|
96
162
|
for (const bra of batchReqApis) {
|
|
97
163
|
if (reqApiIds.has(bra.provenTxReqId))
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TaskSendWaiting.js","sourceRoot":"","sources":["../../../../src/monitor/tasks/TaskSendWaiting.ts"],"names":[],"mappings":";;;AACA,wCAAoC;AACpC,2DAAuD;AACvD,iGAA6F;AAC7F,qEAAuE;AAEvE,iEAA2D;AAE3D,uFAAmF;AAEnF,MAAa,eAAgB,SAAQ,qCAAiB;
|
|
1
|
+
{"version":3,"file":"TaskSendWaiting.js","sourceRoot":"","sources":["../../../../src/monitor/tasks/TaskSendWaiting.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TaskReviewDoubleSpends.test.d.ts","sourceRoot":"","sources":["../../../../../src/monitor/tasks/__tests/TaskReviewDoubleSpends.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const TaskReviewDoubleSpends_1 = require("../TaskReviewDoubleSpends");
|
|
4
|
+
function makeReq(provenTxReqId, txid, updatedAt) {
|
|
5
|
+
const now = new Date();
|
|
6
|
+
return {
|
|
7
|
+
provenTxReqId,
|
|
8
|
+
created_at: now,
|
|
9
|
+
updated_at: updatedAt,
|
|
10
|
+
txid,
|
|
11
|
+
status: 'doubleSpend',
|
|
12
|
+
history: '{}',
|
|
13
|
+
notify: '{}',
|
|
14
|
+
attempts: 0,
|
|
15
|
+
notified: false
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
function makeMonitor(statusByTxid, reqs, monitorEvents = []) {
|
|
19
|
+
const updateProvenTxReq = jest.fn().mockResolvedValue(undefined);
|
|
20
|
+
const findProvenTxReqs = jest.fn(async ({ paged }) => reqs.slice(paged.offset, paged.offset + paged.limit));
|
|
21
|
+
const findMonitorEvents = jest.fn().mockResolvedValue(monitorEvents);
|
|
22
|
+
const runAsStorageProvider = jest.fn(async (fn) => await fn({ updateProvenTxReq, findMonitorEvents }));
|
|
23
|
+
const logEvent = jest.fn().mockResolvedValue(undefined);
|
|
24
|
+
return {
|
|
25
|
+
monitor: {
|
|
26
|
+
storage: {
|
|
27
|
+
findProvenTxReqs,
|
|
28
|
+
runAsStorageProvider
|
|
29
|
+
},
|
|
30
|
+
services: {
|
|
31
|
+
getStatusForTxids: jest.fn(async (txids) => ({
|
|
32
|
+
results: txids.map(txid => { var _a; return ({ txid, status: (_a = statusByTxid[txid]) !== null && _a !== void 0 ? _a : 'unknown' }); })
|
|
33
|
+
}))
|
|
34
|
+
},
|
|
35
|
+
logEvent
|
|
36
|
+
},
|
|
37
|
+
updateProvenTxReq,
|
|
38
|
+
findProvenTxReqs,
|
|
39
|
+
findMonitorEvents,
|
|
40
|
+
runAsStorageProvider,
|
|
41
|
+
logEvent
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
describe('TaskReviewDoubleSpends', () => {
|
|
45
|
+
afterEach(() => {
|
|
46
|
+
jest.restoreAllMocks();
|
|
47
|
+
});
|
|
48
|
+
test('0 uses the normal cadence after a partial review chunk and stores checkpoint offset after unfails are removed', async () => {
|
|
49
|
+
const now = new Date('2026-01-01T12:00:00.000Z');
|
|
50
|
+
jest.spyOn(Date, 'now').mockReturnValue(now.getTime());
|
|
51
|
+
const reqs = [
|
|
52
|
+
makeReq(1, 'tx1', new Date('2026-01-01T10:30:00.000Z')),
|
|
53
|
+
makeReq(2, 'tx2', new Date('2026-01-01T10:40:00.000Z'))
|
|
54
|
+
];
|
|
55
|
+
const m = makeMonitor({ tx1: 'success', tx2: 'unknown' }, reqs);
|
|
56
|
+
const task = new TaskReviewDoubleSpends_1.TaskReviewDoubleSpends(m.monitor, 0, 100, 60, 60);
|
|
57
|
+
const log = await task.runTask();
|
|
58
|
+
expect(m.findProvenTxReqs).toHaveBeenCalledWith({
|
|
59
|
+
partial: { status: 'doubleSpend' },
|
|
60
|
+
paged: { limit: 100, offset: 0 }
|
|
61
|
+
});
|
|
62
|
+
expect(m.updateProvenTxReq).toHaveBeenCalledWith([1], { status: 'unfail' });
|
|
63
|
+
expect(m.logEvent).not.toHaveBeenCalled();
|
|
64
|
+
expect(log).toContain('"reviewed":2');
|
|
65
|
+
expect(log).toContain('"unfails":1');
|
|
66
|
+
expect(log).toContain('"resumeOffset":0');
|
|
67
|
+
expect(log).toContain('"expectedProvenTxReqId":2');
|
|
68
|
+
expect(log).toContain('unfail 1 tx1 status:success');
|
|
69
|
+
expect(task.triggerNextMsecs).toBe(0);
|
|
70
|
+
});
|
|
71
|
+
test('0a stores the retained req offset in the post-unfail doubleSpend list', async () => {
|
|
72
|
+
const now = new Date('2026-01-01T12:00:00.000Z');
|
|
73
|
+
jest.spyOn(Date, 'now').mockReturnValue(now.getTime());
|
|
74
|
+
const reqs = [
|
|
75
|
+
makeReq(1, 'tx1', new Date('2026-01-01T10:30:00.000Z')),
|
|
76
|
+
makeReq(2, 'tx2', new Date('2026-01-01T10:35:00.000Z')),
|
|
77
|
+
makeReq(3, 'tx3', new Date('2026-01-01T10:40:00.000Z'))
|
|
78
|
+
];
|
|
79
|
+
const m = makeMonitor({ tx1: 'success', tx2: 'unknown', tx3: 'unknown' }, reqs);
|
|
80
|
+
const task = new TaskReviewDoubleSpends_1.TaskReviewDoubleSpends(m.monitor, 0, 100, 60, 60);
|
|
81
|
+
const log = await task.runTask();
|
|
82
|
+
expect(m.updateProvenTxReq).toHaveBeenCalledWith([1], { status: 'unfail' });
|
|
83
|
+
expect(log).toContain('"resumeOffset":1');
|
|
84
|
+
expect(log).toContain('"expectedProvenTxReqId":3');
|
|
85
|
+
});
|
|
86
|
+
test('1 skips reqs newer than the minAgeMinutes cutoff and returns empty when nothing is eligible', async () => {
|
|
87
|
+
const now = new Date('2026-01-01T12:00:00.000Z');
|
|
88
|
+
jest.spyOn(Date, 'now').mockReturnValue(now.getTime());
|
|
89
|
+
const reqs = [makeReq(1, 'tx1', new Date('2026-01-01T11:30:01.000Z'))];
|
|
90
|
+
const m = makeMonitor({ tx1: 'unknown' }, reqs);
|
|
91
|
+
const task = new TaskReviewDoubleSpends_1.TaskReviewDoubleSpends(m.monitor, 0, 100, 60, 60);
|
|
92
|
+
const log = await task.runTask();
|
|
93
|
+
expect(m.updateProvenTxReq).not.toHaveBeenCalled();
|
|
94
|
+
expect(m.logEvent).not.toHaveBeenCalled();
|
|
95
|
+
expect(log).toBe('');
|
|
96
|
+
expect(task.triggerNextMsecs).toBe(0);
|
|
97
|
+
});
|
|
98
|
+
test('1b uses the quick cadence after consuming a full review chunk', async () => {
|
|
99
|
+
const now = new Date('2026-01-01T12:00:00.000Z');
|
|
100
|
+
jest.spyOn(Date, 'now').mockReturnValue(now.getTime());
|
|
101
|
+
const reqs = [
|
|
102
|
+
makeReq(1, 'tx1', new Date('2026-01-01T10:30:00.000Z')),
|
|
103
|
+
makeReq(2, 'tx2', new Date('2026-01-01T10:40:00.000Z'))
|
|
104
|
+
];
|
|
105
|
+
const m = makeMonitor({ tx1: 'success', tx2: 'unknown' }, reqs);
|
|
106
|
+
const task = new TaskReviewDoubleSpends_1.TaskReviewDoubleSpends(m.monitor, 0, 2, 60, 60);
|
|
107
|
+
await task.runTask();
|
|
108
|
+
expect(task.triggerNextMsecs).toBe(60);
|
|
109
|
+
});
|
|
110
|
+
test('2 resumes from the checkpoint offset and advances it', async () => {
|
|
111
|
+
const now = new Date('2026-01-01T12:00:00.000Z');
|
|
112
|
+
jest.spyOn(Date, 'now').mockReturnValue(now.getTime());
|
|
113
|
+
const reqs = [
|
|
114
|
+
makeReq(1, 'tx1', new Date('2026-01-01T10:00:00.000Z')),
|
|
115
|
+
makeReq(2, 'tx2', new Date('2026-01-01T10:05:00.000Z')),
|
|
116
|
+
makeReq(3, 'tx3', new Date('2026-01-01T10:10:00.000Z'))
|
|
117
|
+
];
|
|
118
|
+
const m = makeMonitor({ tx2: 'unknown', tx3: 'success' }, reqs, [
|
|
119
|
+
{ details: JSON.stringify({ resumeOffset: 1, expectedProvenTxReqId: 2 }) }
|
|
120
|
+
]);
|
|
121
|
+
const task = new TaskReviewDoubleSpends_1.TaskReviewDoubleSpends(m.monitor, 0, 2, 60);
|
|
122
|
+
const log = await task.runTask();
|
|
123
|
+
expect(m.findProvenTxReqs).toHaveBeenNthCalledWith(1, {
|
|
124
|
+
partial: { status: 'doubleSpend' },
|
|
125
|
+
paged: { limit: 1, offset: 1 }
|
|
126
|
+
});
|
|
127
|
+
expect(m.findProvenTxReqs).toHaveBeenNthCalledWith(2, {
|
|
128
|
+
partial: { status: 'doubleSpend' },
|
|
129
|
+
paged: { limit: 2, offset: 2 }
|
|
130
|
+
});
|
|
131
|
+
expect(m.updateProvenTxReq).toHaveBeenCalledWith([3], { status: 'unfail' });
|
|
132
|
+
expect(log).toContain('"reviewed":1');
|
|
133
|
+
expect(log).not.toContain('"resumeOffset"');
|
|
134
|
+
expect(log).not.toContain('"expectedProvenTxReqId"');
|
|
135
|
+
});
|
|
136
|
+
test('3 restarts at offset zero when the checkpoint verification id no longer matches', async () => {
|
|
137
|
+
const now = new Date('2026-01-01T12:00:00.000Z');
|
|
138
|
+
jest.spyOn(Date, 'now').mockReturnValue(now.getTime());
|
|
139
|
+
const reqs = [
|
|
140
|
+
makeReq(10, 'tx10', new Date('2026-01-01T10:00:00.000Z')),
|
|
141
|
+
makeReq(11, 'tx11', new Date('2026-01-01T10:05:00.000Z'))
|
|
142
|
+
];
|
|
143
|
+
const m = makeMonitor({ tx10: 'unknown', tx11: 'success' }, reqs, [
|
|
144
|
+
{ details: JSON.stringify({ resumeOffset: 1, expectedProvenTxReqId: 99 }) }
|
|
145
|
+
]);
|
|
146
|
+
const task = new TaskReviewDoubleSpends_1.TaskReviewDoubleSpends(m.monitor, 0, 2, 60);
|
|
147
|
+
const log = await task.runTask();
|
|
148
|
+
expect(m.findProvenTxReqs).toHaveBeenNthCalledWith(1, {
|
|
149
|
+
partial: { status: 'doubleSpend' },
|
|
150
|
+
paged: { limit: 1, offset: 1 }
|
|
151
|
+
});
|
|
152
|
+
expect(m.findProvenTxReqs).toHaveBeenNthCalledWith(2, {
|
|
153
|
+
partial: { status: 'doubleSpend' },
|
|
154
|
+
paged: { limit: 2, offset: 0 }
|
|
155
|
+
});
|
|
156
|
+
expect(m.updateProvenTxReq).toHaveBeenCalledWith([11], { status: 'unfail' });
|
|
157
|
+
expect(log).toContain('"resumeOffset":0');
|
|
158
|
+
expect(log).toContain('"expectedProvenTxReqId":10');
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
//# sourceMappingURL=TaskReviewDoubleSpends.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TaskReviewDoubleSpends.test.js","sourceRoot":"","sources":["../../../../../src/monitor/tasks/__tests/TaskReviewDoubleSpends.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TaskReviewProvenTxs.test.d.ts","sourceRoot":"","sources":["../../../../../src/monitor/tasks/__tests/TaskReviewProvenTxs.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const TaskReviewProvenTxs_1 = require("../TaskReviewProvenTxs");
|
|
4
|
+
const HeightRange_1 = require("../../../services/chaintracker/chaintracks/util/HeightRange");
|
|
5
|
+
function makeMonitor(options) {
|
|
6
|
+
const reviewHeightRange = jest.fn().mockResolvedValue(options.reviewResult || {
|
|
7
|
+
log: '',
|
|
8
|
+
reviewedHeights: 0,
|
|
9
|
+
mismatchedHeights: 0,
|
|
10
|
+
affectedTransactions: 0,
|
|
11
|
+
updatedTransactions: 0
|
|
12
|
+
});
|
|
13
|
+
const findStaleMerkleRoots = jest.fn(async ({ height }) => { var _a, _b; return (_b = (_a = options.staleRootsByHeight) === null || _a === void 0 ? void 0 : _a[height]) !== null && _b !== void 0 ? _b : []; });
|
|
14
|
+
const findMonitorEvents = jest.fn(async () => options.monitorEvents || []);
|
|
15
|
+
const runAsStorageProvider = jest.fn(async (fn) => await fn({ findStaleMerkleRoots }));
|
|
16
|
+
const reproveHeightMerkleRoot = jest.fn(async (height, staleRoot) => {
|
|
17
|
+
var _a;
|
|
18
|
+
return (((_a = options.reproveResultsByHeightRoot) === null || _a === void 0 ? void 0 : _a[`${height}:${staleRoot}`]) || {
|
|
19
|
+
log: ` reproved ${height}:${staleRoot}\n`,
|
|
20
|
+
updated: [],
|
|
21
|
+
unchanged: [],
|
|
22
|
+
unavailable: []
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
const logEvent = jest.fn().mockResolvedValue(undefined);
|
|
26
|
+
const chaintracks = {
|
|
27
|
+
currentHeight: jest.fn().mockResolvedValue(options.tipHeight),
|
|
28
|
+
findHeaderForHeight: jest.fn(async (height) => { var _a; return (_a = options.headersByHeight) === null || _a === void 0 ? void 0 : _a[height]; })
|
|
29
|
+
};
|
|
30
|
+
return {
|
|
31
|
+
monitor: {
|
|
32
|
+
storage: {
|
|
33
|
+
runAsStorageProvider,
|
|
34
|
+
reproveHeightMerkleRoot
|
|
35
|
+
},
|
|
36
|
+
chaintracks,
|
|
37
|
+
chaintracksWithEvents: undefined,
|
|
38
|
+
logEvent
|
|
39
|
+
},
|
|
40
|
+
reviewHeightRange,
|
|
41
|
+
findStaleMerkleRoots,
|
|
42
|
+
findMonitorEvents,
|
|
43
|
+
runAsStorageProvider,
|
|
44
|
+
reproveHeightMerkleRoot,
|
|
45
|
+
logEvent,
|
|
46
|
+
chaintracks
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
describe('TaskReviewProvenTxs tests', () => {
|
|
50
|
+
test('0 reviewHeightRange uses findStaleMerkleRoots and reproves only stale roots in the requested range', async () => {
|
|
51
|
+
const m = makeMonitor({
|
|
52
|
+
tipHeight: 120,
|
|
53
|
+
headersByHeight: {
|
|
54
|
+
107: { height: 107, merkleRoot: 'root-107', hash: 'hash-107' },
|
|
55
|
+
108: { height: 108, merkleRoot: 'root-108-new', hash: 'hash-108' }
|
|
56
|
+
},
|
|
57
|
+
staleRootsByHeight: {
|
|
58
|
+
107: [],
|
|
59
|
+
108: ['root-108-old']
|
|
60
|
+
},
|
|
61
|
+
reproveResultsByHeightRoot: {
|
|
62
|
+
'108:root-108-old': {
|
|
63
|
+
log: ' height 108 stale merkleRoot root-108-old with 2 impacted transactions\n',
|
|
64
|
+
updated: [{}],
|
|
65
|
+
unchanged: [{}],
|
|
66
|
+
unavailable: []
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
const task = new TaskReviewProvenTxs_1.TaskReviewProvenTxs(m.monitor, 0, 2, 12);
|
|
71
|
+
const result = await task.reviewHeightRange(new HeightRange_1.HeightRange(107, 108));
|
|
72
|
+
expect(m.findStaleMerkleRoots).toHaveBeenNthCalledWith(1, { height: 107, merkleRoot: 'root-107' });
|
|
73
|
+
expect(m.findStaleMerkleRoots).toHaveBeenNthCalledWith(2, { height: 108, merkleRoot: 'root-108-new' });
|
|
74
|
+
expect(m.reproveHeightMerkleRoot).toHaveBeenCalledTimes(1);
|
|
75
|
+
expect(m.reproveHeightMerkleRoot).toHaveBeenCalledWith(108, 'root-108-old');
|
|
76
|
+
expect(result.reviewedHeights).toBe(2);
|
|
77
|
+
expect(result.mismatchedHeights).toBe(1);
|
|
78
|
+
expect(result.affectedTransactions).toBe(2);
|
|
79
|
+
expect(result.updatedTransactions).toBe(1);
|
|
80
|
+
expect(result.log).toContain('height 108 canonical root-108-new stale root-108-old');
|
|
81
|
+
});
|
|
82
|
+
test('1 reviewHeightRange records unavailable headers and skips empty ranges cleanly', async () => {
|
|
83
|
+
const m = makeMonitor({
|
|
84
|
+
tipHeight: 120,
|
|
85
|
+
headersByHeight: {
|
|
86
|
+
10: undefined
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
const task = new TaskReviewProvenTxs_1.TaskReviewProvenTxs(m.monitor, 0, 2, 12);
|
|
90
|
+
const result = await task.reviewHeightRange(new HeightRange_1.HeightRange(10, 10));
|
|
91
|
+
const empty = await task.reviewHeightRange(HeightRange_1.HeightRange.empty);
|
|
92
|
+
expect(m.reproveHeightMerkleRoot).not.toHaveBeenCalled();
|
|
93
|
+
expect(result.reviewedHeights).toBe(1);
|
|
94
|
+
expect(result.log).toContain('height 10 canonical header unavailable');
|
|
95
|
+
expect(empty.reviewedHeights).toBe(0);
|
|
96
|
+
expect(empty.log).toBe('');
|
|
97
|
+
});
|
|
98
|
+
test('2 getLastReviewedHeight skips plain-text events and uses the latest checkpoint event', async () => {
|
|
99
|
+
const m = makeMonitor({
|
|
100
|
+
tipHeight: 120,
|
|
101
|
+
monitorEvents: [
|
|
102
|
+
{ details: 'reviewing heights 10..20 tip=120 minAge=100 maxPerRun=100' },
|
|
103
|
+
{ details: JSON.stringify({ reviewedThroughHeight: 20 }) },
|
|
104
|
+
{ details: JSON.stringify({ reviewedThroughHeight: 7 }) }
|
|
105
|
+
]
|
|
106
|
+
});
|
|
107
|
+
const task = new TaskReviewProvenTxs_1.TaskReviewProvenTxs(m.monitor);
|
|
108
|
+
jest
|
|
109
|
+
.spyOn(task.storage, 'runAsStorageProvider')
|
|
110
|
+
.mockImplementation(async (fn) => await fn({ findMonitorEvents: m.findMonitorEvents }));
|
|
111
|
+
const lastReviewedHeight = await task.getLastReviewedHeight();
|
|
112
|
+
expect(lastReviewedHeight).toBe(20);
|
|
113
|
+
});
|
|
114
|
+
test('3 runTask starts from height 0 on cold start and caps the range by batch size and minimum age', async () => {
|
|
115
|
+
const m = makeMonitor({
|
|
116
|
+
tipHeight: 250,
|
|
117
|
+
reviewResult: {
|
|
118
|
+
log: '',
|
|
119
|
+
reviewedHeights: 100,
|
|
120
|
+
mismatchedHeights: 0,
|
|
121
|
+
affectedTransactions: 0,
|
|
122
|
+
updatedTransactions: 0
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
const task = new TaskReviewProvenTxs_1.TaskReviewProvenTxs(m.monitor, 0, 100, 100);
|
|
126
|
+
jest.spyOn(task, 'getLastReviewedHeight').mockResolvedValue(undefined);
|
|
127
|
+
const reviewSpy = jest.spyOn(task, 'reviewHeightRange').mockResolvedValue(m.reviewHeightRange());
|
|
128
|
+
const log = await task.runTask();
|
|
129
|
+
expect(reviewSpy).toHaveBeenCalledWith(new HeightRange_1.HeightRange(0, 99));
|
|
130
|
+
expect(log).toContain('"reviewedThroughHeight":99');
|
|
131
|
+
expect(log).toContain('"minBlockAge":100');
|
|
132
|
+
expect(log).toContain('reviewing heights 0..99 tip=250 minAge=100 maxPerRun=100');
|
|
133
|
+
expect(m.logEvent).not.toHaveBeenCalled();
|
|
134
|
+
});
|
|
135
|
+
test('4 runTask resumes from the last reviewed height plus one', async () => {
|
|
136
|
+
const m = makeMonitor({
|
|
137
|
+
tipHeight: 250,
|
|
138
|
+
reviewResult: {
|
|
139
|
+
log: ' height 121 canonical root-121-new stale root-121-old\n reproved stale root\n',
|
|
140
|
+
reviewedHeights: 21,
|
|
141
|
+
mismatchedHeights: 1,
|
|
142
|
+
affectedTransactions: 1,
|
|
143
|
+
updatedTransactions: 0
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
const task = new TaskReviewProvenTxs_1.TaskReviewProvenTxs(m.monitor, 0, 100, 100);
|
|
147
|
+
jest.spyOn(task, 'getLastReviewedHeight').mockResolvedValue(100);
|
|
148
|
+
const reviewSpy = jest.spyOn(task, 'reviewHeightRange').mockResolvedValue(m.reviewHeightRange());
|
|
149
|
+
const log = await task.runTask();
|
|
150
|
+
expect(reviewSpy).toHaveBeenCalledTimes(1);
|
|
151
|
+
expect(reviewSpy).toHaveBeenCalledWith(new HeightRange_1.HeightRange(101, 150));
|
|
152
|
+
expect(log).toContain('"reviewedThroughHeight":150');
|
|
153
|
+
expect(log).toContain('"minBlockAge":100');
|
|
154
|
+
expect(log).toContain('reviewing heights 101..150 tip=250 minAge=100 maxPerRun=100');
|
|
155
|
+
expect(log).toContain('height 121 canonical root-121-new stale root-121-old');
|
|
156
|
+
expect(m.logEvent).not.toHaveBeenCalled();
|
|
157
|
+
});
|
|
158
|
+
test('5 runTask returns review logs even when the range is clean', async () => {
|
|
159
|
+
const m = makeMonitor({
|
|
160
|
+
tipHeight: 250,
|
|
161
|
+
reviewResult: {
|
|
162
|
+
log: '',
|
|
163
|
+
reviewedHeights: 50,
|
|
164
|
+
mismatchedHeights: 0,
|
|
165
|
+
affectedTransactions: 0,
|
|
166
|
+
updatedTransactions: 0
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
const task = new TaskReviewProvenTxs_1.TaskReviewProvenTxs(m.monitor, 0, 50, 100);
|
|
170
|
+
jest.spyOn(task, 'getLastReviewedHeight').mockResolvedValue(149);
|
|
171
|
+
const reviewSpy = jest.spyOn(task, 'reviewHeightRange').mockResolvedValue(m.reviewHeightRange());
|
|
172
|
+
const log = await task.runTask();
|
|
173
|
+
expect(reviewSpy).toHaveBeenCalledTimes(1);
|
|
174
|
+
expect(reviewSpy).toHaveBeenCalledWith(new HeightRange_1.HeightRange(150, 150));
|
|
175
|
+
expect(log).toContain('"reviewedThroughHeight":150');
|
|
176
|
+
expect(log).toContain('"minBlockAge":100');
|
|
177
|
+
expect(log).toContain('reviewing heights 150..150 tip=250 minAge=100 maxPerRun=50');
|
|
178
|
+
expect(m.logEvent).not.toHaveBeenCalled();
|
|
179
|
+
});
|
|
180
|
+
test('6 runTask returns early when the chain tip is below the minimum age window', async () => {
|
|
181
|
+
const m = makeMonitor({
|
|
182
|
+
tipHeight: 5
|
|
183
|
+
});
|
|
184
|
+
const task = new TaskReviewProvenTxs_1.TaskReviewProvenTxs(m.monitor, 0, 100, 100);
|
|
185
|
+
jest.spyOn(task, 'getLastReviewedHeight').mockResolvedValue(undefined);
|
|
186
|
+
const log = await task.runTask();
|
|
187
|
+
expect(m.reviewHeightRange).not.toHaveBeenCalled();
|
|
188
|
+
expect(log).toBe('');
|
|
189
|
+
expect(m.logEvent).not.toHaveBeenCalled();
|
|
190
|
+
});
|
|
191
|
+
test('7 runTask returns early when all eligible heights have already been reviewed', async () => {
|
|
192
|
+
const m = makeMonitor({
|
|
193
|
+
tipHeight: 250
|
|
194
|
+
});
|
|
195
|
+
const task = new TaskReviewProvenTxs_1.TaskReviewProvenTxs(m.monitor, 0, 100, 100);
|
|
196
|
+
jest.spyOn(task, 'getLastReviewedHeight').mockResolvedValue(200);
|
|
197
|
+
const log = await task.runTask();
|
|
198
|
+
expect(m.reviewHeightRange).not.toHaveBeenCalled();
|
|
199
|
+
expect(log).toBe('');
|
|
200
|
+
expect(m.logEvent).not.toHaveBeenCalled();
|
|
201
|
+
});
|
|
202
|
+
test('8 runTask returns empty log when the computed range is empty', async () => {
|
|
203
|
+
const m = makeMonitor({
|
|
204
|
+
tipHeight: 250
|
|
205
|
+
});
|
|
206
|
+
const task = new TaskReviewProvenTxs_1.TaskReviewProvenTxs(m.monitor, 0, 0, 100);
|
|
207
|
+
jest.spyOn(task, 'getLastReviewedHeight').mockResolvedValue(undefined);
|
|
208
|
+
const log = await task.runTask();
|
|
209
|
+
expect(m.reviewHeightRange).not.toHaveBeenCalled();
|
|
210
|
+
expect(log).toBe('');
|
|
211
|
+
expect(m.logEvent).not.toHaveBeenCalled();
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
//# sourceMappingURL=TaskReviewProvenTxs.test.js.map
|