smoldot 1.0.4 → 1.0.6
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 +58 -0
- package/dist/cjs/bytecode-browser.d.ts +5 -0
- package/dist/cjs/bytecode-browser.js +42 -0
- package/dist/cjs/bytecode-deno.d.ts +5 -0
- package/dist/cjs/bytecode-deno.js +87 -0
- package/dist/cjs/bytecode-nodejs.d.ts +5 -0
- package/dist/cjs/bytecode-nodejs.js +41 -0
- package/dist/cjs/index-browser.d.ts +2 -2
- package/dist/cjs/index-browser.js +10 -507
- package/dist/cjs/index-deno.d.ts +2 -2
- package/dist/cjs/index-deno.js +10 -283
- package/dist/cjs/index-nodejs.d.ts +2 -2
- package/dist/cjs/index-nodejs.js +10 -211
- package/dist/cjs/internals/bytecode/wasm0.js +4 -0
- package/dist/cjs/internals/bytecode/wasm1.js +4 -0
- package/dist/cjs/internals/bytecode/wasm2.js +4 -0
- package/dist/cjs/{instance/bindings-smoldot-light.d.ts → internals/client.d.ts} +15 -34
- package/dist/cjs/internals/client.js +376 -0
- package/dist/cjs/internals/local-instance.d.ts +144 -0
- package/dist/cjs/internals/local-instance.js +566 -0
- package/dist/cjs/internals/remote-instance.d.ts +38 -0
- package/dist/cjs/internals/remote-instance.js +374 -0
- package/dist/cjs/no-auto-bytecode-browser.d.ts +11 -0
- package/dist/cjs/no-auto-bytecode-browser.js +481 -0
- package/dist/cjs/no-auto-bytecode-deno.d.ts +10 -0
- package/dist/cjs/no-auto-bytecode-deno.js +220 -0
- package/dist/cjs/no-auto-bytecode-nodejs.d.ts +10 -0
- package/dist/cjs/no-auto-bytecode-nodejs.js +189 -0
- package/dist/cjs/{client.d.ts → public-types.d.ts} +51 -3
- package/dist/cjs/public-types.js +76 -0
- package/dist/cjs/worker-browser.d.ts +11 -0
- package/dist/cjs/worker-browser.js +63 -0
- package/dist/cjs/worker-deno.d.ts +11 -0
- package/dist/cjs/worker-deno.js +54 -0
- package/dist/cjs/worker-nodejs.d.ts +11 -0
- package/dist/cjs/worker-nodejs.js +55 -0
- package/dist/mjs/bytecode-browser.d.ts +5 -0
- package/dist/mjs/bytecode-browser.js +38 -0
- package/dist/mjs/bytecode-deno.d.ts +5 -0
- package/dist/mjs/bytecode-deno.js +83 -0
- package/dist/mjs/bytecode-nodejs.d.ts +5 -0
- package/dist/mjs/bytecode-nodejs.js +37 -0
- package/dist/mjs/index-browser.d.ts +2 -2
- package/dist/mjs/index-browser.js +4 -501
- package/dist/mjs/index-deno.d.ts +2 -2
- package/dist/mjs/index-deno.js +4 -277
- package/dist/mjs/index-nodejs.d.ts +2 -2
- package/dist/mjs/index-nodejs.js +4 -205
- package/dist/mjs/internals/bytecode/wasm0.js +1 -0
- package/dist/mjs/internals/bytecode/wasm1.js +1 -0
- package/dist/mjs/internals/bytecode/wasm2.js +1 -0
- package/dist/mjs/{instance/bindings-smoldot-light.d.ts → internals/client.d.ts} +15 -34
- package/dist/mjs/internals/client.js +372 -0
- package/dist/mjs/internals/local-instance.d.ts +144 -0
- package/dist/mjs/internals/local-instance.js +561 -0
- package/dist/mjs/internals/remote-instance.d.ts +38 -0
- package/dist/mjs/internals/remote-instance.js +369 -0
- package/dist/mjs/no-auto-bytecode-browser.d.ts +11 -0
- package/dist/mjs/no-auto-bytecode-browser.js +471 -0
- package/dist/mjs/no-auto-bytecode-deno.d.ts +10 -0
- package/dist/mjs/no-auto-bytecode-deno.js +210 -0
- package/dist/mjs/no-auto-bytecode-nodejs.d.ts +10 -0
- package/dist/mjs/no-auto-bytecode-nodejs.js +179 -0
- package/dist/mjs/{client.d.ts → public-types.d.ts} +51 -3
- package/dist/mjs/public-types.js +67 -0
- package/dist/mjs/worker-browser.d.ts +11 -0
- package/dist/mjs/worker-browser.js +59 -0
- package/dist/mjs/worker-deno.d.ts +11 -0
- package/dist/mjs/worker-deno.js +50 -0
- package/dist/mjs/worker-nodejs.d.ts +11 -0
- package/dist/mjs/worker-nodejs.js +51 -0
- package/package.json +40 -8
- package/dist/cjs/client.js +0 -172
- package/dist/cjs/instance/autogen/wasm0.js +0 -4
- package/dist/cjs/instance/autogen/wasm1.js +0 -4
- package/dist/cjs/instance/autogen/wasm2.js +0 -4
- package/dist/cjs/instance/bindings-smoldot-light.js +0 -285
- package/dist/cjs/instance/bindings-wasi.d.ts +0 -27
- package/dist/cjs/instance/bindings-wasi.js +0 -172
- package/dist/cjs/instance/bindings.d.ts +0 -31
- package/dist/cjs/instance/bindings.js +0 -5
- package/dist/cjs/instance/instance.d.ts +0 -45
- package/dist/cjs/instance/instance.js +0 -277
- package/dist/cjs/instance/raw-instance.d.ts +0 -56
- package/dist/cjs/instance/raw-instance.js +0 -129
- package/dist/mjs/client.js +0 -162
- package/dist/mjs/instance/autogen/wasm0.js +0 -1
- package/dist/mjs/instance/autogen/wasm1.js +0 -1
- package/dist/mjs/instance/autogen/wasm2.js +0 -1
- package/dist/mjs/instance/bindings-smoldot-light.js +0 -280
- package/dist/mjs/instance/bindings-wasi.d.ts +0 -27
- package/dist/mjs/instance/bindings-wasi.js +0 -170
- package/dist/mjs/instance/bindings.d.ts +0 -31
- package/dist/mjs/instance/bindings.js +0 -4
- package/dist/mjs/instance/instance.d.ts +0 -45
- package/dist/mjs/instance/instance.js +0 -269
- package/dist/mjs/instance/raw-instance.d.ts +0 -56
- package/dist/mjs/instance/raw-instance.js +0 -124
- /package/dist/cjs/{base64.d.ts → internals/base64.d.ts} +0 -0
- /package/dist/cjs/{base64.js → internals/base64.js} +0 -0
- /package/dist/cjs/{instance → internals}/buffer.d.ts +0 -0
- /package/dist/cjs/{instance → internals}/buffer.js +0 -0
- /package/dist/cjs/{instance/autogen → internals/bytecode}/wasm.d.ts +0 -0
- /package/dist/cjs/{instance/autogen → internals/bytecode}/wasm.js +0 -0
- /package/dist/cjs/{instance/autogen → internals/bytecode}/wasm0.d.ts +0 -0
- /package/dist/cjs/{instance/autogen → internals/bytecode}/wasm1.d.ts +0 -0
- /package/dist/cjs/{instance/autogen → internals/bytecode}/wasm2.d.ts +0 -0
- /package/dist/mjs/{base64.d.ts → internals/base64.d.ts} +0 -0
- /package/dist/mjs/{base64.js → internals/base64.js} +0 -0
- /package/dist/mjs/{instance → internals}/buffer.d.ts +0 -0
- /package/dist/mjs/{instance → internals}/buffer.js +0 -0
- /package/dist/mjs/{instance/autogen → internals/bytecode}/wasm.d.ts +0 -0
- /package/dist/mjs/{instance/autogen → internals/bytecode}/wasm.js +0 -0
- /package/dist/mjs/{instance/autogen → internals/bytecode}/wasm0.d.ts +0 -0
- /package/dist/mjs/{instance/autogen → internals/bytecode}/wasm1.d.ts +0 -0
- /package/dist/mjs/{instance/autogen → internals/bytecode}/wasm2.d.ts +0 -0
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
* When `buffer_size` or `buffer_index` are called, the buffer is found here.
|
|
8
|
-
*/
|
|
9
|
-
bufferIndices: Array<Uint8Array>;
|
|
1
|
+
import { Client, ClientOptions, SmoldotBytecode } from '../public-types.js';
|
|
2
|
+
import * as instance from './local-instance.js';
|
|
3
|
+
/**
|
|
4
|
+
* Contains functions that the client will use when it needs to leverage the platform.
|
|
5
|
+
*/
|
|
6
|
+
export interface PlatformBindings {
|
|
10
7
|
/**
|
|
11
8
|
* Tries to open a new connection using the given configuration.
|
|
12
9
|
*
|
|
@@ -15,15 +12,13 @@ export interface Config {
|
|
|
15
12
|
*/
|
|
16
13
|
connect(config: ConnectionConfig): Connection;
|
|
17
14
|
/**
|
|
18
|
-
*
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
* Returns the number of milliseconds since an arbitrary epoch.
|
|
16
|
+
*/
|
|
17
|
+
performanceNow: () => number;
|
|
18
|
+
/**
|
|
19
|
+
* Fills the given buffer with randomly-generated bytes.
|
|
21
20
|
*/
|
|
22
|
-
|
|
23
|
-
logCallback: (level: number, target: string, message: string) => void;
|
|
24
|
-
jsonRpcResponsesNonEmptyCallback: (chainId: number) => void;
|
|
25
|
-
advanceExecutionReadyCallback: () => void;
|
|
26
|
-
currentTaskCallback?: (taskName: string | null) => void;
|
|
21
|
+
getRandomValues: (buffer: Uint8Array) => void;
|
|
27
22
|
}
|
|
28
23
|
/**
|
|
29
24
|
* Connection to a remote node.
|
|
@@ -114,12 +109,9 @@ export interface Connection {
|
|
|
114
109
|
*/
|
|
115
110
|
export interface ConnectionConfig {
|
|
116
111
|
/**
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
* Note that this address shouldn't be trusted. The value in this field might have been chosen
|
|
120
|
-
* by a potentially malicious peer.
|
|
112
|
+
* Parsed multiaddress, as returned by the `parseMultiaddr` function.
|
|
121
113
|
*/
|
|
122
|
-
address:
|
|
114
|
+
address: instance.ParsedMultiaddr;
|
|
123
115
|
/**
|
|
124
116
|
* Callback called when the connection transitions from the `Opening` to the `Open` state.
|
|
125
117
|
*
|
|
@@ -181,15 +173,4 @@ export interface ConnectionConfig {
|
|
|
181
173
|
*/
|
|
182
174
|
onMessage: (message: Uint8Array, streamId?: number) => void;
|
|
183
175
|
}
|
|
184
|
-
|
|
185
|
-
* Emitted by `connect` if the multiaddress couldn't be parsed or contains an invalid protocol.
|
|
186
|
-
*
|
|
187
|
-
* @see connect
|
|
188
|
-
*/
|
|
189
|
-
export declare class ConnectionError extends Error {
|
|
190
|
-
constructor(message: string);
|
|
191
|
-
}
|
|
192
|
-
export default function (config: Config): {
|
|
193
|
-
imports: WebAssembly.ModuleImports;
|
|
194
|
-
killAll: () => void;
|
|
195
|
-
};
|
|
176
|
+
export declare function start(options: ClientOptions, wasmModule: SmoldotBytecode | Promise<SmoldotBytecode>, platformBindings: PlatformBindings): Client;
|
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Smoldot
|
|
3
|
+
// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd.
|
|
4
|
+
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
|
|
5
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
6
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
7
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
8
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
9
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
10
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
11
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
12
|
+
});
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.start = void 0;
|
|
16
|
+
// This program is free software: you can redistribute it and/or modify
|
|
17
|
+
// it under the terms of the GNU General Public License as published by
|
|
18
|
+
// the Free Software Foundation, either version 3 of the License, or
|
|
19
|
+
// (at your option) any later version.
|
|
20
|
+
// This program is distributed in the hope that it will be useful,
|
|
21
|
+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
22
|
+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
23
|
+
// GNU General Public License for more details.
|
|
24
|
+
// You should have received a copy of the GNU General Public License
|
|
25
|
+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
26
|
+
const public_types_js_1 = require("../public-types.js");
|
|
27
|
+
const instance = require("./local-instance.js");
|
|
28
|
+
const remote = require("./remote-instance.js");
|
|
29
|
+
// This function is similar to the `start` function found in `index.ts`, except with an extra
|
|
30
|
+
// parameter containing the platform-specific bindings.
|
|
31
|
+
// Contrary to the one within `index.js`, this function is not supposed to be directly used.
|
|
32
|
+
function start(options, wasmModule, platformBindings) {
|
|
33
|
+
const logCallback = options.logCallback || ((level, target, message) => {
|
|
34
|
+
// The first parameter of the methods of `console` has some printf-like substitution
|
|
35
|
+
// capabilities. We don't really need to use this, but not using it means that the logs might
|
|
36
|
+
// not get printed correctly if they contain `%`.
|
|
37
|
+
if (level <= 1) {
|
|
38
|
+
console.error("[%s] %s", target, message);
|
|
39
|
+
}
|
|
40
|
+
else if (level == 2) {
|
|
41
|
+
console.warn("[%s] %s", target, message);
|
|
42
|
+
}
|
|
43
|
+
else if (level == 3) {
|
|
44
|
+
console.info("[%s] %s", target, message);
|
|
45
|
+
}
|
|
46
|
+
else if (level == 4) {
|
|
47
|
+
console.debug("[%s] %s", target, message);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
console.trace("[%s] %s", target, message);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
if (!(wasmModule instanceof Promise)) {
|
|
54
|
+
wasmModule = Promise.resolve(wasmModule);
|
|
55
|
+
}
|
|
56
|
+
// Extract (to make sure the value doesn't change) and sanitize `cpuRateLimit`.
|
|
57
|
+
let cpuRateLimit = options.cpuRateLimit || 1.0;
|
|
58
|
+
if (isNaN(cpuRateLimit))
|
|
59
|
+
cpuRateLimit = 1.0;
|
|
60
|
+
if (cpuRateLimit > 1.0)
|
|
61
|
+
cpuRateLimit = 1.0;
|
|
62
|
+
if (cpuRateLimit < 0.0)
|
|
63
|
+
cpuRateLimit = 0.0;
|
|
64
|
+
// This object holds the state of everything.
|
|
65
|
+
const state = {
|
|
66
|
+
instance: { status: "not-created" },
|
|
67
|
+
chainIds: new WeakMap(),
|
|
68
|
+
currentTaskName: null,
|
|
69
|
+
connections: new Map(),
|
|
70
|
+
addChainResults: [],
|
|
71
|
+
onExecutorShutdownOrWasmPanic: () => { },
|
|
72
|
+
chains: new Map(),
|
|
73
|
+
};
|
|
74
|
+
// Callback called during the execution of the instance.
|
|
75
|
+
const eventCallback = (event) => {
|
|
76
|
+
switch (event.ty) {
|
|
77
|
+
case "wasm-panic": {
|
|
78
|
+
console.error("Smoldot has panicked" +
|
|
79
|
+
(state.currentTaskName ? (" while executing task `" + state.currentTaskName + "`") : "") +
|
|
80
|
+
". This is a bug in smoldot. Please open an issue at " +
|
|
81
|
+
"https://github.com/smol-dot/smoldot/issues with the following message:\n" +
|
|
82
|
+
event.message);
|
|
83
|
+
state.instance = {
|
|
84
|
+
status: "destroyed",
|
|
85
|
+
error: new public_types_js_1.CrashError(event.message),
|
|
86
|
+
};
|
|
87
|
+
state.connections.forEach((connec) => connec.reset());
|
|
88
|
+
state.connections.clear();
|
|
89
|
+
for (const addChainResult of state.addChainResults) {
|
|
90
|
+
addChainResult({ success: false, error: "Smoldot has crashed" });
|
|
91
|
+
}
|
|
92
|
+
state.addChainResults = [];
|
|
93
|
+
for (const chain of Array.from(state.chains.values())) {
|
|
94
|
+
for (const callback of chain.jsonRpcResponsesPromises) {
|
|
95
|
+
callback();
|
|
96
|
+
}
|
|
97
|
+
chain.jsonRpcResponsesPromises = [];
|
|
98
|
+
}
|
|
99
|
+
state.chains.clear();
|
|
100
|
+
state.currentTaskName = null;
|
|
101
|
+
const cb = state.onExecutorShutdownOrWasmPanic;
|
|
102
|
+
state.onExecutorShutdownOrWasmPanic = () => { };
|
|
103
|
+
cb();
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
case "executor-shutdown": {
|
|
107
|
+
const cb = state.onExecutorShutdownOrWasmPanic;
|
|
108
|
+
state.onExecutorShutdownOrWasmPanic = () => { };
|
|
109
|
+
cb();
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
case "log": {
|
|
113
|
+
logCallback(event.level, event.target, event.message);
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
case "add-chain-result": {
|
|
117
|
+
(state.addChainResults.shift())(event);
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
case "json-rpc-responses-non-empty": {
|
|
121
|
+
// Notify every single promise found in `jsonRpcResponsesPromises`.
|
|
122
|
+
const callbacks = state.chains.get(event.chainId).jsonRpcResponsesPromises;
|
|
123
|
+
while (callbacks.length !== 0) {
|
|
124
|
+
(callbacks.shift())();
|
|
125
|
+
}
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
case "current-task": {
|
|
129
|
+
state.currentTaskName = event.taskName;
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
case "new-connection": {
|
|
133
|
+
const connectionId = event.connectionId;
|
|
134
|
+
state.connections.set(connectionId, platformBindings.connect({
|
|
135
|
+
address: event.address,
|
|
136
|
+
onConnectionReset(message) {
|
|
137
|
+
if (state.instance.status !== "ready")
|
|
138
|
+
throw new Error();
|
|
139
|
+
state.connections.delete(connectionId);
|
|
140
|
+
state.instance.instance.connectionReset(connectionId, message);
|
|
141
|
+
},
|
|
142
|
+
onMessage(message, streamId) {
|
|
143
|
+
if (state.instance.status !== "ready")
|
|
144
|
+
throw new Error();
|
|
145
|
+
state.instance.instance.streamMessage(connectionId, message, streamId);
|
|
146
|
+
},
|
|
147
|
+
onStreamOpened(streamId, direction, initialWritableBytes) {
|
|
148
|
+
if (state.instance.status !== "ready")
|
|
149
|
+
throw new Error();
|
|
150
|
+
state.instance.instance.streamOpened(connectionId, streamId, direction, initialWritableBytes);
|
|
151
|
+
},
|
|
152
|
+
onOpen(info) {
|
|
153
|
+
if (state.instance.status !== "ready")
|
|
154
|
+
throw new Error();
|
|
155
|
+
state.instance.instance.connectionOpened(connectionId, info);
|
|
156
|
+
},
|
|
157
|
+
onWritableBytes(numExtra, streamId) {
|
|
158
|
+
if (state.instance.status !== "ready")
|
|
159
|
+
throw new Error();
|
|
160
|
+
state.instance.instance.streamWritableBytes(connectionId, numExtra, streamId);
|
|
161
|
+
},
|
|
162
|
+
onStreamReset(streamId) {
|
|
163
|
+
if (state.instance.status !== "ready")
|
|
164
|
+
throw new Error();
|
|
165
|
+
state.instance.instance.streamReset(connectionId, streamId);
|
|
166
|
+
},
|
|
167
|
+
}));
|
|
168
|
+
break;
|
|
169
|
+
}
|
|
170
|
+
case "connection-reset": {
|
|
171
|
+
const connection = state.connections.get(event.connectionId);
|
|
172
|
+
connection.reset();
|
|
173
|
+
state.connections.delete(event.connectionId);
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
176
|
+
case "connection-stream-open": {
|
|
177
|
+
const connection = state.connections.get(event.connectionId);
|
|
178
|
+
connection.openOutSubstream();
|
|
179
|
+
break;
|
|
180
|
+
}
|
|
181
|
+
case "connection-stream-reset": {
|
|
182
|
+
const connection = state.connections.get(event.connectionId);
|
|
183
|
+
connection.reset(event.streamId);
|
|
184
|
+
break;
|
|
185
|
+
}
|
|
186
|
+
case "stream-send": {
|
|
187
|
+
const connection = state.connections.get(event.connectionId);
|
|
188
|
+
connection.send(event.data, event.streamId);
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
case "stream-send-close": {
|
|
192
|
+
const connection = state.connections.get(event.connectionId);
|
|
193
|
+
connection.closeSend(event.streamId);
|
|
194
|
+
break;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
const portToWorker = options.portToWorker;
|
|
199
|
+
if (!portToWorker) {
|
|
200
|
+
// Start a local instance.
|
|
201
|
+
state.instance = {
|
|
202
|
+
status: "not-ready",
|
|
203
|
+
whenReady: wasmModule
|
|
204
|
+
.then((wasmModule) => {
|
|
205
|
+
return instance.startLocalInstance({
|
|
206
|
+
forbidTcp: options.forbidTcp || false,
|
|
207
|
+
forbidWs: options.forbidWs || false,
|
|
208
|
+
forbidNonLocalWs: options.forbidNonLocalWs || false,
|
|
209
|
+
forbidWss: options.forbidWss || false,
|
|
210
|
+
forbidWebRtc: options.forbidWebRtc || false,
|
|
211
|
+
maxLogLevel: options.maxLogLevel || 3,
|
|
212
|
+
cpuRateLimit,
|
|
213
|
+
envVars: [],
|
|
214
|
+
performanceNow: platformBindings.performanceNow,
|
|
215
|
+
getRandomValues: platformBindings.getRandomValues,
|
|
216
|
+
}, wasmModule.wasm, eventCallback);
|
|
217
|
+
})
|
|
218
|
+
.then((instance) => {
|
|
219
|
+
// The Wasm instance might have been crashed before this callback is called.
|
|
220
|
+
if (state.instance.status === "destroyed")
|
|
221
|
+
return;
|
|
222
|
+
state.instance = {
|
|
223
|
+
status: "ready",
|
|
224
|
+
instance,
|
|
225
|
+
};
|
|
226
|
+
})
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
// Connect to the remote instance.
|
|
231
|
+
state.instance = {
|
|
232
|
+
status: "not-ready",
|
|
233
|
+
whenReady: remote.connectToInstanceServer({
|
|
234
|
+
wasmModule: wasmModule.then((b) => b.wasm),
|
|
235
|
+
forbidTcp: options.forbidTcp || false,
|
|
236
|
+
forbidWs: options.forbidWs || false,
|
|
237
|
+
forbidNonLocalWs: options.forbidNonLocalWs || false,
|
|
238
|
+
forbidWss: options.forbidWss || false,
|
|
239
|
+
forbidWebRtc: options.forbidWebRtc || false,
|
|
240
|
+
maxLogLevel: options.maxLogLevel || 3,
|
|
241
|
+
cpuRateLimit,
|
|
242
|
+
portToServer: portToWorker,
|
|
243
|
+
eventCallback
|
|
244
|
+
}).then((instance) => {
|
|
245
|
+
// The Wasm instance might have been crashed before this callback is called.
|
|
246
|
+
if (state.instance.status === "destroyed")
|
|
247
|
+
return;
|
|
248
|
+
state.instance = {
|
|
249
|
+
status: "ready",
|
|
250
|
+
instance,
|
|
251
|
+
};
|
|
252
|
+
})
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
return {
|
|
256
|
+
addChain: (options) => __awaiter(this, void 0, void 0, function* () {
|
|
257
|
+
if (state.instance.status === "not-ready")
|
|
258
|
+
yield state.instance.whenReady;
|
|
259
|
+
if (state.instance.status === "destroyed")
|
|
260
|
+
throw state.instance.error;
|
|
261
|
+
if (state.instance.status === "not-created" || state.instance.status === "not-ready")
|
|
262
|
+
throw new Error(); // Internal error, not supposed to ever happen.
|
|
263
|
+
// Passing a JSON object for the chain spec is an easy mistake, so we provide a more
|
|
264
|
+
// readable error.
|
|
265
|
+
if (!(typeof options.chainSpec === 'string'))
|
|
266
|
+
throw new Error("Chain specification must be a string");
|
|
267
|
+
let potentialRelayChainsIds = [];
|
|
268
|
+
if (!!options.potentialRelayChains) {
|
|
269
|
+
for (const chain of options.potentialRelayChains) {
|
|
270
|
+
// The content of `options.potentialRelayChains` are supposed to be chains earlier
|
|
271
|
+
// returned by `addChain`.
|
|
272
|
+
const id = state.chainIds.get(chain);
|
|
273
|
+
if (id === undefined) // It is possible for `id` to be missing if it has earlier been removed.
|
|
274
|
+
continue;
|
|
275
|
+
potentialRelayChainsIds.push(id);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
const promise = new Promise((resolve) => state.addChainResults.push(resolve));
|
|
279
|
+
state.instance.instance.addChain(options.chainSpec, typeof options.databaseContent === 'string' ? options.databaseContent : "", potentialRelayChainsIds, !!options.disableJsonRpc);
|
|
280
|
+
const outcome = yield promise;
|
|
281
|
+
if (!outcome.success)
|
|
282
|
+
throw new public_types_js_1.AddChainError(outcome.error);
|
|
283
|
+
const chainId = outcome.chainId;
|
|
284
|
+
state.chains.set(chainId, {
|
|
285
|
+
jsonRpcResponsesPromises: new Array()
|
|
286
|
+
});
|
|
287
|
+
const newChain = {
|
|
288
|
+
sendJsonRpc: (request) => {
|
|
289
|
+
if (state.instance.status === "destroyed")
|
|
290
|
+
throw state.instance.error;
|
|
291
|
+
if (state.instance.status !== "ready")
|
|
292
|
+
throw new Error(); // Internal error. Never supposed to happen.
|
|
293
|
+
if (!state.chains.has(chainId))
|
|
294
|
+
throw new public_types_js_1.AlreadyDestroyedError();
|
|
295
|
+
if (options.disableJsonRpc)
|
|
296
|
+
throw new public_types_js_1.JsonRpcDisabledError();
|
|
297
|
+
if (request.length >= 64 * 1024 * 1024) {
|
|
298
|
+
throw new public_types_js_1.MalformedJsonRpcError();
|
|
299
|
+
}
|
|
300
|
+
;
|
|
301
|
+
const retVal = state.instance.instance.request(request, chainId);
|
|
302
|
+
switch (retVal) {
|
|
303
|
+
case 0: break;
|
|
304
|
+
case 1: throw new public_types_js_1.MalformedJsonRpcError();
|
|
305
|
+
case 2: throw new public_types_js_1.QueueFullError();
|
|
306
|
+
default: throw new Error("Internal error: unknown json_rpc_send error code: " + retVal);
|
|
307
|
+
}
|
|
308
|
+
},
|
|
309
|
+
nextJsonRpcResponse: () => __awaiter(this, void 0, void 0, function* () {
|
|
310
|
+
if (!state.chains.has(chainId))
|
|
311
|
+
throw new public_types_js_1.AlreadyDestroyedError();
|
|
312
|
+
if (options.disableJsonRpc)
|
|
313
|
+
return Promise.reject(new public_types_js_1.JsonRpcDisabledError());
|
|
314
|
+
while (true) {
|
|
315
|
+
if (state.instance.status === "destroyed")
|
|
316
|
+
throw state.instance.error;
|
|
317
|
+
if (state.instance.status !== "ready")
|
|
318
|
+
throw new Error(); // Internal error. Never supposed to happen.
|
|
319
|
+
// Try to pop a message from the queue.
|
|
320
|
+
const message = state.instance.instance.peekJsonRpcResponse(chainId);
|
|
321
|
+
if (message)
|
|
322
|
+
return message;
|
|
323
|
+
// If no message is available, wait for one to be.
|
|
324
|
+
yield new Promise((resolve) => {
|
|
325
|
+
state.chains.get(chainId).jsonRpcResponsesPromises.push(resolve);
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
}),
|
|
329
|
+
remove: () => {
|
|
330
|
+
if (state.instance.status === "destroyed")
|
|
331
|
+
throw state.instance.error;
|
|
332
|
+
if (state.instance.status !== "ready")
|
|
333
|
+
throw new Error(); // Internal error. Never supposed to happen.
|
|
334
|
+
if (!state.chains.has(chainId))
|
|
335
|
+
throw new public_types_js_1.AlreadyDestroyedError();
|
|
336
|
+
console.assert(state.chainIds.has(newChain));
|
|
337
|
+
state.chainIds.delete(newChain);
|
|
338
|
+
for (const callback of state.chains.get(chainId).jsonRpcResponsesPromises) {
|
|
339
|
+
callback();
|
|
340
|
+
}
|
|
341
|
+
state.chains.delete(chainId);
|
|
342
|
+
state.instance.instance.removeChain(chainId);
|
|
343
|
+
},
|
|
344
|
+
};
|
|
345
|
+
state.chainIds.set(newChain, chainId);
|
|
346
|
+
return newChain;
|
|
347
|
+
}),
|
|
348
|
+
terminate: () => __awaiter(this, void 0, void 0, function* () {
|
|
349
|
+
if (state.instance.status === "not-ready")
|
|
350
|
+
yield state.instance.whenReady;
|
|
351
|
+
if (state.instance.status === "destroyed")
|
|
352
|
+
throw state.instance.error;
|
|
353
|
+
if (state.instance.status !== "ready")
|
|
354
|
+
throw new Error(); // Internal error. Never supposed to happen.
|
|
355
|
+
state.instance.instance.shutdownExecutor();
|
|
356
|
+
state.instance = { status: "destroyed", error: new public_types_js_1.AlreadyDestroyedError() };
|
|
357
|
+
state.connections.forEach((connec) => connec.reset());
|
|
358
|
+
state.connections.clear();
|
|
359
|
+
for (const addChainResult of state.addChainResults) {
|
|
360
|
+
addChainResult({ success: false, error: "Smoldot has crashed" });
|
|
361
|
+
}
|
|
362
|
+
state.addChainResults = [];
|
|
363
|
+
for (const chain of Array.from(state.chains.values())) {
|
|
364
|
+
for (const callback of chain.jsonRpcResponsesPromises) {
|
|
365
|
+
callback();
|
|
366
|
+
}
|
|
367
|
+
chain.jsonRpcResponsesPromises = [];
|
|
368
|
+
}
|
|
369
|
+
state.chains.clear();
|
|
370
|
+
state.currentTaskName = null;
|
|
371
|
+
// Wait for the `executor-shutdown` event to be generated.
|
|
372
|
+
yield new Promise((resolve) => state.onExecutorShutdownOrWasmPanic = resolve);
|
|
373
|
+
})
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
exports.start = start;
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration for {@link startLocalInstance}.
|
|
3
|
+
*/
|
|
4
|
+
export interface Config {
|
|
5
|
+
forbidTcp: boolean;
|
|
6
|
+
forbidWs: boolean;
|
|
7
|
+
forbidNonLocalWs: boolean;
|
|
8
|
+
forbidWss: boolean;
|
|
9
|
+
forbidWebRtc: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Maximum level of the logs that are generated.
|
|
12
|
+
*/
|
|
13
|
+
maxLogLevel: number;
|
|
14
|
+
/**
|
|
15
|
+
* Number between 0.0 and 1.0 indicating how much of the CPU time the instance is allowed to
|
|
16
|
+
* consume.
|
|
17
|
+
*/
|
|
18
|
+
cpuRateLimit: number;
|
|
19
|
+
/**
|
|
20
|
+
* Environment variables that the instance can pull.
|
|
21
|
+
*/
|
|
22
|
+
envVars: string[];
|
|
23
|
+
/**
|
|
24
|
+
* Returns the number of milliseconds since an arbitrary epoch.
|
|
25
|
+
*/
|
|
26
|
+
performanceNow: () => number;
|
|
27
|
+
/**
|
|
28
|
+
* Fills the given buffer with randomly-generated bytes.
|
|
29
|
+
*/
|
|
30
|
+
getRandomValues: (buffer: Uint8Array) => void;
|
|
31
|
+
}
|
|
32
|
+
export type Event = {
|
|
33
|
+
ty: "add-chain-result";
|
|
34
|
+
success: true;
|
|
35
|
+
chainId: number;
|
|
36
|
+
} | {
|
|
37
|
+
ty: "add-chain-result";
|
|
38
|
+
success: false;
|
|
39
|
+
error: string;
|
|
40
|
+
} | {
|
|
41
|
+
ty: "log";
|
|
42
|
+
level: number;
|
|
43
|
+
target: string;
|
|
44
|
+
message: string;
|
|
45
|
+
} | {
|
|
46
|
+
ty: "json-rpc-responses-non-empty";
|
|
47
|
+
chainId: number;
|
|
48
|
+
} | {
|
|
49
|
+
ty: "current-task";
|
|
50
|
+
taskName: string | null;
|
|
51
|
+
} | {
|
|
52
|
+
ty: "wasm-panic";
|
|
53
|
+
message: string;
|
|
54
|
+
} | {
|
|
55
|
+
ty: "executor-shutdown";
|
|
56
|
+
} | {
|
|
57
|
+
ty: "new-connection";
|
|
58
|
+
connectionId: number;
|
|
59
|
+
address: ParsedMultiaddr;
|
|
60
|
+
} | {
|
|
61
|
+
ty: "connection-reset";
|
|
62
|
+
connectionId: number;
|
|
63
|
+
} | {
|
|
64
|
+
ty: "connection-stream-open";
|
|
65
|
+
connectionId: number;
|
|
66
|
+
} | {
|
|
67
|
+
ty: "connection-stream-reset";
|
|
68
|
+
connectionId: number;
|
|
69
|
+
streamId: number;
|
|
70
|
+
} | {
|
|
71
|
+
ty: "stream-send";
|
|
72
|
+
connectionId: number;
|
|
73
|
+
streamId?: number;
|
|
74
|
+
data: Uint8Array;
|
|
75
|
+
} | {
|
|
76
|
+
ty: "stream-send-close";
|
|
77
|
+
connectionId: number;
|
|
78
|
+
streamId?: number;
|
|
79
|
+
};
|
|
80
|
+
export type ParsedMultiaddr = {
|
|
81
|
+
ty: "tcp";
|
|
82
|
+
hostname: string;
|
|
83
|
+
port: number;
|
|
84
|
+
} | {
|
|
85
|
+
ty: "websocket";
|
|
86
|
+
url: string;
|
|
87
|
+
} | {
|
|
88
|
+
ty: "webrtc";
|
|
89
|
+
targetPort: string;
|
|
90
|
+
ipVersion: string;
|
|
91
|
+
targetIp: string;
|
|
92
|
+
remoteCertMultibase: string;
|
|
93
|
+
};
|
|
94
|
+
export interface Instance {
|
|
95
|
+
request: (request: string, chainId: number) => number;
|
|
96
|
+
peekJsonRpcResponse: (chainId: number) => string | null;
|
|
97
|
+
addChain: (chainSpec: string, databaseContent: string, potentialRelayChains: number[], disableJsonRpc: boolean) => void;
|
|
98
|
+
removeChain: (chainId: number) => void;
|
|
99
|
+
/**
|
|
100
|
+
* Notifies the background executor that it should stop. Once it has effectively stopped,
|
|
101
|
+
* a `shutdown-finished` event will be generated.
|
|
102
|
+
* Note that the instance can technically still be used, and all the functions still work, but
|
|
103
|
+
* in practice nothing is being run in the background and as such it won't do much.
|
|
104
|
+
* Existing connections are *not* closed. It is the responsibility of the API user to close
|
|
105
|
+
* all connections.
|
|
106
|
+
*/
|
|
107
|
+
shutdownExecutor: () => void;
|
|
108
|
+
connectionOpened: (connectionId: number, info: {
|
|
109
|
+
type: 'single-stream';
|
|
110
|
+
handshake: 'multistream-select-noise-yamux';
|
|
111
|
+
initialWritableBytes: number;
|
|
112
|
+
writeClosable: boolean;
|
|
113
|
+
} | {
|
|
114
|
+
type: 'multi-stream';
|
|
115
|
+
handshake: 'webrtc';
|
|
116
|
+
localTlsCertificateMultihash: Uint8Array;
|
|
117
|
+
remoteTlsCertificateMultihash: Uint8Array;
|
|
118
|
+
}) => void;
|
|
119
|
+
connectionReset: (connectionId: number, message: string) => void;
|
|
120
|
+
streamWritableBytes: (connectionId: number, numExtra: number, streamId?: number) => void;
|
|
121
|
+
streamMessage: (connectionId: number, message: Uint8Array, streamId?: number) => void;
|
|
122
|
+
streamOpened: (connectionId: number, streamId: number, direction: 'inbound' | 'outbound', initialWritableBytes: number) => void;
|
|
123
|
+
streamReset: (connectionId: number, streamId: number) => void;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Starts a new instance using the given configuration.
|
|
127
|
+
*
|
|
128
|
+
* Even though this function doesn't do anything asynchronous, it needs to be asynchronous due to
|
|
129
|
+
* the fact that `WebAssembly.instantiate` is for some reason asynchronous.
|
|
130
|
+
*
|
|
131
|
+
* After this function returns, the execution of CPU-heavy tasks of smoldot will happen
|
|
132
|
+
* asynchronously in the background.
|
|
133
|
+
*
|
|
134
|
+
* This instance is low-level in the sense that invalid input can lead to crashes and that input
|
|
135
|
+
* isn't sanitized. In other words, you know what you're doing.
|
|
136
|
+
*/
|
|
137
|
+
export declare function startLocalInstance(config: Config, wasmModule: WebAssembly.Module, eventCallback: (event: Event) => void): Promise<Instance>;
|
|
138
|
+
export declare function parseMultiaddr(address: string, forbidTcp: boolean, forbidWs: boolean, forbidNonLocalWs: boolean, forbidWss: boolean, forbidWebRtc: boolean): {
|
|
139
|
+
success: true;
|
|
140
|
+
address: ParsedMultiaddr;
|
|
141
|
+
} | {
|
|
142
|
+
success: false;
|
|
143
|
+
error: string;
|
|
144
|
+
};
|