@deroll/cmio 0.1.0

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 (27) hide show
  1. package/AUTHORS +1 -0
  2. package/LICENSE +202 -0
  3. package/README.md +122 -0
  4. package/binding.gyp +53 -0
  5. package/deps/machine-guest-tools/AUTHORS +7 -0
  6. package/deps/machine-guest-tools/sys-utils/libcmt/include/libcmt/abi.h +589 -0
  7. package/deps/machine-guest-tools/sys-utils/libcmt/include/libcmt/buf.h +82 -0
  8. package/deps/machine-guest-tools/sys-utils/libcmt/include/libcmt/io.h +168 -0
  9. package/deps/machine-guest-tools/sys-utils/libcmt/include/libcmt/keccak.h +131 -0
  10. package/deps/machine-guest-tools/sys-utils/libcmt/include/libcmt/merkle.h +118 -0
  11. package/deps/machine-guest-tools/sys-utils/libcmt/include/libcmt/rollup.h +260 -0
  12. package/deps/machine-guest-tools/sys-utils/libcmt/include/libcmt/util.h +34 -0
  13. package/deps/machine-guest-tools/sys-utils/libcmt/src/abi.c +315 -0
  14. package/deps/machine-guest-tools/sys-utils/libcmt/src/buf.c +121 -0
  15. package/deps/machine-guest-tools/sys-utils/libcmt/src/io-mock.c +319 -0
  16. package/deps/machine-guest-tools/sys-utils/libcmt/src/io.c +164 -0
  17. package/deps/machine-guest-tools/sys-utils/libcmt/src/keccak.c +156 -0
  18. package/deps/machine-guest-tools/sys-utils/libcmt/src/merkle.c +202 -0
  19. package/deps/machine-guest-tools/sys-utils/libcmt/src/rollup.c +455 -0
  20. package/deps/machine-guest-tools/sys-utils/libcmt/src/util.c +52 -0
  21. package/lib/index.d.mts +18 -0
  22. package/lib/index.d.ts +162 -0
  23. package/lib/index.js +230 -0
  24. package/lib/index.mjs +19 -0
  25. package/package.json +70 -0
  26. package/prebuilds/darwin-arm64/@deroll+cmio.node +0 -0
  27. package/src/addon.cc +411 -0
