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.
Files changed (116) hide show
  1. package/README.md +58 -0
  2. package/dist/cjs/bytecode-browser.d.ts +5 -0
  3. package/dist/cjs/bytecode-browser.js +42 -0
  4. package/dist/cjs/bytecode-deno.d.ts +5 -0
  5. package/dist/cjs/bytecode-deno.js +87 -0
  6. package/dist/cjs/bytecode-nodejs.d.ts +5 -0
  7. package/dist/cjs/bytecode-nodejs.js +41 -0
  8. package/dist/cjs/index-browser.d.ts +2 -2
  9. package/dist/cjs/index-browser.js +10 -507
  10. package/dist/cjs/index-deno.d.ts +2 -2
  11. package/dist/cjs/index-deno.js +10 -283
  12. package/dist/cjs/index-nodejs.d.ts +2 -2
  13. package/dist/cjs/index-nodejs.js +10 -211
  14. package/dist/cjs/internals/bytecode/wasm0.js +4 -0
  15. package/dist/cjs/internals/bytecode/wasm1.js +4 -0
  16. package/dist/cjs/internals/bytecode/wasm2.js +4 -0
  17. package/dist/cjs/{instance/bindings-smoldot-light.d.ts → internals/client.d.ts} +15 -34
  18. package/dist/cjs/internals/client.js +376 -0
  19. package/dist/cjs/internals/local-instance.d.ts +144 -0
  20. package/dist/cjs/internals/local-instance.js +566 -0
  21. package/dist/cjs/internals/remote-instance.d.ts +38 -0
  22. package/dist/cjs/internals/remote-instance.js +374 -0
  23. package/dist/cjs/no-auto-bytecode-browser.d.ts +11 -0
  24. package/dist/cjs/no-auto-bytecode-browser.js +481 -0
  25. package/dist/cjs/no-auto-bytecode-deno.d.ts +10 -0
  26. package/dist/cjs/no-auto-bytecode-deno.js +220 -0
  27. package/dist/cjs/no-auto-bytecode-nodejs.d.ts +10 -0
  28. package/dist/cjs/no-auto-bytecode-nodejs.js +189 -0
  29. package/dist/cjs/{client.d.ts → public-types.d.ts} +51 -3
  30. package/dist/cjs/public-types.js +76 -0
  31. package/dist/cjs/worker-browser.d.ts +11 -0
  32. package/dist/cjs/worker-browser.js +63 -0
  33. package/dist/cjs/worker-deno.d.ts +11 -0
  34. package/dist/cjs/worker-deno.js +54 -0
  35. package/dist/cjs/worker-nodejs.d.ts +11 -0
  36. package/dist/cjs/worker-nodejs.js +55 -0
  37. package/dist/mjs/bytecode-browser.d.ts +5 -0
  38. package/dist/mjs/bytecode-browser.js +38 -0
  39. package/dist/mjs/bytecode-deno.d.ts +5 -0
  40. package/dist/mjs/bytecode-deno.js +83 -0
  41. package/dist/mjs/bytecode-nodejs.d.ts +5 -0
  42. package/dist/mjs/bytecode-nodejs.js +37 -0
  43. package/dist/mjs/index-browser.d.ts +2 -2
  44. package/dist/mjs/index-browser.js +4 -501
  45. package/dist/mjs/index-deno.d.ts +2 -2
  46. package/dist/mjs/index-deno.js +4 -277
  47. package/dist/mjs/index-nodejs.d.ts +2 -2
  48. package/dist/mjs/index-nodejs.js +4 -205
  49. package/dist/mjs/internals/bytecode/wasm0.js +1 -0
  50. package/dist/mjs/internals/bytecode/wasm1.js +1 -0
  51. package/dist/mjs/internals/bytecode/wasm2.js +1 -0
  52. package/dist/mjs/{instance/bindings-smoldot-light.d.ts → internals/client.d.ts} +15 -34
  53. package/dist/mjs/internals/client.js +372 -0
  54. package/dist/mjs/internals/local-instance.d.ts +144 -0
  55. package/dist/mjs/internals/local-instance.js +561 -0
  56. package/dist/mjs/internals/remote-instance.d.ts +38 -0
  57. package/dist/mjs/internals/remote-instance.js +369 -0
  58. package/dist/mjs/no-auto-bytecode-browser.d.ts +11 -0
  59. package/dist/mjs/no-auto-bytecode-browser.js +471 -0
  60. package/dist/mjs/no-auto-bytecode-deno.d.ts +10 -0
  61. package/dist/mjs/no-auto-bytecode-deno.js +210 -0
  62. package/dist/mjs/no-auto-bytecode-nodejs.d.ts +10 -0
  63. package/dist/mjs/no-auto-bytecode-nodejs.js +179 -0
  64. package/dist/mjs/{client.d.ts → public-types.d.ts} +51 -3
  65. package/dist/mjs/public-types.js +67 -0
  66. package/dist/mjs/worker-browser.d.ts +11 -0
  67. package/dist/mjs/worker-browser.js +59 -0
  68. package/dist/mjs/worker-deno.d.ts +11 -0
  69. package/dist/mjs/worker-deno.js +50 -0
  70. package/dist/mjs/worker-nodejs.d.ts +11 -0
  71. package/dist/mjs/worker-nodejs.js +51 -0
  72. package/package.json +40 -8
  73. package/dist/cjs/client.js +0 -172
  74. package/dist/cjs/instance/autogen/wasm0.js +0 -4
  75. package/dist/cjs/instance/autogen/wasm1.js +0 -4
  76. package/dist/cjs/instance/autogen/wasm2.js +0 -4
  77. package/dist/cjs/instance/bindings-smoldot-light.js +0 -285
  78. package/dist/cjs/instance/bindings-wasi.d.ts +0 -27
  79. package/dist/cjs/instance/bindings-wasi.js +0 -172
  80. package/dist/cjs/instance/bindings.d.ts +0 -31
  81. package/dist/cjs/instance/bindings.js +0 -5
  82. package/dist/cjs/instance/instance.d.ts +0 -45
  83. package/dist/cjs/instance/instance.js +0 -277
  84. package/dist/cjs/instance/raw-instance.d.ts +0 -56
  85. package/dist/cjs/instance/raw-instance.js +0 -129
  86. package/dist/mjs/client.js +0 -162
  87. package/dist/mjs/instance/autogen/wasm0.js +0 -1
  88. package/dist/mjs/instance/autogen/wasm1.js +0 -1
  89. package/dist/mjs/instance/autogen/wasm2.js +0 -1
  90. package/dist/mjs/instance/bindings-smoldot-light.js +0 -280
  91. package/dist/mjs/instance/bindings-wasi.d.ts +0 -27
  92. package/dist/mjs/instance/bindings-wasi.js +0 -170
  93. package/dist/mjs/instance/bindings.d.ts +0 -31
  94. package/dist/mjs/instance/bindings.js +0 -4
  95. package/dist/mjs/instance/instance.d.ts +0 -45
  96. package/dist/mjs/instance/instance.js +0 -269
  97. package/dist/mjs/instance/raw-instance.d.ts +0 -56
  98. package/dist/mjs/instance/raw-instance.js +0 -124
  99. /package/dist/cjs/{base64.d.ts → internals/base64.d.ts} +0 -0
  100. /package/dist/cjs/{base64.js → internals/base64.js} +0 -0
  101. /package/dist/cjs/{instance → internals}/buffer.d.ts +0 -0
  102. /package/dist/cjs/{instance → internals}/buffer.js +0 -0
  103. /package/dist/cjs/{instance/autogen → internals/bytecode}/wasm.d.ts +0 -0
  104. /package/dist/cjs/{instance/autogen → internals/bytecode}/wasm.js +0 -0
  105. /package/dist/cjs/{instance/autogen → internals/bytecode}/wasm0.d.ts +0 -0
  106. /package/dist/cjs/{instance/autogen → internals/bytecode}/wasm1.d.ts +0 -0
  107. /package/dist/cjs/{instance/autogen → internals/bytecode}/wasm2.d.ts +0 -0
  108. /package/dist/mjs/{base64.d.ts → internals/base64.d.ts} +0 -0
  109. /package/dist/mjs/{base64.js → internals/base64.js} +0 -0
  110. /package/dist/mjs/{instance → internals}/buffer.d.ts +0 -0
  111. /package/dist/mjs/{instance → internals}/buffer.js +0 -0
  112. /package/dist/mjs/{instance/autogen → internals/bytecode}/wasm.d.ts +0 -0
  113. /package/dist/mjs/{instance/autogen → internals/bytecode}/wasm.js +0 -0
  114. /package/dist/mjs/{instance/autogen → internals/bytecode}/wasm0.d.ts +0 -0
  115. /package/dist/mjs/{instance/autogen → internals/bytecode}/wasm1.d.ts +0 -0
  116. /package/dist/mjs/{instance/autogen → internals/bytecode}/wasm2.d.ts +0 -0
