From ba822feb8146e973654524228c7f280164ba58be Mon Sep 17 00:00:00 2001 From: zhangsoledad <787953403@qq.com> Date: Sun, 23 Apr 2023 05:15:31 +0800 Subject: [PATCH] VM Syscalls 3 --- rfcs/0147-vm-syscalls-3/0147-vm-syscalls-3.md | 154 ++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 rfcs/0147-vm-syscalls-3/0147-vm-syscalls-3.md diff --git a/rfcs/0147-vm-syscalls-3/0147-vm-syscalls-3.md b/rfcs/0147-vm-syscalls-3/0147-vm-syscalls-3.md new file mode 100644 index 000000000..e90f03df6 --- /dev/null +++ b/rfcs/0147-vm-syscalls-3/0147-vm-syscalls-3.md @@ -0,0 +1,154 @@ +--- +Number: "0147" +Category: Standards Track +Status: Draft +Author: Xu Jiandong , Dingwei Zhang +Created: 2023-04-17 +--- + +# VM Syscalls 3 + +## Abstract + +This document describes the addition of the syscalls during the ckb-2023. This update significantly enhances the flexibility of CKB Script. + +The following three syscalls are added: + +- [Spawn] +- [Get Memory Limit] +- [Set Content] +- [Load Extension] + +### Spawn +[Spawn]: #spawn + +The syscall Spawn is the core part of this update. The *Spawn* and the latter two syscalls: *Get Memory Limit* and *Set Content* together, implement a way to call another CKB Script in a CKB Script. Unlike the *Exec*[1](../0034-vm-syscalls-2/0034-vm-syscalls-2.md) syscall, *Spawn* saves the execution context of the current script, like [posix_spawn](https://man7.org/linux/man-pages/man3/posix_spawn.3.html), the parent script blocks until the child script ends. + +```c +int ckb_spawn(uint64_t memory_limit, size_t index, size_t source, + size_t bounds, int argc, char* argv[], int8_t* exit_code, + uint8_t* content, uint64_t* content_length); +``` + +The arguments used here are: + +- `memory_limit`: an integer value denoting the memory size to use(Not including descendant children scripts), possible values include: + - 1 (0.5 M) + - 2 (1 M) + - 3 (1.5 M) + - 4 (2 M) + - 5 (2.5 M) + - 6 (3 M) + - 7 (3.5 M) + - 8 (4 M) +- `index`: an index value denoting the index of entries to read. +- `source`: a flag denoting the source of cells to locate, possible values include: + - 1: input cells. + - `0x0100000000000001`: input cells with the same running script as current script + - 2: output cells. + - `0x0100000000000002`: output cells with the same running script as current script + - 3: dep cells. +- `bounds`: high 32 bits means `offset`, low 32 bits means `length`. if `length` equals to zero, it read to end instead of reading 0 bytes. +- `argc`: argc contains the number of arguments passed to the program +- `argv`: argv is a one-dimensional array of strings +- `exit_code`: an int8 pointer denoting where we save the exit code of child script. +- `content`: a pointer to a buffer in VM memory space denoting where we would load the sub-script data. The child script will write data in this buffer via `set_content`. +- `content_length`: a pointer to a 64-bit unsigned integer in VM memory space. When calling the syscall, this memory location should store the length of the buffer specified by `content` . When returning from the syscall, CKB VM would fill in `content_length` with the actual length of the buffer. `content_length` up to 256K. + +The arguments used here `index`, `source` ,`bounds` ,`argc` and `argv` follow the usage described in *Exec*[1]. + +This syscall might return the following results: + +- 0: Success. +- 1-3: Reserved. These values are already assigned to other syscalls. +- 4: Elf format error +- 5: Exceeded max content length. +- 6: Wrong memory limit +- 7: Exceeded max peak memory + +Note that now we have a new limit called *Peak Memory Usage*. The maximum memory usage of the parent script and its descendant ********children cannot exceed this value. Currently this limit is set at 32M. + +Unlike cycles which always increase, the current memory can decrease or increase. When a child script is returned, the occupied memory is freed. This makes current memory usage lower. + + +### Get Memory Limit +[Get Memory Limit]: #get-memory-limit + +Get the maximum available memory for the current script. + +```c +int ckb_get_memory_limit(); +``` + +For the prime script, it will always return 8(4M). For the child script, it depends on the parameters set by *Spawn*. + +### Set Content +[Set Content]: #set-content + +The child script can return bytes data to the parent script through `Set Content`. + +```c +int ckb_set_content(uint8_t* content, uint64_t* length); +``` + +- Length up to 256K. +- If the written length is greater than the limit given by *Spawn*, the final written length is the minimum of the two. +- This function is optional. Not every child script needs to call this. + +- This function is optional. Not every child script needs to call this. + +## Spawn example + +Suppose we write a dependency library, the function of this library is very simple: receive parameters, then concatenates the parameters together and return to the caller. + +**lib_strcat.c** + +```c +#include +#include + +#include "ckb_syscalls.h" + +int main(int argc, char *argv[]) { + char content[80]; + for (int i = 0; i < argc; i++) { + strcat(content, argv[i]); + } + uint64_t content_size = (uint64_t)strlen(content); + ckb_set_content(&content[0], &content_size); + if (content_size != (uint64_t)strlen(content)) { + return 1; + } + return 0; +} +``` + +We can call this dependent library in the prime script. The prime script passes in two parameters "hello", "world" and checks if the return value is equal to "helloworld”: + +**prime.c** + +```c +#include +#include + +#include "ckb_syscalls.h" + +int main() { + const char *argv[] = {"hello", "world"}; + int8_t exit_code = 255; + uint8_t content[80] = {}; + uint64_t content_length = 80; + + ckb_spawn(8, 1, 3, 0, 2, argv, &exit_code, &content[0], &content_length); + if (strlen(content) != 10) { + return 1; + } + if (strcmp(content, "helloworld") != 0) { + return 1; + } + if (exit_code != 0) { + return 1; + } + return 0; +} +```