#ifndef CKB_C_STDLIB_CKB_SYSCALLS_H_
#define CKB_C_STDLIB_CKB_SYSCALLS_H_
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "ckb_consts.h"
#include "ckb_syscall_apis.h"
int ckb_checked_load_tx_hash(void* addr, uint64_t* len, size_t offset) {
uint64_t old_len = *len;
int ret = ckb_load_tx_hash(addr, len, offset);
if (ret == CKB_SUCCESS && (*len) > old_len) {
ret = CKB_LENGTH_NOT_ENOUGH;
}
return ret;
}
int ckb_checked_load_script_hash(void* addr, uint64_t* len, size_t offset) {
uint64_t old_len = *len;
int ret = ckb_load_script_hash(addr, len, offset);
if (ret == CKB_SUCCESS && (*len) > old_len) {
ret = CKB_LENGTH_NOT_ENOUGH;
}
return ret;
}
int ckb_checked_load_cell(void* addr, uint64_t* len, size_t offset,
size_t index, size_t source) {
uint64_t old_len = *len;
int ret = ckb_load_cell(addr, len, offset, index, source);
if (ret == CKB_SUCCESS && (*len) > old_len) {
ret = CKB_LENGTH_NOT_ENOUGH;
}
return ret;
}
int ckb_checked_load_input(void* addr, uint64_t* len, size_t offset,
size_t index, size_t source) {
uint64_t old_len = *len;
int ret = ckb_load_input(addr, len, offset, index, source);
if (ret == CKB_SUCCESS && (*len) > old_len) {
ret = CKB_LENGTH_NOT_ENOUGH;
}
return ret;
}
int ckb_checked_load_header(void* addr, uint64_t* len, size_t offset,
size_t index, size_t source) {
uint64_t old_len = *len;
int ret = ckb_load_header(addr, len, offset, index, source);
if (ret == CKB_SUCCESS && (*len) > old_len) {
ret = CKB_LENGTH_NOT_ENOUGH;
}
return ret;
}
int ckb_checked_load_witness(void* addr, uint64_t* len, size_t offset,
size_t index, size_t source) {
uint64_t old_len = *len;
int ret = ckb_load_witness(addr, len, offset, index, source);
if (ret == CKB_SUCCESS && (*len) > old_len) {
ret = CKB_LENGTH_NOT_ENOUGH;
}
return ret;
}
int ckb_checked_load_script(void* addr, uint64_t* len, size_t offset) {
uint64_t old_len = *len;
int ret = ckb_load_script(addr, len, offset);
if (ret == CKB_SUCCESS && (*len) > old_len) {
ret = CKB_LENGTH_NOT_ENOUGH;
}
return ret;
}
int ckb_checked_load_transaction(void* addr, uint64_t* len, size_t offset) {
uint64_t old_len = *len;
int ret = ckb_load_transaction(addr, len, offset);
if (ret == CKB_SUCCESS && (*len) > old_len) {
ret = CKB_LENGTH_NOT_ENOUGH;
}
return ret;
}
int ckb_checked_load_cell_by_field(void* addr, uint64_t* len, size_t offset,
size_t index, size_t source, size_t field) {
uint64_t old_len = *len;
int ret = ckb_load_cell_by_field(addr, len, offset, index, source, field);
if (ret == CKB_SUCCESS && (*len) > old_len) {
ret = CKB_LENGTH_NOT_ENOUGH;
}
return ret;
}
int ckb_checked_load_header_by_field(void* addr, uint64_t* len, size_t offset,
size_t index, size_t source,
size_t field) {
uint64_t old_len = *len;
int ret = ckb_load_header_by_field(addr, len, offset, index, source, field);
if (ret == CKB_SUCCESS && (*len) > old_len) {
ret = CKB_LENGTH_NOT_ENOUGH;
}
return ret;
}
int ckb_checked_load_input_by_field(void* addr, uint64_t* len, size_t offset,
size_t index, size_t source, size_t field) {
uint64_t old_len = *len;
int ret = ckb_load_input_by_field(addr, len, offset, index, source, field);
if (ret == CKB_SUCCESS && (*len) > old_len) {
ret = CKB_LENGTH_NOT_ENOUGH;
}
return ret;
}
int ckb_checked_load_cell_data(void* addr, uint64_t* len, size_t offset,
size_t index, size_t source) {
uint64_t old_len = *len;
int ret = ckb_load_cell_data(addr, len, offset, index, source);
if (ret == CKB_SUCCESS && (*len) > old_len) {
ret = CKB_LENGTH_NOT_ENOUGH;
}
return ret;
}
int ckb_load_actual_type_witness(uint8_t* buf, uint64_t* len, size_t index,
size_t* type_source) {
*type_source = CKB_SOURCE_GROUP_INPUT;
uint64_t tmp_len = 0;
if (ckb_load_cell_by_field(NULL, &tmp_len, 0, 0, CKB_SOURCE_GROUP_INPUT,
CKB_CELL_FIELD_CAPACITY) ==
CKB_INDEX_OUT_OF_BOUND) {
*type_source = CKB_SOURCE_GROUP_OUTPUT;
}
return ckb_checked_load_witness(buf, len, 0, index, *type_source);
}
int ckb_calculate_inputs_len() {
uint64_t len = 0;
int lo = 0;
int hi = 4;
int ret;
while (1) {
ret = ckb_load_input_by_field(NULL, &len, 0, hi, CKB_SOURCE_INPUT,
CKB_INPUT_FIELD_SINCE);
if (ret == CKB_SUCCESS) {
lo = hi;
hi *= 2;
} else {
break;
}
}
int i;
while (lo + 1 != hi) {
i = (lo + hi) / 2;
ret = ckb_load_input_by_field(NULL, &len, 0, i, CKB_SOURCE_INPUT,
CKB_INPUT_FIELD_SINCE);
if (ret == CKB_SUCCESS) {
lo = i;
} else {
hi = i;
}
}
return hi;
}
int ckb_look_for_dep_with_hash2(const uint8_t* code_hash, uint8_t hash_type,
size_t* index) {
size_t current = 0;
size_t field =
(hash_type == 1) ? CKB_CELL_FIELD_TYPE_HASH : CKB_CELL_FIELD_DATA_HASH;
while (current < SIZE_MAX) {
uint64_t len = 32;
uint8_t hash[32];
int ret = ckb_load_cell_by_field(hash, &len, 0, current,
CKB_SOURCE_CELL_DEP, field);
switch (ret) {
case CKB_ITEM_MISSING:
break;
case CKB_SUCCESS:
if (memcmp(code_hash, hash, 32) == 0) {
*index = current;
return CKB_SUCCESS;
}
break;
default:
return CKB_INDEX_OUT_OF_BOUND;
}
current++;
}
return CKB_INDEX_OUT_OF_BOUND;
}
int ckb_look_for_dep_with_hash(const uint8_t* data_hash, size_t* index) {
return ckb_look_for_dep_with_hash2(data_hash, 0, index);
}
#ifndef CKB_STDLIB_NO_SYSCALL_IMPL
#define memory_barrier() asm volatile("fence" ::: "memory")
static inline long __internal_syscall(long n, long _a0, long _a1, long _a2,
long _a3, long _a4, long _a5) {
register long a0 asm("a0") = _a0;
register long a1 asm("a1") = _a1;
register long a2 asm("a2") = _a2;
register long a3 asm("a3") = _a3;
register long a4 asm("a4") = _a4;
register long a5 asm("a5") = _a5;
#ifdef __riscv_32e
register long syscall_id asm("t0") = n;
#else
register long syscall_id asm("a7") = n;
#endif
asm volatile("scall"
: "+r"(a0)
: "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a5), "r"(syscall_id));
memory_barrier();
return a0;
}
#define syscall(n, a, b, c, d, e, f) \
__internal_syscall(n, (long)(a), (long)(b), (long)(c), (long)(d), (long)(e), \
(long)(f))
int ckb_exit(int8_t code) { return syscall(SYS_exit, code, 0, 0, 0, 0, 0); }
int ckb_load_tx_hash(void* addr, uint64_t* len, size_t offset) {
volatile uint64_t inner_len = *len;
int ret = syscall(SYS_ckb_load_tx_hash, addr, &inner_len, offset, 0, 0, 0);
*len = inner_len;
return ret;
}
int ckb_load_script_hash(void* addr, uint64_t* len, size_t offset) {
volatile uint64_t inner_len = *len;
int ret =
syscall(SYS_ckb_load_script_hash, addr, &inner_len, offset, 0, 0, 0);
*len = inner_len;
return ret;
}
int ckb_load_cell(void* addr, uint64_t* len, size_t offset, size_t index,
size_t source) {
volatile uint64_t inner_len = *len;
int ret =
syscall(SYS_ckb_load_cell, addr, &inner_len, offset, index, source, 0);
*len = inner_len;
return ret;
}
int ckb_load_input(void* addr, uint64_t* len, size_t offset, size_t index,
size_t source) {
volatile uint64_t inner_len = *len;
int ret =
syscall(SYS_ckb_load_input, addr, &inner_len, offset, index, source, 0);
*len = inner_len;
return ret;
}
int ckb_load_header(void* addr, uint64_t* len, size_t offset, size_t index,
size_t source) {
volatile uint64_t inner_len = *len;
int ret =
syscall(SYS_ckb_load_header, addr, &inner_len, offset, index, source, 0);
*len = inner_len;
return ret;
}
int ckb_load_witness(void* addr, uint64_t* len, size_t offset, size_t index,
size_t source) {
volatile uint64_t inner_len = *len;
int ret =
syscall(SYS_ckb_load_witness, addr, &inner_len, offset, index, source, 0);
*len = inner_len;
return ret;
}
int ckb_load_script(void* addr, uint64_t* len, size_t offset) {
volatile uint64_t inner_len = *len;
int ret = syscall(SYS_ckb_load_script, addr, &inner_len, offset, 0, 0, 0);
*len = inner_len;
return ret;
}
int ckb_load_transaction(void* addr, uint64_t* len, size_t offset) {
volatile uint64_t inner_len = *len;
int ret =
syscall(SYS_ckb_load_transaction, addr, &inner_len, offset, 0, 0, 0);
*len = inner_len;
return ret;
}
int ckb_load_cell_by_field(void* addr, uint64_t* len, size_t offset,
size_t index, size_t source, size_t field) {
volatile uint64_t inner_len = *len;
int ret = syscall(SYS_ckb_load_cell_by_field, addr, &inner_len, offset, index,
source, field);
*len = inner_len;
return ret;
}
int ckb_load_header_by_field(void* addr, uint64_t* len, size_t offset,
size_t index, size_t source, size_t field) {
volatile uint64_t inner_len = *len;
int ret = syscall(SYS_ckb_load_header_by_field, addr, &inner_len, offset,
index, source, field);
*len = inner_len;
return ret;
}
int ckb_load_input_by_field(void* addr, uint64_t* len, size_t offset,
size_t index, size_t source, size_t field) {
volatile uint64_t inner_len = *len;
int ret = syscall(SYS_ckb_load_input_by_field, addr, &inner_len, offset,
index, source, field);
*len = inner_len;
return ret;
}
int ckb_load_cell_data(void* addr, uint64_t* len, size_t offset, size_t index,
size_t source) {
volatile uint64_t inner_len = *len;
int ret = syscall(SYS_ckb_load_cell_data, addr, &inner_len, offset, index,
source, 0);
*len = inner_len;
return ret;
}
int ckb_debug(const char* s) {
return syscall(SYS_ckb_debug, s, 0, 0, 0, 0, 0);
}
int ckb_vm_version() { return syscall(SYS_ckb_vm_version, 0, 0, 0, 0, 0, 0); }
uint64_t ckb_current_cycles() {
return syscall(SYS_ckb_current_cycles, 0, 0, 0, 0, 0, 0);
}
int ckb_exec_cell(const uint8_t* code_hash, uint8_t hash_type, uint32_t offset,
uint32_t length, int argc, const char* argv[]) {
size_t index = SIZE_MAX;
int ret = ckb_look_for_dep_with_hash2(code_hash, hash_type, &index);
if (ret != CKB_SUCCESS) {
return ret;
}
size_t bounds = ((size_t)offset << 32) | length;
return syscall(SYS_ckb_exec, index, CKB_SOURCE_CELL_DEP, 0, bounds, argc,
argv);
}
int ckb_spawn(size_t index, size_t source, size_t place, size_t bounds,
spawn_args_t* spawn_args) {
return syscall(SYS_ckb_spawn, index, source, place, bounds, spawn_args, 0);
}
int ckb_spawn_cell(const uint8_t* code_hash, uint8_t hash_type, uint32_t offset,
uint32_t length, spawn_args_t* spawn_args) {
size_t index = SIZE_MAX;
int ret = ckb_look_for_dep_with_hash2(code_hash, hash_type, &index);
if (ret != CKB_SUCCESS) {
return ret;
}
size_t bounds = ((size_t)offset << 32) | length;
return syscall(SYS_ckb_spawn, index, CKB_SOURCE_CELL_DEP, 0, bounds,
spawn_args, 0);
}
int ckb_wait(uint64_t pid, int8_t* exit_code) {
return syscall(SYS_ckb_wait, pid, exit_code, 0, 0, 0, 0);
}
uint64_t ckb_process_id() {
return syscall(SYS_ckb_process_id, 0, 0, 0, 0, 0, 0);
}
int ckb_pipe(uint64_t fds[2]) {
return syscall(SYS_ckb_pipe, fds, 0, 0, 0, 0, 0);
}
int ckb_read(uint64_t fd, void* buffer, size_t* length) {
volatile size_t l = *length;
int ret = syscall(SYS_ckb_read, fd, buffer, &l, 0, 0, 0);
*length = l;
return ret;
}
int ckb_write(uint64_t fd, const void* buffer, size_t* length) {
volatile size_t l = *length;
int ret = syscall(SYS_ckb_write, fd, buffer, &l, 0, 0, 0);
*length = l;
return ret;
}
int ckb_load_block_extension(void* addr, uint64_t* len, size_t offset,
size_t index, size_t source) {
return syscall(SYS_ckb_load_block_extension, addr, len, offset, index, source,
0);
}
int ckb_inherited_fds(uint64_t* fds, size_t* length) {
volatile size_t l = *length;
int ret = syscall(SYS_ckb_inherited_fds, fds, &l, 0, 0, 0, 0);
*length = l;
return ret;
}
int ckb_close(uint64_t fd) { return syscall(SYS_ckb_close, fd, 0, 0, 0, 0, 0); }
#endif
#endif