smoldot 1.0.1 → 1.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.
@@ -2,9 +2,11 @@ import type { SmoldotWasmInstance } from './bindings.js';
2
2
  export interface Config {
3
3
  instance?: SmoldotWasmInstance;
4
4
  /**
5
- * Returns the number of milliseconds since an arbitrary epoch.
5
+ * Array used to store the buffers provided to the Rust code.
6
+ *
7
+ * When `buffer_size` or `buffer_index` are called, the buffer is found here.
6
8
  */
7
- performanceNow: () => number;
9
+ bufferIndices: Array<Uint8Array>;
8
10
  /**
9
11
  * Tries to open a new connection using the given configuration.
10
12
  *
@@ -65,7 +67,7 @@ export interface Connection {
65
67
  *
66
68
  * The connection and stream must currently be in the `Open` state.
67
69
  *
68
- * The number of bytes most never exceed the number of "writable bytes" of the stream.
70
+ * The number of bytes must never exceed the number of "writable bytes" of the stream.
69
71
  * `onWritableBytes` can be used in order to notify that more writable bytes are available.
70
72
  *
71
73
  * The `streamId` must be provided if and only if the connection is of type "multi-stream".
@@ -154,7 +156,8 @@ export interface ConnectionConfig {
154
156
  */
155
157
  onStreamReset: (streamId: number) => void;
156
158
  /**
157
- * Callback called when more data can be written on the stream.
159
+ * Callback called when some data sent using {@link Connection.send} has effectively been
160
+ * written on the stream, meaning that some buffer space is now free.
158
161
  *
159
162
  * Can only happen while the connection is in the `Open` state.
160
163
  *
@@ -162,6 +165,9 @@ export interface ConnectionConfig {
162
165
  *
163
166
  * The `streamId` parameter must be provided if and only if the connection is of type
164
167
  * "multi-stream".
168
+ *
169
+ * Only a number of bytes equal to the size of the data provided to {@link Connection.send}
170
+ * must be reported. In other words, the `initialWritableBytes` must never be exceeded.
165
171
  */
166
172
  onWritableBytes: (numExtra: number, streamId?: number) => void;
167
173
  /**
@@ -55,6 +55,16 @@ function default_1(config) {
55
55
  const message = buffer.utf8BytesToString(new Uint8Array(instance.exports.memory.buffer), ptr, len);
56
56
  config.onPanic(message);
57
57
  },
58
+ buffer_size: (bufferIndex) => {
59
+ const buf = config.bufferIndices[bufferIndex];
60
+ return buf.byteLength;
61
+ },
62
+ buffer_copy: (bufferIndex, targetPtr) => {
63
+ const instance = config.instance;
64
+ targetPtr = targetPtr >>> 0;
65
+ const buf = config.bufferIndices[bufferIndex];
66
+ new Uint8Array(instance.exports.memory.buffer).set(buf, targetPtr);
67
+ },
58
68
  // Used by the Rust side to notify that a JSON-RPC response or subscription notification
59
69
  // is available in the queue of JSON-RPC responses.
60
70
  json_rpc_responses_non_empty: (chainId) => {
@@ -79,10 +89,6 @@ function default_1(config) {
79
89
  config.logCallback(level, target, message);
80
90
  }
81
91
  },
82
- // Must return the UNIX time in milliseconds.
83
- unix_time_ms: () => Date.now(),
84
- // Must return the value of a monotonic clock in milliseconds.
85
- monotonic_clock_ms: () => config.performanceNow(),
86
92
  // Must call `timer_finished` after the given number of milliseconds has elapsed.
87
93
  start_timer: (id, ms) => {
88
94
  if (killedTracked.killed)
@@ -120,11 +126,11 @@ function default_1(config) {
120
126
  },
121
127
  // Must create a new connection object. This implementation stores the created object in
122
128
  // `connections`.
123
- connection_new: (connectionId, addrPtr, addrLen, errorPtrPtr) => {
129
+ connection_new: (connectionId, addrPtr, addrLen, errorBufferIndexPtr) => {
124
130
  const instance = config.instance;
125
131
  addrPtr >>>= 0;
126
132
  addrLen >>>= 0;
127
- errorPtrPtr >>>= 0;
133
+ errorBufferIndexPtr >>>= 0;
128
134
  if (!!connections[connectionId]) {
129
135
  throw new Error("internal error: connection already allocated");
130
136
  }
@@ -144,13 +150,13 @@ function default_1(config) {
144
150
  break;
145
151
  }
146
152
  case 'multi-stream': {
147
- const bufferLen = 1 + info.localTlsCertificateMultihash.length + info.remoteTlsCertificateMultihash.length;
148
- const ptr = instance.exports.alloc(bufferLen) >>> 0;
149
- const mem = new Uint8Array(instance.exports.memory.buffer);
150
- buffer.writeUInt8(mem, ptr, 0);
151
- mem.set(info.localTlsCertificateMultihash, ptr + 1);
152
- mem.set(info.remoteTlsCertificateMultihash, ptr + 1 + info.localTlsCertificateMultihash.length);
153
- instance.exports.connection_open_multi_stream(connectionId, ptr, bufferLen);
153
+ const handshakeTy = new Uint8Array(1 + info.localTlsCertificateMultihash.length + info.remoteTlsCertificateMultihash.length);
154
+ buffer.writeUInt8(handshakeTy, 0, 0);
155
+ handshakeTy.set(info.localTlsCertificateMultihash, 1);
156
+ handshakeTy.set(info.remoteTlsCertificateMultihash, 1 + info.localTlsCertificateMultihash.length);
157
+ config.bufferIndices[0] = handshakeTy;
158
+ instance.exports.connection_open_multi_stream(connectionId, 0);
159
+ delete config.bufferIndices[0];
154
160
  break;
155
161
  }
156
162
  }
@@ -161,10 +167,9 @@ function default_1(config) {
161
167
  if (killedTracked.killed)
162
168
  return;
163
169
  try {
164
- const encoded = new TextEncoder().encode(message);
165
- const ptr = instance.exports.alloc(encoded.length) >>> 0;
166
- new Uint8Array(instance.exports.memory.buffer).set(encoded, ptr);
167
- instance.exports.connection_reset(connectionId, ptr, encoded.length);
170
+ config.bufferIndices[0] = new TextEncoder().encode(message);
171
+ instance.exports.connection_reset(connectionId, 0);
172
+ delete config.bufferIndices[0];
168
173
  }
169
174
  catch (_error) { }
170
175
  },
@@ -180,9 +185,9 @@ function default_1(config) {
180
185
  if (killedTracked.killed)
181
186
  return;
182
187
  try {
183
- const ptr = instance.exports.alloc(message.length) >>> 0;
184
- new Uint8Array(instance.exports.memory.buffer).set(message, ptr);
185
- instance.exports.stream_message(connectionId, streamId || 0, ptr, message.length);
188
+ config.bufferIndices[0] = message;
189
+ instance.exports.stream_message(connectionId, streamId || 0, 0);
190
+ delete config.bufferIndices[0];
186
191
  }
187
192
  catch (_error) { }
188
193
  },
@@ -213,12 +218,9 @@ function default_1(config) {
213
218
  errorStr = error.toString();
214
219
  }
215
220
  const mem = new Uint8Array(instance.exports.memory.buffer);
216
- const encoded = new TextEncoder().encode(errorStr);
217
- const ptr = instance.exports.alloc(encoded.length) >>> 0;
218
- mem.set(encoded, ptr);
219
- buffer.writeUInt32LE(mem, errorPtrPtr, ptr);
220
- buffer.writeUInt32LE(mem, errorPtrPtr + 4, encoded.length);
221
- buffer.writeUInt8(mem, errorPtrPtr + 8, isBadAddress ? 1 : 0);
221
+ config.bufferIndices[0] = new TextEncoder().encode(errorStr);
222
+ buffer.writeUInt32LE(mem, errorBufferIndexPtr, 0);
223
+ buffer.writeUInt8(mem, errorBufferIndexPtr + 4, isBadAddress ? 1 : 0);
222
224
  return 1;
223
225
  }
224
226
  },
@@ -5,6 +5,10 @@ export interface Config {
5
5
  * Fills the given buffer with randomly-generated bytes.
6
6
  */
7
7
  getRandomValues: (buffer: Uint8Array) => void;
8
+ /**
9
+ * Returns the number of milliseconds since an arbitrary epoch.
10
+ */
11
+ performanceNow: () => number;
8
12
  /**
9
13
  * List of environment variables to feed to the Rust program. An array of strings.
10
14
  * Example: `["RUST_BACKTRACE=1", "RUST_LOG=foo"];`
@@ -41,6 +41,36 @@ exports.default = (config) => {
41
41
  }
42
42
  return 0;
43
43
  },
44
+ clock_time_get: (clockId, _precision, outPtr) => {
45
+ // See <https://github.com/rust-lang/rust/blob/master/library/std/src/sys/wasi/time.rs>
46
+ // and <docs.rs/wasi/> for help.
47
+ const instance = config.instance;
48
+ const mem = new Uint8Array(instance.exports.memory.buffer);
49
+ outPtr >>>= 0;
50
+ // We ignore the precision, as it can't be implemented anyway.
51
+ switch (clockId) {
52
+ case 0: {
53
+ // Realtime clock.
54
+ const now = BigInt(Math.floor(Date.now())) * BigInt(1000000);
55
+ buffer.writeUInt64LE(mem, outPtr, now);
56
+ // Success.
57
+ return 0;
58
+ }
59
+ case 1: {
60
+ // Monotonic clock.
61
+ const nowMs = config.performanceNow();
62
+ const nowMsInt = Math.floor(nowMs);
63
+ const now = BigInt(nowMsInt) * BigInt(1000000) +
64
+ BigInt(Math.floor(((nowMs - nowMsInt) * 1000000)));
65
+ buffer.writeUInt64LE(mem, outPtr, now);
66
+ // Success.
67
+ return 0;
68
+ }
69
+ default:
70
+ // Return an `EINVAL` error.
71
+ return 28;
72
+ }
73
+ },
44
74
  // Writing to a file descriptor is used in order to write to stdout/stderr.
45
75
  fd_write: (fd, addr, num, outPtr) => {
46
76
  const instance = config.instance;
@@ -9,22 +9,21 @@ export interface SmoldotWasmExports extends WebAssembly.Exports {
9
9
  init: (maxLogLevel: number, enableCurrentTask: number, cpuRateLimit: number, periodicallyYield: number) => void;
10
10
  set_periodically_yield: (periodicallyYield: number) => void;
11
11
  start_shutdown: () => void;
12
- alloc: (len: number) => number;
13
- add_chain: (chainSpecPointer: number, chainSpecLen: number, databaseContentPointer: number, databaseContentLen: number, jsonRpcRunning: number, potentialRelayChainsPtr: number, potentialRelayChainsLen: number) => number;
12
+ add_chain: (chainSpecBufferIndex: number, databaseContentBufferIndex: number, jsonRpcRunning: number, potentialRelayChainsBufferIndex: number) => number;
14
13
  remove_chain: (chainId: number) => void;
15
14
  chain_is_ok: (chainId: number) => number;
16
15
  chain_error_len: (chainId: number) => number;
17
16
  chain_error_ptr: (chainId: number) => number;
18
- json_rpc_send: (textPtr: number, textLen: number, chainId: number) => number;
17
+ json_rpc_send: (textBufferIndex: number, chainId: number) => number;
19
18
  json_rpc_responses_peek: (chainId: number) => number;
20
19
  json_rpc_responses_pop: (chainId: number) => void;
21
20
  timer_finished: (timerId: number) => void;
22
21
  connection_open_single_stream: (connectionId: number, handshakeTy: number, initialWritableBytes: number, writeClosable: number) => void;
23
- connection_open_multi_stream: (connectionId: number, handshakeTyPtr: number, handshakeTyLen: number) => void;
22
+ connection_open_multi_stream: (connectionId: number, handshakeTyBufferIndex: number) => void;
24
23
  stream_writable_bytes: (connectionId: number, streamId: number, numBytes: number) => void;
25
- stream_message: (connectionId: number, streamId: number, ptr: number, len: number) => void;
24
+ stream_message: (connectionId: number, streamId: number, bufferIndex: number) => void;
26
25
  connection_stream_opened: (connectionId: number, streamId: number, outbound: number, initialWritableBytes: number) => void;
27
- connection_reset: (connectionId: number, ptr: number, len: number) => void;
26
+ connection_reset: (connectionId: number, bufferIndex: number) => void;
28
27
  stream_reset: (connectionId: number, streamId: number) => void;
29
28
  }
30
29
  export interface SmoldotWasmInstance extends WebAssembly.Instance {
@@ -8,3 +8,4 @@ export declare function readUInt32LE(buffer: Uint8Array, offset: number): number
8
8
  */
9
9
  export declare function writeUInt8(buffer: Uint8Array, offset: number, value: number): void;
10
10
  export declare function writeUInt32LE(buffer: Uint8Array, offset: number, value: number): void;
11
+ export declare function writeUInt64LE(buffer: Uint8Array, offset: number, value: bigint): void;
@@ -3,7 +3,7 @@
3
3
  // Copyright (C) 2019-2022 Parity Technologies (UK) Ltd.
4
4
  // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.writeUInt32LE = exports.writeUInt8 = exports.readUInt32LE = exports.utf8BytesToString = void 0;
6
+ exports.writeUInt64LE = exports.writeUInt32LE = exports.writeUInt8 = exports.readUInt32LE = exports.utf8BytesToString = void 0;
7
7
  // This program is free software: you can redistribute it and/or modify
8
8
  // it under the terms of the GNU General Public License as published by
9
9
  // the Free Software Foundation, either version 3 of the License, or
@@ -45,6 +45,18 @@ function writeUInt32LE(buffer, offset, value) {
45
45
  buffer[offset] = value & 0xff;
46
46
  }
47
47
  exports.writeUInt32LE = writeUInt32LE;
48
+ function writeUInt64LE(buffer, offset, value) {
49
+ checkRange(buffer, offset, 8);
50
+ buffer[offset + 7] = Number((value >> BigInt(56)) & BigInt(0xff));
51
+ buffer[offset + 6] = Number((value >> BigInt(48)) & BigInt(0xff));
52
+ buffer[offset + 5] = Number((value >> BigInt(40)) & BigInt(0xff));
53
+ buffer[offset + 4] = Number((value >> BigInt(32)) & BigInt(0xff));
54
+ buffer[offset + 3] = Number((value >> BigInt(24)) & BigInt(0xff));
55
+ buffer[offset + 2] = Number((value >> BigInt(16)) & BigInt(0xff));
56
+ buffer[offset + 1] = Number((value >> BigInt(8)) & BigInt(0xff));
57
+ buffer[offset] = Number(value & BigInt(0xff));
58
+ }
59
+ exports.writeUInt64LE = writeUInt64LE;
48
60
  function checkRange(buffer, offset, length) {
49
61
  if (!Number.isInteger(offset) || offset < 0)
50
62
  throw new RangeError();
@@ -104,7 +104,7 @@ function start(configMessage, platformBindings) {
104
104
  cpuRateLimit: configMessage.cpuRateLimit,
105
105
  };
106
106
  state = {
107
- initialized: false, promise: instance.startInstance(config, platformBindings).then((instance) => {
107
+ initialized: false, promise: instance.startInstance(config, platformBindings).then(([instance, bufferIndices]) => {
108
108
  // `config.cpuRateLimit` is a floating point that should be between 0 and 1, while the value
109
109
  // to pass as parameter must be between `0` and `2^32-1`.
110
110
  // The few lines of code below should handle all possible values of `number`, including
@@ -127,8 +127,8 @@ function start(configMessage, platformBindings) {
127
127
  }
128
128
  });
129
129
  instance.exports.init(configMessage.maxLogLevel, configMessage.enableCurrentTask ? 1 : 0, cpuRateLimit, periodicallyYield ? 1 : 0);
130
- state = { initialized: true, instance, unregisterCallback };
131
- return instance;
130
+ state = { initialized: true, instance, bufferIndices, unregisterCallback };
131
+ return [instance, bufferIndices];
132
132
  })
133
133
  };
134
134
  function queueOperation(operation) {
@@ -138,11 +138,11 @@ function start(configMessage, platformBindings) {
138
138
  if (!state.initialized) {
139
139
  // A message has been received while the Wasm VM is still initializing. Queue it for when
140
140
  // initialization is over.
141
- return state.promise.then((instance) => operation(instance));
141
+ return state.promise.then(([instance, bufferIndices]) => operation(instance, bufferIndices));
142
142
  }
143
143
  else {
144
144
  // Everything is already initialized. Process the message synchronously.
145
- return operation(state.instance);
145
+ return operation(state.instance, state.bufferIndices);
146
146
  }
147
147
  });
148
148
  }
@@ -157,10 +157,8 @@ function start(configMessage, platformBindings) {
157
157
  throw crashError.error;
158
158
  let retVal;
159
159
  try {
160
- const encoded = new TextEncoder().encode(request);
161
- const ptr = state.instance.exports.alloc(encoded.length) >>> 0;
162
- new Uint8Array(state.instance.exports.memory.buffer).set(encoded, ptr);
163
- retVal = state.instance.exports.json_rpc_send(ptr, encoded.length, chainId) >>> 0;
160
+ state.bufferIndices[0] = new TextEncoder().encode(request);
161
+ retVal = state.instance.exports.json_rpc_send(0, chainId) >>> 0;
164
162
  }
165
163
  catch (_error) {
166
164
  console.assert(crashError.error);
@@ -207,29 +205,25 @@ function start(configMessage, platformBindings) {
207
205
  }
208
206
  }),
209
207
  addChain: (chainSpec, databaseContent, potentialRelayChains, disableJsonRpc) => {
210
- return queueOperation((instance) => {
208
+ return queueOperation((instance, bufferIndices) => {
211
209
  if (crashError.error)
212
210
  throw crashError.error;
213
211
  try {
214
- // Write the chain specification into memory.
215
- const chainSpecEncoded = new TextEncoder().encode(chainSpec);
216
- const chainSpecPtr = instance.exports.alloc(chainSpecEncoded.length) >>> 0;
217
- new Uint8Array(instance.exports.memory.buffer).set(chainSpecEncoded, chainSpecPtr);
218
- // Write the database content into memory.
219
- const databaseContentEncoded = new TextEncoder().encode(databaseContent);
220
- const databaseContentPtr = instance.exports.alloc(databaseContentEncoded.length) >>> 0;
221
- new Uint8Array(instance.exports.memory.buffer).set(databaseContentEncoded, databaseContentPtr);
222
- // Write the potential relay chains into memory.
223
- const potentialRelayChainsLen = potentialRelayChains.length;
224
- const potentialRelayChainsPtr = instance.exports.alloc(potentialRelayChainsLen * 4) >>> 0;
225
- for (let idx = 0; idx < potentialRelayChains.length; ++idx) {
226
- buffer.writeUInt32LE(new Uint8Array(instance.exports.memory.buffer), potentialRelayChainsPtr + idx * 4, potentialRelayChains[idx]);
227
- }
228
212
  // `add_chain` unconditionally allocates a chain id. If an error occurs, however, this chain
229
213
  // id will refer to an *erroneous* chain. `chain_is_ok` is used below to determine whether it
230
214
  // has succeeeded or not.
231
215
  // Note that `add_chain` properly de-allocates buffers even if it failed.
232
- const chainId = instance.exports.add_chain(chainSpecPtr, chainSpecEncoded.length, databaseContentPtr, databaseContentEncoded.length, disableJsonRpc ? 0 : 1, potentialRelayChainsPtr, potentialRelayChainsLen);
216
+ bufferIndices[0] = new TextEncoder().encode(chainSpec);
217
+ bufferIndices[1] = new TextEncoder().encode(databaseContent);
218
+ const potentialRelayChainsEncoded = new Uint8Array(potentialRelayChains.length * 4);
219
+ for (let idx = 0; idx < potentialRelayChains.length; ++idx) {
220
+ buffer.writeUInt32LE(potentialRelayChainsEncoded, idx * 4, potentialRelayChains[idx]);
221
+ }
222
+ bufferIndices[2] = potentialRelayChainsEncoded;
223
+ const chainId = instance.exports.add_chain(0, 1, disableJsonRpc ? 0 : 1, 2);
224
+ delete bufferIndices[0];
225
+ delete bufferIndices[1];
226
+ delete bufferIndices[2];
233
227
  if (instance.exports.chain_is_ok(chainId) != 0) {
234
228
  console.assert(!chains.has(chainId));
235
229
  chains.set(chainId, {
@@ -62,4 +62,4 @@ export interface PlatformBindings {
62
62
  */
63
63
  connect(config: ConnectionConfig): Connection;
64
64
  }
65
- export declare function startInstance(config: Config, platformBindings: PlatformBindings): Promise<SmoldotWasmInstance>;
65
+ export declare function startInstance(config: Config, platformBindings: PlatformBindings): Promise<[SmoldotWasmInstance, Array<Uint8Array>]>;
@@ -36,8 +36,9 @@ function startInstance(config, platformBindings) {
36
36
  // cross-platform cross-bundler approach.
37
37
  const wasmBytecode = yield platformBindings.trustedBase64DecodeAndZlibInflate(wasm_js_1.default);
38
38
  let killAll;
39
+ const bufferIndices = new Array;
39
40
  // Used to bind with the smoldot-light bindings. See the `bindings-smoldot-light.js` file.
40
- const smoldotJsConfig = Object.assign({ performanceNow: platformBindings.performanceNow, connect: platformBindings.connect, onPanic: (message) => {
41
+ const smoldotJsConfig = Object.assign({ bufferIndices, connect: platformBindings.connect, onPanic: (message) => {
41
42
  killAll();
42
43
  config.onWasmPanic(message);
43
44
  throw new Error();
@@ -46,6 +47,7 @@ function startInstance(config, platformBindings) {
46
47
  const wasiConfig = {
47
48
  envVars: [],
48
49
  getRandomValues: platformBindings.getRandomValues,
50
+ performanceNow: platformBindings.performanceNow,
49
51
  onProcExit: (retCode) => {
50
52
  killAll();
51
53
  config.onWasmPanic(`proc_exit called: ${retCode}`);
@@ -66,7 +68,7 @@ function startInstance(config, platformBindings) {
66
68
  const instance = result.instance;
67
69
  smoldotJsConfig.instance = instance;
68
70
  wasiConfig.instance = instance;
69
- return instance;
71
+ return [instance, bufferIndices];
70
72
  });
71
73
  }
72
74
  exports.startInstance = startInstance;
@@ -77,10 +77,10 @@ export function start(options, platformBindings) {
77
77
  // For each chain object returned by `addChain`, the associated internal chain id.
78
78
  //
79
79
  // Immediately cleared when `remove()` is called on a chain.
80
- let chainIds = new WeakMap();
80
+ const chainIds = new WeakMap();
81
81
  // If `Client.terminate()̀ is called, this error is set to a value.
82
82
  // All the functions of the public API check if this contains a value.
83
- let alreadyDestroyedError = null;
83
+ const alreadyDestroyedError = { value: null };
84
84
  const instance = startInstance({
85
85
  // Maximum level of log entries sent by the client.
86
86
  // 0 = Logging disabled, 1 = Error, 2 = Warn, 3 = Info, 4 = Debug, 5 = Trace
@@ -94,8 +94,8 @@ export function start(options, platformBindings) {
94
94
  }, platformBindings);
95
95
  return {
96
96
  addChain: (options) => __awaiter(this, void 0, void 0, function* () {
97
- if (alreadyDestroyedError)
98
- throw alreadyDestroyedError;
97
+ if (alreadyDestroyedError.value)
98
+ throw alreadyDestroyedError.value;
99
99
  // Passing a JSON object for the chain spec is an easy mistake, so we provide a more
100
100
  // readable error.
101
101
  if (!(typeof options.chainSpec === 'string'))
@@ -120,8 +120,8 @@ export function start(options, platformBindings) {
120
120
  // Resolve the promise that `addChain` returned to the user.
121
121
  const newChain = {
122
122
  sendJsonRpc: (request) => {
123
- if (alreadyDestroyedError)
124
- throw alreadyDestroyedError;
123
+ if (alreadyDestroyedError.value)
124
+ throw alreadyDestroyedError.value;
125
125
  if (wasDestroyed.destroyed)
126
126
  throw new AlreadyDestroyedError();
127
127
  if (options.disableJsonRpc)
@@ -133,8 +133,8 @@ export function start(options, platformBindings) {
133
133
  instance.request(request, chainId);
134
134
  },
135
135
  nextJsonRpcResponse: () => {
136
- if (alreadyDestroyedError)
137
- return Promise.reject(alreadyDestroyedError);
136
+ if (alreadyDestroyedError.value)
137
+ return Promise.reject(alreadyDestroyedError.value);
138
138
  if (wasDestroyed.destroyed)
139
139
  return Promise.reject(new AlreadyDestroyedError());
140
140
  if (options.disableJsonRpc)
@@ -142,8 +142,8 @@ export function start(options, platformBindings) {
142
142
  return instance.nextJsonRpcResponse(chainId);
143
143
  },
144
144
  remove: () => {
145
- if (alreadyDestroyedError)
146
- throw alreadyDestroyedError;
145
+ if (alreadyDestroyedError.value)
146
+ throw alreadyDestroyedError.value;
147
147
  if (wasDestroyed.destroyed)
148
148
  throw new AlreadyDestroyedError();
149
149
  wasDestroyed.destroyed = true;
@@ -156,9 +156,9 @@ export function start(options, platformBindings) {
156
156
  return newChain;
157
157
  }),
158
158
  terminate: () => __awaiter(this, void 0, void 0, function* () {
159
- if (alreadyDestroyedError)
160
- throw alreadyDestroyedError;
161
- alreadyDestroyedError = new AlreadyDestroyedError();
159
+ if (alreadyDestroyedError.value)
160
+ throw alreadyDestroyedError.value;
161
+ alreadyDestroyedError.value = new AlreadyDestroyedError();
162
162
  instance.startShutdown();
163
163
  })
164
164
  };