smoldot 1.0.1 → 1.0.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.
@@ -1,6 +1,12 @@
1
1
  import type { SmoldotWasmInstance } from './bindings.js';
2
2
  export interface Config {
3
3
  instance?: SmoldotWasmInstance;
4
+ /**
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.
8
+ */
9
+ bufferIndices: Array<Uint8Array>;
4
10
  /**
5
11
  * Returns the number of milliseconds since an arbitrary epoch.
6
12
  */
@@ -51,6 +51,16 @@ export default function (config) {
51
51
  const message = buffer.utf8BytesToString(new Uint8Array(instance.exports.memory.buffer), ptr, len);
52
52
  config.onPanic(message);
53
53
  },
54
+ buffer_size: (bufferIndex) => {
55
+ const buf = config.bufferIndices[bufferIndex];
56
+ return buf.byteLength;
57
+ },
58
+ buffer_copy: (bufferIndex, targetPtr) => {
59
+ const instance = config.instance;
60
+ targetPtr = targetPtr >>> 0;
61
+ const buf = config.bufferIndices[bufferIndex];
62
+ new Uint8Array(instance.exports.memory.buffer).set(buf, targetPtr);
63
+ },
54
64
  // Used by the Rust side to notify that a JSON-RPC response or subscription notification
55
65
  // is available in the queue of JSON-RPC responses.
56
66
  json_rpc_responses_non_empty: (chainId) => {
@@ -116,11 +126,11 @@ export default function (config) {
116
126
  },
117
127
  // Must create a new connection object. This implementation stores the created object in
118
128
  // `connections`.
119
- connection_new: (connectionId, addrPtr, addrLen, errorPtrPtr) => {
129
+ connection_new: (connectionId, addrPtr, addrLen, errorBufferIndexPtr) => {
120
130
  const instance = config.instance;
121
131
  addrPtr >>>= 0;
122
132
  addrLen >>>= 0;
123
- errorPtrPtr >>>= 0;
133
+ errorBufferIndexPtr >>>= 0;
124
134
  if (!!connections[connectionId]) {
125
135
  throw new Error("internal error: connection already allocated");
126
136
  }
@@ -140,13 +150,13 @@ export default function (config) {
140
150
  break;
141
151
  }
142
152
  case 'multi-stream': {
143
- const bufferLen = 1 + info.localTlsCertificateMultihash.length + info.remoteTlsCertificateMultihash.length;
144
- const ptr = instance.exports.alloc(bufferLen) >>> 0;
145
- const mem = new Uint8Array(instance.exports.memory.buffer);
146
- buffer.writeUInt8(mem, ptr, 0);
147
- mem.set(info.localTlsCertificateMultihash, ptr + 1);
148
- mem.set(info.remoteTlsCertificateMultihash, ptr + 1 + info.localTlsCertificateMultihash.length);
149
- 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];
150
160
  break;
151
161
  }
152
162
  }
@@ -157,10 +167,9 @@ export default function (config) {
157
167
  if (killedTracked.killed)
158
168
  return;
159
169
  try {
160
- const encoded = new TextEncoder().encode(message);
161
- const ptr = instance.exports.alloc(encoded.length) >>> 0;
162
- new Uint8Array(instance.exports.memory.buffer).set(encoded, ptr);
163
- 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];
164
173
  }
165
174
  catch (_error) { }
166
175
  },
@@ -176,9 +185,9 @@ export default function (config) {
176
185
  if (killedTracked.killed)
177
186
  return;
178
187
  try {
179
- const ptr = instance.exports.alloc(message.length) >>> 0;
180
- new Uint8Array(instance.exports.memory.buffer).set(message, ptr);
181
- 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];
182
191
  }
183
192
  catch (_error) { }
184
193
  },
@@ -209,12 +218,9 @@ export default function (config) {
209
218
  errorStr = error.toString();
210
219
  }
211
220
  const mem = new Uint8Array(instance.exports.memory.buffer);
