Skip to content

Commit 379d4a2

Browse files
authored
Merge pull request #17 from TheWaWaR/add-ckb2021-syscalls
feat: add ckb2021 syscalls: vm_version, current_cycles, exec
2 parents 3939759 + 0361d47 commit 379d4a2

File tree

19 files changed

+435
-22
lines changed

19 files changed

+435
-22
lines changed

Cargo.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "ckb-std"
3-
version = "0.8.0"
3+
version = "0.9.0"
44
authors = ["Nervos network"]
55
edition = "2018"
66
license = "MIT"
@@ -19,6 +19,7 @@ simulator = [ "ckb-x64-simulator" ]
1919
cc = "1.0"
2020

2121
[dependencies]
22-
ckb-types = { package = "ckb-standalone-types", version = "0.1.1", default-features = false, optional = true }
22+
cstr_core = { version = "0.2.4", default-features = false, features = ["alloc"] }
23+
ckb-types = { package = "ckb-standalone-types", version = "0.1.2", default-features = false, optional = true }
2324
buddy-alloc = { version = "0.4.1", optional = true }
2425
ckb-x64-simulator = { version = "0.5.0", optional = true }

examples/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#![no_std]
22
#![no_main]
3+
#![feature(asm)]
34
#![feature(lang_items)]
45
#![feature(alloc_error_handler)]
56
#![feature(panic_info_message)]

src/ckb_constants.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
pub const SYS_EXIT: u64 = 93;
2+
pub const SYS_VM_VERSION: u64 = 2041;
3+
pub const SYS_CURRENT_CYCLES: u64 = 2042;
4+
pub const SYS_EXEC: u64 = 2043;
25
pub const SYS_LOAD_TRANSACTION: u64 = 2051;
36
pub const SYS_LOAD_SCRIPT: u64 = 2052;
47
pub const SYS_LOAD_TX_HASH: u64 = 2061;