package/src/addon.cc ADDED
@@ -0,0 +1,411 @@
1
+ // Copyright Cartesi and individual authors (see AUTHORS)
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ //
4
+ // Licensed under the Apache License, Version 2.0 (the "License");
5
+ // you may not use this file except in compliance with the License.
6
+ // You may obtain a copy of the License at
7
+ //
8
+ // http://www.apache.org/licenses/LICENSE-2.0
9
+ //
10
+ // Unless required by applicable law or agreed to in writing, software
11
+ // distributed under the License is distributed on an "AS IS" BASIS,
12
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ // See the License for the specific language governing permissions and
14
+ // limitations under the License.
15
+ //
16
+
17
+ // The whole API is synchronous on purpose: calls that "block" (finish, gio)
18
+ // yield the machine, which pauses the entire guest — including the Node.js
19
+ // event loop — so there is nothing to run concurrently while they wait.
20
+
21
+ #include <cerrno>
22
+ #include <cstdint>
23
+ #include <cstdio>
24
+ #include <cstring>
25
+ #include <string>
26
+
27
+ #include <napi.h>
28
+
29
+ extern "C" {
30
+ #include <libcmt/rollup.h>
31
+ }
32
+
33
+ namespace {
34
+
35
+ Napi::Error errno_error(Napi::Env env, const char *what, int rc) {
36
+ char msg[256];
37
+ (void) snprintf(msg, sizeof msg, "%s failed: %s (%d)", what, strerror(-rc), rc);
38
+ Napi::Error err = Napi::Error::New(env, msg);
39
+ err.Set("errno", Napi::Number::New(env, rc));
40
+ err.Set("syscall", Napi::String::New(env, what));
41
+ return err;
42
+ }
43
+
44
+ // Extracts a byte view from a Buffer/Uint8Array argument. The view borrows the
45
+ // underlying ArrayBuffer storage: valid only while no JS runs.
46
+ bool get_bytes(Napi::Env env, const Napi::Value &value, const char *name, const uint8_t **data, size_t *length,
47
+ ptrdiff_t exact_length = -1) {
48
+ if (!value.IsTypedArray() || value.As<Napi::TypedArray>().TypedArrayType() != napi_uint8_array) {
49
+ Napi::TypeError::New(env, std::string(name) + " must be a Buffer or Uint8Array").ThrowAsJavaScriptException();
50
+ return false;
51
+ }
52
+ Napi::Uint8Array array = value.As<Napi::Uint8Array>();
53
+ if (exact_length >= 0 && array.ByteLength() != static_cast<size_t>(exact_length)) {
54
+ Napi::TypeError::New(env,
55
+ std::string(name) + " must be exactly " + std::to_string(exact_length) + " bytes long")
56
+ .ThrowAsJavaScriptException();
57
+ return false;
58
+ }
59
+ *data = array.Data();
60
+ *length = array.ByteLength();
61
+ return true;
62
+ }
63
+
64
+ class Rollup final : public Napi::ObjectWrap<Rollup> {
65
+ public:
66
+ static Napi::Object Init(Napi::Env env, Napi::Object exports);
67
+ explicit Rollup(const Napi::CallbackInfo &info);
68
+ ~Rollup() override;
69
+
70
+ Rollup(const Rollup &) = delete;
71
+ Rollup &operator=(const Rollup &) = delete;
72
+ Rollup(Rollup &&) = delete;
73
+ Rollup &operator=(Rollup &&) = delete;
74
+
75
+ private:
76
+ bool usable(Napi::Env env);
77
+
78
+ Napi::Value Finish(const Napi::CallbackInfo &info);
79
+ Napi::Value EmitVoucher(const Napi::CallbackInfo &info);
80
+ Napi::Value EmitDelegateCallVoucher(const Napi::CallbackInfo &info);
81
+ Napi::Value EmitNotice(const Napi::CallbackInfo &info);
82
+ Napi::Value EmitReport(const Napi::CallbackInfo &info);
83
+ Napi::Value EmitException(const Napi::CallbackInfo &info);
84
+ Napi::Value Progress(const Napi::CallbackInfo &info);
85
+ Napi::Value Gio(const Napi::CallbackInfo &info);
86
+ Napi::Value LoadMerkle(const Napi::CallbackInfo &info);
87
+ Napi::Value SaveMerkle(const Napi::CallbackInfo &info);
88
+ Napi::Value ResetMerkle(const Napi::CallbackInfo &info);
89
+ Napi::Value Close(const Napi::CallbackInfo &info);
90
+
91
+ cmt_rollup_t rollup_{};
92
+ bool open_ = false;
93
+ };
94
+
95
+ Rollup::Rollup(const Napi::CallbackInfo &info) : Napi::ObjectWrap<Rollup>(info) {
96
+ Napi::Env env = info.Env();
97
+ int rc = cmt_rollup_init(&rollup_);
98
+ if (rc < 0) {
99
+ errno_error(env, "cmt_rollup_init", rc).ThrowAsJavaScriptException();
100
+ return;
101
+ }
102
+ open_ = true;
103
+ }
104
+
105
+ Rollup::~Rollup() {
106
+ if (open_) {
107
+ cmt_rollup_fini(&rollup_);
108
+ open_ = false;
109
+ }
110
+ }
111
+
112
+ bool Rollup::usable(Napi::Env env) {
113
+ if (!open_) {
114
+ Napi::Error::New(env, "rollup is closed").ThrowAsJavaScriptException();
115
+ return false;
116
+ }
117
+ return true;
118
+ }
119
+
120
+ Napi::Value Rollup::Finish(const Napi::CallbackInfo &info) {
121
+ Napi::Env env = info.Env();
122
+ if (!usable(env)) {
123
+ return env.Undefined();
124
+ }
125
+ if (info.Length() < 1 || !info[0].IsBoolean()) {
126
+ Napi::TypeError::New(env, "accept must be a boolean").ThrowAsJavaScriptException();
127
+ return env.Undefined();
128
+ }
129
+ cmt_rollup_finish_t finish{};
130
+ finish.accept_previous_request = info[0].As<Napi::Boolean>().Value();
131
+ int rc = cmt_rollup_finish(&rollup_, &finish);
132
+ if (rc < 0) {
133
+ errno_error(env, "cmt_rollup_finish", rc).ThrowAsJavaScriptException();
134
+ return env.Undefined();
135
+ }
136
+ Napi::Object request = Napi::Object::New(env);
137
+ if (finish.next_request_type == HTIF_YIELD_REASON_ADVANCE) {
138
+ cmt_rollup_advance_t advance{};
139
+ rc = cmt_rollup_read_advance_state(&rollup_, &advance);
140
+ if (rc < 0) {
141
+ errno_error(env, "cmt_rollup_read_advance_state", rc).ThrowAsJavaScriptException();
142
+ return env.Undefined();
143
+ }
144
+ request.Set("type", Napi::String::New(env, "advance"));
145
+ request.Set("chainId", Napi::BigInt::New(env, advance.chain_id));
146
+ request.Set("appContract", Napi::Buffer<uint8_t>::Copy(env, advance.app_contract.data, CMT_ABI_ADDRESS_LENGTH));
147
+ request.Set("msgSender", Napi::Buffer<uint8_t>::Copy(env, advance.msg_sender.data, CMT_ABI_ADDRESS_LENGTH));
148
+ request.Set("blockNumber", Napi::BigInt::New(env, advance.block_number));
149
+ request.Set("blockTimestamp", Napi::BigInt::New(env, advance.block_timestamp));
150
+ request.Set("prevRandao", Napi::Buffer<uint8_t>::Copy(env, advance.prev_randao.data, CMT_ABI_U256_LENGTH));
151
+ request.Set("index", Napi::BigInt::New(env, advance.index));
152
+ request.Set("payload",
153
+ Napi::Buffer<uint8_t>::Copy(env, static_cast<const uint8_t *>(advance.payload.data),
154
+ advance.payload.length));
155
+ } else {
156
+ cmt_rollup_inspect_t inspect{};
157
+ rc = cmt_rollup_read_inspect_state(&rollup_, &inspect);
158
+ if (rc < 0) {
159
+ errno_error(env, "cmt_rollup_read_inspect_state", rc).ThrowAsJavaScriptException();
160
+ return env.Undefined();
161
+ }
162
+ request.Set("type", Napi::String::New(env, "inspect"));
163
+ request.Set("payload",
164
+ Napi::Buffer<uint8_t>::Copy(env, static_cast<const uint8_t *>(inspect.payload.data),
165
+ inspect.payload.length));
166
+ }
167
+ return request;
168
+ }
169
+
170
+ Napi::Value Rollup::EmitVoucher(const Napi::CallbackInfo &info) {
171
+ Napi::Env env = info.Env();
172
+ if (!usable(env)) {
173
+ return env.Undefined();
174
+ }
175
+ const uint8_t *address_data = nullptr;
176
+ const uint8_t *value_data = nullptr;
177
+ const uint8_t *payload_data = nullptr;
178
+ size_t address_length = 0;
179
+ size_t value_length = 0;
180
+ size_t payload_length = 0;
181
+ if (!get_bytes(env, info[0], "destination", &address_data, &address_length, CMT_ABI_ADDRESS_LENGTH) ||
182
+ !get_bytes(env, info[1], "value", &value_data, &value_length, CMT_ABI_U256_LENGTH) ||
183
+ !get_bytes(env, info[2], "payload", &payload_data, &payload_length)) {
184
+ return env.Undefined();
185
+ }
186
+ cmt_abi_address_t address{};
187
+ cmt_abi_u256_t value{};
188
+ memcpy(address.data, address_data, CMT_ABI_ADDRESS_LENGTH);
189
+ memcpy(value.data, value_data, CMT_ABI_U256_LENGTH);
190
+ const cmt_abi_bytes_t payload{payload_length, const_cast<uint8_t *>(payload_data)};
191
+ uint64_t index = 0;
192
+ int rc = cmt_rollup_emit_voucher(&rollup_, &address, &value, &payload, &index);
193
+ if (rc < 0) {
194
+ errno_error(env, "cmt_rollup_emit_voucher", rc).ThrowAsJavaScriptException();
195
+ return env.Undefined();
196
+ }
197
+ return Napi::BigInt::New(env, index);
198
+ }
199
+
200
+ Napi::Value Rollup::EmitDelegateCallVoucher(const Napi::CallbackInfo &info) {
201
+ Napi::Env env = info.Env();
202
+ if (!usable(env)) {
203
+ return env.Undefined();
204
+ }
205
+ const uint8_t *address_data = nullptr;
206
+ const uint8_t *payload_data = nullptr;
207
+ size_t address_length = 0;
208
+ size_t payload_length = 0;
209
+ if (!get_bytes(env, info[0], "destination", &address_data, &address_length, CMT_ABI_ADDRESS_LENGTH) ||
210
+ !get_bytes(env, info[1], "payload", &payload_data, &payload_length)) {
211
+ return env.Undefined();
212
+ }
213
+ cmt_abi_address_t address{};
214
+ memcpy(address.data, address_data, CMT_ABI_ADDRESS_LENGTH);
215
+ const cmt_abi_bytes_t payload{payload_length, const_cast<uint8_t *>(payload_data)};
216
+ uint64_t index = 0;
217
+ int rc = cmt_rollup_emit_delegate_call_voucher(&rollup_, &address, &payload, &index);
218
+ if (rc < 0) {
219
+ errno_error(env, "cmt_rollup_emit_delegate_call_voucher", rc).ThrowAsJavaScriptException();
220
+ return env.Undefined();
221
+ }
222
+ return Napi::BigInt::New(env, index);
223
+ }
224
+
225
+ Napi::Value Rollup::EmitNotice(const Napi::CallbackInfo &info) {
226
+ Napi::Env env = info.Env();
227
+ if (!usable(env)) {
228
+ return env.Undefined();
229
+ }
230
+ const uint8_t *payload_data = nullptr;
231
+ size_t payload_length = 0;
232
+ if (!get_bytes(env, info[0], "payload", &payload_data, &payload_length)) {
233
+ return env.Undefined();
234
+ }
235
+ const cmt_abi_bytes_t payload{payload_length, const_cast<uint8_t *>(payload_data)};
236
+ uint64_t index = 0;
237
+ int rc = cmt_rollup_emit_notice(&rollup_, &payload, &index);
238
+ if (rc < 0) {
239
+ errno_error(env, "cmt_rollup_emit_notice", rc).ThrowAsJavaScriptException();
240
+ return env.Undefined();
241
+ }
242
+ return Napi::BigInt::New(env, index);
243
+ }
244
+
245
+ Napi::Value Rollup::EmitReport(const Napi::CallbackInfo &info) {
246
+ Napi::Env env = info.Env();
247
+ if (!usable(env)) {
248
+ return env.Undefined();
249
+ }
250
+ const uint8_t *payload_data = nullptr;
251
+ size_t payload_length = 0;
252
+ if (!get_bytes(env, info[0], "payload", &payload_data, &payload_length)) {
253
+ return env.Undefined();
254
+ }
255
+ const cmt_abi_bytes_t payload{payload_length, const_cast<uint8_t *>(payload_data)};
256
+ int rc = cmt_rollup_emit_report(&rollup_, &payload);
257
+ if (rc < 0) {
258
+ errno_error(env, "cmt_rollup_emit_report", rc).ThrowAsJavaScriptException();
259
+ }
260
+ return env.Undefined();
261
+ }
262
+
263
+ Napi::Value Rollup::EmitException(const Napi::CallbackInfo &info) {
264
+ Napi::Env env = info.Env();
265
+ if (!usable(env)) {
266
+ return env.Undefined();
267
+ }
268
+ const uint8_t *payload_data = nullptr;
269
+ size_t payload_length = 0;
270
+ if (!get_bytes(env, info[0], "payload", &payload_data, &payload_length)) {
271
+ return env.Undefined();
272
+ }
273
+ const cmt_abi_bytes_t payload{payload_length, const_cast<uint8_t *>(payload_data)};
274
+ int rc = cmt_rollup_emit_exception(&rollup_, &payload);
275
+ if (rc < 0) {
276
+ errno_error(env, "cmt_rollup_emit_exception", rc).ThrowAsJavaScriptException();
277
+ }
278
+ return env.Undefined();
279
+ }
280
+
281
+ Napi::Value Rollup::Progress(const Napi::CallbackInfo &info) {
282
+ Napi::Env env = info.Env();
283
+ if (!usable(env)) {
284
+ return env.Undefined();
285
+ }
286
+ if (info.Length() < 1 || !info[0].IsNumber()) {
287
+ Napi::TypeError::New(env, "progress must be a number").ThrowAsJavaScriptException();
288
+ return env.Undefined();
289
+ }
290
+ int rc = cmt_rollup_progress(&rollup_, info[0].As<Napi::Number>().Uint32Value());
291
+ if (rc < 0) {
292
+ errno_error(env, "cmt_rollup_progress", rc).ThrowAsJavaScriptException();
293
+ }
294
+ return env.Undefined();
295
+ }
296
+
297
+ Napi::Value Rollup::Gio(const Napi::CallbackInfo &info) {
298
+ Napi::Env env = info.Env();
299
+ if (!usable(env)) {
300
+ return env.Undefined();
301
+ }
302
+ if (info.Length() < 1 || !info[0].IsNumber()) {
303
+ Napi::TypeError::New(env, "domain must be a number").ThrowAsJavaScriptException();
304
+ return env.Undefined();
305
+ }
306
+ uint32_t domain = info[0].As<Napi::Number>().Uint32Value();
307
+ if (domain > UINT16_MAX) {
308
+ Napi::RangeError::New(env, "domain must fit in 16 bits").ThrowAsJavaScriptException();
309
+ return env.Undefined();
310
+ }
311
+ const uint8_t *id_data = nullptr;
312
+ size_t id_length = 0;
313
+ if (!get_bytes(env, info[1], "id", &id_data, &id_length)) {
314
+ return env.Undefined();
315
+ }
316
+ cmt_gio_t request{};
317
+ request.domain = static_cast<uint16_t>(domain);
318
+ request.id = const_cast<uint8_t *>(id_data);
319
+ request.id_length = static_cast<uint32_t>(id_length);
320
+ int rc = cmt_gio_request(&rollup_, &request);
321
+ if (rc < 0) {
322
+ errno_error(env, "cmt_gio_request", rc).ThrowAsJavaScriptException();
323
+ return env.Undefined();
324
+ }
325
+ Napi::Object response = Napi::Object::New(env);
326
+ response.Set("responseCode", Napi::Number::New(env, request.response_code));
327
+ response.Set("responseData",
328
+ Napi::Buffer<uint8_t>::Copy(env, static_cast<const uint8_t *>(request.response_data),
329
+ request.response_data_length));
330
+ return response;
331
+ }
332
+
333
+ Napi::Value Rollup::LoadMerkle(const Napi::CallbackInfo &info) {
334
+ Napi::Env env = info.Env();
335
+ if (!usable(env)) {
336
+ return env.Undefined();
337
+ }
338
+ if (info.Length() < 1 || !info[0].IsString()) {
339
+ Napi::TypeError::New(env, "path must be a string").ThrowAsJavaScriptException();
340
+ return env.Undefined();
341
+ }
342
+ std::string path = info[0].As<Napi::String>().Utf8Value();
343
+ int rc = cmt_rollup_load_merkle(&rollup_, path.c_str());
344
+ if (rc < 0) {
345
+ errno_error(env, "cmt_rollup_load_merkle", rc).ThrowAsJavaScriptException();
346
+ }
347
+ return env.Undefined();
348
+ }
349
+
350
+ Napi::Value Rollup::SaveMerkle(const Napi::CallbackInfo &info) {
351
+ Napi::Env env = info.Env();
352
+ if (!usable(env)) {
353
+ return env.Undefined();
354
+ }
355
+ if (info.Length() < 1 || !info[0].IsString()) {
356
+ Napi::TypeError::New(env, "path must be a string").ThrowAsJavaScriptException();
357
+ return env.Undefined();
358
+ }
359
+ std::string path = info[0].As<Napi::String>().Utf8Value();
360
+ int rc = cmt_rollup_save_merkle(&rollup_, path.c_str());
361
+ if (rc < 0) {
362
+ errno_error(env, "cmt_rollup_save_merkle", rc).ThrowAsJavaScriptException();
363
+ }
364
+ return env.Undefined();
365
+ }
366
+
367
+ Napi::Value Rollup::ResetMerkle(const Napi::CallbackInfo &info) {
368
+ Napi::Env env = info.Env();
369
+ if (!usable(env)) {
370
+ return env.Undefined();
371
+ }
372
+ cmt_rollup_reset_merkle(&rollup_);
373
+ return env.Undefined();
374
+ }
375
+
376
+ Napi::Value Rollup::Close(const Napi::CallbackInfo &info) {
377
+ Napi::Env env = info.Env();
378
+ if (open_) {
379
+ cmt_rollup_fini(&rollup_);
380
+ open_ = false;
381
+ }
382
+ return env.Undefined();
383
+ }
384
+
385
+ Napi::Object Rollup::Init(Napi::Env env, Napi::Object exports) {
386
+ Napi::Function func = DefineClass(env, "Rollup",
387
+ {
388
+ InstanceMethod<&Rollup::Finish>("finish"),
389
+ InstanceMethod<&Rollup::EmitVoucher>("emitVoucher"),
390
+ InstanceMethod<&Rollup::EmitDelegateCallVoucher>("emitDelegateCallVoucher"),
391
+ InstanceMethod<&Rollup::EmitNotice>("emitNotice"),
392
+ InstanceMethod<&Rollup::EmitReport>("emitReport"),
393
+ InstanceMethod<&Rollup::EmitException>("emitException"),
394
+ InstanceMethod<&Rollup::Progress>("progress"),
395
+ InstanceMethod<&Rollup::Gio>("gio"),
396
+ InstanceMethod<&Rollup::LoadMerkle>("loadMerkle"),
397
+ InstanceMethod<&Rollup::SaveMerkle>("saveMerkle"),
398
+ InstanceMethod<&Rollup::ResetMerkle>("resetMerkle"),
399
+ InstanceMethod<&Rollup::Close>("close"),
400
+ });
401
+ exports.Set("Rollup", func);
402
+ return exports;
403
+ }
404
+
405
+ Napi::Object InitModule(Napi::Env env, Napi::Object exports) {
406
+ return Rollup::Init(env, exports);
407
+ }
408
+
409
+ } // namespace
410
+
411
+ NODE_API_MODULE(libcmt, InitModule)