@@ -0,0 +1,210 @@
1
+ // Smoldot
2
+ // Copyright (C) 2019-2022 Parity Technologies (UK) Ltd.
3
+ // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
4
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
5
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
6
+ return new (P || (P = Promise))(function (resolve, reject) {
7
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
8
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
9
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
10
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
11
+ });
12
+ };
13
+ import { start as innerStart } from './internals/client.js';
14
+ export { AddChainError, AlreadyDestroyedError, CrashError, MalformedJsonRpcError, QueueFullError, JsonRpcDisabledError } from './public-types.js';
15
+ /**
16
+ * Initializes a new client. This is a pre-requisite to connecting to a blockchain.
17
+ *
18
+ * Can never fail.
19
+ *
20
+ * @param options Configuration of the client.
21
+ */
22
+ export function startWithBytecode(options) {
23
+ options.forbidWebRtc = true;
24
+ return innerStart(options || {}, options.bytecode, {
25
+ performanceNow: () => {
26
+ return performance.now();
27
+ },
28
+ getRandomValues: (buffer) => {
29
+ const crypto = globalThis.crypto;
30
+ if (!crypto)
31
+ throw new Error('randomness not available');
32
+ crypto.getRandomValues(buffer);
33
+ },
34
+ connect: (config) => {
35
+ return connect(config);
36
+ }
37
+ });
38
+ }
39
+ /**
40
+ * Tries to open a new connection using the given configuration.
41
+ *
42
+ * @see Connection
43
+ * @throws {@link ConnectionError} If the multiaddress couldn't be parsed or contains an invalid protocol.
44
+ */
45
+ function connect(config) {
46
+ if (config.address.ty === "websocket") {
47
+ const socket = new WebSocket(config.address.url);
48
+ socket.binaryType = 'arraybuffer';
49
+ const bufferedAmountCheck = { quenedUnreportedBytes: 0, nextTimeout: 10 };
50
+ const checkBufferedAmount = () => {
51
+ if (socket.readyState != 1)
52
+ return;
53
+ // Note that we might expect `bufferedAmount` to always be <= the sum of the lengths
54
+ // of all the data that has been sent, but that might not be the case. For this
55
+ // reason, we use `bufferedAmount` as a hint rather than a correct value.
56
+ const bufferedAmount = socket.bufferedAmount;
57
+ let wasSent = bufferedAmountCheck.quenedUnreportedBytes - bufferedAmount;
58
+ if (wasSent < 0)
59
+ wasSent = 0;
60
+ bufferedAmountCheck.quenedUnreportedBytes -= wasSent;
61
+ if (bufferedAmountCheck.quenedUnreportedBytes != 0) {
62
+ setTimeout(checkBufferedAmount, bufferedAmountCheck.nextTimeout);
63
+ bufferedAmountCheck.nextTimeout *= 2;
64
+ if (bufferedAmountCheck.nextTimeout > 500)
65
+ bufferedAmountCheck.nextTimeout = 500;
66
+ }
67
+ // Note: it is important to call `onWritableBytes` at the very end, as it might
68
+ // trigger a call to `send`.
69
+ if (wasSent != 0)
70
+ config.onWritableBytes(wasSent);
71
+ };
72
+ socket.onopen = () => {
73
+ config.onOpen({ type: 'single-stream', handshake: 'multistream-select-noise-yamux', initialWritableBytes: 1024 * 1024, writeClosable: false });
74
+ };
75
+ socket.onclose = (event) => {
76
+ const message = "Error code " + event.code + (!!event.reason ? (": " + event.reason) : "");
77
+ config.onConnectionReset(message);
78
+ };
79
+ socket.onmessage = (msg) => {
80
+ config.onMessage(new Uint8Array(msg.data));
81
+ };
82
+ return {
83
+ reset: () => {
84
+ // We can't set these fields to null because the TypeScript definitions don't
85
+ // allow it, but we can set them to dummy values.
86
+ socket.onopen = () => { };
87
+ socket.onclose = () => { };
88
+ socket.onmessage = () => { };
89
+ socket.onerror = () => { };
90
+ socket.close();
91
+ },
92
+ send: (data) => {
93
+ // The WebSocket library that we use seems to spontaneously transition connections
94
+ // to the "closed" state but not call the `onclosed` callback immediately. Calling
95
+ // `send` on that object throws an exception. In order to avoid panicking smoldot,
96
+ // we thus absorb any exception thrown here.
97
+ // See also <https://github.com/paritytech/smoldot/issues/2937>.
98
+ try {
99
+ socket.send(data);
100
+ if (bufferedAmountCheck.quenedUnreportedBytes == 0) {
101
+ bufferedAmountCheck.nextTimeout = 10;
102
+ setTimeout(checkBufferedAmount, 10);
103
+ }
104
+ bufferedAmountCheck.quenedUnreportedBytes += data.length;
105
+ }
106
+ catch (_error) { }
107
+ },
108
+ closeSend: () => { throw new Error('Wrong connection type'); },
109
+ openOutSubstream: () => { throw new Error('Wrong connection type'); }
110
+ };
111
+ }
112
+ else if (config.address.ty === "tcp") {
113
+ const socket = {
114
+ destroyed: false,
115
+ inner: Deno.connect({
116
+ hostname: config.address.hostname,
117
+ port: config.address.port,
118
+ }).catch((error) => {
119
+ socket.destroyed = true;
120
+ config.onConnectionReset(error.toString());
121
+ return null;
122
+ })
123
+ };
124
+ socket.inner = socket.inner.then((established) => {
125
+ // TODO: at the time of writing of this comment, `setNoDelay` is still unstable
126
+ //established.setNoDelay();
127
+ if (socket.destroyed)
128
+ return established;
129
+ config.onOpen({ type: 'single-stream', handshake: 'multistream-select-noise-yamux', initialWritableBytes: 1024 * 1024, writeClosable: true });
130
+ // Spawns an asynchronous task that continuously reads from the socket.
131
+ // Every time data is read, the task re-executes itself in order to continue reading.
132
+ // The task ends automatically if an EOF or error is detected, which should also happen
133
+ // if the user calls `close()`.
134
+ const read = (readBuffer) => __awaiter(this, void 0, void 0, function* () {
135
+ if (socket.destroyed || established === null)
136
+ return;
137
+ let outcome = null;
138
+ try {
139
+ outcome = yield established.read(readBuffer);
140
+ }
141
+ catch (error) {
142
+ // The type of `error` is unclear, but we assume that it implements `Error`
143
+ outcome = error.toString();
144
+ }
145
+ if (socket.destroyed)
146
+ return;
147
+ if (typeof outcome !== 'number' || outcome === null) {
148
+ // The socket is reported closed, but `socket.destroyed` is still `false` (see
149
+ // check above). As such, we must inform the inner layers.
150
+ socket.destroyed = true;
151
+ config.onConnectionReset(outcome === null ? "EOF when reading socket" : outcome);
152
+ return;
153
+ }
154
+ console.assert(outcome !== 0); // `read` guarantees to return a non-zero value.
155
+ config.onMessage(readBuffer.slice(0, outcome));
156
+ return read(readBuffer);
157
+ });
158
+ read(new Uint8Array(32768));
159
+ return established;
160
+ });
161
+ return {
162
+ reset: () => {
163
+ socket.destroyed = true;
164
+ socket.inner.then((connec) => connec.close());
165
+ },
166
+ send: (data) => {
167
+ let dataCopy = Uint8Array.from(data); // Deep copy of the data
168
+ socket.inner = socket.inner.then((c) => __awaiter(this, void 0, void 0, function* () {
169
+ while (dataCopy.length > 0) {
170
+ if (socket.destroyed || c === null)
171
+ return c;
172
+ let outcome;
173
+ try {
174
+ outcome = yield c.write(dataCopy);
175
+ config.onWritableBytes(dataCopy.length);
176
+ }
177
+ catch (error) {
178
+ // The type of `error` is unclear, but we assume that it implements `Error`
179
+ outcome = error.toString();
180
+ }
181
+ if (typeof outcome !== 'number') {
182
+ // The socket is reported closed, but `socket.destroyed` is still
183
+ // `false` (see check above). As such, we must inform the inner layers.
184
+ socket.destroyed = true;
185
+ config.onConnectionReset(outcome);
186
+ return c;
187
+ }
188
+ // Note that, contrary to `read`, it is possible for `outcome` to be 0.
189
+ // This happen if the write had to be interrupted, and the only thing
190
+ // we have to do is try writing again.
191
+ dataCopy = dataCopy.slice(outcome);
192
+ }
193
+ return c;
194
+ }));
195
+ },
196
+ closeSend: () => {
197
+ socket.inner = socket.inner.then((c) => __awaiter(this, void 0, void 0, function* () {
198
+ yield (c === null || c === void 0 ? void 0 : c.closeWrite());
199
+ return c;
200
+ }));
201
+ },
202
+ openOutSubstream: () => { throw new Error('Wrong connection type'); }
203
+ };
204
+ }
205
+ else {
206
+ // Should never happen, as we tweak the options to refuse connection types that
207
+ // we don't support.
208
+ throw new Error();
209
+ }
210
+ }
@@ -0,0 +1,10 @@
1
+ import { Client, ClientOptionsWithBytecode } from './public-types.js';
2
+ export { AddChainError, AddChainOptions, AlreadyDestroyedError, Chain, Client, ClientOptions, ClientOptionsWithBytecode, SmoldotBytecode, CrashError, MalformedJsonRpcError, QueueFullError, JsonRpcDisabledError, LogCallback } from './public-types.js';
3
+ /**
4
+ * Initializes a new client. This is a pre-requisite to connecting to a blockchain.
5
+ *
6
+ * Can never fail.
7
+ *
8
+ * @param options Configuration of the client.
9
+ */
10
+ export declare function startWithBytecode(options: ClientOptionsWithBytecode): Client;
@@ -0,0 +1,179 @@
1
+ // Smoldot
2
+ // Copyright (C) 2019-2022 Parity Technologies (UK) Ltd.
3
+ // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
4
+ import { start as innerStart } from './internals/client.js';
5
+ import { WebSocket } from 'ws';
6
+ import { performance } from 'node:perf_hooks';
7
+ import { createConnection as nodeCreateConnection } from 'node:net';
8
+ import { randomFillSync } from 'node:crypto';
9
+ export { AddChainError, AlreadyDestroyedError, CrashError, MalformedJsonRpcError, QueueFullError, JsonRpcDisabledError } from './public-types.js';
10
+ /**
11
+ * Initializes a new client. This is a pre-requisite to connecting to a blockchain.
12
+ *
13
+ * Can never fail.
14
+ *
15
+ * @param options Configuration of the client.
16
+ */
17
+ export function startWithBytecode(options) {
18
+ options.forbidWebRtc = true;
19
+ return innerStart(options || {}, options.bytecode, {
20
+ performanceNow: () => {
21
+ return performance.now();
22
+ },
23
+ getRandomValues: (buffer) => {
24
+ if (buffer.length >= 1024 * 1024)
25
+ throw new Error('getRandomValues buffer too large');
26
+ randomFillSync(buffer);
27
+ },
28
+ connect: (config) => {
29
+ return connect(config);
30
+ }
31
+ });
32
+ }
33
+ /**
34
+ * Tries to open a new connection using the given configuration.
35
+ *
36
+ * @see Connection
37
+ * @throws {@link ConnectionError} If the multiaddress couldn't be parsed or contains an invalid protocol.
38
+ */
39
+ function connect(config) {
40
+ if (config.address.ty === "websocket") {
41
+ const socket = new WebSocket(config.address.url);
42
+ socket.binaryType = 'arraybuffer';
43
+ const bufferedAmountCheck = { quenedUnreportedBytes: 0, nextTimeout: 10 };
44
+ const checkBufferedAmount = () => {
45
+ if (socket.readyState != 1)
46
+ return;
47
+ // Note that we might expect `bufferedAmount` to always be <= the sum of the lengths
48
+ // of all the data that has been sent, but that seems to not be the case. It is
49
+ // unclear whether this is intended or a bug, but is is likely that `bufferedAmount`
50
+ // also includes WebSocket headers. For this reason, we use `bufferedAmount` as a hint
51
+ // rather than a correct value.
52
+ const bufferedAmount = socket.bufferedAmount;
53
+ let wasSent = bufferedAmountCheck.quenedUnreportedBytes - bufferedAmount;
54
+ if (wasSent < 0)
55
+ wasSent = 0;
56
+ bufferedAmountCheck.quenedUnreportedBytes -= wasSent;
57
+ if (bufferedAmountCheck.quenedUnreportedBytes != 0) {
58
+ setTimeout(checkBufferedAmount, bufferedAmountCheck.nextTimeout);
59
+ bufferedAmountCheck.nextTimeout *= 2;
60
+ if (bufferedAmountCheck.nextTimeout > 500)
61
+ bufferedAmountCheck.nextTimeout = 500;
62
+ }
63
+ // Note: it is important to call `onWritableBytes` at the very end, as it might
64
+ // trigger a call to `send`.
65
+ if (wasSent != 0)
66
+ config.onWritableBytes(wasSent);
67
+ };
68
+ socket.onopen = () => {
69
+ config.onOpen({ type: 'single-stream', handshake: 'multistream-select-noise-yamux', initialWritableBytes: 1024 * 1024, writeClosable: false });
70
+ };
71
+ socket.onclose = (event) => {
72
+ const message = "Error code " + event.code + (!!event.reason ? (": " + event.reason) : "");
73
+ config.onConnectionReset(message);
74
+ socket.onopen = () => { };
75
+ socket.onclose = () => { };
76
+ socket.onmessage = () => { };
77
+ socket.onerror = () => { };
78
+ };
79
+ socket.onerror = (event) => {
80
+ config.onConnectionReset(event.message);
81
+ socket.onopen = () => { };
82
+ socket.onclose = () => { };
83
+ socket.onmessage = () => { };
84
+ socket.onerror = () => { };
85
+ };
86
+ socket.onmessage = (msg) => {
87
+ config.onMessage(new Uint8Array(msg.data));
88
+ };
89
+ return {
90
+ reset: () => {
91
+ // We can't set these fields to null because the TypeScript definitions don't
92
+ // allow it, but we can set them to dummy values.
93
+ socket.onopen = () => { };
94
+ socket.onclose = () => { };
95
+ socket.onmessage = () => { };
96
+ socket.onerror = () => { };
97
+ socket.close();
98
+ },
99
+ send: (data) => {
100
+ socket.send(data);
101
+ if (bufferedAmountCheck.quenedUnreportedBytes == 0) {
102
+ bufferedAmountCheck.nextTimeout = 10;
103
+ setTimeout(checkBufferedAmount, 10);
104
+ }
105
+ bufferedAmountCheck.quenedUnreportedBytes += data.length;
106
+ },
107
+ closeSend: () => { throw new Error('Wrong connection type'); },
108
+ openOutSubstream: () => { throw new Error('Wrong connection type'); }
109
+ };
110
+ }
111
+ else if (config.address.ty === "tcp") {
112
+ const socket = nodeCreateConnection({
113
+ host: config.address.hostname,
114
+ port: config.address.port,
115
+ });
116
+ // Number of bytes queued using `socket.write` and where `write` has returned false.
117
+ const drainingBytes = { num: 0 };
118
+ socket.setNoDelay();
119
+ socket.on('connect', () => {
120
+ if (socket.destroyed)
121
+ return;
122
+ config.onOpen({
123
+ type: 'single-stream', handshake: 'multistream-select-noise-yamux',
124
+ initialWritableBytes: socket.writableHighWaterMark, writeClosable: true
125
+ });
126
+ });
127
+ socket.on('close', (hasError) => {
128
+ if (socket.destroyed)
129
+ return;
130
+ // NodeJS doesn't provide a reason why the closing happened, but only
131
+ // whether it was caused by an error.
132
+ const message = hasError ? "Error" : "Closed gracefully";
133
+ config.onConnectionReset(message);
134
+ });
135
+ socket.on('error', () => { });
136
+ socket.on('data', (message) => {
137
+ if (socket.destroyed)
138
+ return;
139
+ config.onMessage(new Uint8Array(message.buffer));
140
+ });
141
+ socket.on('drain', () => {
142
+ // The bytes queued using `socket.write` and where `write` has returned false have now
143
+ // been sent. Notify the API that it can write more data.
144
+ if (socket.destroyed)
145
+ return;
146
+ const val = drainingBytes.num;
147
+ drainingBytes.num = 0;
148
+ config.onWritableBytes(val);
149
+ });
150
+ return {
151
+ reset: () => {
152
+ socket.destroy();
153
+ },
154
+ send: (data) => {
155
+ const dataLen = data.length;
156
+ const allWritten = socket.write(data);
157
+ if (allWritten) {
158
+ setImmediate(() => {
159
+ if (!socket.writable)
160
+ return;
161
+ config.onWritableBytes(dataLen);
162
+ });
163
+ }
164
+ else {
165
+ drainingBytes.num += dataLen;
166
+ }
167
+ },
168
+ closeSend: () => {
169
+ socket.end();
170
+ },
171
+ openOutSubstream: () => { throw new Error('Wrong connection type'); }
172
+ };
173
+ }
174
+ else {
175
+ // Should never happen, as we tweak the options to refuse connection types that
176
+ // we don't support.
177
+ throw new Error();
178
+ }
179
+ }
@@ -1,5 +1,3 @@
1
- import { PlatformBindings } from './instance/instance.js';
2
- export { MalformedJsonRpcError, QueueFullError, CrashError } from './instance/instance.js';
3
1
  /**
4
2
  * Thrown in case of a problem when initializing the chain.
5
3
  */
