Skip to content

Commit

Permalink
spawn
Browse files Browse the repository at this point in the history
  • Loading branch information
mohanson committed Sep 11, 2024
1 parent 34210cb commit 8874a23
Show file tree
Hide file tree
Showing 3 changed files with 242 additions and 1 deletion.
1 change: 0 additions & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
[submodule "deps/compiler-rt-builtins-riscv"]
path = deps/compiler-rt-builtins-riscv
url = https://github.com/nervosnetwork/compiler-rt-builtins-riscv
branch = update
[submodule "deps/musl"]
path = deps/musl
url = https://github.com/xxuejie/musl
213 changes: 213 additions & 0 deletions quickjs/ckb_module.c
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,210 @@ static int get_property(JSContext *ctx, JSValueConst *obj, const char *prop, int
return err;
}

static JSValue syscall_spawn_cell(JSContext *ctx, JSValueConst this_value, int argc, JSValueConst *argv) {
int err = 0;
size_t code_hash_len = 0;
uint8_t code_hash[32];
uint32_t hash_type = 0;
uint32_t offset = 0;
uint32_t length = 0;
uint32_t spgs_argc = 0;
const char* spgs_argv[32] = {};
uint64_t spgs_pid = 0;
uint64_t spgs_fds[32] = {0};

JSValue buffer = JS_GetTypedArrayBuffer(ctx, argv[0], NULL, NULL, NULL);
CHECK2(!JS_IsException(buffer), SyscallErrorArgument);
uint8_t *p = JS_GetArrayBuffer(ctx, &code_hash_len, buffer);
CHECK2(code_hash_len == 32 && p != NULL, -1);
memcpy(code_hash, p, 32);

err = JS_ToUint32(ctx, &hash_type, argv[1]);
CHECK(err);
err = JS_ToUint32(ctx, &offset, argv[2]);
CHECK(err);
err = JS_ToUint32(ctx, &length, argv[3]);
CHECK(err);

JSValue val;
val = JS_GetPropertyStr(ctx, argv[4], "argv");
CHECK2(!JS_IsException(val), SyscallErrorArgument);
if (!JS_IsUndefined(val)) {
for (int i = 0; i < 32; i++) {
const JSValue elem = JS_GetPropertyUint32(ctx, val, i);
if (JS_IsUndefined(elem)) {
break;
}
const char *str = JS_ToCString(ctx, elem);
spgs_argc += 1;
spgs_argv[i] = str;
}
}
JS_FreeValue(ctx, val);

val = JS_GetPropertyStr(ctx, argv[4], "inherited_fds");
CHECK2(!JS_IsException(val), SyscallErrorArgument);
if (!JS_IsUndefined(val)) {
uint32_t temp;
for (int i = 0; i < 32; i++) {
const JSValue elem = JS_GetPropertyUint32(ctx, val, i);
if (JS_IsUndefined(elem)) {
break;
}
err = JS_ToUint32(ctx, &temp, elem);
CHECK(err);
spgs_fds[i] = temp;
}
}
JS_FreeValue(ctx, val);

spawn_args_t spgs = {
.argc = spgs_argc,
.argv = spgs_argv,
.process_id = &spgs_pid,
.inherited_fds = &spgs_fds[0],
};

err = ckb_spawn_cell(code_hash, hash_type, offset, length, &spgs);
CHECK(err);
exit:
if (err != 0) {
return JS_EXCEPTION;
} else {
return JS_NewInt64(ctx, spgs_pid);
}
}

static JSValue syscall_pipe(JSContext *ctx, JSValueConst this_value, int argc, JSValueConst *argv) {
int err = 0;
uint64_t fds[2];
err = ckb_pipe(fds);
CHECK(err);
JSValue obj = JS_NewArray(ctx);
CHECK2(!JS_IsException(obj), SyscallErrorArgument);
JS_SetPropertyUint32(ctx, obj, 0, JS_NewUint32(ctx, fds[0]));
JS_SetPropertyUint32(ctx, obj, 1, JS_NewUint32(ctx, fds[1]));
exit:
if (err != 0) {
return JS_EXCEPTION;
} else {
return obj;
}
}

