-
Notifications
You must be signed in to change notification settings - Fork 158
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
7248f62
commit ba822fe
Showing
1 changed file
with
154 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
--- | ||
Number: "0147" | ||
Category: Standards Track | ||
Status: Draft | ||
Author: Xu Jiandong <lynndon@gmail.com>, Dingwei Zhang <zhangsoledad@gmail.com> | ||
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 <stdint.h> | ||
#include <string.h> | ||
#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 <stdint.h> | ||
#include <string.h> | ||
|
||
#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; | ||
} | ||
``` |