src/entry.rs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,34 @@ macro_rules! entry {
1919

2020
#[no_mangle]
2121
pub extern "C" fn _start() -> ! {
22-
let f: fn() -> i8 = $main;
23-
$crate::syscalls::exit(f())
22+
#[cfg(target_arch = "riscv64")]
23+
unsafe {
24+
asm!(
25+
"lw a0, 0(sp)",
26+
"addi a1, sp, 8",
27+
"li a2, 0",
28+
"call {}",
29+
"li a7, 93",
30+
"ecall",
31+
sym $main,
32+
options(noreturn)
33+
);
34+
}
35+
#[cfg(not(target_arch = "riscv64"))]
36+
unsafe {
37+
asm!(
38+
"mov rsp, rdi",
39+
"mov rsp, rsi",
40+
"add 8, rsi",
41+
"mov 0 rdx",
42+
"call {}",
43+
"mov rax rdi",
44+
"mov 60 rax",
45+
"syscall",
46+
sym $main,
47+
options(noreturn)
48+
);
49+
}
2450
}
2551

2652
#[lang = "eh_personality"]

src/error.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ impl SysError {
2626
if actual_data_len > load_len {
2727
return Err(LengthNotEnough(actual_data_len));
2828
}
29-
return Ok(actual_data_len);
29+
Ok(actual_data_len)
3030
}
3131
1 => Err(IndexOutOfBound),
3232
2 => Err(ItemMissing),

src/high_level.rs

Lines changed: 59 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ use crate::ckb_constants::*;
22
use crate::debug;
33
use crate::error::SysError;
44
use crate::syscalls;
5-
use alloc::vec::Vec;
6-
use ckb_types::{packed::*, prelude::*};
5+
use alloc::{vec, vec::Vec};
6+
use ckb_types::{core::ScriptHashType, packed::*, prelude::*};
7+
use cstr_core::CStr;
78

89
/// Default buffer size
910
pub const BUF_SIZE: usize = 1024;
@@ -48,8 +49,7 @@ fn load_data<F: Fn(&mut [u8], usize) -> Result<usize, SysError>>(
4849
match syscall(&mut buf, 0) {
4950
Ok(len) => Ok(buf[..len].to_vec()),
5051
Err(SysError::LengthNotEnough(actual_size)) => {
51-
let mut data = Vec::with_capacity(actual_size);
52-
data.resize(actual_size, 0);
52+
let mut data = vec![0; actual_size];
5353
let loaded_len = buf.len();
5454
data[..loaded_len].copy_from_slice(&buf);
5555
let len = syscall(&mut data[loaded_len..], loaded_len)?;
@@ -554,3 +554,58 @@ pub fn find_cell_by_data_hash(data_hash: &[u8], source: Source) -> Result<Option
554554
}
555555
Ok(None)
556556
}
557+
558+
/// Look for a dep cell with specific code hash, code_hash should be a buffer
559+
/// with 32 bytes.
560+
///
561+
pub fn look_for_dep_with_hash2(
562+
code_hash: &[u8],
563+
hash_type: ScriptHashType,
564+
) -> Result<usize, SysError> {
565+
let field = match hash_type {
566+
ScriptHashType::Type => CellField::TypeHash,
567+
_ => CellField::DataHash,
568+
};
569+
let mut current: usize = 0;
570+
loop {
571+
let mut buf = [0u8; 32];
572+
match syscalls::load_cell_by_field(&mut buf, 0, current, Source::CellDep, field) {
573+
Ok(len) => {
574+
debug_assert_eq!(len, buf.len());
575+
if buf == code_hash {
576+
return Ok(current);
577+
}
578+
}
579+
Err(SysError::ItemMissing) => {}
580+
Err(SysError::IndexOutOfBound) => {
581+
return Err(SysError::IndexOutOfBound);
582+
}
583+
Err(err) => {
584+
return Err(err);
585+
}
586+
}
587+
current += 1;
588+
}
589+
}
590+
591+
pub fn look_for_dep_with_data_hash(data_hash: &[u8]) -> Result<usize, SysError> {
592+
look_for_dep_with_hash2(data_hash, ScriptHashType::Data)
593+
}
594+
595+
/// Exec a cell in cell dep.
596+
///
597+
/// # Arguments
598+
///
599+
/// * `code_hash` - the code hash to search cell in cell deps.
600+
/// * `hash_type` - the hash type to search cell in cell deps.
601+
pub fn exec_cell(
602+
code_hash: &[u8],
603+
hash_type: ScriptHashType,
604+
offset: u32,
605+
length: u32,
606+
argv: &[&CStr],
607+
) -> Result<u64, SysError> {
608+
let index = look_for_dep_with_hash2(code_hash, hash_type)?;
609+
let bounds: usize = (offset as usize) << 32 | (length as usize);
610+
Ok(syscalls::exec(index, Source::CellDep, 0, bounds, argv))
611+
}

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,4 @@ pub mod dynamic_loading;
2828
pub mod dynamic_loading_c_impl;
2929
#[cfg(feature = "allocator")]
3030
pub use buddy_alloc;
31+
pub use cstr_core;

src/syscalls/native.rs

Lines changed: 83 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::{ckb_constants::*, error::SysError};
2+
use cstr_core::CStr;
23

34
#[cfg(target_arch = "riscv64")]
45
#[link(name = "ckb-syscall")]
@@ -7,8 +8,17 @@ extern "C" {
78
}
89

910
#[cfg(not(target_arch = "riscv64"))]
10-
fn syscall(a0: u64, a1: u64, a2: u64, a3: u64, a4: u64, a5: u64, a6: u64, a7: u64) -> u64 {
11-
return u64::MAX;
11+
unsafe fn syscall(
12+
_a0: u64,
13+
_a1: u64,
14+
_a2: u64,
15+
_a3: u64,
16+
_a4: u64,
17+
_a5: u64,
18+
_a6: u64,
19+
_a7: u64,
20+
) -> u64 {
21+
u64::MAX
1222
}
1323

1424
/// Exit, this script will be terminated after the exit syscall.
@@ -480,3 +490,74 @@ pub fn load_cell_code(
480490
};
481491
SysError::build_syscall_result(ret, len, len)
482492
}
493+
494+
/// *VM version* syscall returns current running VM version, so far 2 values will be returned:
495+
/// - Error for Lina CKB-VM version
496+
/// - 1 for the new hardfork CKB-VM version.
497+
///
498+
/// This syscall consumes 500 cycles.
499+
pub fn vm_version() -> Result<u64, SysError> {
500+
let ret = unsafe { syscall(0, 0, 0, 0, 0, 0, 0, SYS_VM_VERSION) };
501+
if ret == 1 {
502+
Ok(1)
503+
} else {
504+
Err(SysError::Unknown(ret))
505+
}
506+
}
507+
508+
/// *Current Cycles* returns current cycle consumption just before executing this syscall.
509+
/// This syscall consumes 500 cycles.
510+
pub fn current_cycles() -> u64 {
511+
unsafe { syscall(0, 0, 0, 0, 0, 0, 0, SYS_CURRENT_CYCLES) }
512+
}
513+
514+
/// Exec runs an executable file from specified cell data in the context of an
515+
/// already existing machine, replacing the previous executable. The used cycles
516+
/// does not change, but the code, registers and memory of the vm are replaced
517+
/// by those of the new program. It's cycles consumption consists of two parts:
518+
///
519+
/// - Fixed 500 cycles
520+
/// - Initial Loading Cycles (https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0014-vm-cycle-limits/0014-vm-cycle-limits.md)
521+
///
522+
/// The arguments used here are:
523+
///
524+
/// * `index`: an index value denoting the index of entries to read.
525+
/// * `source`: a flag denoting the source of cells or witnesses to locate, possible values include:
526+
/// + 1: input cells.
527+
/// + `0x0100000000000001`: input cells with the same running script as current script
528+
/// + 2: output cells.
529+
/// + `0x0100000000000002`: output cells with the same running script as current script
530+
/// + 3: dep cells.
531+
/// * `place`: A value of 0 or 1:
532+
/// + 0: read from cell data
533+
/// + 1: read from witness
534+
/// * `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.
535+
/// * `argc`: argc contains the number of arguments passed to the program
536+
/// * `argv`: argv is a one-dimensional array of strings
537+
pub fn exec(
538+
index: usize,
539+
source: Source,
540+
place: usize,
541+
bounds: usize,
542+
// argc: i32,
543+
argv: &[&CStr],
544+
) -> u64 {
545+
// https://www.gnu.org/software/libc/manual/html_node/Program-Arguments.html
546+
let argc = argv.len();
547+
let mut argv_ptr = alloc::vec![core::ptr::null(); argc + 1];
548+
for (idx, cstr) in argv.into_iter().enumerate() {
549+
argv_ptr[idx] = cstr.as_ptr();
550+
}
551+
unsafe {
552+
syscall(
553+
index as u64,
554+
source as u64,
555+
place as u64,
556+
bounds as u64,
557+
argc as u64,
558+
argv_ptr.as_ptr() as u64,
559+
0,
560+
SYS_EXEC,
561+
)
562+
}
563+
}

test/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@ edition = "2018"
77
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
88

99
[dependencies]
10-
ckb-testtool = "0.5"
10+
ckb-testtool = "0.6.1"

test/Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,12 @@ build:
66
cd contract && cargo build
77

88
C := contract/target/riscv64imac-unknown-none-elf/debug/contract
9+
EXEC_CALLER := contract/target/riscv64imac-unknown-none-elf/debug/exec-caller
10+
EXEC_CALLEE := contract/target/riscv64imac-unknown-none-elf/debug/exec-callee
911
patch:
1012
ckb-binary-patcher -i $C -o $C
13+
ckb-binary-patcher -i ${EXEC_CALLER} -o ${EXEC_CALLER}
14+
ckb-binary-patcher -i ${EXEC_CALLEE} -o ${EXEC_CALLEE}
1115

1216
clean:
1317
cd contract && cargo clean

0 commit comments

Comments
 (0)