static JSValue syscall_inherited_fds(JSContext *ctx, JSValueConst this_value, int argc, JSValueConst *argv) {
int err = 0;
uint64_t fds[2];
uint64_t length;
err = ckb_inherited_fds(fds, &length);
CHECK(err);
JSValue obj = JS_NewArray(ctx);
CHECK2(!JS_IsException(obj), SyscallErrorArgument);
for (int i = 0; i < length; i++) {
JS_SetPropertyUint32(ctx, obj, i, JS_NewUint32(ctx, (uint32_t)fds[i]));
}
exit:
if (err != 0) {
return JS_EXCEPTION;
} else {
return obj;
}
}

static JSValue syscall_read(JSContext *ctx, JSValueConst this_value, int argc, JSValueConst *argv) {
int err = 0;
uint64_t fd = 0;
void* buffer = {};
size_t length = 0;
uint32_t u32 = 0;
err = JS_ToUint32(ctx, &u32, argv[0]);
CHECK(err);
fd = u32;
err = JS_ToUint32(ctx, &u32, argv[1]);
CHECK(err);
length = u32;
CHECK2(length <= 1024, SyscallErrorArgument);
err = ckb_read(fd, buffer, &length);
CHECK(err);
exit:
if (err != 0) {
return JS_EXCEPTION;
} else {
return JS_NewArrayBuffer(ctx, buffer, length, my_free, buffer, false);
}
}

static JSValue syscall_write(JSContext *ctx, JSValueConst this_value, int argc, JSValueConst *argv) {
int err = 0;
uint64_t fd = 0;
uint32_t u32 = 0;
err = JS_ToUint32(ctx, &u32, argv[0]);
CHECK(err);
fd = (uint64_t)u32;
size_t length = 0;
JSValue buffer = JS_GetTypedArrayBuffer(ctx, argv[1], NULL, NULL, NULL);
CHECK2(!JS_IsException(buffer), SyscallErrorArgument);
uint8_t *content = JS_GetArrayBuffer(ctx, &length, buffer);
CHECK2(content != NULL, SyscallErrorUnknown);
err = ckb_write(fd, content, &length);
CHECK(err);
exit:
if (err != 0) {
return JS_EXCEPTION;
} else {
return JS_UNDEFINED;
}
}

static JSValue syscall_close(JSContext *ctx, JSValueConst this_value, int argc, JSValueConst *argv) {
int err = 0;
uint32_t fd = 0;
err = JS_ToUint32(ctx, &fd, argv[0]);
CHECK(err);
err = ckb_close((uint64_t)fd);
CHECK(err);
exit:
if (err != 0) {
return JS_EXCEPTION;
} else {
return JS_UNDEFINED;
}
}

static JSValue syscall_wait(JSContext *ctx, JSValueConst this_value, int argc, JSValueConst *argv) {
int err = 0;
uint32_t fd = 0;
int8_t exit = 0;
err = JS_ToUint32(ctx, &fd, argv[0]);
CHECK(err);
err = ckb_wait((uint64_t)fd, &exit);
CHECK(err);
exit:
if (err != 0) {
return JS_EXCEPTION;
} else {
return JS_NewInt32(ctx, exit);
}
}

static JSValue syscall_process_id(JSContext *ctx, JSValueConst this_value, int argc, JSValueConst *argv) {
uint64_t pid = ckb_process_id();
return JS_NewUint32(ctx, (uint32_t)pid);
}

static int _load_block_extension(void *addr, uint64_t *len, LoadData *data) {
return ckb_load_block_extension(addr, len, data->offset, data->index, data->source);
}

static JSValue syscall_load_block_extension(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) {
LoadData data = {0};
JSValue ret = parse_args(ctx, &data, false, argc, argv, _load_block_extension);
if (JS_IsException(ret)) {
return ret;
}
return syscall_load(ctx, &data);
}