@@ -19,6 +17,32 @@ export declare class AlreadyDestroyedError extends Error {
19
17
  export declare class JsonRpcDisabledError extends Error {
20
18
  constructor();
21
19
  }
20
+ /**
21
+ * Thrown in case the underlying client encounters an unexpected crash.
22
+ *
23
+ * This is always an internal bug in smoldot and is never supposed to happen.
24
+ */
25
+ export declare class CrashError extends Error {
26
+ constructor(message: string);
27
+ }
28
+ /**
29
+ * Thrown in case a malformed JSON-RPC request is sent.
30
+ */
31
+ export declare class MalformedJsonRpcError extends Error {
32
+ constructor();
33
+ }
34
+ /**
35
+ * Thrown in case the buffer of JSON-RPC requests is full and cannot accept any more request.
36
+ */
37
+ export declare class QueueFullError extends Error {
38
+ constructor();
39
+ }
40
+ /**
41
+ * Bytecode of the smoldot client.
42
+ */
43
+ export interface SmoldotBytecode {
44
+ readonly wasm: WebAssembly.Module;
45
+ }
22
46
  /**
23
47
  * Client with zero or more active connections to blockchains.
24
48
  */
@@ -150,6 +174,19 @@ export type LogCallback = (level: number, target: string, message: string) => vo
150
174
  * Configuration of a client.
151
175
  */
152
176
  export interface ClientOptions {
177
+ /**
178
+ * One end of a port (created using `new MessageChannel`). The other end must be passed to the
179
+ * `run` function found in `smoldot/worker`.
180
+ *
181
+ * If this option isn't set then the smoldot light client will run entirely on the "current
182
+ * thread", which might slow down other components that also run on this thread.
183
+ * If this option is set, then the {@link Client} that is created is merely a frontend that
184
+ * sends messages on the provided port.
185
+ *
186
+ * It is intended that the other end of this port is sent to a background worker, and the
187
+ * `run` function be called in this background worker. However this is in no way mandatory.
188
+ */
189
+ portToWorker?: MessagePort;
153
190
  /**
154
191
  * Callback that the client will invoke in order to report a log event.
155
192
  *
@@ -176,6 +213,9 @@ export interface ClientOptions {
176
213
  * Note that this is implemented by sleeping for certain amounts of time in order for the average
177
214
  * CPU consumption to not go beyond the given limit. It is therefore still possible for the
178
215
  * client to use high amounts of CPU for short amounts of time.
216
+ *
217
+ * If {@link ClientOptions.portToWorker} is set, then the CPU rate limit applies to the
218
+ * worker.
179
219
  */
180
220
  cpuRateLimit?: number;
181
221
  /**
@@ -233,6 +273,15 @@ export interface ClientOptions {
233
273
  */
234
274
  forbidWebRtc?: boolean;
235
275
  }
276
+ /**
277
+ * Configuration of a client.
278
+ */
279
+ export interface ClientOptionsWithBytecode extends ClientOptions {
280
+ /**
281
+ * Smoldot bytecode. Can be either fully loaded or a `Promise`.
282
+ */
283
+ bytecode: SmoldotBytecode | Promise<SmoldotBytecode>;
284
+ }
236
285
  /**
237
286
  * Configuration of a blockchain.
238
287
  */
@@ -317,4 +366,3 @@ export interface AddChainOptions {
317
366
  */
318
367
  disableJsonRpc?: boolean;
319
368
  }
320
- export declare function start(options: ClientOptions, wasmModule: Promise<WebAssembly.Module>, platformBindings: PlatformBindings): Client;
@@ -0,0 +1,67 @@
1
+ // Smoldot
2
+ // Copyright (C) 2019-2022 Parity Technologies (UK) Ltd.
3
+ // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
4
+ // This program is free software: you can redistribute it and/or modify
5
+ // it under the terms of the GNU General Public License as published by
6
+ // the Free Software Foundation, either version 3 of the License, or
7
+ // (at your option) any later version.
8
+ // This program is distributed in the hope that it will be useful,
9
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ // GNU General Public License for more details.
12
+ // You should have received a copy of the GNU General Public License
13
+ // along with this program. If not, see <http://www.gnu.org/licenses/>.
14
+ /**
15
+ * Thrown in case of a problem when initializing the chain.
16
+ */
17
+ export class AddChainError extends Error {
18
+ constructor(message) {
19
+ super(message);
20
+ this.name = "AddChainError";
21
+ }
22
+ }
23
+ /**
24
+ * Thrown in case the API user tries to use a chain or client that has already been destroyed.
25
+ */
26
+ export class AlreadyDestroyedError extends Error {
27
+ constructor() {
28
+ super();
29
+ this.name = "AlreadyDestroyedError";
30
+ }
31
+ }
32
+ /**
33
+ * Thrown when trying to send a JSON-RPC message to a chain whose JSON-RPC system hasn't been
34
+ * enabled.
35
+ */
36
+ export class JsonRpcDisabledError extends Error {
37
+ constructor() {
38
+ super();
39
+ this.name = "JsonRpcDisabledError";
40
+ }
41
+ }
42
+ /**
43
+ * Thrown in case the underlying client encounters an unexpected crash.
44
+ *
45
+ * This is always an internal bug in smoldot and is never supposed to happen.
46
+ */
47
+ export class CrashError extends Error {
48
+ constructor(message) {
49
+ super(message);
50
+ }
51
+ }
52
+ /**
53
+ * Thrown in case a malformed JSON-RPC request is sent.
54
+ */
55
+ export class MalformedJsonRpcError extends Error {
56
+ constructor() {
57
+ super("JSON-RPC request is malformed");
58
+ }
59
+ }
60
+ /**
61
+ * Thrown in case the buffer of JSON-RPC requests is full and cannot accept any more request.
62
+ */
63
+ export class QueueFullError extends Error {
64
+ constructor() {
65
+ super("JSON-RPC requests queue is full");
66
+ }
67
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Runs the CPU-heavy parts of smoldot. Must be passed a port whose other end is passed to
3
+ * `ClientOptions.portToWorker`.
4
+ *
5
+ * Returns a `Promise` that is ready when the smoldot client is shut down (either because it
6
+ * crashes or intentionally with a call to `Client.terminate`).
7
+ * Since this function is asynchronous, this `Promise` is wrapped around another `Promise`. In
8
+ * other words, the outer `Promise` is ready when execution starts, and the inner `Promise` is
9
+ * ready when execution ends.
10
+ */
11
+ export declare function run(messagePort: MessagePort): Promise<Promise<void>>;
@@ -0,0 +1,59 @@
1
+ // Smoldot
2
+ // Copyright (C) 2023 Pierre Krieger
3
+ // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
4
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
5
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
6
+ return new (P || (P = Promise))(function (resolve, reject) {
7
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
8
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
9
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
10
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
11
+ });
12
+ };
13
+ // This program is free software: you can redistribute it and/or modify
14
+ // it under the terms of the GNU General Public License as published by
15
+ // the Free Software Foundation, either version 3 of the License, or
16
+ // (at your option) any later version.
17
+ // This program is distributed in the hope that it will be useful,
18
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
19
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20
+ // GNU General Public License for more details.
21
+ // You should have received a copy of the GNU General Public License
22
+ // along with this program. If not, see <http://www.gnu.org/licenses/>.
23
+ import * as instance from './internals/remote-instance.js';
24
+ /**
25
+ * Runs the CPU-heavy parts of smoldot. Must be passed a port whose other end is passed to
26
+ * `ClientOptions.portToWorker`.
27
+ *
28
+ * Returns a `Promise` that is ready when the smoldot client is shut down (either because it
29
+ * crashes or intentionally with a call to `Client.terminate`).
30
+ * Since this function is asynchronous, this `Promise` is wrapped around another `Promise`. In
31
+ * other words, the outer `Promise` is ready when execution starts, and the inner `Promise` is
32
+ * ready when execution ends.
33
+ */
34
+ export function run(messagePort) {
35
+ return __awaiter(this, void 0, void 0, function* () {
36
+ const whenShutdown = yield instance.startInstanceServer({
37
+ envVars: [],
38
+ performanceNow: () => {
39
+ return performance.now();
40
+ },
41
+ getRandomValues: (buffer) => {
42
+ const crypto = globalThis.crypto;
43
+ if (!crypto)
44
+ throw new Error('randomness not available');
45
+ // Browsers have this completely undocumented behavior (it's not even part of a spec)
46
+ // that for some reason `getRandomValues` can't be called on arrayviews back by
47
+ // `SharedArrayBuffer`s and they throw an exception if you try.
48
+ if (buffer.buffer instanceof ArrayBuffer)
49
+ crypto.getRandomValues(buffer);
50
+ else {
51
+ const tmpArray = new Uint8Array(buffer.length);
52
+ crypto.getRandomValues(tmpArray);
53
+ buffer.set(tmpArray);
54
+ }
55
+ },
56
+ }, messagePort);
57
+ return whenShutdown;
58
+ });
59
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Runs the CPU-heavy parts of smoldot. Must be passed a port whose other end is passed to
3
+ * `ClientOptions.portToWorker`.
4
+ *
5
+ * Returns a `Promise` that is ready when the smoldot client is shut down (either because it
6
+ * crashes or intentionally with a call to `Client.terminate`).
7
+ * Since this function is asynchronous, this `Promise` is wrapped around another `Promise`. In
8
+ * other words, the outer `Promise` is ready when execution starts, and the inner `Promise` is
9
+ * ready when execution ends.
10
+ */
11
+ export declare function run(messagePort: MessagePort): Promise<Promise<void>>;