Skip to main content

fluentbase_runtime/syscall_handler/host/
resume.rs

1/// Syscall entry points for resuming a previously interrupted runtime.
2use crate::syscall_handler::syscall_process_exit_code;
3use crate::{
4    executor::{default_runtime_executor, RuntimeExecutor},
5    RuntimeContext,
6};
7use fluentbase_types::{
8    byteorder::{ByteOrder, LittleEndian},
9    ExitCode,
10};
11use rwasm::{StoreTr, TrapCode, Value};
12
13/// Handles the resume syscall. Copies return data, applies fuel, resumes the target, and writes back the exit code.
14pub fn syscall_resume_handler(
15    caller: &mut impl StoreTr<RuntimeContext>,
16    params: &[Value],
17    result: &mut [Value],
18) -> Result<(), TrapCode> {
19    let (call_id, return_data_ptr, return_data_len, exit_code, fuel16_ptr) = (
20        params[0].i32().unwrap() as u32,
21        params[1].i32().unwrap() as usize,
22        params[2].i32().unwrap() as usize,
23        params[3].i32().unwrap(),
24        params[4].i32().unwrap() as usize,
25    );
26    let return_data = caller.memory_read_into_vec(return_data_ptr, return_data_len)?;
27    let (fuel_consumed, fuel_refunded) = if fuel16_ptr > 0 {
28        let mut fuel_buffer = [0u8; 16];
29        caller.memory_read(fuel16_ptr, &mut fuel_buffer)?;
30        let fuel_consumed = LittleEndian::read_i64(&fuel_buffer[..8]) as u64;
31        let fuel_refunded = LittleEndian::read_i64(&fuel_buffer[8..]);
32        (fuel_consumed, fuel_refunded)
33    } else {
34        (0, 0)
35    };
36    let (fuel_consumed, fuel_refunded, exit_code) = syscall_resume_impl(
37        caller.data_mut(),
38        call_id,
39        &return_data,
40        exit_code,
41        fuel_consumed,
42        fuel_refunded,
43        fuel16_ptr as u32,
44    )
45    .map_err(|exit_code| syscall_process_exit_code(caller, exit_code))?;
46    if fuel16_ptr > 0 {
47        caller.memory_write(fuel16_ptr, &fuel_consumed.to_le_bytes())?;
48        caller.memory_write(fuel16_ptr + 8, &fuel_refunded.to_le_bytes())?;
49    }
50    result[0] = Value::I32(exit_code);
51    Ok(())
52}
53
54/// Resumes the runtime identified by call_id using the provided return data and fuel accounting.
55pub fn syscall_resume_impl(
56    ctx: &mut RuntimeContext,
57    call_id: u32,
58    return_data: &[u8],
59    exit_code: i32,
60    fuel_consumed: u64,
61    fuel_refunded: i64,
62    fuel16_ptr: u32,
63) -> Result<(u64, i64, i32), ExitCode> {
64    // only root can use resume function
65    if ctx.call_depth > 0 {
66        return Err(ExitCode::RootCallOnly);
67    }
68    let result = default_runtime_executor().resume(
69        call_id,
70        return_data,
71        fuel16_ptr,
72        fuel_consumed,
73        fuel_refunded,
74        exit_code,
75    );
76    // Move output into parent's return data
77    ctx.execution_result.return_data = result.output;
78    Ok((
79        result.fuel_consumed,
80        result.fuel_refunded,
81        // We return `call_id` as exit code, it's safe since exit code can't be positive
82        result.exit_code,
83    ))
84}