smoldot 3.3.0 → 3.3.2

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.
@@ -75,7 +75,7 @@ export function start(options, wasmModule, platformBindings) {
75
75
  console.error("Smoldot has panicked" +
76
76
  (event.currentTask ? (" while executing task `" + event.currentTask + "`") : "") +
77
77
  ". This is a bug in smoldot. Please open an issue at " +
78
- "https://github.com/smol-dot/smoldot/issues with the following message:\n" +
78
+ "https://github.com/paritytech/smoldot/issues with the following message:\n" +
79
79
  event.message);
80
80
  state.instance = {
81
81
  status: "destroyed",
@@ -301,6 +301,7 @@ export function startLocalInstance(config, wasmModule, eventCallback) {
301
301
  // panic happens.
302
302
  const shutdownExecutorOrWasmPanicPromise = new Promise((resolve) => state.onShutdownExecutorOrWasmPanic = () => resolve("stop"));
303
303
  (() => __awaiter(this, void 0, void 0, function* () {
304
+ var _a;
304
305
  const cpuRateLimit = config.cpuRateLimit;
305
306
  // In order to avoid calling `setTimeout` too often, we accumulate sleep up until
306
307
  // a certain threshold.
@@ -313,7 +314,30 @@ export function startLocalInstance(config, wasmModule, eventCallback) {
313
314
  try {
314
315
  state.instance.exports.advance_execution();
315
316
  }
316
- catch (_error) {
317
+ catch (error) {
318
+ // Two kinds of exceptions can reach this point:
319
+ //
320
+ // - A Rust panic. The `panic` binding has already emitted the `wasm-panic`
321
+ // event, notified the shutdown callback, and set `state.instance` to `null`.
322
+ //
323
+ // - An exception thrown by JavaScript code called from within the Wasm (for
324
+ // example a platform binding, see
325
+ // <https://github.com/paritytech/smoldot/issues/3302>). The exception has
326
+ // unwound through the Wasm frames without the Rust code being aware of it,
327
+ // leaving the instance in an unusable state (locks still held, etc.).
328
+ // Swallowing it would leave a zombie instance that panics at every
329
+ // subsequent entry point. Instead, report it as a crash, the same way as
330
+ // a panic.
331
+ if (state.instance) {
332
+ state.instance = null;
333
+ eventCallback({
334
+ ty: "wasm-panic",
335
+ message: error instanceof Error ? ((_a = error.stack) !== null && _a !== void 0 ? _a : error.toString()) : String(error),
336
+ currentTask: state.currentTask
337
+ });
338
+ state.onShutdownExecutorOrWasmPanic();
339
+ state.onShutdownExecutorOrWasmPanic = () => { };
340
+ }
317
341
  return;
318
342
  }
319
343
  const afterExec = config.performanceNow();
@@ -21,6 +21,10 @@ export { AddChainError, AlreadyDestroyedError, CrashError, JsonRpcDisabledError,
21
21
  */
22
22
  export function startWithBytecode(options) {
23
23
  options.forbidTcp = true;
24
+ // Browsers only expose the WebRTC API on `Window`, it doesn't exist in worker global
25
+ // scopes, and consequently there is no way to open WebRTC connections from here.
26
+ if (typeof RTCPeerConnection === 'undefined')
27
+ options.forbidWebRtc = true;
24
28
  // When in a secure context, browsers refuse to open non-secure WebSocket connections to
25
29
  // non-localhost. There is an exception if the page is localhost, in which case all connections
26
30
  // are allowed.
@@ -160,6 +164,27 @@ function connect(config) {
160
164
  };
161
165
  }
162
166
  else if (config.address.ty === "webrtc") {
167
+ // Browsers only expose the WebRTC API on `Window`.
168
+ // When running in a worker, opening a WebRTC connection is impossible.
169
+ // Instead of throwing an exception (which would crash the entire client),
170
+ // report the connection as reset so that smoldot moves on to other
171
+ // addresses.
172
+ //
173
+ // Note: `startWithBytecode` sets `forbidWebRtc` in that situation, making
174
+ // this code path unreachable, but better be defensive.
175
+ if (typeof RTCPeerConnection === 'undefined') {
176
+ let cancelled = false;
177
+ setTimeout(() => {
178
+ if (!cancelled)
179
+ config.onConnectionReset('RTCPeerConnection is not available in this environment');
180
+ }, 1);
181
+ return {
182
+ reset: () => { cancelled = true; },
183
+ send: () => { throw new Error('Connection is closed'); },
184
+ closeSend: () => { throw new Error('Connection is closed'); },
185
+ openOutSubstream: () => { throw new Error('Connection is closed'); },
186
+ };
187
+ }
163
188
  const { targetPort, ipVersion, targetIp, remoteTlsCertificateSha256 } = config.address;
164
189
  const state = {
165
190
  pc: undefined,
@@ -199,7 +224,13 @@ function connect(config) {
199
224
  dataChannel.binaryType = 'arraybuffer';
200
225
  let isOpen = { value: false };
201
226
  dataChannel.onopen = () => {
227
+ // Guard against the `open` event firing more than once for the same channel.
228
+ // Reporting the same stream id twice would make smoldot panic (observed in
229
+ // production as "same stream_id used multiple times in
230
+ // connection_stream_opened").
202
231
  console.assert(!isOpen.value, "substream opened twice");
232
+ if (isOpen.value)
233
+ return;
203
234
  isOpen.value = true;
204
235
  config.onStreamOpened(streamId, direction);
205
236
  config.onWritableBytes(65536, streamId);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "smoldot",
3
- "version": "3.3.0",
3
+ "version": "3.3.2",
4
4
  "description": "Light client that connects to Polkadot and Substrate-based blockchains",
5
5
  "contributors": [
6
6
  "Parity Technologies <admin@parity.io>",