static JSValue mount(JSContext *ctx, JSValueConst this_value, int argc, JSValueConst *argv) {
JSValue buf = syscall_load_cell_data(ctx, this_value, argc, argv);
if (JS_IsException(buf)) {
Expand Down Expand Up @@ -416,6 +620,15 @@ int js_init_module_ckb(JSContext *ctx) {
JS_SetPropertyStr(ctx, ckb, "vm_version", JS_NewCFunction(ctx, syscall_vm_version, "vm_version", 0));
JS_SetPropertyStr(ctx, ckb, "current_cycles", JS_NewCFunction(ctx, syscall_current_cycles, "current_cycles", 0));
JS_SetPropertyStr(ctx, ckb, "exec_cell", JS_NewCFunction(ctx, syscall_exec_cell, "exec_cell", 4));
JS_SetPropertyStr(ctx, ckb, "spawn_cell", JS_NewCFunction(ctx, syscall_spawn_cell, "spawn_cell", 5));
JS_SetPropertyStr(ctx, ckb, "pipe", JS_NewCFunction(ctx, syscall_pipe, "pipe", 0));
JS_SetPropertyStr(ctx, ckb, "inherited_fds", JS_NewCFunction(ctx, syscall_inherited_fds, "inherited_fds", 0));
JS_SetPropertyStr(ctx, ckb, "read", JS_NewCFunction(ctx, syscall_read, "read", 2));
JS_SetPropertyStr(ctx, ckb, "write", JS_NewCFunction(ctx, syscall_write, "write", 2));
JS_SetPropertyStr(ctx, ckb, "close", JS_NewCFunction(ctx, syscall_close, "close", 1));
JS_SetPropertyStr(ctx, ckb, "wait", JS_NewCFunction(ctx, syscall_wait, "wait", 1));
JS_SetPropertyStr(ctx, ckb, "process_id", JS_NewCFunction(ctx, syscall_process_id, "process_id", 0));
JS_SetPropertyStr(ctx, ckb, "load_block_extension", JS_NewCFunction(ctx, syscall_load_block_extension, "load_block_extension", 3));
JS_SetPropertyStr(ctx, ckb, "mount", JS_NewCFunction(ctx, mount, "mount", 2));
JS_SetPropertyStr(ctx, ckb, "SOURCE_INPUT", JS_NewInt64(ctx, CKB_SOURCE_INPUT));
JS_SetPropertyStr(ctx, ckb, "SOURCE_OUTPUT", JS_NewInt64(ctx, CKB_SOURCE_OUTPUT));
Expand Down
29 changes: 29 additions & 0 deletions tests/ckb_js_tests/test_data/syscall.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,34 @@ function test_misc() {
console.log('test_misc done');
}

function test_spawn() {
console.log('test_spawn ...');
const js_code = `
let fds = ckb.inherited_fds();
ckb.write(fds[0], new Uint8Array([0, 1, 2, 3]));
ckb.close(fds[0]);
ckb.exit(42);
`;
let code_hash = new Uint8Array([
0xdf, 0x97, 0x77, 0x78, 0x08, 0x9b, 0xf3, 0x3f, 0xc5, 0x1f, 0x22, 0x45, 0xfa, 0x6d, 0xb7, 0xfa,
0x18, 0x19, 0xd5, 0x03, 0x11, 0x31, 0xa8, 0x3d, 0x4e, 0xcb, 0xcb, 0x6c, 0xba, 0x07, 0xce, 0x91
]);
let fds = ckb.pipe();
let spawn_args = {
argv: ['-e', js_code],
inherited_fds: [fds[1]],
};
let pid = ckb.spawn_cell(code_hash, ckb.SCRIPT_HASH_TYPE_TYPE, 0, 0, spawn_args);
let txt = new Uint8Array(ckb.read(fds[0], 4));
console.assert(txt[0] == 0);
console.assert(txt[1] == 1);
console.assert(txt[2] == 2);
console.assert(txt[3] == 3);
let ret = ckb.wait(pid);
console.assert(ret == 42);
console.log('test_spawn done');
}

test_misc();
test_partial_loading(ckb.load_witness);
test_partial_loading(ckb.load_cell_data);
Expand All @@ -119,5 +147,6 @@ test_partial_loading_without_comparing(ckb.load_script);
test_partial_loading_without_comparing(ckb.load_cell);
test_partial_loading_field_without_comparing(ckb.load_cell_by_field, ckb.CELL_FIELD_CAPACITY);
test_partial_loading_field_without_comparing(ckb.load_input_by_field, ckb.INPUT_FIELD_OUT_POINT);
test_spawn()

ckb.exit(0);

0 comments on commit 8874a23

Please sign in to comment.