@spirobel/monero-wallet-api 0.5.2 → 0.5.4
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/README.md +6 -0
- package/dist/api.d.ts +1 -1
- package/dist/api.js +1 -1
- package/dist/io/logging.d.ts +6 -6
- package/dist/io/logging.js +4 -3
- package/dist/multisig/escrow.js +0 -1
- package/dist/scanning-syncing/backgroundWorker.d.ts +0 -1
- package/dist/scanning-syncing/backgroundWorker.js +21 -33
- package/dist/scanning-syncing/connectionStatusOpened.d.ts +1 -1
- package/dist/scanning-syncing/connectionStatusOpened.js +2 -2
- package/dist/scanning-syncing/scanresult/scanCacheOpened.d.ts +4 -0
- package/dist/scanning-syncing/scanresult/scanCacheOpened.js +87 -61
- package/dist/scanning-syncing/scanresult/scanCoordination.d.ts +0 -22
- package/dist/scanning-syncing/scanresult/scanCoordination.js +3 -185
- package/dist/scanning-syncing/worker-entrypoints/worker.js +1 -1
- package/dist/scanning-syncing/worker-mains/coordinator-main.js +0 -1
- package/dist/scanning-syncing/worker-mains/cpubound-main.d.ts +5 -2
- package/dist/scanning-syncing/worker-mains/cpubound-main.js +8 -7
- package/dist/scanning-syncing/worker-mains/worker.js +6 -1
- package/dist/scansettings/scanSettingsOpened.d.ts +25 -0
- package/dist/scansettings/scanSettingsOpened.js +181 -8
- package/dist/tools/monero-tools.js +1 -1
- package/dist/viewpair/ViewPair.js +9 -4
- package/dist/wasm-processing/wasmFile.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
package/dist/api.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ export * from "./multisig/multisig";
|
|
|
14
14
|
export * from "./multisig/DistributedKeyGenerator";
|
|
15
15
|
export * from "./multisig/escrow";
|
|
16
16
|
export * from "./multisig/MultiSigTxSigner";
|
|
17
|
-
export {
|
|
17
|
+
export { createWebworker, makeWebworkerScript, } from "./scanning-syncing/backgroundWorker";
|
|
18
18
|
export { spendable } from "./scanning-syncing/scanresult/scanResult";
|
|
19
19
|
export { openWallets, openWallet } from "./scanning-syncing/openWallet";
|
|
20
20
|
export * from "./scanning-syncing/blocksbuffer/blocksBufferFetchLoop";
|
package/dist/api.js
CHANGED
|
@@ -13,7 +13,7 @@ export * from "./multisig/multisig";
|
|
|
13
13
|
export * from "./multisig/DistributedKeyGenerator";
|
|
14
14
|
export * from "./multisig/escrow";
|
|
15
15
|
export * from "./multisig/MultiSigTxSigner";
|
|
16
|
-
export {
|
|
16
|
+
export { createWebworker, makeWebworkerScript, } from "./scanning-syncing/backgroundWorker";
|
|
17
17
|
export { spendable } from "./scanning-syncing/scanresult/scanResult";
|
|
18
18
|
export { openWallets, openWallet } from "./scanning-syncing/openWallet";
|
|
19
19
|
export * from "./scanning-syncing/blocksbuffer/blocksBufferFetchLoop";
|
package/dist/io/logging.d.ts
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* "logs_include": ["blocksBufferFetchLoop", "makeWorkItemsFromBlocksBuffer", "logBufStatus"]
|
|
14
14
|
* -> block fetching, reconciliation, buffer state.
|
|
15
15
|
*
|
|
16
|
-
* "logs_include": ["processScanResult", "processWorkItem"
|
|
16
|
+
* "logs_include": ["processScanResult", "processWorkItem"]
|
|
17
17
|
* -> result processing, cache updates, reorg detection.
|
|
18
18
|
*
|
|
19
19
|
* "logs_include": ["handleConnectionStatusChanges", "handleScanError"]
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
* "logs": "file" writes to `<coordinator|cpubound|mainthread>-<id>-<timestamp>.log`.
|
|
24
24
|
* "logs": "console-and-file" writes to file and console.
|
|
25
25
|
*/
|
|
26
|
-
export declare const LOGGING_FUNCTIONS: readonly ["findWorkToBeDone", "workToBeDoneForBatch", "makeWorkItemsFromBlocksBuffer", "reconcileWorkItemDone", "
|
|
26
|
+
export declare const LOGGING_FUNCTIONS: readonly ["findWorkToBeDone", "workToBeDoneForBatch", "makeWorkItemsFromBlocksBuffer", "reconcileWorkItemDone", "processWorkItem", "logBufStatus", "coordinatorMain", "coordinatorMainMultithreaded", "scheduleWorkOnCpuPorts", "processScanResult", "handleScanError", "createWebworker", "startWebworker", "blocksBufferFetchLoop", "reduceStartHeightToTip", "handleConnectionStatusChanges", "handleCpuboundScan", "coordinatorMainWorker", "CPU_PORT_HANDLER", "atomicWrite", "multisigMainWorkerCall"];
|
|
27
27
|
export type PossibleLogs = (typeof LOGGING_FUNCTIONS)[number];
|
|
28
28
|
export type LogSetting = "console" | "file" | "console-and-file" | "off";
|
|
29
29
|
export type FileLogMessage = {
|
|
@@ -31,10 +31,10 @@ export type FileLogMessage = {
|
|
|
31
31
|
message: any;
|
|
32
32
|
};
|
|
33
33
|
export declare function setupLoggingPath(scan_settings_path: string, path_prefix: string, role: "coordinator" | "cpubound" | "mainthread" | "multisig", cpu_worker_id?: number): Promise<{
|
|
34
|
-
logs:
|
|
35
|
-
logs_include: ("findWorkToBeDone" | "workToBeDoneForBatch" | "makeWorkItemsFromBlocksBuffer" | "reconcileWorkItemDone" | "
|
|
36
|
-
logs_exclude: ("findWorkToBeDone" | "workToBeDoneForBatch" | "makeWorkItemsFromBlocksBuffer" | "reconcileWorkItemDone" | "
|
|
34
|
+
logs: "console" | "file" | "console-and-file";
|
|
35
|
+
logs_include: ("findWorkToBeDone" | "workToBeDoneForBatch" | "makeWorkItemsFromBlocksBuffer" | "reconcileWorkItemDone" | "processWorkItem" | "logBufStatus" | "coordinatorMain" | "coordinatorMainMultithreaded" | "scheduleWorkOnCpuPorts" | "processScanResult" | "handleScanError" | "createWebworker" | "startWebworker" | "blocksBufferFetchLoop" | "reduceStartHeightToTip" | "handleConnectionStatusChanges" | "handleCpuboundScan" | "coordinatorMainWorker" | "CPU_PORT_HANDLER" | "atomicWrite" | "multisigMainWorkerCall")[] | undefined;
|
|
36
|
+
logs_exclude: ("findWorkToBeDone" | "workToBeDoneForBatch" | "makeWorkItemsFromBlocksBuffer" | "reconcileWorkItemDone" | "processWorkItem" | "logBufStatus" | "coordinatorMain" | "coordinatorMainMultithreaded" | "scheduleWorkOnCpuPorts" | "processScanResult" | "handleScanError" | "createWebworker" | "startWebworker" | "blocksBufferFetchLoop" | "reduceStartHeightToTip" | "handleConnectionStatusChanges" | "handleCpuboundScan" | "coordinatorMainWorker" | "CPU_PORT_HANDLER" | "atomicWrite" | "multisigMainWorkerCall")[] | undefined;
|
|
37
37
|
file_logbuffer: FileLogMessage[];
|
|
38
38
|
global_logging_path: string;
|
|
39
|
-
}>;
|
|
39
|
+
} | undefined>;
|
|
40
40
|
export declare function log(fnname: string, message: any): void;
|
package/dist/io/logging.js
CHANGED
|
@@ -15,7 +15,7 @@ import { atomicWrite } from "./atomicWrite";
|
|
|
15
15
|
* "logs_include": ["blocksBufferFetchLoop", "makeWorkItemsFromBlocksBuffer", "logBufStatus"]
|
|
16
16
|
* -> block fetching, reconciliation, buffer state.
|
|
17
17
|
*
|
|
18
|
-
* "logs_include": ["processScanResult", "processWorkItem"
|
|
18
|
+
* "logs_include": ["processScanResult", "processWorkItem"]
|
|
19
19
|
* -> result processing, cache updates, reorg detection.
|
|
20
20
|
*
|
|
21
21
|
* "logs_include": ["handleConnectionStatusChanges", "handleScanError"]
|
|
@@ -31,7 +31,6 @@ export const LOGGING_FUNCTIONS = [
|
|
|
31
31
|
"workToBeDoneForBatch",
|
|
32
32
|
"makeWorkItemsFromBlocksBuffer",
|
|
33
33
|
"reconcileWorkItemDone",
|
|
34
|
-
"processScanResultForWorkItem",
|
|
35
34
|
"processWorkItem",
|
|
36
35
|
"logBufStatus",
|
|
37
36
|
"coordinatorMain",
|
|
@@ -63,6 +62,8 @@ export const LOGGING_FUNCTIONS = [
|
|
|
63
62
|
export async function setupLoggingPath(scan_settings_path, path_prefix, role, cpu_worker_id) {
|
|
64
63
|
const scanSettings = await openScanSettingsFile(scan_settings_path);
|
|
65
64
|
const logs = scanSettings?.logs;
|
|
65
|
+
if (logs === "off" || typeof logs === "undefined")
|
|
66
|
+
return;
|
|
66
67
|
const logs_include = scanSettings?.logs_include;
|
|
67
68
|
const logs_exclude = scanSettings?.logs_exclude;
|
|
68
69
|
const file_logbuffer = [];
|
|
@@ -147,7 +148,7 @@ export function log(fnname, message) {
|
|
|
147
148
|
if (!setup)
|
|
148
149
|
return;
|
|
149
150
|
const { logs, logs_include, logs_exclude, file_logbuffer } = setup;
|
|
150
|
-
if (logs === "off")
|
|
151
|
+
if (logs === "off" || typeof logs === "undefined")
|
|
151
152
|
return;
|
|
152
153
|
// Apply include/exclude filters
|
|
153
154
|
if (logs_include && logs_include.length > 0 && !logs_include.includes(fnname))
|
package/dist/multisig/escrow.js
CHANGED
|
@@ -7,5 +7,4 @@ export type WorkerSet = {
|
|
|
7
7
|
};
|
|
8
8
|
export declare function createWebworker(handle_result?: (result: CacheChangedCallbackParameters) => void, scan_settings_path?: string, pathPrefix?: string, handle_error?: (error: unknown) => void): Promise<WorkerSet | undefined>;
|
|
9
9
|
export declare function makeWebworkerScript(): string;
|
|
10
|
-
export declare function startWebworker(handle_result?: (result: unknown) => void, handle_error?: (error: unknown) => void): Worker;
|
|
11
10
|
export declare function startWebworkerReady(): Promise<Worker>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { LOCAL_NODE_DEFAULT_URL } from "../node-interaction/nodeUrl";
|
|
2
2
|
import {} from "./scanresult/scanCache";
|
|
3
|
-
import { openScanSettingsFile, SCAN_SETTINGS_STORE_NAME_DEFAULT } from "../api";
|
|
3
|
+
import { openScanSettingsFile, SCAN_SETTINGS_STORE_NAME_DEFAULT, sleep, } from "../api";
|
|
4
4
|
import { log, setupLoggingPath } from "../io/logging";
|
|
5
5
|
import { workerMainCode } from "./worker-entrypoints/worker";
|
|
6
6
|
export const CPU_POOL_SIZE = 4;
|
|
@@ -8,10 +8,11 @@ export async function createWebworker(handle_result, scan_settings_path, pathPre
|
|
|
8
8
|
try {
|
|
9
9
|
const resolvedPath = scan_settings_path || SCAN_SETTINGS_STORE_NAME_DEFAULT;
|
|
10
10
|
const scanSettings = await openScanSettingsFile(resolvedPath);
|
|
11
|
-
|
|
11
|
+
if (scanSettings?.logs !== "off" && scanSettings?.logs)
|
|
12
|
+
await setupLoggingPath(resolvedPath, pathPrefix ?? "", "mainthread");
|
|
12
13
|
const node_url = scanSettings?.node_url || LOCAL_NODE_DEFAULT_URL;
|
|
13
14
|
const cpu_worker_count = typeof scanSettings?.cpu_worker_count !== "undefined"
|
|
14
|
-
? scanSettings?.cpu_worker_count
|
|
15
|
+
? scanSettings?.cpu_worker_count || 1
|
|
15
16
|
: CPU_POOL_SIZE;
|
|
16
17
|
// spawn CPU workers
|
|
17
18
|
const cpuWorkers = [];
|
|
@@ -32,6 +33,7 @@ export async function createWebworker(handle_result, scan_settings_path, pathPre
|
|
|
32
33
|
};
|
|
33
34
|
cpuWorkers.push(cpuWorker);
|
|
34
35
|
cpuPorts.push(channel.port2);
|
|
36
|
+
await sleep(50);
|
|
35
37
|
}
|
|
36
38
|
const coordinationWorker = await startWebworkerReady();
|
|
37
39
|
coordinationWorker.postMessage({
|
|
@@ -39,9 +41,7 @@ export async function createWebworker(handle_result, scan_settings_path, pathPre
|
|
|
39
41
|
scan_settings_path: resolvedPath,
|
|
40
42
|
pathPrefix,
|
|
41
43
|
role: "coordinator",
|
|
42
|
-
|
|
43
|
-
start_height: 0,
|
|
44
|
-
}, cpuPorts); // transfer CPU port2s to coordination worker
|
|
44
|
+
}, cpuPorts); // transfer CPU ports to coordination worker
|
|
45
45
|
log("createWebworker", [
|
|
46
46
|
"coordinator worker started, node_url=" + node_url,
|
|
47
47
|
", cpuPorts=" + cpuPorts.length,
|
|
@@ -60,9 +60,17 @@ export async function createWebworker(handle_result, scan_settings_path, pathPre
|
|
|
60
60
|
fetchWorker: coordinationWorker,
|
|
61
61
|
cpuWorkers,
|
|
62
62
|
terminate: () => {
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
for (const p of cpuPorts) {
|
|
64
|
+
p.close();
|
|
65
|
+
}
|
|
66
|
+
coordinationWorker.onmessage = null;
|
|
67
|
+
coordinationWorker.onerror = null;
|
|
68
|
+
for (const w of cpuWorkers) {
|
|
69
|
+
w.onerror = null;
|
|
70
|
+
w.onmessage = null;
|
|
65
71
|
w.terminate();
|
|
72
|
+
}
|
|
73
|
+
coordinationWorker.terminate();
|
|
66
74
|
},
|
|
67
75
|
};
|
|
68
76
|
}
|
|
@@ -73,36 +81,16 @@ export async function createWebworker(handle_result, scan_settings_path, pathPre
|
|
|
73
81
|
export function makeWebworkerScript() {
|
|
74
82
|
return workerMainCode;
|
|
75
83
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
const url = URL.createObjectURL(blob);
|
|
81
|
-
const worker = new Worker(url, { type: "module" });
|
|
82
|
-
worker.onmessage = (event) => {
|
|
83
|
-
switch (event.data.type) {
|
|
84
|
-
case "RESULT":
|
|
85
|
-
if (handle_result)
|
|
86
|
-
handle_result(event.data.payload);
|
|
87
|
-
break;
|
|
88
|
-
case "ERROR":
|
|
89
|
-
case "scan_error":
|
|
90
|
-
if (handle_error)
|
|
91
|
-
handle_error(event.data.payload ?? event.data.error);
|
|
92
|
-
break;
|
|
93
|
-
case "DEBUG":
|
|
94
|
-
log("startWebworker", ["worker debug:", event.data.payload]);
|
|
95
|
-
break;
|
|
96
|
-
}
|
|
97
|
-
};
|
|
98
|
-
return worker;
|
|
99
|
-
}
|
|
84
|
+
const blob = new Blob([workerMainCode], {
|
|
85
|
+
type: "text/javascript",
|
|
86
|
+
});
|
|
87
|
+
const url = URL.createObjectURL(blob);
|
|
100
88
|
// creates a worker via startWebworker, then waits for it to signal
|
|
101
89
|
// WORKER_READY (meaning self.onmessage = handleMessage has executed).
|
|
102
90
|
// after that, postMessage is safe, no race between worker startup
|
|
103
91
|
// and message delivery.
|
|
104
92
|
export function startWebworkerReady() {
|
|
105
|
-
const worker =
|
|
93
|
+
const worker = new Worker(url, { type: "module" });
|
|
106
94
|
return new Promise((resolve) => {
|
|
107
95
|
const onReady = (e) => {
|
|
108
96
|
if (e.data?.type === "WORKER_READY") {
|
|
@@ -6,7 +6,7 @@ export declare class ConnectionStatusOpened {
|
|
|
6
6
|
private _prevConnected;
|
|
7
7
|
private _path;
|
|
8
8
|
constructor(scan_settings_path: string, _onChange?: ((status: ConnectionStatus | null) => void) | null | undefined);
|
|
9
|
-
watch(intervalMs?: number): void
|
|
9
|
+
watch(intervalMs?: number): Promise<void>;
|
|
10
10
|
unwatch(): void;
|
|
11
11
|
get connectionStatus(): ConnectionStatus | null;
|
|
12
12
|
get isConnected(): boolean;
|
|
@@ -9,10 +9,10 @@ export class ConnectionStatusOpened {
|
|
|
9
9
|
this._onChange = _onChange;
|
|
10
10
|
this._path = connectionStatusFilePath(scan_settings_path);
|
|
11
11
|
}
|
|
12
|
-
watch(intervalMs = 2500) {
|
|
12
|
+
async watch(intervalMs = 2500) {
|
|
13
13
|
if (this._timer)
|
|
14
14
|
return;
|
|
15
|
-
this._poll();
|
|
15
|
+
await this._poll();
|
|
16
16
|
this._timer = setInterval(() => this._poll(), intervalMs);
|
|
17
17
|
}
|
|
18
18
|
unwatch() {
|
|
@@ -70,6 +70,7 @@ export declare class ScanCacheOpened {
|
|
|
70
70
|
setMerchantConfirmations(merchant_confirmations: number | null): Promise<void>;
|
|
71
71
|
setCpuWorkerCount(cpu_worker_count: number | undefined): Promise<void>;
|
|
72
72
|
setLogSettings(logs?: LogSetting | null, logs_include?: PossibleLogs[] | null, logs_exclude?: PossibleLogs[] | null): Promise<void>;
|
|
73
|
+
setWalletName(name?: string): Promise<void>;
|
|
73
74
|
retry(): Promise<boolean>;
|
|
74
75
|
sendTransaction(signedTx: string): Promise<SendRawTransactionResult>;
|
|
75
76
|
signTransaction(unsignedTx: string): Promise<string>;
|
|
@@ -130,6 +131,7 @@ export declare class ScanCacheOpened {
|
|
|
130
131
|
pause(): Promise<void>;
|
|
131
132
|
stopWorker(): void;
|
|
132
133
|
unpause(): Promise<void>;
|
|
134
|
+
private _onWorkerError;
|
|
133
135
|
/**
|
|
134
136
|
* selectInputs returns array of inputs, whose sum is larger than amount
|
|
135
137
|
* adds approximate fee for 10kb transaction to amount if feePerByte is supplied
|
|
@@ -200,6 +202,8 @@ export declare class ManyScanCachesOpened {
|
|
|
200
202
|
setMerchantConfirmations(merchant_confirmations: number | null): Promise<void>;
|
|
201
203
|
setCpuWorkerCount(cpu_worker_count: number | undefined): Promise<void>;
|
|
202
204
|
setLogSettings(logs?: LogSetting | null, logs_include?: PossibleLogs[] | null, logs_exclude?: PossibleLogs[] | null): Promise<void>;
|
|
205
|
+
setWalletName(primary_address: string, name?: string): Promise<void>;
|
|
206
|
+
setWalletSlot(primary_address: string, slot?: number): Promise<void>;
|
|
203
207
|
changeStartHeight(start_height: number | null): Promise<void>;
|
|
204
208
|
private static _buildWallets;
|
|
205
209
|
static create(options: ManyScanCachesOpenedCreateOptions): Promise<ManyScanCachesOpened | undefined>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { NodeUrl, signTransaction, ViewPair, } from "../../api";
|
|
1
|
+
import { get_info, NodeUrl, signTransaction, ViewPair, } from "../../api";
|
|
2
2
|
import { prepareInput, sumPayments, } from "../../send-functionality/inputSelection";
|
|
3
3
|
import { createWebworker } from "../backgroundWorker";
|
|
4
4
|
import { spendable } from "./scanResult";
|
|
@@ -92,10 +92,7 @@ export class ScanCacheOpened {
|
|
|
92
92
|
return this._stats.height;
|
|
93
93
|
}
|
|
94
94
|
async changeStartHeight(start_height) {
|
|
95
|
-
|
|
96
|
-
this.worker.terminate();
|
|
97
|
-
delete this.worker;
|
|
98
|
-
}
|
|
95
|
+
this.stopWorker();
|
|
99
96
|
await this._scanSettings.setStartHeight(start_height);
|
|
100
97
|
this._start_height = start_height;
|
|
101
98
|
await this.unpause();
|
|
@@ -170,10 +167,7 @@ export class ScanCacheOpened {
|
|
|
170
167
|
return this._scanSettings.logs_exclude;
|
|
171
168
|
}
|
|
172
169
|
async changeNodeUrlAndStartHeight(node_url, start_height) {
|
|
173
|
-
|
|
174
|
-
this.worker.terminate();
|
|
175
|
-
delete this.worker;
|
|
176
|
-
}
|
|
170
|
+
this.stopWorker();
|
|
177
171
|
if (node_url !== undefined) {
|
|
178
172
|
await this._scanSettings.setNodeUrl(node_url);
|
|
179
173
|
this.node_url = node_url;
|
|
@@ -185,18 +179,13 @@ export class ScanCacheOpened {
|
|
|
185
179
|
await this.unpause();
|
|
186
180
|
}
|
|
187
181
|
async changeNodeUrl(node_url) {
|
|
188
|
-
|
|
189
|
-
this.worker.terminate();
|
|
190
|
-
delete this.worker;
|
|
191
|
-
}
|
|
182
|
+
this.stopWorker();
|
|
192
183
|
await this._scanSettings.setNodeUrl(node_url);
|
|
193
184
|
this.node_url = node_url;
|
|
194
185
|
await this.unpause();
|
|
195
186
|
}
|
|
196
187
|
async setMerchantConfirmations(merchant_confirmations) {
|
|
197
|
-
this.stopWorker();
|
|
198
188
|
await this._scanSettings.setMerchantConfirmations(merchant_confirmations);
|
|
199
|
-
await this.unpause();
|
|
200
189
|
}
|
|
201
190
|
async setCpuWorkerCount(cpu_worker_count) {
|
|
202
191
|
this.stopWorker();
|
|
@@ -204,15 +193,15 @@ export class ScanCacheOpened {
|
|
|
204
193
|
await this.unpause();
|
|
205
194
|
}
|
|
206
195
|
async setLogSettings(logs, logs_include, logs_exclude) {
|
|
207
|
-
this.stopWorker();
|
|
196
|
+
await this.stopWorker();
|
|
208
197
|
await this._scanSettings.setLogSettings(logs, logs_include, logs_exclude);
|
|
209
198
|
await this.unpause();
|
|
210
199
|
}
|
|
200
|
+
async setWalletName(name) {
|
|
201
|
+
await this._scanSettings.setWalletName(this.view_pair.primary_address, name);
|
|
202
|
+
}
|
|
211
203
|
async retry() {
|
|
212
|
-
|
|
213
|
-
this.worker.terminate();
|
|
214
|
-
delete this.worker;
|
|
215
|
-
}
|
|
204
|
+
this.stopWorker();
|
|
216
205
|
// scansettings so external changes (e.g. from a sidebar frontend instance) are picked up
|
|
217
206
|
await this._scanSettings.reload();
|
|
218
207
|
const walletStillExists = this._scanSettings.walletExists(this.primary_address);
|
|
@@ -244,7 +233,7 @@ export class ScanCacheOpened {
|
|
|
244
233
|
const feeFor10kb = feePerByte * 10000n;
|
|
245
234
|
//2. check if fee is too high
|
|
246
235
|
if (feeFor10kb > max_plausible_fee) {
|
|
247
|
-
throw new Error(`fee too high:
|
|
236
|
+
throw new Error(`fee too high:
|
|
248
237
|
${feeFor10kb} (fee for 10kb tx size) > ${max_plausible_fee} (0.001 XMR)
|
|
249
238
|
most likely your node is faulty. connect to another node.
|
|
250
239
|
preferably run one yourself locally.`);
|
|
@@ -263,7 +252,7 @@ export class ScanCacheOpened {
|
|
|
263
252
|
const feeFor10kb = feePerByte * 10000n;
|
|
264
253
|
//2. check if fee is too high
|
|
265
254
|
if (feeFor10kb > max_plausible_fee) {
|
|
266
|
-
throw new Error(`fee too high:
|
|
255
|
+
throw new Error(`fee too high:
|
|
267
256
|
${feeFor10kb} (fee for 10kb tx size) > ${max_plausible_fee} (0.001 XMR)
|
|
268
257
|
most likely your node is faulty. connect to another node.
|
|
269
258
|
preferably run one yourself locally.`);
|
|
@@ -407,10 +396,7 @@ export class ScanCacheOpened {
|
|
|
407
396
|
if (sendResult.status !== "OK")
|
|
408
397
|
throw new Error("send raw transaction rpc returned error");
|
|
409
398
|
// before writing the scan cache, we stop the worker to avoid a race
|
|
410
|
-
|
|
411
|
-
this.worker.terminate();
|
|
412
|
-
delete this.worker;
|
|
413
|
-
}
|
|
399
|
+
this.stopWorker();
|
|
414
400
|
// write txlog to cache + update pending_spent_utxos (affects stats + spendability)
|
|
415
401
|
await writeCacheFileDefaultLocationThrows({
|
|
416
402
|
primary_address: this.primary_address,
|
|
@@ -454,10 +440,7 @@ export class ScanCacheOpened {
|
|
|
454
440
|
}
|
|
455
441
|
catch (e) {
|
|
456
442
|
// before writing the scan cache, we stop the worker to avoid a race
|
|
457
|
-
|
|
458
|
-
this.worker.terminate();
|
|
459
|
-
delete this.worker;
|
|
460
|
-
}
|
|
443
|
+
this.stopWorker();
|
|
461
444
|
// write txlog error to cache
|
|
462
445
|
await writeCacheFileDefaultLocationThrows({
|
|
463
446
|
primary_address: this.primary_address,
|
|
@@ -567,43 +550,45 @@ export class ScanCacheOpened {
|
|
|
567
550
|
};
|
|
568
551
|
}
|
|
569
552
|
async pause() {
|
|
570
|
-
|
|
571
|
-
this.worker.terminate();
|
|
553
|
+
this.stopWorker();
|
|
572
554
|
return await this._scanSettings.haltWallet(this.view_pair.primary_address);
|
|
573
555
|
}
|
|
574
556
|
stopWorker() {
|
|
575
557
|
if (this.worker) {
|
|
576
558
|
this.worker.terminate();
|
|
559
|
+
this.worker.cpuWorkers = [];
|
|
560
|
+
this.worker.fetchWorker = undefined;
|
|
577
561
|
delete this.worker;
|
|
578
562
|
}
|
|
579
563
|
}
|
|
580
564
|
async unpause() {
|
|
581
565
|
// if worker does not exist yet, start it (if we are not slave / no_worker)
|
|
582
566
|
if (!this.worker && !this.no_worker) {
|
|
583
|
-
this.worker = await createWebworker(async (params) => await this.feed(params), this.scan_settings_path, this.pathPrefix, (
|
|
584
|
-
const workerErrCB = this.workerError;
|
|
585
|
-
this.stopWorker();
|
|
586
|
-
readWriteConnectionStatusFile((cs) => {
|
|
587
|
-
if (cs?.last_packet.status === "catastrophic_reorg")
|
|
588
|
-
return;
|
|
589
|
-
const connectionStatus = {
|
|
590
|
-
...cs,
|
|
591
|
-
last_packet: {
|
|
592
|
-
status: "connection_failed",
|
|
593
|
-
bytes_read: 0,
|
|
594
|
-
node_url: this.node_url,
|
|
595
|
-
timestamp: new Date().toISOString(),
|
|
596
|
-
},
|
|
597
|
-
};
|
|
598
|
-
return connectionStatus;
|
|
599
|
-
}, this.scan_settings_path).then(() => {
|
|
600
|
-
if (workerErrCB)
|
|
601
|
-
workerErrCB(error);
|
|
602
|
-
});
|
|
603
|
-
});
|
|
567
|
+
this.worker = await createWebworker(async (params) => await this.feed(params), this.scan_settings_path, this.pathPrefix, (params) => this._onWorkerError(params));
|
|
604
568
|
}
|
|
605
569
|
return await this._scanSettings.unhaltWallet(this.view_pair.primary_address);
|
|
606
570
|
}
|
|
571
|
+
_onWorkerError = (error) => {
|
|
572
|
+
const workerErrCB = this.workerError;
|
|
573
|
+
this.stopWorker();
|
|
574
|
+
readWriteConnectionStatusFile((cs) => {
|
|
575
|
+
if (cs?.last_packet.status === "catastrophic_reorg")
|
|
576
|
+
return;
|
|
577
|
+
const connectionStatus = {
|
|
578
|
+
...cs,
|
|
579
|
+
last_packet: {
|
|
580
|
+
status: "connection_failed",
|
|
581
|
+
bytes_read: 0,
|
|
582
|
+
node_url: this.node_url,
|
|
583
|
+
timestamp: new Date().toISOString(),
|
|
584
|
+
},
|
|
585
|
+
};
|
|
586
|
+
return connectionStatus;
|
|
587
|
+
}, this.scan_settings_path).then(() => {
|
|
588
|
+
if (workerErrCB)
|
|
589
|
+
workerErrCB(error);
|
|
590
|
+
});
|
|
591
|
+
};
|
|
607
592
|
/**
|
|
608
593
|
* selectInputs returns array of inputs, whose sum is larger than amount
|
|
609
594
|
* adds approximate fee for 10kb transaction to amount if feePerByte is supplied
|
|
@@ -798,6 +783,12 @@ export class ManyScanCachesOpened {
|
|
|
798
783
|
throw new Error("no wallets");
|
|
799
784
|
return await this.wallets[0].setLogSettings(logs, logs_include, logs_exclude);
|
|
800
785
|
}
|
|
786
|
+
async setWalletName(primary_address, name) {
|
|
787
|
+
await this._scanSettings.setWalletName(primary_address, name);
|
|
788
|
+
}
|
|
789
|
+
async setWalletSlot(primary_address, slot) {
|
|
790
|
+
await this._scanSettings.setWalletSlot(primary_address, slot);
|
|
791
|
+
}
|
|
801
792
|
async changeStartHeight(start_height) {
|
|
802
793
|
if (this.wallets.length === 0)
|
|
803
794
|
throw new Error("no wallets");
|
|
@@ -866,31 +857,66 @@ export class ManyScanCachesOpened {
|
|
|
866
857
|
// wrap workerError with auto-retry
|
|
867
858
|
let retryTimer;
|
|
868
859
|
let instance = null;
|
|
860
|
+
const retryFn = async () => {
|
|
861
|
+
await instance?.buildWallets();
|
|
862
|
+
const node_url = instance?.node_url;
|
|
863
|
+
if (!node_url)
|
|
864
|
+
throw new Error("No nodeurl set, can't retry connection");
|
|
865
|
+
const getinfo_result = await get_info(node_url)
|
|
866
|
+
.then((r) => {
|
|
867
|
+
r?.status === "OK";
|
|
868
|
+
})
|
|
869
|
+
.catch(() => false);
|
|
870
|
+
if (getinfo_result)
|
|
871
|
+
await instance?.retry();
|
|
872
|
+
clearTimeout(retryTimer);
|
|
873
|
+
retryTimer = undefined;
|
|
874
|
+
};
|
|
869
875
|
const newOptions = { ...options };
|
|
876
|
+
let connectionFailedShown = false;
|
|
870
877
|
if (autoRetry) {
|
|
871
878
|
const originalError = options.workerError;
|
|
872
879
|
newOptions.workerError = (err) => {
|
|
873
880
|
originalError?.(err);
|
|
881
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
882
|
+
if (csOpened.connectionStatus?.last_packet?.status ===
|
|
883
|
+
"catastrophic_reorg") {
|
|
884
|
+
clearTimeout(retryTimer);
|
|
885
|
+
instance?.stopWorker();
|
|
886
|
+
throw new Error("catastrophic reorg, aborting ...");
|
|
887
|
+
}
|
|
888
|
+
if (msg.includes("connect") ||
|
|
889
|
+
msg.includes("fetch") ||
|
|
890
|
+
msg.includes("NetworkError")) {
|
|
891
|
+
if (!connectionFailedShown) {
|
|
892
|
+
connectionFailedShown = true;
|
|
893
|
+
console.error("unable to connect to node ... retrying ...");
|
|
894
|
+
}
|
|
895
|
+
}
|
|
874
896
|
if (!retryTimer) {
|
|
875
|
-
retryTimer = setTimeout(
|
|
876
|
-
retryTimer = undefined;
|
|
877
|
-
instance?.retry();
|
|
878
|
-
}, retryDelayMs ?? 1000);
|
|
897
|
+
retryTimer = setTimeout(retryFn, retryDelayMs ?? 5000);
|
|
879
898
|
}
|
|
880
899
|
};
|
|
881
900
|
}
|
|
882
901
|
const wallets = await this._buildWallets(scanSettingsOpened, newOptions);
|
|
883
902
|
if (!wallets)
|
|
884
903
|
return undefined;
|
|
885
|
-
const csOpened = new ConnectionStatusOpened(scan_settings_path || SCAN_SETTINGS_STORE_NAME_DEFAULT,
|
|
904
|
+
const csOpened = new ConnectionStatusOpened(scan_settings_path || SCAN_SETTINGS_STORE_NAME_DEFAULT, autoRetry
|
|
905
|
+
? (status) => {
|
|
906
|
+
if (status?.last_packet?.status === "OK" && connectionFailedShown) {
|
|
907
|
+
connectionFailedShown = false;
|
|
908
|
+
console.log("connection to node established");
|
|
909
|
+
}
|
|
910
|
+
if (onConnectionStatusChange)
|
|
911
|
+
onConnectionStatusChange(status);
|
|
912
|
+
}
|
|
913
|
+
: (onConnectionStatusChange ?? null));
|
|
886
914
|
csOpened.watch(connectionStatusIntervalMs);
|
|
887
915
|
instance = new ManyScanCachesOpened(wallets, csOpened, scanSettingsOpened, newOptions);
|
|
888
916
|
return instance;
|
|
889
917
|
}
|
|
890
918
|
async buildWallets() {
|
|
891
|
-
|
|
892
|
-
w.stopWorker();
|
|
893
|
-
}
|
|
919
|
+
this.stopWorker();
|
|
894
920
|
await this._scanSettings.reload();
|
|
895
921
|
const newWallets = await ManyScanCachesOpened._buildWallets(this._scanSettings, this._options);
|
|
896
922
|
if (!newWallets)
|
|
@@ -45,26 +45,12 @@ export declare function makeWorkItemsForAllWallets(wallet_configs: WalletConfigP
|
|
|
45
45
|
* blocks buffer if no remaining work items reference it.
|
|
46
46
|
*/
|
|
47
47
|
export declare function reconcileWorkItemDone(blocksBuffer: GetBlocksBinBufferItem[], workItemBuffer: WorkItem[]): void;
|
|
48
|
-
/**
|
|
49
|
-
* one round of the select race. takes two primed promises (blocks, scan),
|
|
50
|
-
* races them, returns winner info. the loser stays in flight.
|
|
51
|
-
*/
|
|
52
|
-
export declare function raceStep(blocksPromise: Promise<IteratorResult<BlocksBufferLoopResult>>, scanPromise: Promise<IteratorResult<ScanLoopYield, void>>): Promise<{
|
|
53
|
-
src: "blocks" | "scan";
|
|
54
|
-
value: IteratorResult<BlocksBufferLoopResult> | IteratorResult<ScanLoopYield, void>;
|
|
55
|
-
done: boolean;
|
|
56
|
-
}>;
|
|
57
48
|
/**
|
|
58
49
|
* handle a yield from the blocks buffer fetch loop.
|
|
59
50
|
*/
|
|
60
51
|
export declare function handleBlocksYield(value: BlocksBufferLoopResult, scanSettingsPath?: string): Promise<{
|
|
61
52
|
isBlocksBufferChanged: boolean;
|
|
62
53
|
}>;
|
|
63
|
-
/**
|
|
64
|
-
* process a scan result for a completed work item.
|
|
65
|
-
* updates the cache, writes to disk, marks work item done, reconciles.
|
|
66
|
-
*/
|
|
67
|
-
export declare function processScanResultForWorkItem(value: ScanLoopYield, workBuffer: WorkItem[], blocksBuffer: GetBlocksBinBufferItem[], pathPrefix: string, secret_spend_key?: string): Promise<void>;
|
|
68
54
|
/**
|
|
69
55
|
* process a scan result for a completed work item.
|
|
70
56
|
* updates the cache, writes to disk, marks work item done, reconciles blockbuffer with this.
|
|
@@ -90,14 +76,6 @@ export type CoordinatorEvent = {
|
|
|
90
76
|
type: "error";
|
|
91
77
|
error: Error;
|
|
92
78
|
};
|
|
93
|
-
/**
|
|
94
|
-
* coordinator main: async generator that drives the full scan cycle.
|
|
95
|
-
* takes only scanSettingsPath, derives everything else internally.
|
|
96
|
-
* yields events for some of the underlying generator events,
|
|
97
|
-
* look at CoordinatorEvent, processing not decoupled from cpu bound scan work,
|
|
98
|
-
* as this single threaded, there is no point
|
|
99
|
-
*/
|
|
100
|
-
export declare function coordinatorMain(scanSettingsPath?: string, pathPrefix?: string): AsyncGenerator<CoordinatorEvent>;
|
|
101
79
|
export declare function setupCoordinator(scanSettingsPath?: string, pathPrefix?: string): Promise<false | {
|
|
102
80
|
blocksGenerator: AsyncGenerator<BlocksBufferLoopResult, any, any>;
|
|
103
81
|
workBuffer: WorkItem[];
|