212
- const encoded = new TextEncoder().encode(errorStr);
213
- const ptr = instance.exports.alloc(encoded.length) >>> 0;
214
- mem.set(encoded, ptr);
215
- buffer.writeUInt32LE(mem, errorPtrPtr, ptr);
216
- buffer.writeUInt32LE(mem, errorPtrPtr + 4, encoded.length);
217
- 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);
218
224
  return 1;
219
225
  }
220
226
  },
@@ -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 {
@@ -97,7 +97,7 @@ export function start(configMessage, platformBindings) {
97
97
  cpuRateLimit: configMessage.cpuRateLimit,
98
98
  };
99
99
  state = {
100
- initialized: false, promise: instance.startInstance(config, platformBindings).then((instance) => {
100
+ initialized: false, promise: instance.startInstance(config, platformBindings).then(([instance, bufferIndices]) => {
101
101
  // `config.cpuRateLimit` is a floating point that should be between 0 and 1, while the value
102
102
  // to pass as parameter must be between `0` and `2^32-1`.
103
103
  // The few lines of code below should handle all possible values of `number`, including
@@ -120,8 +120,8 @@ export function start(configMessage, platformBindings) {
120
120
  }
121
121
  });
122
122
  instance.exports.init(configMessage.maxLogLevel, configMessage.enableCurrentTask ? 1 : 0, cpuRateLimit, periodicallyYield ? 1 : 0);
123
- state = { initialized: true, instance, unregisterCallback };
124
- return instance;
123
+ state = { initialized: true, instance, bufferIndices, unregisterCallback };
124
+ return [instance, bufferIndices];
125
125
  })
126
126
  };
127
127
  function queueOperation(operation) {
@@ -131,11 +131,11 @@ export function start(configMessage, platformBindings) {
131
131
  if (!state.initialized) {
132
132
  // A message has been received while the Wasm VM is still initializing. Queue it for when
133
133
  // initialization is over.
134
- return state.promise.then((instance) => operation(instance));
134
+ return state.promise.then(([instance, bufferIndices]) => operation(instance, bufferIndices));
135
135
  }
136
136
  else {
137
137
  // Everything is already initialized. Process the message synchronously.
138
- return operation(state.instance);
138
+ return operation(state.instance, state.bufferIndices);
139
139
  }
140
140
  });
141
141
  }
@@ -150,10 +150,8 @@ export function start(configMessage, platformBindings) {
150
150
  throw crashError.error;
151
151
  let retVal;
152
152
  try {
153
- const encoded = new TextEncoder().encode(request);
154
- const ptr = state.instance.exports.alloc(encoded.length) >>> 0;
155
- new Uint8Array(state.instance.exports.memory.buffer).set(encoded, ptr);
156
- retVal = state.instance.exports.json_rpc_send(ptr, encoded.length, chainId) >>> 0;
153
+ state.bufferIndices[0] = new TextEncoder().encode(request);
154
+ retVal = state.instance.exports.json_rpc_send(0, chainId) >>> 0;
157
155
  }
158
156
  catch (_error) {
159
157
  console.assert(crashError.error);
@@ -200,29 +198,25 @@ export function start(configMessage, platformBindings) {
200
198
  }
201
199
  }),
