@spirobel/monero-wallet-api 0.3.18 → 0.4.1
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/dist/api.d.ts +5 -2
- package/dist/api.js +5 -1
- package/dist/io/atomicWrite.js +3 -1
- package/dist/io/indexedDB.js +7 -2
- package/dist/io/logging.d.ts +40 -0
- package/dist/io/logging.js +172 -0
- package/dist/keypairs-seeds/keypairs.d.ts +21 -0
- package/dist/keypairs-seeds/keypairs.js +21 -0
- package/dist/node-interaction/binaryEndpoints.d.ts +31 -2
- package/dist/node-interaction/binaryEndpoints.js +61 -43
- package/dist/node-interaction/jsonEndpoints.d.ts +257 -130
- package/dist/node-interaction/jsonEndpoints.js +159 -119
- package/dist/node-interaction/nodeUrl.d.ts +21 -6
- package/dist/node-interaction/nodeUrl.js +50 -8
- package/dist/scanning-syncing/backgroundWorker.d.ts +10 -6
- package/dist/scanning-syncing/backgroundWorker.js +88 -39
- package/dist/scanning-syncing/blocksbuffer/blocksBufferFetchLoop.d.ts +44 -0
- package/dist/scanning-syncing/blocksbuffer/blocksBufferFetchLoop.js +355 -0
- package/dist/scanning-syncing/blocksbuffer/blocksbufferCoordination.d.ts +15 -0
- package/dist/scanning-syncing/blocksbuffer/blocksbufferCoordination.js +28 -0
- package/dist/scanning-syncing/{scanresult → blocksbuffer}/getBlocksbinBuffer.d.ts +5 -5
- package/dist/scanning-syncing/{scanresult → blocksbuffer}/getBlocksbinBuffer.js +7 -5
- package/dist/scanning-syncing/connectionStatus.d.ts +33 -9
- package/dist/scanning-syncing/connectionStatus.js +89 -19
- package/dist/scanning-syncing/scanSettings.d.ts +21 -0
- package/dist/scanning-syncing/scanSettings.js +29 -0
- package/dist/scanning-syncing/scanresult/reorg.d.ts +0 -11
- package/dist/scanning-syncing/scanresult/reorg.js +39 -16
- package/dist/scanning-syncing/scanresult/scanCache.d.ts +16 -2
- package/dist/scanning-syncing/scanresult/scanCache.js +65 -5
- package/dist/scanning-syncing/scanresult/scanCacheOpened.d.ts +18 -0
- package/dist/scanning-syncing/scanresult/scanCacheOpened.js +56 -11
- package/dist/scanning-syncing/scanresult/scanCoordination.d.ts +127 -0
- package/dist/scanning-syncing/scanresult/scanCoordination.js +602 -0
- package/dist/scanning-syncing/scanresult/scanLoop.d.ts +20 -0
- package/dist/scanning-syncing/scanresult/scanLoop.js +116 -0
- package/dist/scanning-syncing/scanresult/scanResult.d.ts +24 -3
- package/dist/scanning-syncing/scanresult/scanResult.js +159 -97
- package/dist/scanning-syncing/worker-entrypoints/worker.js +1 -1
- package/dist/scanning-syncing/worker-mains/coordinator-main.d.ts +1 -0
- package/dist/scanning-syncing/worker-mains/coordinator-main.js +24 -0
- package/dist/scanning-syncing/worker-mains/cpubound-main.d.ts +5 -0
- package/dist/scanning-syncing/worker-mains/cpubound-main.js +122 -0
- package/dist/scanning-syncing/worker-mains/worker.d.ts +1 -1
- package/dist/scanning-syncing/worker-mains/worker.js +62 -6
- package/dist/viewpair/ViewPair.d.ts +30 -7
- package/dist/viewpair/ViewPair.js +56 -118
- package/dist/wasm-processing/wasmFile.js +1 -1
- package/package.json +22 -24
- package/dist/io/extension.d.ts +0 -18
- package/dist/io/extension.js +0 -11
package/dist/api.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import "./io/indexedDB";
|
|
2
|
-
export type { ScanResult, ScanResultCallback, } from "./scanning-syncing/scanresult/scanResult";
|
|
3
2
|
export type { CacheChangedCallback, CacheChangedCallbackParameters, } from "./scanning-syncing/scanresult/scanCache";
|
|
4
3
|
export { NodeUrl } from "./node-interaction/nodeUrl";
|
|
5
4
|
export { ViewPair } from "./viewpair/ViewPair";
|
|
@@ -12,14 +11,18 @@ export * from "./io/sleep";
|
|
|
12
11
|
export { writeScanSettings, readScanSettings, } from "./scanning-syncing/scanSettings";
|
|
13
12
|
export { signTransaction, parseAddress, type ParsedAddress, type ParseAddressError, } from "./send-functionality/transactionBuilding";
|
|
14
13
|
export { computeKeyImage } from "./scanning-syncing/scanresult/computeKeyImage";
|
|
15
|
-
export {
|
|
14
|
+
export { startWebworker, createWebworker, makeWebworkerScript, } from "./scanning-syncing/backgroundWorker";
|
|
16
15
|
export { spendable } from "./scanning-syncing/scanresult/scanResult";
|
|
17
16
|
export { openWallets, openWallet } from "./scanning-syncing/openWallet";
|
|
17
|
+
export * from "./scanning-syncing/blocksbuffer/blocksBufferFetchLoop";
|
|
18
|
+
export * from "./scanning-syncing/blocksbuffer/blocksbufferCoordination";
|
|
18
19
|
export * from "./scanning-syncing/connectionStatus";
|
|
19
20
|
export * from "./scanning-syncing/scanSettings";
|
|
20
21
|
export * from "./scanning-syncing/scanresult/scanResult";
|
|
21
22
|
export * from "./scanning-syncing/scanresult/scanStats";
|
|
22
23
|
export * from "./scanning-syncing/scanresult/scanCache";
|
|
24
|
+
export * from "./scanning-syncing/scanresult/scanCoordination";
|
|
25
|
+
export * from "./scanning-syncing/scanresult/scanLoop";
|
|
23
26
|
export * from "./keypairs-seeds/writeKeypairs";
|
|
24
27
|
export * from "./keypairs-seeds/keypairs";
|
|
25
28
|
export * from "./send-functionality/conversion";
|
package/dist/api.js
CHANGED
|
@@ -10,14 +10,18 @@ export * from "./io/sleep";
|
|
|
10
10
|
export { writeScanSettings, readScanSettings, } from "./scanning-syncing/scanSettings";
|
|
11
11
|
export { signTransaction, parseAddress, } from "./send-functionality/transactionBuilding";
|
|
12
12
|
export { computeKeyImage } from "./scanning-syncing/scanresult/computeKeyImage";
|
|
13
|
-
export {
|
|
13
|
+
export { startWebworker, createWebworker, makeWebworkerScript, } from "./scanning-syncing/backgroundWorker";
|
|
14
14
|
export { spendable } from "./scanning-syncing/scanresult/scanResult";
|
|
15
15
|
export { openWallets, openWallet } from "./scanning-syncing/openWallet";
|
|
16
|
+
export * from "./scanning-syncing/blocksbuffer/blocksBufferFetchLoop";
|
|
17
|
+
export * from "./scanning-syncing/blocksbuffer/blocksbufferCoordination";
|
|
16
18
|
export * from "./scanning-syncing/connectionStatus";
|
|
17
19
|
export * from "./scanning-syncing/scanSettings";
|
|
18
20
|
export * from "./scanning-syncing/scanresult/scanResult";
|
|
19
21
|
export * from "./scanning-syncing/scanresult/scanStats";
|
|
20
22
|
export * from "./scanning-syncing/scanresult/scanCache";
|
|
23
|
+
export * from "./scanning-syncing/scanresult/scanCoordination";
|
|
24
|
+
export * from "./scanning-syncing/scanresult/scanLoop";
|
|
21
25
|
export * from "./keypairs-seeds/writeKeypairs";
|
|
22
26
|
export * from "./keypairs-seeds/keypairs";
|
|
23
27
|
export * from "./send-functionality/conversion";
|
package/dist/io/atomicWrite.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import { log } from "./logging";
|
|
1
2
|
export async function atomicWrite(targetPath, data) {
|
|
3
|
+
log("atomicWrite", ["writing to", targetPath]);
|
|
2
4
|
// in the browser we don't have rename + indexedDB writes are atomic in any case
|
|
3
5
|
if (areWeInTheBrowser)
|
|
4
6
|
return await Bun.write(targetPath, data);
|
|
5
7
|
const { rename } = await import("node:fs/promises");
|
|
6
|
-
const tempPath = targetPath + ".tmp";
|
|
8
|
+
const tempPath = targetPath + ".tmp." + Date.now() + "." + Math.random();
|
|
7
9
|
const bytesWritten = await Bun.write(tempPath, data);
|
|
8
10
|
try {
|
|
9
11
|
await rename(tempPath, targetPath);
|
package/dist/io/indexedDB.js
CHANGED
|
@@ -45,8 +45,11 @@ class IndexedDBFile {
|
|
|
45
45
|
return new BunFileSink();
|
|
46
46
|
}
|
|
47
47
|
exists() {
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
if (!this.path)
|
|
49
|
+
return Promise.resolve(false);
|
|
50
|
+
return getFileFromIndexedDB(this.path)
|
|
51
|
+
.then((r) => r !== undefined)
|
|
52
|
+
.catch(() => false);
|
|
50
53
|
}
|
|
51
54
|
delete() {
|
|
52
55
|
return deleteFileFromIndexedDB(this.path);
|
|
@@ -158,6 +161,8 @@ else {
|
|
|
158
161
|
browserGlobal.areWeInTheBrowser = false;
|
|
159
162
|
}
|
|
160
163
|
export async function refreshEnvIndexedDB() {
|
|
164
|
+
if (!areWeInTheBrowser)
|
|
165
|
+
return;
|
|
161
166
|
browserGlobal.Bun.env = await readEnvIndexedDB();
|
|
162
167
|
}
|
|
163
168
|
// we need this to change the env at runtime from inside the Browser extension,
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* logging function names registry.
|
|
3
|
+
*
|
|
4
|
+
* useful filter combinations for `scanSettings.json`:
|
|
5
|
+
*
|
|
6
|
+
* "logs": "console",
|
|
7
|
+
* "logs_include": ["handleCpuboundScan", "logBufStatus"]
|
|
8
|
+
* -> cpu worker progress + buffer/work status.
|
|
9
|
+
*
|
|
10
|
+
* "logs_include": ["coordinatorMainMultithreaded", "scheduleWorkOnCpuPorts", "workToBeDoneForBatch"]
|
|
11
|
+
* -> coordinator events: race count, work dispatch, batch decisions.
|
|
12
|
+
*
|
|
13
|
+
* "logs_include": ["blocksBufferFetchLoop", "makeWorkItemsFromBlocksBuffer", "logBufStatus"]
|
|
14
|
+
* -> block fetching, reconciliation, buffer state.
|
|
15
|
+
*
|
|
16
|
+
* "logs_include": ["processScanResult", "processWorkItem", "processScanResultForWorkItem"]
|
|
17
|
+
* -> result processing, cache updates, reorg detection.
|
|
18
|
+
*
|
|
19
|
+
* "logs_include": ["handleConnectionStatusChanges", "handleScanError"]
|
|
20
|
+
* -> connection events and scan errors.
|
|
21
|
+
*
|
|
22
|
+
* "logs": "off" disables all logging.
|
|
23
|
+
* "logs": "file" writes to `<coordinator|cpubound|mainthread>-<id>-<timestamp>.log`.
|
|
24
|
+
* "logs": "console-and-file" writes to file and console.
|
|
25
|
+
*/
|
|
26
|
+
export declare const LOGGING_FUNCTIONS: readonly ["findWorkToBeDone", "workToBeDoneForBatch", "makeWorkItemsFromBlocksBuffer", "reconcileWorkItemDone", "processScanResultForWorkItem", "processWorkItem", "logBufStatus", "coordinatorMain", "coordinatorMainMultithreaded", "scheduleWorkOnCpuPorts", "processScanResult", "handleScanError", "createWebworker", "startWebworker", "blocksBufferFetchLoop", "reduceStartHeightToTip", "handleConnectionStatusChanges", "handleCpuboundScan", "coordinatorMainWorker", "CPU_PORT_HANDLER", "atomicWrite"];
|
|
27
|
+
export type PossibleLogs = (typeof LOGGING_FUNCTIONS)[number];
|
|
28
|
+
export type LogSetting = "console" | "file" | "console-and-file" | "off";
|
|
29
|
+
export type FileLogMessage = {
|
|
30
|
+
timestamp: string;
|
|
31
|
+
message: any;
|
|
32
|
+
};
|
|
33
|
+
export declare function setupLoggingPath(scan_settings_path: string, path_prefix: string, role: "coordinator" | "cpubound" | "mainthread", cpu_worker_id?: number): Promise<{
|
|
34
|
+
logs: LogSetting | undefined;
|
|
35
|
+
logs_include: ("findWorkToBeDone" | "workToBeDoneForBatch" | "makeWorkItemsFromBlocksBuffer" | "reconcileWorkItemDone" | "processScanResultForWorkItem" | "processWorkItem" | "logBufStatus" | "coordinatorMain" | "coordinatorMainMultithreaded" | "scheduleWorkOnCpuPorts" | "processScanResult" | "handleScanError" | "createWebworker" | "startWebworker" | "blocksBufferFetchLoop" | "reduceStartHeightToTip" | "handleConnectionStatusChanges" | "handleCpuboundScan" | "coordinatorMainWorker" | "CPU_PORT_HANDLER" | "atomicWrite")[] | undefined;
|
|
36
|
+
logs_exclude: ("findWorkToBeDone" | "workToBeDoneForBatch" | "makeWorkItemsFromBlocksBuffer" | "reconcileWorkItemDone" | "processScanResultForWorkItem" | "processWorkItem" | "logBufStatus" | "coordinatorMain" | "coordinatorMainMultithreaded" | "scheduleWorkOnCpuPorts" | "processScanResult" | "handleScanError" | "createWebworker" | "startWebworker" | "blocksBufferFetchLoop" | "reduceStartHeightToTip" | "handleConnectionStatusChanges" | "handleCpuboundScan" | "coordinatorMainWorker" | "CPU_PORT_HANDLER" | "atomicWrite")[] | undefined;
|
|
37
|
+
file_logbuffer: FileLogMessage[];
|
|
38
|
+
global_logging_path: string;
|
|
39
|
+
}>;
|
|
40
|
+
export declare function log(fnname: string, message: any): void;
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { getPathPrefix, openScanSettingsFile } from "../api";
|
|
2
|
+
import { atomicWrite } from "./atomicWrite";
|
|
3
|
+
/**
|
|
4
|
+
* logging function names registry.
|
|
5
|
+
*
|
|
6
|
+
* useful filter combinations for `scanSettings.json`:
|
|
7
|
+
*
|
|
8
|
+
* "logs": "console",
|
|
9
|
+
* "logs_include": ["handleCpuboundScan", "logBufStatus"]
|
|
10
|
+
* -> cpu worker progress + buffer/work status.
|
|
11
|
+
*
|
|
12
|
+
* "logs_include": ["coordinatorMainMultithreaded", "scheduleWorkOnCpuPorts", "workToBeDoneForBatch"]
|
|
13
|
+
* -> coordinator events: race count, work dispatch, batch decisions.
|
|
14
|
+
*
|
|
15
|
+
* "logs_include": ["blocksBufferFetchLoop", "makeWorkItemsFromBlocksBuffer", "logBufStatus"]
|
|
16
|
+
* -> block fetching, reconciliation, buffer state.
|
|
17
|
+
*
|
|
18
|
+
* "logs_include": ["processScanResult", "processWorkItem", "processScanResultForWorkItem"]
|
|
19
|
+
* -> result processing, cache updates, reorg detection.
|
|
20
|
+
*
|
|
21
|
+
* "logs_include": ["handleConnectionStatusChanges", "handleScanError"]
|
|
22
|
+
* -> connection events and scan errors.
|
|
23
|
+
*
|
|
24
|
+
* "logs": "off" disables all logging.
|
|
25
|
+
* "logs": "file" writes to `<coordinator|cpubound|mainthread>-<id>-<timestamp>.log`.
|
|
26
|
+
* "logs": "console-and-file" writes to file and console.
|
|
27
|
+
*/
|
|
28
|
+
export const LOGGING_FUNCTIONS = [
|
|
29
|
+
// scanCoordination.ts
|
|
30
|
+
"findWorkToBeDone",
|
|
31
|
+
"workToBeDoneForBatch",
|
|
32
|
+
"makeWorkItemsFromBlocksBuffer",
|
|
33
|
+
"reconcileWorkItemDone",
|
|
34
|
+
"processScanResultForWorkItem",
|
|
35
|
+
"processWorkItem",
|
|
36
|
+
"logBufStatus",
|
|
37
|
+
"coordinatorMain",
|
|
38
|
+
"coordinatorMainMultithreaded",
|
|
39
|
+
"scheduleWorkOnCpuPorts",
|
|
40
|
+
// scanResult.ts
|
|
41
|
+
"processScanResult",
|
|
42
|
+
// scanCache.ts
|
|
43
|
+
"handleScanError",
|
|
44
|
+
// backgroundWorker.ts
|
|
45
|
+
"createWebworker",
|
|
46
|
+
"startWebworker",
|
|
47
|
+
// blocksBufferFetchLoop.ts
|
|
48
|
+
"blocksBufferFetchLoop",
|
|
49
|
+
"reduceStartHeightToTip",
|
|
50
|
+
// blocksbufferCoordination.ts
|
|
51
|
+
"handleConnectionStatusChanges",
|
|
52
|
+
// cpubound-main.ts
|
|
53
|
+
"handleCpuboundScan",
|
|
54
|
+
// coordinator-main.ts
|
|
55
|
+
"coordinatorMainWorker",
|
|
56
|
+
// worker.ts
|
|
57
|
+
"CPU_PORT_HANDLER",
|
|
58
|
+
// io/atomicWrite.ts
|
|
59
|
+
"atomicWrite",
|
|
60
|
+
];
|
|
61
|
+
export async function setupLoggingPath(scan_settings_path, path_prefix, role, cpu_worker_id) {
|
|
62
|
+
const scanSettings = await openScanSettingsFile(scan_settings_path);
|
|
63
|
+
const logs = scanSettings?.logs;
|
|
64
|
+
const logs_include = scanSettings?.logs_include;
|
|
65
|
+
const logs_exclude = scanSettings?.logs_exclude;
|
|
66
|
+
const file_logbuffer = [];
|
|
67
|
+
const logging_path_prefix = getPathPrefix(scan_settings_path, path_prefix);
|
|
68
|
+
const timestamp = new Date().toISOString().slice(0, 19).replace("T", " ");
|
|
69
|
+
const global_logging_path = `${logging_path_prefix}${role}-${cpu_worker_id ?? ""}-${timestamp}.log`;
|
|
70
|
+
const global_log_setup = {
|
|
71
|
+
logs,
|
|
72
|
+
logs_include,
|
|
73
|
+
logs_exclude,
|
|
74
|
+
file_logbuffer,
|
|
75
|
+
global_logging_path,
|
|
76
|
+
};
|
|
77
|
+
globalThis.__global_log_setup = global_log_setup;
|
|
78
|
+
startLogFlusher(global_log_setup);
|
|
79
|
+
return global_log_setup;
|
|
80
|
+
}
|
|
81
|
+
function safeStringify(value) {
|
|
82
|
+
try {
|
|
83
|
+
return JSON.stringify(value, (_key, v) => {
|
|
84
|
+
if (typeof v === "bigint")
|
|
85
|
+
return v.toString();
|
|
86
|
+
if (typeof v === "function")
|
|
87
|
+
return `fn ${v.name || "anon"}`;
|
|
88
|
+
if (v !== null && typeof v === "object") {
|
|
89
|
+
// promise or thenable
|
|
90
|
+
if (typeof v.then === "function") {
|
|
91
|
+
try {
|
|
92
|
+
return typeof Bun !== "undefined" && Bun.inspect
|
|
93
|
+
? Bun.inspect(v)
|
|
94
|
+
: "Promise";
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
return "Promise";
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// message port
|
|
101
|
+
const ctor = v.constructor;
|
|
102
|
+
if (ctor?.name === "MessagePort")
|
|
103
|
+
return "MessagePort";
|
|
104
|
+
}
|
|
105
|
+
return v;
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
return String(value);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
const flusherRef = new WeakMap();
|
|
113
|
+
function startLogFlusher(setup) {
|
|
114
|
+
if (setup.logs !== "file" && setup.logs !== "console-and-file")
|
|
115
|
+
return;
|
|
116
|
+
if (flusherRef.has(setup))
|
|
117
|
+
return; // already running
|
|
118
|
+
let writtenIndex = 0;
|
|
119
|
+
const id = setInterval(async () => {
|
|
120
|
+
const buffer = setup.file_logbuffer;
|
|
121
|
+
if (buffer.length <= writtenIndex)
|
|
122
|
+
return; // nothing new
|
|
123
|
+
const newEntries = buffer.slice(writtenIndex);
|
|
124
|
+
writtenIndex = buffer.length;
|
|
125
|
+
if (newEntries.length === 0)
|
|
126
|
+
return;
|
|
127
|
+
const lines = newEntries
|
|
128
|
+
.map((e) => `[${e.timestamp}] ${safeStringify(e.message)}`)
|
|
129
|
+
.join("\n");
|
|
130
|
+
try {
|
|
131
|
+
const existing = await Bun.file(setup.global_logging_path)
|
|
132
|
+
.text()
|
|
133
|
+
.catch(() => "");
|
|
134
|
+
const newContent = existing ? existing + "\n" + lines : lines;
|
|
135
|
+
await atomicWrite(setup.global_logging_path, newContent);
|
|
136
|
+
}
|
|
137
|
+
catch (err) {
|
|
138
|
+
console.error("[logFlusher] write failed:", err);
|
|
139
|
+
}
|
|
140
|
+
}, 2000);
|
|
141
|
+
flusherRef.set(setup, id);
|
|
142
|
+
}
|
|
143
|
+
export function log(fnname, message) {
|
|
144
|
+
const setup = globalThis.__global_log_setup;
|
|
145
|
+
if (!setup)
|
|
146
|
+
return;
|
|
147
|
+
const { logs, logs_include, logs_exclude, file_logbuffer } = setup;
|
|
148
|
+
if (logs === "off")
|
|
149
|
+
return;
|
|
150
|
+
// Apply include/exclude filters
|
|
151
|
+
if (logs_include && logs_include.length > 0 && !logs_include.includes(fnname))
|
|
152
|
+
return;
|
|
153
|
+
if (logs_exclude && logs_exclude.includes(fnname))
|
|
154
|
+
return;
|
|
155
|
+
// skip messages that are about writing to the log file itself
|
|
156
|
+
// (prevents atomicWrite calls inside the flusher from feeding back)
|
|
157
|
+
const logPath = setup.global_logging_path;
|
|
158
|
+
if (logPath) {
|
|
159
|
+
const msg = message;
|
|
160
|
+
if ((typeof msg === "string" && msg.includes(logPath)) ||
|
|
161
|
+
(Array.isArray(msg) &&
|
|
162
|
+
msg.some((m) => typeof m === "string" && m.includes(logPath))))
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
const timestamp = new Date().toISOString().slice(0, 19).replace("T", " ");
|
|
166
|
+
if (logs === "console" || logs === "console-and-file") {
|
|
167
|
+
console.log(`[${fnname}]`, ...(Array.isArray(message) ? message : [message]));
|
|
168
|
+
}
|
|
169
|
+
if (logs === "file" || logs === "console-and-file") {
|
|
170
|
+
file_logbuffer.push({ timestamp, message });
|
|
171
|
+
}
|
|
172
|
+
}
|
|
@@ -18,6 +18,20 @@
|
|
|
18
18
|
* duffed the implementation."
|
|
19
19
|
*/
|
|
20
20
|
export type SpendKey = string;
|
|
21
|
+
export type Keypair = {
|
|
22
|
+
spend_key: SpendKey;
|
|
23
|
+
view_key: ViewPairJson;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* use this function to generate a keypair for testing
|
|
27
|
+
* @returns spendkey and viewkey (contains primary address, for mainnet, testnet,stagenet)
|
|
28
|
+
*/
|
|
29
|
+
export declare function makeTestKeyPair(): Promise<Keypair>;
|
|
30
|
+
/**
|
|
31
|
+
* use this function to generate a spend key for testing
|
|
32
|
+
* use the spend key to generate a view key with the makeViewKey function
|
|
33
|
+
* @returns SpendKey
|
|
34
|
+
*/
|
|
21
35
|
export declare function makeSpendKey(): Promise<SpendKey>;
|
|
22
36
|
export declare function makeSpendKeyFromSeed(wallet_secret: string): Promise<SpendKey>;
|
|
23
37
|
export type ViewPairJson = {
|
|
@@ -26,4 +40,11 @@ export type ViewPairJson = {
|
|
|
26
40
|
stagenet_primary: string;
|
|
27
41
|
testnet_primary: string;
|
|
28
42
|
};
|
|
43
|
+
/**
|
|
44
|
+
* spend private key is hashed with keccak to make the view private key
|
|
45
|
+
* this is according to the convention in the monero code base,
|
|
46
|
+
* read the comment at the top of the file for more details & link to source
|
|
47
|
+
* @param spend_private_key the spendkey the viewkey will be derived from
|
|
48
|
+
* @returns the viewkey that was derive from the spendkey
|
|
49
|
+
*/
|
|
29
50
|
export declare function makeViewKey(spend_private_key: string): Promise<ViewPairJson>;
|
|
@@ -61,6 +61,20 @@
|
|
|
61
61
|
// 4849 crypto::ElectrumWords::bytes_to_words(recovery_val, electrum_words, mnemonic_language);
|
|
62
62
|
// https://github.com/monero-project/monero/blob/48ad374b0d6d6e045128729534dc2508e6999afe/src/simplewallet/simplewallet.cpp#L4849
|
|
63
63
|
import { WasmProcessor } from "../wasm-processing/wasmProcessor";
|
|
64
|
+
/**
|
|
65
|
+
* use this function to generate a keypair for testing
|
|
66
|
+
* @returns spendkey and viewkey (contains primary address, for mainnet, testnet,stagenet)
|
|
67
|
+
*/
|
|
68
|
+
export async function makeTestKeyPair() {
|
|
69
|
+
const spend_key = await makeSpendKey();
|
|
70
|
+
const view_key = await makeViewKey(spend_key);
|
|
71
|
+
return { spend_key, view_key };
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* use this function to generate a spend key for testing
|
|
75
|
+
* use the spend key to generate a view key with the makeViewKey function
|
|
76
|
+
* @returns SpendKey
|
|
77
|
+
*/
|
|
64
78
|
export async function makeSpendKey() {
|
|
65
79
|
const wasmProcessor = await WasmProcessor.init();
|
|
66
80
|
let result = undefined;
|
|
@@ -94,6 +108,13 @@ export async function makeSpendKeyFromSeed(wallet_secret) {
|
|
|
94
108
|
}
|
|
95
109
|
return result;
|
|
96
110
|
}
|
|
111
|
+
/**
|
|
112
|
+
* spend private key is hashed with keccak to make the view private key
|
|
113
|
+
* this is according to the convention in the monero code base,
|
|
114
|
+
* read the comment at the top of the file for more details & link to source
|
|
115
|
+
* @param spend_private_key the spendkey the viewkey will be derived from
|
|
116
|
+
* @returns the viewkey that was derive from the spendkey
|
|
117
|
+
*/
|
|
97
118
|
export async function makeViewKey(spend_private_key) {
|
|
98
119
|
if (spend_private_key.length !== 64) {
|
|
99
120
|
throw new Error(`Invalid spendkey length: ${spend_private_key.length}.
|
|
@@ -56,7 +56,6 @@ export type GetBlocksResultMeta = {
|
|
|
56
56
|
new_height: number;
|
|
57
57
|
daemon_height: number;
|
|
58
58
|
status: Status;
|
|
59
|
-
primary_address: "parsing-monerod-response-without-wallet" | "error-address-not-set" | string;
|
|
60
59
|
block_infos: BlockInfo[];
|
|
61
60
|
};
|
|
62
61
|
export type BlockInfo = {
|
|
@@ -102,7 +101,6 @@ export declare function getBlocksBinMakeRequest<T extends WasmProcessor>(process
|
|
|
102
101
|
export declare function getBlocksBinExecuteRequest<T extends WasmProcessor & HasNodeUrl>(processor: T, params: GetBlocksBinRequest, stopSync?: AbortSignal): Promise<Uint8Array<ArrayBufferLike>>;
|
|
103
102
|
export declare function getBlocksBinScanResponse<T extends WasmProcessor>(processor: T, getBlocksBinResponseBuffer: Uint8Array, metaCallBack?: GetBlocksBinMetaCallback): Promise<ScanResult | ErrorResponse | undefined>;
|
|
104
103
|
export declare function getBlocksBinScan<T extends WasmProcessor & HasNodeUrl>(processor: T, params: GetBlocksBinRequest, metaCallBack?: GetBlocksBinMetaCallback, stopSync?: AbortSignal): Promise<ScanResult | ErrorResponse | undefined>;
|
|
105
|
-
export declare function getBlocksBinJson<T extends WasmProcessor & HasNodeUrl>(processor: T, params: GetBlocksBinRequest): Promise<GetBlocksBinResponse | ErrorResponse>;
|
|
106
104
|
/**
|
|
107
105
|
* throws error on failure to create request
|
|
108
106
|
* @param processor wasmprocessor
|
|
@@ -113,5 +111,36 @@ export declare function getOutsBinMakeRequest<T extends WasmProcessor>(processor
|
|
|
113
111
|
export type GetOutsResponseBuffer = Uint8Array;
|
|
114
112
|
export declare function getOutsBinExecuteRequest<T extends WasmProcessor & HasNodeUrl>(processor: T, params: GetOutsBinRequest): Promise<GetOutsResponseBuffer>;
|
|
115
113
|
export declare function getOutsBinJson<T extends WasmProcessor & HasNodeUrl>(processor: T, params: GetOutsBinRequest): Promise<GetOutsBinResponse>;
|
|
114
|
+
/**
|
|
115
|
+
* Loads a getBlocks.bin response into the WASM module for later single-block scanning
|
|
116
|
+
* via repeated calls to scan_block. Unlike getBlocksBinScanResponse, this does not
|
|
117
|
+
* scan any outputs,it only returns the block metadata (heights, timestamps, hashes).
|
|
118
|
+
* Each call overwrites the previously stored response, so it can be called repeatedly
|
|
119
|
+
* without leaking memory.
|
|
120
|
+
* @param processor the WASM processor used to interface with the Rust module, eg ViewPair in viewpair.ts
|
|
121
|
+
* @param getBlocksBinResponseBuffer the raw binary response from the get_blocks.bin endpoint
|
|
122
|
+
* @returns metadata about the loaded blocks (new_height, daemon_height, status, block_infos)
|
|
123
|
+
*/
|
|
124
|
+
export declare function loadGetBlocksBinResponse<T extends WasmProcessor>(processor: T, getBlocksBinResponseBuffer: Uint8Array): Promise<GetBlocksResultMeta>;
|
|
125
|
+
/**
|
|
126
|
+
* Scans a single block from the previously loaded getBlocks.bin response.
|
|
127
|
+
* Call loadGetBlocksBinResponse first to load a response into WASM memory.
|
|
128
|
+
* @param processor the WASM processor
|
|
129
|
+
* @param blockIndex index of the block within the loaded response (0-based)
|
|
130
|
+
* @returns scan result with outputs and key images for that one block
|
|
131
|
+
*
|
|
132
|
+
* ErrorResponse type:
|
|
133
|
+
* the error messages come from the rust side in rust/src/:
|
|
134
|
+
* - "Block index {} out of bounds (total blocks: {})"
|
|
135
|
+
* in lib.rs get_blocks_bin_scan_one_block, guards blockIndex against response.blocks.len
|
|
136
|
+
* - "No getBlocks.bin response loaded. Call loadGetBlocksBinResponse first."
|
|
137
|
+
* in lib.rs get_blocks_bin_scan_one_block, when GLOBAL_GET_BLOCKS_BIN_RESPONSE is None
|
|
138
|
+
* - "Error scanning miner transaction: {}"
|
|
139
|
+
* in block_parsing/mod.rs scan_block, scanner.scan_transaction failed when parsing miner tx of block
|
|
140
|
+
* - "Error scanning block: {}"
|
|
141
|
+
* in block_parsing/mod.rs scan_block, scanner.scan(scan_block) failed
|
|
142
|
+
* all errors are returned as { error: string } (ErrorResponse type)
|
|
143
|
+
*/
|
|
144
|
+
export declare function getBlocksBinScanOneBlock<T extends WasmProcessor>(processor: T, blockIndex: number): Promise<ScanResult | ErrorResponse>;
|
|
116
145
|
export declare function binaryFetchRequest(url: string, body: Uint8Array, stopSync?: AbortSignal): Promise<Uint8Array>;
|
|
117
146
|
export {};
|
|
@@ -68,7 +68,6 @@ export async function getBlocksBinScanResponse(processor, getBlocksBinResponseBu
|
|
|
68
68
|
});
|
|
69
69
|
if (!("error" in result)) {
|
|
70
70
|
result.new_height = resultMeta.new_height;
|
|
71
|
-
result.primary_address = resultMeta.primary_address;
|
|
72
71
|
result.block_infos = resultMeta.block_infos;
|
|
73
72
|
result.daemon_height = resultMeta.daemon_height;
|
|
74
73
|
}
|
|
@@ -82,27 +81,6 @@ export async function getBlocksBinScan(processor, params, metaCallBack, stopSync
|
|
|
82
81
|
const getBlocksBinResponseBuffer = await getBlocksBinExecuteRequest(processor, params, stopSync);
|
|
83
82
|
return getBlocksBinScanResponse(processor, getBlocksBinResponseBuffer, metaCallBack);
|
|
84
83
|
}
|
|
85
|
-
export async function getBlocksBinJson(processor, params) {
|
|
86
|
-
const getBlocksRequestArray = getBlocksBinMakeRequest(processor, params);
|
|
87
|
-
const getBlocksBinResponseBuffer = await binaryFetchRequest(processor.node_url + "/getblocks.bin", getBlocksRequestArray);
|
|
88
|
-
processor.writeToWasmMemory = (ptr, len) => {
|
|
89
|
-
processor.writeArray(ptr, len, getBlocksBinResponseBuffer);
|
|
90
|
-
};
|
|
91
|
-
let resultMeta;
|
|
92
|
-
let result;
|
|
93
|
-
processor.readFromWasmMemory = (ptr, len) => {
|
|
94
|
-
resultMeta = JSON.parse(processor.readString(ptr, len));
|
|
95
|
-
processor.readFromWasmMemory = (ptr, len) => {
|
|
96
|
-
result = JSON.parse(processor.readString(ptr, len));
|
|
97
|
-
if (!("error" in result)) {
|
|
98
|
-
result.new_height = resultMeta.new_height;
|
|
99
|
-
}
|
|
100
|
-
};
|
|
101
|
-
};
|
|
102
|
-
//@ts-ignore
|
|
103
|
-
processor.tinywasi.instance.exports.convert_get_blocks_bin_response_to_json(getBlocksBinResponseBuffer.length);
|
|
104
|
-
return result; //result written in convert_get_blocks_bin_response_to_json
|
|
105
|
-
}
|
|
106
84
|
/**
|
|
107
85
|
* throws error on failure to create request
|
|
108
86
|
* @param processor wasmprocessor
|
|
@@ -148,6 +126,60 @@ export async function getOutsBinJson(processor, params) {
|
|
|
148
126
|
}
|
|
149
127
|
return result;
|
|
150
128
|
}
|
|
129
|
+
/**
|
|
130
|
+
* Loads a getBlocks.bin response into the WASM module for later single-block scanning
|
|
131
|
+
* via repeated calls to scan_block. Unlike getBlocksBinScanResponse, this does not
|
|
132
|
+
* scan any outputs,it only returns the block metadata (heights, timestamps, hashes).
|
|
133
|
+
* Each call overwrites the previously stored response, so it can be called repeatedly
|
|
134
|
+
* without leaking memory.
|
|
135
|
+
* @param processor the WASM processor used to interface with the Rust module, eg ViewPair in viewpair.ts
|
|
136
|
+
* @param getBlocksBinResponseBuffer the raw binary response from the get_blocks.bin endpoint
|
|
137
|
+
* @returns metadata about the loaded blocks (new_height, daemon_height, status, block_infos)
|
|
138
|
+
*/
|
|
139
|
+
export async function loadGetBlocksBinResponse(processor, getBlocksBinResponseBuffer) {
|
|
140
|
+
processor.writeToWasmMemory = (ptr, len) => {
|
|
141
|
+
processor.writeArray(ptr, len, getBlocksBinResponseBuffer);
|
|
142
|
+
};
|
|
143
|
+
let resultMeta;
|
|
144
|
+
processor.readFromWasmMemory = (ptr, len) => {
|
|
145
|
+
resultMeta = JSON.parse(processor.readString(ptr, len));
|
|
146
|
+
};
|
|
147
|
+
//@ts-ignore
|
|
148
|
+
processor.tinywasi.instance.exports.load_get_blocks_bin_response(getBlocksBinResponseBuffer.length);
|
|
149
|
+
return resultMeta;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Scans a single block from the previously loaded getBlocks.bin response.
|
|
153
|
+
* Call loadGetBlocksBinResponse first to load a response into WASM memory.
|
|
154
|
+
* @param processor the WASM processor
|
|
155
|
+
* @param blockIndex index of the block within the loaded response (0-based)
|
|
156
|
+
* @returns scan result with outputs and key images for that one block
|
|
157
|
+
*
|
|
158
|
+
* ErrorResponse type:
|
|
159
|
+
* the error messages come from the rust side in rust/src/:
|
|
160
|
+
* - "Block index {} out of bounds (total blocks: {})"
|
|
161
|
+
* in lib.rs get_blocks_bin_scan_one_block, guards blockIndex against response.blocks.len
|
|
162
|
+
* - "No getBlocks.bin response loaded. Call loadGetBlocksBinResponse first."
|
|
163
|
+
* in lib.rs get_blocks_bin_scan_one_block, when GLOBAL_GET_BLOCKS_BIN_RESPONSE is None
|
|
164
|
+
* - "Error scanning miner transaction: {}"
|
|
165
|
+
* in block_parsing/mod.rs scan_block, scanner.scan_transaction failed when parsing miner tx of block
|
|
166
|
+
* - "Error scanning block: {}"
|
|
167
|
+
* in block_parsing/mod.rs scan_block, scanner.scan(scan_block) failed
|
|
168
|
+
* all errors are returned as { error: string } (ErrorResponse type)
|
|
169
|
+
*/
|
|
170
|
+
export async function getBlocksBinScanOneBlock(processor, blockIndex) {
|
|
171
|
+
let result;
|
|
172
|
+
processor.readFromWasmMemory = (ptr, len) => {
|
|
173
|
+
result = JSON.parse(processor.readString(ptr, len), (key, value) => {
|
|
174
|
+
if (key === "amount")
|
|
175
|
+
return BigInt(value);
|
|
176
|
+
return value;
|
|
177
|
+
});
|
|
178
|
+
};
|
|
179
|
+
//@ts-ignore
|
|
180
|
+
processor.tinywasi.instance.exports.get_blocks_bin_scan_one_block(blockIndex);
|
|
181
|
+
return result;
|
|
182
|
+
}
|
|
151
183
|
export async function binaryFetchRequest(url, body, stopSync) {
|
|
152
184
|
const response = await fetch(url, {
|
|
153
185
|
body: body,
|
|
@@ -156,28 +188,14 @@ export async function binaryFetchRequest(url, body, stopSync) {
|
|
|
156
188
|
});
|
|
157
189
|
if (!response.ok)
|
|
158
190
|
throw new Error(`HTTP ${response.status}`);
|
|
159
|
-
const reader = response.body.getReader();
|
|
160
|
-
const chunks = [];
|
|
161
|
-
let totalBytes = 0;
|
|
162
191
|
const MAX_SIZE = 125829120; // 120MB
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
if (done)
|
|
167
|
-
break;
|
|
168
|
-
totalBytes += value.length;
|
|
169
|
-
if (totalBytes > MAX_SIZE)
|
|
170
|
-
throw new Error(`Response exceeds 120MB (${totalBytes} bytes)`);
|
|
171
|
-
chunks.push(value);
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
catch (readError) {
|
|
175
|
-
console.error("Reader error:", readError, "Partial bytes:", totalBytes);
|
|
176
|
-
// Eat the error - continue to return partial data
|
|
192
|
+
const contentLength = parseInt(response.headers.get("content-length") || "0", 10);
|
|
193
|
+
if (contentLength > MAX_SIZE) {
|
|
194
|
+
throw new Error(`Response exceeds 120MB (${contentLength} bytes)`);
|
|
177
195
|
}
|
|
178
|
-
|
|
179
|
-
|
|
196
|
+
const buffer = await response.arrayBuffer();
|
|
197
|
+
if (buffer.byteLength > MAX_SIZE) {
|
|
198
|
+
throw new Error(`Response exceeds 120MB (${buffer.byteLength} bytes)`);
|
|
180
199
|
}
|
|
181
|
-
|
|
182
|
-
return Uint8Array.from(chunks.reduce((acc, chunk) => [...acc, ...chunk], []));
|
|
200
|
+
return new Uint8Array(buffer);
|
|
183
201
|
}
|