smoldot 2.0.1 → 2.0.3
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/cjs/internals/bytecode/wasm0.js +1 -1
- package/dist/cjs/internals/bytecode/wasm1.js +1 -1
- package/dist/cjs/internals/bytecode/wasm2.js +1 -1
- package/dist/cjs/internals/client.js +7 -4
- package/dist/cjs/internals/local-instance.js +24 -153
- package/dist/cjs/public-types.d.ts +13 -5
- package/dist/mjs/internals/bytecode/wasm0.js +1 -1
- package/dist/mjs/internals/bytecode/wasm1.js +1 -1
- package/dist/mjs/internals/bytecode/wasm2.js +1 -1
- package/dist/mjs/internals/client.js +7 -4
- package/dist/mjs/internals/local-instance.js +24 -153
- package/dist/mjs/public-types.d.ts +13 -5
- package/package.json +1 -1
|
@@ -360,11 +360,16 @@ export function start(options, wasmModule, platformBindings) {
|
|
|
360
360
|
if (state.instance.status !== "ready")
|
|
361
361
|
throw new Error(); // Internal error. Never supposed to happen.
|
|
362
362
|
state.instance.instance.shutdownExecutor();
|
|
363
|
-
|
|
363
|
+
// Wait for the `executor-shutdown` event to be generated.
|
|
364
|
+
yield new Promise((resolve) => state.onExecutorShutdownOrWasmPanic = resolve);
|
|
365
|
+
// In case the instance crashes while we were waiting, we don't want to overwrite
|
|
366
|
+
// the error.
|
|
367
|
+
if (state.instance.status === "ready")
|
|
368
|
+
state.instance = { status: "destroyed", error: new AlreadyDestroyedError() };
|
|
364
369
|
state.connections.forEach((connec) => connec.reset());
|
|
365
370
|
state.connections.clear();
|
|
366
371
|
for (const addChainResult of state.addChainResults) {
|
|
367
|
-
addChainResult({ success: false, error: "
|
|
372
|
+
addChainResult({ success: false, error: "Client.terminate() has been called" });
|
|
368
373
|
}
|
|
369
374
|
state.addChainResults = [];
|
|
370
375
|
for (const chain of Array.from(state.chains.values())) {
|
|
@@ -374,8 +379,6 @@ export function start(options, wasmModule, platformBindings) {
|
|
|
374
379
|
chain.jsonRpcResponsesPromises = [];
|
|
375
380
|
}
|
|
376
381
|
state.chains.clear();
|
|
377
|
-
// Wait for the `executor-shutdown` event to be generated.
|
|
378
|
-
yield new Promise((resolve) => state.onExecutorShutdownOrWasmPanic = resolve);
|
|
379
382
|
})
|
|
380
383
|
};
|
|
381
384
|
}
|
|
@@ -58,6 +58,30 @@ export function startLocalInstance(config, wasmModule, eventCallback) {
|
|
|
58
58
|
state.onShutdownExecutorOrWasmPanic = () => { };
|
|
59
59
|
throw new Error();
|
|
60
60
|
},
|
|
61
|
+
random_get: (ptr, len) => {
|
|
62
|
+
const instance = state.instance;
|
|
63
|
+
ptr >>>= 0;
|
|
64
|
+
len >>>= 0;
|
|
65
|
+
const baseBuffer = new Uint8Array(instance.exports.memory.buffer)
|
|
66
|
+
.subarray(ptr, ptr + len);
|
|
67
|
+
for (let iter = 0; iter < len; iter += 65536) {
|
|
68
|
+
// `baseBuffer.subarray` automatically saturates at the end of the buffer
|
|
69
|
+
config.getRandomValues(baseBuffer.subarray(iter, iter + 65536));
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
unix_timestamp_us: () => {
|
|
73
|
+
const value = Math.floor(Date.now());
|
|
74
|
+
if (value < 0)
|
|
75
|
+
throw new Error("UNIX timestamp inferior to 0");
|
|
76
|
+
return BigInt(value) * BigInt(1000);
|
|
77
|
+
},
|
|
78
|
+
monotonic_clock_us: () => {
|
|
79
|
+
const nowMs = config.performanceNow();
|
|
80
|
+
const nowMsInt = Math.floor(nowMs);
|
|
81
|
+
const now = BigInt(nowMsInt) * BigInt(1000) +
|
|
82
|
+
BigInt(Math.floor(((nowMs - nowMsInt) * 1000)));
|
|
83
|
+
return now;
|
|
84
|
+
},
|
|
61
85
|
buffer_size: (bufferIndex) => {
|
|
62
86
|
const buf = state.bufferIndices[bufferIndex];
|
|
63
87
|
return buf.byteLength;
|
|
@@ -245,165 +269,12 @@ export function startLocalInstance(config, wasmModule, eventCallback) {
|
|
|
245
269
|
state.currentTask = null;
|
|
246
270
|
}
|
|
247
271
|
};
|
|
248
|
-
const wasiBindings = {
|
|
249
|
-
// Need to fill the buffer described by `ptr` and `len` with random data.
|
|
250
|
-
// This data will be used in order to generate secrets. Do not use a dummy implementation!
|
|
251
|
-
random_get: (ptr, len) => {
|
|
252
|
-
const instance = state.instance;
|
|
253
|
-
ptr >>>= 0;
|
|
254
|
-
len >>>= 0;
|
|
255
|
-
const baseBuffer = new Uint8Array(instance.exports.memory.buffer)
|
|
256
|
-
.subarray(ptr, ptr + len);
|
|
257
|
-
for (let iter = 0; iter < len; iter += 65536) {
|
|
258
|
-
// `baseBuffer.subarray` automatically saturates at the end of the buffer
|
|
259
|
-
config.getRandomValues(baseBuffer.subarray(iter, iter + 65536));
|
|
260
|
-
}
|
|
261
|
-
return 0;
|
|
262
|
-
},
|
|
263
|
-
clock_time_get: (clockId, _precision, outPtr) => {
|
|
264
|
-
// See <https://github.com/rust-lang/rust/blob/master/library/std/src/sys/wasi/time.rs>
|
|
265
|
-
// and <docs.rs/wasi/> for help.
|
|
266
|
-
const instance = state.instance;
|
|
267
|
-
const mem = new Uint8Array(instance.exports.memory.buffer);
|
|
268
|
-
outPtr >>>= 0;
|
|
269
|
-
// We ignore the precision, as it can't be implemented anyway.
|
|
270
|
-
switch (clockId) {
|
|
271
|
-
case 0: {
|
|
272
|
-
// Realtime clock.
|
|
273
|
-
const now = BigInt(Math.floor(Date.now())) * BigInt(1000000);
|
|
274
|
-
buffer.writeUInt64LE(mem, outPtr, now);
|
|
275
|
-
// Success.
|
|
276
|
-
return 0;
|
|
277
|
-
}
|
|
278
|
-
case 1: {
|
|
279
|
-
// Monotonic clock.
|
|
280
|
-
const nowMs = config.performanceNow();
|
|
281
|
-
const nowMsInt = Math.floor(nowMs);
|
|
282
|
-
const now = BigInt(nowMsInt) * BigInt(1000000) +
|
|
283
|
-
BigInt(Math.floor(((nowMs - nowMsInt) * 1000000)));
|
|
284
|
-
buffer.writeUInt64LE(mem, outPtr, now);
|
|
285
|
-
// Success.
|
|
286
|
-
return 0;
|
|
287
|
-
}
|
|
288
|
-
default:
|
|
289
|
-
// Return an `EINVAL` error.
|
|
290
|
-
return 28;
|
|
291
|
-
}
|
|
292
|
-
},
|
|
293
|
-
// Writing to a file descriptor is used in order to write to stdout/stderr.
|
|
294
|
-
fd_write: (fd, addr, num, outPtr) => {
|
|
295
|
-
const instance = state.instance;
|
|
296
|
-
outPtr >>>= 0;
|
|
297
|
-
// Only stdout and stderr are open for writing.
|
|
298
|
-
if (fd != 1 && fd != 2) {
|
|
299
|
-
return 8;
|
|
300
|
-
}
|
|
301
|
-
const mem = new Uint8Array(instance.exports.memory.buffer);
|
|
302
|
-
// `fd_write` passes a buffer containing itself a list of pointers and lengths to the
|
|
303
|
-
// actual buffers. See writev(2).
|
|
304
|
-
let toWrite = "";
|
|
305
|
-
let totalLength = 0;
|
|
306
|
-
for (let i = 0; i < num; i++) {
|
|
307
|
-
const buf = buffer.readUInt32LE(mem, addr + 4 * i * 2);
|
|
308
|
-
const bufLen = buffer.readUInt32LE(mem, addr + 4 * (i * 2 + 1));
|
|
309
|
-
toWrite += buffer.utf8BytesToString(mem, buf, bufLen);
|
|
310
|
-
totalLength += bufLen;
|
|
311
|
-
}
|
|
312
|
-
const flushBuffer = (string) => {
|
|
313
|
-
// As documented in the documentation of `println!`, lines are always split by a
|
|
314
|
-
// single `\n` in Rust.
|
|
315
|
-
while (true) {
|
|
316
|
-
const index = string.indexOf('\n');
|
|
317
|
-
if (index != -1) {
|
|
318
|
-
// Note that it is questionnable to use `console.log` from within a
|
|
319
|
-
// library. However this simply reflects the usage of `println!` in the
|
|
320
|
-
// Rust code. In other words, it is `println!` that shouldn't be used in
|
|
321
|
-
// the first place. The harm of not showing text printed with `println!`
|
|
322
|
-
// at all is greater than the harm possibly caused by accidentally leaving
|
|
323
|
-
// a `println!` in the code.
|
|
324
|
-
console.log(string.substring(0, index));
|
|
325
|
-
string = string.substring(index + 1);
|
|
326
|
-
}
|
|
327
|
-
else {
|
|
328
|
-
return string;
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
};
|
|
332
|
-
// Append the newly-written data to either `stdout_buffer` or `stderr_buffer`, and
|
|
333
|
-
// print their content if necessary.
|
|
334
|
-
if (fd == 1) {
|
|
335
|
-
state.stdoutBuffer += toWrite;
|
|
336
|
-
state.stdoutBuffer = flushBuffer(state.stdoutBuffer);
|
|
337
|
-
}
|
|
338
|
-
else if (fd == 2) {
|
|
339
|
-
state.stderrBuffer += toWrite;
|
|
340
|
-
state.stderrBuffer = flushBuffer(state.stderrBuffer);
|
|
341
|
-
}
|
|
342
|
-
// Need to write in `out_ptr` how much data was "written".
|
|
343
|
-
buffer.writeUInt32LE(mem, outPtr, totalLength);
|
|
344
|
-
return 0;
|
|
345
|
-
},
|
|
346
|
-
// It's unclear how to properly implement yielding, but a no-op works fine as well.
|
|
347
|
-
sched_yield: () => {
|
|
348
|
-
return 0;
|
|
349
|
-
},
|
|
350
|
-
// Used by Rust in catastrophic situations, such as a double panic.
|
|
351
|
-
proc_exit: (retCode) => {
|
|
352
|
-
state.instance = null;
|
|
353
|
-
eventCallback({
|
|
354
|
-
ty: "wasm-panic",
|
|
355
|
-
message: `proc_exit called: ${retCode}`,
|
|
356
|
-
currentTask: state.currentTask
|
|
357
|
-
});
|
|
358
|
-
state.onShutdownExecutorOrWasmPanic();
|
|
359
|
-
state.onShutdownExecutorOrWasmPanic = () => { };
|
|
360
|
-
throw new Error();
|
|
361
|
-
},
|
|
362
|
-
// Return the number of environment variables and the total size of all environment
|
|
363
|
-
// variables. This is called in order to initialize buffers before `environ_get`.
|
|
364
|
-
environ_sizes_get: (argcOut, argvBufSizeOut) => {
|
|
365
|
-
const instance = state.instance;
|
|
366
|
-
argcOut >>>= 0;
|
|
367
|
-
argvBufSizeOut >>>= 0;
|
|
368
|
-
let totalLen = 0;
|
|
369
|
-
config.envVars.forEach(e => totalLen += new TextEncoder().encode(e).length + 1); // +1 for trailing \0
|
|
370
|
-
const mem = new Uint8Array(instance.exports.memory.buffer);
|
|
371
|
-
buffer.writeUInt32LE(mem, argcOut, config.envVars.length);
|
|
372
|
-
buffer.writeUInt32LE(mem, argvBufSizeOut, totalLen);
|
|
373
|
-
return 0;
|
|
374
|
-
},
|
|
375
|
-
// Write the environment variables to the given pointers.
|
|
376
|
-
// `argv` is a pointer to a buffer that must be overwritten with a list of pointers to
|
|
377
|
-
// environment variables, and `argvBuf` is a pointer to a buffer where to actually store
|
|
378
|
-
// the environment variables.
|
|
379
|
-
// The sizes of the buffers were determined by calling `environ_sizes_get`.
|
|
380
|
-
environ_get: (argv, argvBuf) => {
|
|
381
|
-
const instance = state.instance;
|
|
382
|
-
argv >>>= 0;
|
|
383
|
-
argvBuf >>>= 0;
|
|
384
|
-
const mem = new Uint8Array(instance.exports.memory.buffer);
|
|
385
|
-
let argvPos = 0;
|
|
386
|
-
let argvBufPos = 0;
|
|
387
|
-
config.envVars.forEach(envVar => {
|
|
388
|
-
const encoded = new TextEncoder().encode(envVar);
|
|
389
|
-
buffer.writeUInt32LE(mem, argv + argvPos, argvBuf + argvBufPos);
|
|
390
|
-
argvPos += 4;
|
|
391
|
-
mem.set(encoded, argvBuf + argvBufPos);
|
|
392
|
-
argvBufPos += encoded.length;
|
|
393
|
-
buffer.writeUInt8(mem, argvBuf + argvBufPos, 0);
|
|
394
|
-
argvBufPos += 1;
|
|
395
|
-
});
|
|
396
|
-
return 0;
|
|
397
|
-
},
|
|
398
|
-
};
|
|
399
272
|
// Start the Wasm virtual machine.
|
|
400
273
|
// The Rust code defines a list of imports that must be fulfilled by the environment. The second
|
|
401
274
|
// parameter provides their implementations.
|
|
402
275
|
const result = yield WebAssembly.instantiate(wasmModule, {
|
|
403
276
|
// The functions with the "smoldot" prefix are specific to smoldot.
|
|
404
277
|
"smoldot": smoldotJsBindings,
|
|
405
|
-
// As the Rust code is compiled for wasi, some more wasi-specific imports exist.
|
|
406
|
-
"wasi_snapshot_preview1": wasiBindings,
|
|
407
278
|
});
|
|
408
279
|
state.instance = result;
|
|
409
280
|
// Smoldot requires an initial call to the `init` function in order to do its internal
|
|
@@ -142,12 +142,20 @@ export interface Chain {
|
|
|
142
142
|
* The JSON-RPC callback will no longer be called. This is the case immediately after this
|
|
143
143
|
* function is called. Any on-going JSON-RPC request is instantaneously aborted.
|
|
144
144
|
*
|
|
145
|
-
* Trying to use the chain again will lead to
|
|
145
|
+
* Trying to use the chain again will lead to a {@link AlreadyDestroyedError} exception
|
|
146
|
+
* being thrown.
|
|
146
147
|
*
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
*
|
|
150
|
-
*
|
|
148
|
+
* While the chain instantaneously disappears from the public API as soon as this function is
|
|
149
|
+
* called, its shutdown process actually happens asynchronously in the background. This means
|
|
150
|
+
* for example that networking connections to the chain will remain open for a little bit even
|
|
151
|
+
* after this function returns.
|
|
152
|
+
*
|
|
153
|
+
* If the chain is a relay chain, and that there exists {@link Chain} instances corresponding
|
|
154
|
+
* to parachains that are using this relay chain, then these parachains will continue to work
|
|
155
|
+
* and the relay chain will actually remain connected in the background.
|
|
156
|
+
* Smoldot automatically keeps alive all relay chains that have an active parachains. There
|
|
157
|
+
* is no need to track parachains and relay chains, or to destroy them in the correct order,
|
|
158
|
+
* as this is handled automatically internally.
|
|
151
159
|
*
|
|
152
160
|
* @throws {@link AlreadyDestroyedError} If the chain has already been removed or the client has been terminated.
|
|
153
161
|
* @throws {@link CrashError} If the background client has crashed.
|