pub trait SyscallImpls {
Show 30 methods
// Provided methods
fn syscall(
&self,
_a0: u64,
_a1: u64,
_a2: u64,
_a3: u64,
_a4: u64,
_a5: u64,
_n: u64,
) -> u64 { ... }
fn syscall_load(
&self,
buf: &mut [u8],
offset: usize,
a3: u64,
a4: u64,
a5: u64,
syscall_num: u64,
) -> IoResult { ... }
fn debug(&self, s: &CStr) { ... }
fn exit(&self, code: i8) -> ! { ... }
fn load_cell(
&self,
buf: &mut [u8],
offset: usize,
index: usize,
source: Source,
) -> IoResult { ... }
fn load_cell_by_field(
&self,
buf: &mut [u8],
offset: usize,
index: usize,
source: Source,
field: CellField,
) -> IoResult { ... }
fn load_cell_code(
&self,
buf_ptr: *mut u8,
len: usize,
content_offset: usize,
content_size: usize,
index: usize,
source: Source,
) -> Result<(), Error> { ... }
fn load_cell_data(
&self,
buf: &mut [u8],
offset: usize,
index: usize,
source: Source,
) -> IoResult { ... }
fn load_header(
&self,
buf: &mut [u8],
offset: usize,
index: usize,
source: Source,
) -> IoResult { ... }
fn load_header_by_field(
&self,
buf: &mut [u8],
offset: usize,
index: usize,
source: Source,
field: HeaderField,
) -> IoResult { ... }
fn load_input(
&self,
buf: &mut [u8],
offset: usize,
index: usize,
source: Source,
) -> IoResult { ... }
fn load_input_by_field(
&self,
buf: &mut [u8],
offset: usize,
index: usize,
source: Source,
field: InputField,
) -> IoResult { ... }
fn load_script(&self, buf: &mut [u8], offset: usize) -> IoResult { ... }
fn load_script_hash(&self, buf: &mut [u8], offset: usize) -> IoResult { ... }
fn load_transaction(&self, buf: &mut [u8], offset: usize) -> IoResult { ... }
fn load_tx_hash(&self, buf: &mut [u8], offset: usize) -> IoResult { ... }
fn load_witness(
&self,
buf: &mut [u8],
offset: usize,
index: usize,
source: Source,
) -> IoResult { ... }
fn vm_version(&self) -> u64 { ... }
fn current_cycles(&self) -> u64 { ... }
fn exec(
&self,
index: usize,
source: Source,
place: usize,
bounds: usize,
argv: &[&CStr],
) -> Result<(), Error> { ... }
fn spawn(
&self,
index: usize,
source: Source,
place: usize,
bounds: usize,
argv: &[&CStr],
inherited_fds: &[u64],
) -> Result<u64, Error> { ... }
fn pipe(&self) -> Result<(u64, u64), Error> { ... }
fn inherited_fds(&self, fds: &mut [u64]) -> Result<usize, Error> { ... }
fn read(&self, fd: u64, buffer: &mut [u8]) -> Result<usize, Error> { ... }
fn write(&self, fd: u64, buffer: &[u8]) -> Result<usize, Error> { ... }
fn close(&self, fd: u64) -> Result<(), Error> { ... }
fn wait(&self, pid: u64) -> Result<i8, Error> { ... }
fn process_id(&self) -> u64 { ... }
fn load_block_extension(
&self,
buf: &mut [u8],
offset: usize,
index: usize,
source: Source,
) -> IoResult { ... }
fn debug_s(&self, s: String) { ... }
}
Expand description
This trait serves several purposes:
- Current ckb-std syscall implementations were written at different
time with different mindsets, and accumulated throughout the years.
As a result, it presents certain inconsistencies and issues. Just to
name a few:
- The newly introduced read syscall interprets its return values
differently from old
load_*
syscalls. However they share the same return value type, which can be a source of confusion. - Some signature design could use a little work: for example, spawn
sets returned process ID both in one of the mutable argument, and
also in its return values. This is really duplicate information that
can be revisited. In addition, the
argv
data structured, used by both spawn and exec, are passed differently in both syscalls. In hindset, maybe we don’t need to expose the C styleSpawnArgs
structure in Rust APIs, but keep it as an internal data structure. - The return value of inherited_fds syscall is completely ignored, only the length of written fds is returned.
- The newly introduced read syscall interprets its return values
differently from old
- New features such as native simulators, or fuzzing require customized syscall implementations. There is no proper way we can customize a CKB script for alternative syscall implementations.
On the other hand, compatibility remains a consideration, it might not be possible to alter current syscall implementations, which might affect real usage.
This trait aims to provide a new solution, where all CKB syscalls can be provided by a single trait. It also attempts to clear and unify syscall APIs, in a clear and easy to understand fashion.
Provided Methods§
Sourcefn syscall(
&self,
_a0: u64,
_a1: u64,
_a2: u64,
_a3: u64,
_a4: u64,
_a5: u64,
_n: u64,
) -> u64
fn syscall( &self, _a0: u64, _a1: u64, _a2: u64, _a3: u64, _a4: u64, _a5: u64, _n: u64, ) -> u64
There are 2 ways you can implement this trait: you can either implement
this generic syscall function, where you detect the syscall by the last
n
field, or you can implement each invididual syscall in a type-safe
way. Dummy implementations are provided for each trait method so one can
override only the needed ones.
fn syscall_load( &self, buf: &mut [u8], offset: usize, a3: u64, a4: u64, a5: u64, syscall_num: u64, ) -> IoResult
fn debug(&self, s: &CStr)
fn exit(&self, code: i8) -> !
fn load_cell( &self, buf: &mut [u8], offset: usize, index: usize, source: Source, ) -> IoResult
fn load_cell_by_field( &self, buf: &mut [u8], offset: usize, index: usize, source: Source, field: CellField, ) -> IoResult
fn load_cell_code( &self, buf_ptr: *mut u8, len: usize, content_offset: usize, content_size: usize, index: usize, source: Source, ) -> Result<(), Error>
fn load_cell_data( &self, buf: &mut [u8], offset: usize, index: usize, source: Source, ) -> IoResult
fn load_header( &self, buf: &mut [u8], offset: usize, index: usize, source: Source, ) -> IoResult
fn load_header_by_field( &self, buf: &mut [u8], offset: usize, index: usize, source: Source, field: HeaderField, ) -> IoResult
fn load_input( &self, buf: &mut [u8], offset: usize, index: usize, source: Source, ) -> IoResult
fn load_input_by_field( &self, buf: &mut [u8], offset: usize, index: usize, source: Source, field: InputField, ) -> IoResult
fn load_script(&self, buf: &mut [u8], offset: usize) -> IoResult
fn load_script_hash(&self, buf: &mut [u8], offset: usize) -> IoResult
fn load_transaction(&self, buf: &mut [u8], offset: usize) -> IoResult
fn load_tx_hash(&self, buf: &mut [u8], offset: usize) -> IoResult
fn load_witness( &self, buf: &mut [u8], offset: usize, index: usize, source: Source, ) -> IoResult
fn vm_version(&self) -> u64
fn current_cycles(&self) -> u64
fn exec( &self, index: usize, source: Source, place: usize, bounds: usize, argv: &[&CStr], ) -> Result<(), Error>
Sourcefn spawn(
&self,
index: usize,
source: Source,
place: usize,
bounds: usize,
argv: &[&CStr],
inherited_fds: &[u64],
) -> Result<u64, Error>
fn spawn( &self, index: usize, source: Source, place: usize, bounds: usize, argv: &[&CStr], inherited_fds: &[u64], ) -> Result<u64, Error>
Spawned process ID is returned when the syscall succeeds
fn pipe(&self) -> Result<(u64, u64), Error>
Sourcefn inherited_fds(&self, fds: &mut [u64]) -> Result<usize, Error>
fn inherited_fds(&self, fds: &mut [u64]) -> Result<usize, Error>
Number of available fds is returned when the syscall succeeds, which
can be bigger than the length of the passed argument fds
slice
Sourcefn read(&self, fd: u64, buffer: &mut [u8]) -> Result<usize, Error>
fn read(&self, fd: u64, buffer: &mut [u8]) -> Result<usize, Error>
Number of read bytes is returned when the syscall succeeds. Note
this syscall works unlike the load_*
syscalls, it only returns
the number of bytes read to passed buffer. The syscall has no way
of knowing how many bytes are availble to read.
Sourcefn write(&self, fd: u64, buffer: &[u8]) -> Result<usize, Error>
fn write(&self, fd: u64, buffer: &[u8]) -> Result<usize, Error>
Number of written bytes is returned when the syscall succeeds.
fn close(&self, fd: u64) -> Result<(), Error>
Sourcefn wait(&self, pid: u64) -> Result<i8, Error>
fn wait(&self, pid: u64) -> Result<i8, Error>
Exit code of waited process is returned when the syscall succeeds.