ckb_ssri_std/utils/syscalls/
native.rs

1#[cfg(target_arch = "riscv64")]
2use core::arch::asm;
3
4use ckb_std::{ckb_constants::SYS_VM_VERSION, error::SysError};
5
6/// System call number for finding an OutPoint by type script
7pub const SYS_FIND_OUT_POINT_BY_TYPE: u64 = 2277;
8/// System call number for finding a cell by OutPoint
9pub const SYS_FIND_CELL_BY_OUT_POINT: u64 = 2287;
10/// System call number for finding cell data by OutPoint
11pub const SYS_FIND_CELL_DATA_BY_OUT_POINT: u64 = 2297;
12
13#[cfg(target_arch = "riscv64")]
14#[allow(clippy::too_many_arguments)]
15pub unsafe fn syscall(
16    mut a0: u64,
17    a1: u64,
18    a2: u64,
19    a3: u64,
20    a4: u64,
21    a5: u64,
22    a6: u64,
23    a7: u64,
24) -> u64 {
25    asm!(
26        "ecall",
27        inout("a0") a0,
28        in("a1") a1,
29        in("a2") a2,
30        in("a3") a3,
31        in("a4") a4,
32        in("a5") a5,
33        in("a6") a6,
34        in("a7") a7
35    );
36    a0
37}
38
39#[cfg(not(target_arch = "riscv64"))]
40#[allow(clippy::too_many_arguments)]
41pub unsafe fn syscall(
42    _a0: u64,
43    _a1: u64,
44    _a2: u64,
45    _a3: u64,
46    _a4: u64,
47    _a5: u64,
48    _a6: u64,
49    _a7: u64,
50) -> u64 {
51    u64::MAX
52}
53
54pub fn vm_version() -> u64 {
55    unsafe { syscall(0, 0, 0, 0, 0, 0, 0, SYS_VM_VERSION) }
56}
57
58
59
60/// Load data
61/// Return data length or syscall error
62fn syscall_load(
63    buf_ptr: *mut u8,
64    len: usize,
65    a2: usize,
66    a3: u64,
67    a4: u64,
68    a5: u64,
69    a6: u64,
70    syscall_num: u64,
71) -> Result<usize, SysError> {
72    let mut actual_data_len = len;
73    let len_ptr: *mut usize = &mut actual_data_len;
74    let ret = unsafe {
75        syscall(
76            buf_ptr as u64,
77            len_ptr as u64,
78            a2 as u64,
79            a3,
80            a4,
81            a5,
82            a6,
83            syscall_num,
84        )
85    };
86    build_syscall_result(ret, len, actual_data_len)
87}
88
89fn build_syscall_result(
90    errno: u64,
91    load_len: usize,
92    actual_data_len: usize,
93) -> Result<usize, SysError> {
94    use SysError::*;
95
96    match errno {
97        0 => {
98            if actual_data_len > load_len {
99                return Err(LengthNotEnough(actual_data_len));
100            }
101            Ok(actual_data_len)
102        }
103        1 => Err(IndexOutOfBound),
104        2 => Err(ItemMissing),
105        _ => Err(Unknown(errno)),
106    }
107}
108
109
110/// Find an OutPoint by searching for a specific type script
111///
112/// Searches for a cell with the given type script and returns its OutPoint.
113/// The OutPoint data is written to the provided buffer.
114///
115/// # Arguments
116///
117/// * `buf` - A mutable buffer to receive the OutPoint data
118/// * `type_script` - The serialized type script to search for
119///
120/// # Returns
121///
122/// * `Ok(usize)` - The actual length of the OutPoint data written to the buffer
123/// * `Err(SysError)` - A system error if the operation fails
124///
125/// # Errors
126///
127/// Returns `SysError::LengthNotEnough` if the buffer is too small to hold the data
128/// Returns `SysError::IndexOutOfBound` if the type script is invalid
129/// Returns `SysError::ItemMissing` if no matching cell is found
130pub fn find_out_point_by_type(
131    buf: &mut [u8],
132    type_script: &[u8],
133) -> Result<usize, SysError> {
134    syscall_load(
135        buf.as_mut_ptr(),
136        buf.len(),
137        type_script.as_ptr() as usize,
138        type_script.len() as u64,
139        0,
140        0,
141        0,
142        SYS_FIND_OUT_POINT_BY_TYPE,
143    )
144}
145
146/// Find a cell by its OutPoint
147///
148/// Retrieves cell information using the specified OutPoint.
149/// The cell data is written to the provided buffer.
150///
151/// # Arguments
152///
153/// * `buf` - A mutable buffer to receive the cell data
154/// * `out_point` - The serialized OutPoint identifying the cell to find
155///
156/// # Returns
157///
158/// * `Ok(usize)` - The actual length of the cell data written to the buffer
159/// * `Err(SysError)` - A system error if the operation fails
160///
161/// # Errors
162///
163/// Returns `SysError::LengthNotEnough` if the buffer is too small to hold the data
164/// Returns `SysError::IndexOutOfBound` if the OutPoint is invalid
165/// Returns `SysError::ItemMissing` if the cell cannot be found
166pub fn find_cell_by_out_point(
167    buf: &mut [u8],
168    out_point: &[u8],
169) -> Result<usize, SysError> {
170    syscall_load(
171        buf.as_mut_ptr(),
172        buf.len(),
173        out_point.as_ptr() as usize,
174        0,
175        0,
176        0,
177        0,
178        SYS_FIND_CELL_BY_OUT_POINT,
179    )
180}
181
182/// Find cell data by OutPoint
183///
184/// Retrieves the data contained in a cell identified by the specified OutPoint.
185/// The cell's data is written to the provided buffer.
186///
187/// # Arguments
188///
189/// * `buf` - A mutable buffer to receive the cell's data
190/// * `out_point` - The serialized OutPoint identifying the cell whose data to retrieve
191///
192/// # Returns
193///
194/// * `Ok(usize)` - The actual length of the cell data written to the buffer
195/// * `Err(SysError)` - A system error if the operation fails
196///
197/// # Errors
198///
199/// Returns `SysError::LengthNotEnough` if the buffer is too small to hold the data
200/// Returns `SysError::IndexOutOfBound` if the OutPoint is invalid
201/// Returns `SysError::ItemMissing` if the cell cannot be found
202pub fn find_cell_data_by_out_point(
203    buf: &mut [u8],
204    out_point: &[u8],
205) -> Result<usize, SysError> {
206    syscall_load(
207        buf.as_mut_ptr(),
208        buf.len(),
209        out_point.as_ptr() as usize,
210        0,
211        0,
212        0,
213        0,
214        SYS_FIND_CELL_DATA_BY_OUT_POINT,
215    )
216}
217