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.
@@ -78,7 +78,7 @@ function start(options, wasmModule, platformBindings) {
78
78
  console.error("Smoldot has panicked" +
79
79
  (event.currentTask ? (" while executing task `" + event.currentTask + "`") : "") +
80
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" +
81
+ "https://github.com/paritytech/smoldot/issues with the following message:\n" +
82
82
  event.message);
83
83
  state.instance = {
84
84
  status: "destroyed",
@@ -304,6 +304,7 @@ function startLocalInstance(config, wasmModule, eventCallback) {
304
304
  // panic happens.
305
305
  const shutdownExecutorOrWasmPanicPromise = new Promise((resolve) => state.onShutdownExecutorOrWasmPanic = () => resolve("stop"));
306
306
  (() => __awaiter(this, void 0, void 0, function* () {
307
+ var _a;
307
308
  const cpuRateLimit = config.cpuRateLimit;
308
309
  // In order to avoid calling `setTimeout` too often, we accumulate sleep up until
309
310
  // a certain threshold.
@@ -316,7 +317,30 @@ function startLocalInstance(config, wasmModule, eventCallback) {
316
317
  try {
317
318
  state.instance.exports.advance_execution();
318
319
  }
319
- catch (_error) {
320
+ catch (error) {
321
+ // Two kinds of exceptions can reach this point:
322
+ //
323
+ // - A Rust panic. The `panic` binding has already emitted the `wasm-panic`
324
+ // event, notified the shutdown callback, and set `state.instance` to `null`.
325
+ //
326
+ // - An exception thrown by JavaScript code called from within the Wasm (for
327
+ // example a platform binding, see
328
+ // <https://github.com/paritytech/smoldot/issues/3302>). The exception has
329
+ // unwound through the Wasm frames without the Rust code being aware of it,
330
+ // leaving the instance in an unusable state (locks still held, etc.).
331
+ // Swallowing it would leave a zombie instance that panics at every
332
+ // subsequent entry point. Instead, report it as a crash, the same way as
333
+ // a panic.
334
+ if (state.instance) {
335
+ state.instance = null;
336
+ eventCallback({
337
+ ty: "wasm-panic",
338
+ message: error instanceof Error ? ((_a = error.stack) !== null && _a !== void 0 ? _a : error.toString()) : String(error),
339
+ currentTask: state.currentTask
340
+ });
341
+ state.onShutdownExecutorOrWasmPanic();
342
+ state.onShutdownExecutorOrWasmPanic = () => { };
343
+ }
320
344
  return;
321
345
  }
322
346
  const afterExec = config.performanceNow();
@@ -29,6 +29,10 @@ Object.defineProperty(exports, "QueueFullError", { enumerable: true, get: functi
29
29
  */
30
30
  function startWithBytecode(options) {
31
31
  options.forbidTcp = true;
32
+ // Browsers only expose the WebRTC API on `Window`, it doesn't exist in worker global
33
+ // scopes, and consequently there is no way to open WebRTC connections from here.
34
+ if (typeof RTCPeerConnection === 'undefined')
35
+ options.forbidWebRtc = true;
32
36
  // When in a secure context, browsers refuse to open non-secure WebSocket connections to
33
37
  // non-localhost. There is an exception if the page is localhost, in which case all connections
34
38
  // are allowed.
@@ -169,6 +173,27 @@ function connect(config) {
169
173
  };
170
174
  }
171
175
  else if (config.address.ty === "webrtc") {
176
+ // Browsers only expose the WebRTC API on `Window`.
177
+ // When running in a worker, opening a WebRTC connection is impossible.
178
+ // Instead of throwing an exception (which would crash the entire client),
179
+ // report the connection as reset so that smoldot moves on to other
180
+ // addresses.
181
+ //
182
+ // Note: `startWithBytecode` sets `forbidWebRtc` in that situation, making
183
+ // this code path unreachable, but better be defensive.
184
+ if (typeof RTCPeerConnection === 'undefined') {
185
+ let cancelled = false;
186
+ setTimeout(() => {
187
+ if (!cancelled)
188
+ config.onConnectionReset('RTCPeerConnection is not available in this environment');
189
+ }, 1);
190
+ return {
191
+ reset: () => { cancelled = true; },
192
+ send: () => { throw new Error('Connection is closed'); },
193
+ closeSend: () => { throw new Error('Connection is closed'); },
194
+ openOutSubstream: () => { throw new Error('Connection is closed'); },
195
+ };
196
+ }
172
197
  const { targetPort, ipVersion, targetIp, remoteTlsCertificateSha256 } = config.address;
173
198
  const state = {
174
199
  pc: undefined,
@@ -208,7 +233,13 @@ function connect(config) {
208
233
  dataChannel.binaryType = 'arraybuffer';
209
234
  let isOpen = { value: false };
210
235
  dataChannel.onopen = () => {
236
+ // Guard against the `open` event firing more than once for the same channel.
237
+ // Reporting the same stream id twice would make smoldot panic (observed in
238
+ // production as "same stream_id used multiple times in
239
+ // connection_stream_opened").
211
240
  console.assert(!isOpen.value, "substream opened twice");
241
+ if (isOpen.value)
242
+ return;
212
243
  isOpen.value = true;
213
244
  config.onStreamOpened(streamId, direction);
214
245
  config.onWritableBytes(65536, streamId);