Comparing version 2.0.1 to 2.0.2
@@ -64,2 +64,26 @@ "use strict"; | ||
}, | ||
random_get: (ptr, len) => { | ||
const instance = state.instance; | ||
ptr >>>= 0; | ||
len >>>= 0; | ||
const baseBuffer = new Uint8Array(instance.exports.memory.buffer) | ||
.subarray(ptr, ptr + len); | ||
for (let iter = 0; iter < len; iter += 65536) { | ||
// `baseBuffer.subarray` automatically saturates at the end of the buffer | ||
config.getRandomValues(baseBuffer.subarray(iter, iter + 65536)); | ||
} | ||
}, | ||
unix_timestamp_us: () => { | ||
const value = Math.floor(Date.now()); | ||
if (value < 0) | ||
throw new Error("UNIX timestamp inferior to 0"); | ||
return BigInt(value) * BigInt(1000); | ||
}, | ||
monotonic_clock_us: () => { | ||
const nowMs = config.performanceNow(); | ||
const nowMsInt = Math.floor(nowMs); | ||
const now = BigInt(nowMsInt) * BigInt(1000) + | ||
BigInt(Math.floor(((nowMs - nowMsInt) * 1000))); | ||
return now; | ||
}, | ||
buffer_size: (bufferIndex) => { | ||
@@ -252,153 +276,2 @@ const buf = state.bufferIndices[bufferIndex]; | ||
}; | ||
const wasiBindings = { | ||
// Need to fill the buffer described by `ptr` and `len` with random data. | ||
// This data will be used in order to generate secrets. Do not use a dummy implementation! | ||
random_get: (ptr, len) => { | ||
const instance = state.instance; | ||
ptr >>>= 0; | ||
len >>>= 0; | ||
const baseBuffer = new Uint8Array(instance.exports.memory.buffer) | ||
.subarray(ptr, ptr + len); | ||
for (let iter = 0; iter < len; iter += 65536) { | ||
// `baseBuffer.subarray` automatically saturates at the end of the buffer | ||
config.getRandomValues(baseBuffer.subarray(iter, iter + 65536)); | ||
} | ||
return 0; | ||
}, | ||
clock_time_get: (clockId, _precision, outPtr) => { | ||
// See <https://github.com/rust-lang/rust/blob/master/library/std/src/sys/wasi/time.rs> | ||
// and <docs.rs/wasi/> for help. | ||
const instance = state.instance; | ||
const mem = new Uint8Array(instance.exports.memory.buffer); | ||
outPtr >>>= 0; | ||
// We ignore the precision, as it can't be implemented anyway. | ||
switch (clockId) { | ||
case 0: { | ||
// Realtime clock. | ||
const now = BigInt(Math.floor(Date.now())) * BigInt(1000000); | ||
buffer.writeUInt64LE(mem, outPtr, now); | ||
// Success. | ||
return 0; | ||
} | ||
case 1: { | ||
// Monotonic clock. | ||
const nowMs = config.performanceNow(); | ||
const nowMsInt = Math.floor(nowMs); | ||
const now = BigInt(nowMsInt) * BigInt(1000000) + | ||
BigInt(Math.floor(((nowMs - nowMsInt) * 1000000))); | ||
buffer.writeUInt64LE(mem, outPtr, now); | ||
// Success. | ||
return 0; | ||
} | ||
default: | ||
// Return an `EINVAL` error. | ||
return 28; | ||
} | ||
}, | ||
// Writing to a file descriptor is used in order to write to stdout/stderr. | ||
fd_write: (fd, addr, num, outPtr) => { | ||
const instance = state.instance; | ||
outPtr >>>= 0; | ||
// Only stdout and stderr are open for writing. | ||
if (fd != 1 && fd != 2) { | ||
return 8; | ||
} | ||
const mem = new Uint8Array(instance.exports.memory.buffer); | ||
// `fd_write` passes a buffer containing itself a list of pointers and lengths to the | ||
// actual buffers. See writev(2). | ||
let toWrite = ""; | ||
let totalLength = 0; | ||
for (let i = 0; i < num; i++) { | ||
const buf = buffer.readUInt32LE(mem, addr + 4 * i * 2); | ||
const bufLen = buffer.readUInt32LE(mem, addr + 4 * (i * 2 + 1)); | ||
toWrite += buffer.utf8BytesToString(mem, buf, bufLen); | ||
totalLength += bufLen; | ||
} | ||
const flushBuffer = (string) => { | ||
// As documented in the documentation of `println!`, lines are always split by a | ||
// single `\n` in Rust. | ||
while (true) { | ||
const index = string.indexOf('\n'); | ||
if (index != -1) { | ||
// Note that it is questionnable to use `console.log` from within a | ||
// library. However this simply reflects the usage of `println!` in the | ||
// Rust code. In other words, it is `println!` that shouldn't be used in | ||
// the first place. The harm of not showing text printed with `println!` | ||
// at all is greater than the harm possibly caused by accidentally leaving | ||
// a `println!` in the code. | ||
console.log(string.substring(0, index)); | ||
string = string.substring(index + 1); | ||
} | ||
else { | ||
return string; | ||
} | ||
} | ||
}; | ||
// Append the newly-written data to either `stdout_buffer` or `stderr_buffer`, and | ||
// print their content if necessary. | ||
if (fd == 1) { | ||
state.stdoutBuffer += toWrite; | ||
state.stdoutBuffer = flushBuffer(state.stdoutBuffer); | ||
} | ||
else if (fd == 2) { | ||
state.stderrBuffer += toWrite; | ||
state.stderrBuffer = flushBuffer(state.stderrBuffer); | ||
} | ||
// Need to write in `out_ptr` how much data was "written". | ||
buffer.writeUInt32LE(mem, outPtr, totalLength); | ||
return 0; | ||
}, | ||
// It's unclear how to properly implement yielding, but a no-op works fine as well. | ||
sched_yield: () => { | ||
return 0; | ||
}, | ||
// Used by Rust in catastrophic situations, such as a double panic. | ||
proc_exit: (retCode) => { | ||
state.instance = null; | ||
eventCallback({ | ||
ty: "wasm-panic", | ||
message: `proc_exit called: ${retCode}`, | ||
currentTask: state.currentTask | ||
}); | ||
state.onShutdownExecutorOrWasmPanic(); | ||
state.onShutdownExecutorOrWasmPanic = () => { }; | ||
throw new Error(); | ||
}, | ||
// Return the number of environment variables and the total size of all environment | ||
// variables. This is called in order to initialize buffers before `environ_get`. | ||
environ_sizes_get: (argcOut, argvBufSizeOut) => { | ||
const instance = state.instance; | ||
argcOut >>>= 0; | ||
argvBufSizeOut >>>= 0; | ||
let totalLen = 0; | ||
config.envVars.forEach(e => totalLen += new TextEncoder().encode(e).length + 1); // +1 for trailing \0 | ||
const mem = new Uint8Array(instance.exports.memory.buffer); | ||
buffer.writeUInt32LE(mem, argcOut, config.envVars.length); | ||
buffer.writeUInt32LE(mem, argvBufSizeOut, totalLen); | ||
return 0; | ||
}, | ||
// Write the environment variables to the given pointers. | ||
// `argv` is a pointer to a buffer that must be overwritten with a list of pointers to | ||
// environment variables, and `argvBuf` is a pointer to a buffer where to actually store | ||
// the environment variables. | ||
// The sizes of the buffers were determined by calling `environ_sizes_get`. | ||
environ_get: (argv, argvBuf) => { | ||
const instance = state.instance; | ||
argv >>>= 0; | ||
argvBuf >>>= 0; | ||
const mem = new Uint8Array(instance.exports.memory.buffer); | ||
let argvPos = 0; | ||
let argvBufPos = 0; | ||
config.envVars.forEach(envVar => { | ||
const encoded = new TextEncoder().encode(envVar); | ||
buffer.writeUInt32LE(mem, argv + argvPos, argvBuf + argvBufPos); | ||
argvPos += 4; | ||
mem.set(encoded, argvBuf + argvBufPos); | ||
argvBufPos += encoded.length; | ||
buffer.writeUInt8(mem, argvBuf + argvBufPos, 0); | ||
argvBufPos += 1; | ||
}); | ||
return 0; | ||
}, | ||
}; | ||
// Start the Wasm virtual machine. | ||
@@ -410,4 +283,2 @@ // The Rust code defines a list of imports that must be fulfilled by the environment. The second | ||
"smoldot": smoldotJsBindings, | ||
// As the Rust code is compiled for wasi, some more wasi-specific imports exist. | ||
"wasi_snapshot_preview1": wasiBindings, | ||
}); | ||
@@ -414,0 +285,0 @@ state.instance = result; |
@@ -61,2 +61,26 @@ // Smoldot | ||
}, | ||
random_get: (ptr, len) => { | ||
const instance = state.instance; | ||
ptr >>>= 0; | ||
len >>>= 0; | ||
const baseBuffer = new Uint8Array(instance.exports.memory.buffer) | ||
.subarray(ptr, ptr + len); | ||
for (let iter = 0; iter < len; iter += 65536) { | ||
// `baseBuffer.subarray` automatically saturates at the end of the buffer | ||
config.getRandomValues(baseBuffer.subarray(iter, iter + 65536)); | ||
} | ||
}, | ||
unix_timestamp_us: () => { | ||
const value = Math.floor(Date.now()); | ||
if (value < 0) | ||
throw new Error("UNIX timestamp inferior to 0"); | ||
return BigInt(value) * BigInt(1000); | ||
}, | ||
monotonic_clock_us: () => { | ||
const nowMs = config.performanceNow(); | ||
const nowMsInt = Math.floor(nowMs); | ||
const now = BigInt(nowMsInt) * BigInt(1000) + | ||
BigInt(Math.floor(((nowMs - nowMsInt) * 1000))); | ||
return now; | ||
}, | ||
buffer_size: (bufferIndex) => { | ||
@@ -249,153 +273,2 @@ const buf = state.bufferIndices[bufferIndex]; | ||
}; | ||
const wasiBindings = { | ||
// Need to fill the buffer described by `ptr` and `len` with random data. | ||
// This data will be used in order to generate secrets. Do not use a dummy implementation! | ||
random_get: (ptr, len) => { | ||
const instance = state.instance; | ||
ptr >>>= 0; | ||
len >>>= 0; | ||
const baseBuffer = new Uint8Array(instance.exports.memory.buffer) | ||
.subarray(ptr, ptr + len); | ||
for (let iter = 0; iter < len; iter += 65536) { | ||
// `baseBuffer.subarray` automatically saturates at the end of the buffer | ||
config.getRandomValues(baseBuffer.subarray(iter, iter + 65536)); | ||
} | ||
return 0; | ||
}, | ||
clock_time_get: (clockId, _precision, outPtr) => { | ||
// See <https://github.com/rust-lang/rust/blob/master/library/std/src/sys/wasi/time.rs> | ||
// and <docs.rs/wasi/> for help. | ||
const instance = state.instance; | ||
const mem = new Uint8Array(instance.exports.memory.buffer); | ||
outPtr >>>= 0; | ||
// We ignore the precision, as it can't be implemented anyway. | ||
switch (clockId) { | ||
case 0: { | ||
// Realtime clock. | ||
const now = BigInt(Math.floor(Date.now())) * BigInt(1000000); | ||
buffer.writeUInt64LE(mem, outPtr, now); | ||
// Success. | ||
return 0; | ||
} | ||
case 1: { | ||
// Monotonic clock. | ||
const nowMs = config.performanceNow(); | ||
const nowMsInt = Math.floor(nowMs); | ||
const now = BigInt(nowMsInt) * BigInt(1000000) + | ||
BigInt(Math.floor(((nowMs - nowMsInt) * 1000000))); | ||
buffer.writeUInt64LE(mem, outPtr, now); | ||
// Success. | ||
return 0; | ||
} | ||
default: | ||
// Return an `EINVAL` error. | ||
return 28; | ||
} | ||
}, | ||
// Writing to a file descriptor is used in order to write to stdout/stderr. | ||
fd_write: (fd, addr, num, outPtr) => { | ||
const instance = state.instance; | ||
outPtr >>>= 0; | ||
// Only stdout and stderr are open for writing. | ||
if (fd != 1 && fd != 2) { | ||
return 8; | ||
} | ||
const mem = new Uint8Array(instance.exports.memory.buffer); | ||
// `fd_write` passes a buffer containing itself a list of pointers and lengths to the | ||
// actual buffers. See writev(2). | ||
let toWrite = ""; | ||
let totalLength = 0; | ||
for (let i = 0; i < num; i++) { | ||
const buf = buffer.readUInt32LE(mem, addr + 4 * i * 2); | ||
const bufLen = buffer.readUInt32LE(mem, addr + 4 * (i * 2 + 1)); | ||
toWrite += buffer.utf8BytesToString(mem, buf, bufLen); | ||
totalLength += bufLen; | ||
} | ||
const flushBuffer = (string) => { | ||
// As documented in the documentation of `println!`, lines are always split by a | ||
// single `\n` in Rust. | ||
while (true) { | ||
const index = string.indexOf('\n'); | ||
if (index != -1) { | ||
// Note that it is questionnable to use `console.log` from within a | ||
// library. However this simply reflects the usage of `println!` in the | ||
// Rust code. In other words, it is `println!` that shouldn't be used in | ||
// the first place. The harm of not showing text printed with `println!` | ||
// at all is greater than the harm possibly caused by accidentally leaving | ||
// a `println!` in the code. | ||
console.log(string.substring(0, index)); | ||
string = string.substring(index + 1); | ||
} | ||
else { | ||
return string; | ||
} | ||
} | ||
}; | ||
// Append the newly-written data to either `stdout_buffer` or `stderr_buffer`, and | ||
// print their content if necessary. | ||
if (fd == 1) { | ||
state.stdoutBuffer += toWrite; | ||
state.stdoutBuffer = flushBuffer(state.stdoutBuffer); | ||
} | ||
else if (fd == 2) { | ||
state.stderrBuffer += toWrite; | ||
state.stderrBuffer = flushBuffer(state.stderrBuffer); | ||
} | ||
// Need to write in `out_ptr` how much data was "written". | ||
buffer.writeUInt32LE(mem, outPtr, totalLength); | ||
return 0; | ||
}, | ||
// It's unclear how to properly implement yielding, but a no-op works fine as well. | ||
sched_yield: () => { | ||
return 0; | ||
}, | ||
// Used by Rust in catastrophic situations, such as a double panic. | ||
proc_exit: (retCode) => { | ||
state.instance = null; | ||
eventCallback({ | ||
ty: "wasm-panic", | ||
message: `proc_exit called: ${retCode}`, | ||
currentTask: state.currentTask | ||
}); | ||
state.onShutdownExecutorOrWasmPanic(); | ||
state.onShutdownExecutorOrWasmPanic = () => { }; | ||
throw new Error(); | ||
}, | ||
// Return the number of environment variables and the total size of all environment | ||
// variables. This is called in order to initialize buffers before `environ_get`. | ||
environ_sizes_get: (argcOut, argvBufSizeOut) => { | ||
const instance = state.instance; | ||
argcOut >>>= 0; | ||
argvBufSizeOut >>>= 0; | ||
let totalLen = 0; | ||
config.envVars.forEach(e => totalLen += new TextEncoder().encode(e).length + 1); // +1 for trailing \0 | ||
const mem = new Uint8Array(instance.exports.memory.buffer); | ||
buffer.writeUInt32LE(mem, argcOut, config.envVars.length); | ||
buffer.writeUInt32LE(mem, argvBufSizeOut, totalLen); | ||
return 0; | ||
}, | ||
// Write the environment variables to the given pointers. | ||
// `argv` is a pointer to a buffer that must be overwritten with a list of pointers to | ||
// environment variables, and `argvBuf` is a pointer to a buffer where to actually store | ||
// the environment variables. | ||
// The sizes of the buffers were determined by calling `environ_sizes_get`. | ||
environ_get: (argv, argvBuf) => { | ||
const instance = state.instance; | ||
argv >>>= 0; | ||
argvBuf >>>= 0; | ||
const mem = new Uint8Array(instance.exports.memory.buffer); | ||
let argvPos = 0; | ||
let argvBufPos = 0; | ||
config.envVars.forEach(envVar => { | ||
const encoded = new TextEncoder().encode(envVar); | ||
buffer.writeUInt32LE(mem, argv + argvPos, argvBuf + argvBufPos); | ||
argvPos += 4; | ||
mem.set(encoded, argvBuf + argvBufPos); | ||
argvBufPos += encoded.length; | ||
buffer.writeUInt8(mem, argvBuf + argvBufPos, 0); | ||
argvBufPos += 1; | ||
}); | ||
return 0; | ||
}, | ||
}; | ||
// Start the Wasm virtual machine. | ||
@@ -407,4 +280,2 @@ // The Rust code defines a list of imports that must be fulfilled by the environment. The second | ||
"smoldot": smoldotJsBindings, | ||
// As the Rust code is compiled for wasi, some more wasi-specific imports exist. | ||
"wasi_snapshot_preview1": wasiBindings, | ||
}); | ||
@@ -411,0 +282,0 @@ state.instance = result; |
{ | ||
"name": "smoldot", | ||
"version": "2.0.1", | ||
"version": "2.0.2", | ||
"description": "Light client that connects to Polkadot and Substrate-based blockchains", | ||
@@ -5,0 +5,0 @@ "contributors": [ |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
6172821
29792