Skip to main content

fluentbase_runtime/syscall_handler/host/
resume.rs

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