202
200
  addChain: (chainSpec, databaseContent, potentialRelayChains, disableJsonRpc) => {
203
- return queueOperation((instance) => {
201
+ return queueOperation((instance, bufferIndices) => {
204
202
  if (crashError.error)
205
203
  throw crashError.error;
206
204
  try {
207
- // Write the chain specification into memory.
208
- const chainSpecEncoded = new TextEncoder().encode(chainSpec);
209
- const chainSpecPtr = instance.exports.alloc(chainSpecEncoded.length) >>> 0;
210
- new Uint8Array(instance.exports.memory.buffer).set(chainSpecEncoded, chainSpecPtr);
211
- // Write the database content into memory.
212
- const databaseContentEncoded = new TextEncoder().encode(databaseContent);
213
- const databaseContentPtr = instance.exports.alloc(databaseContentEncoded.length) >>> 0;
214
- new Uint8Array(instance.exports.memory.buffer).set(databaseContentEncoded, databaseContentPtr);
215
- // Write the potential relay chains into memory.
216
- const potentialRelayChainsLen = potentialRelayChains.length;
217
- const potentialRelayChainsPtr = instance.exports.alloc(potentialRelayChainsLen * 4) >>> 0;
218
- for (let idx = 0; idx < potentialRelayChains.length; ++idx) {
219
- buffer.writeUInt32LE(new Uint8Array(instance.exports.memory.buffer), potentialRelayChainsPtr + idx * 4, potentialRelayChains[idx]);
220
- }
221
205
  // `add_chain` unconditionally allocates a chain id. If an error occurs, however, this chain
222
206
  // id will refer to an *erroneous* chain. `chain_is_ok` is used below to determine whether it
223
207
  // has succeeeded or not.
224
208
  // Note that `add_chain` properly de-allocates buffers even if it failed.
225
- const chainId = instance.exports.add_chain(chainSpecPtr, chainSpecEncoded.length, databaseContentPtr, databaseContentEncoded.length, disableJsonRpc ? 0 : 1, potentialRelayChainsPtr, potentialRelayChainsLen);
209
+ bufferIndices[0] = new TextEncoder().encode(chainSpec);
210
+ bufferIndices[1] = new TextEncoder().encode(databaseContent);
211
+ const potentialRelayChainsEncoded = new Uint8Array(potentialRelayChains.length * 4);
212
+ for (let idx = 0; idx < potentialRelayChains.length; ++idx) {
213
+ buffer.writeUInt32LE(potentialRelayChainsEncoded, idx * 4, potentialRelayChains[idx]);
214
+ }
215
+ bufferIndices[2] = potentialRelayChainsEncoded;
216
+ const chainId = instance.exports.add_chain(0, 1, disableJsonRpc ? 0 : 1, 2);
217
+ delete bufferIndices[0];
218
+ delete bufferIndices[1];
219
+ delete bufferIndices[2];
226
220
  if (instance.exports.chain_is_ok(chainId) != 0) {
227
221
  console.assert(!chains.has(chainId));
228
222
  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>]>;
@@ -32,8 +32,9 @@ export function startInstance(config, platformBindings) {
32
32
  // cross-platform cross-bundler approach.
33
33
  const wasmBytecode = yield platformBindings.trustedBase64DecodeAndZlibInflate(wasmBase64);
34
34
  let killAll;
35
+ const bufferIndices = new Array;
35
36
  // Used to bind with the smoldot-light bindings. See the `bindings-smoldot-light.js` file.
36
- const smoldotJsConfig = Object.assign({ performanceNow: platformBindings.performanceNow, connect: platformBindings.connect, onPanic: (message) => {
37
+ const smoldotJsConfig = Object.assign({ bufferIndices, performanceNow: platformBindings.performanceNow, connect: platformBindings.connect, onPanic: (message) => {
37
38
  killAll();
38
39
  config.onWasmPanic(message);
39
40
  throw new Error();
@@ -62,6 +63,6 @@ export function startInstance(config, platformBindings) {
62
63
  const instance = result.instance;
63
64
  smoldotJsConfig.instance = instance;
64
65
  wasiConfig.instance = instance;
65
- return instance;
66
+ return [instance, bufferIndices];
66
67
  });
67
68
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "smoldot",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "Light client that connects to Polkadot and Substrate-based blockchains",
5
5
  "author": "Parity Technologies <admin@parity.io>",
6
6
  "license": "GPL-3.0-or-later WITH Classpath-exception-2.0",
@@ -47,7 +47,7 @@
47
47
  "ava": "^5.0.1",
48
48
  "dtslint": "^4.0.6",
49
49
  "rimraf": "^4.1.2",
50
- "typedoc": "^0.23.15",
50
+ "typedoc": "^0.24.1",
51
51
  "typescript": "^5.0.2"
52
52
  }
53
53
  }