fluentbase_runtime/syscall_handler/host/
exec.rs1use crate::{
3 executor::{default_runtime_executor, RuntimeExecutor},
4 RuntimeContext,
5};
6use alloc::borrow::Cow;
7use fluentbase_types::{
8 byteorder::{ByteOrder, LittleEndian},
9 BytecodeOrHash, ExitCode, SyscallInvocationParams, B256, CALL_STACK_LIMIT,
10};
11use rwasm::{StoreTr, TrapCode, Value};
12use std::{
13 cmp::min,
14 fmt::{Debug, Display, Formatter},
15};
16
17#[derive(Clone)]
18pub struct InterruptionHolder {
20 pub params: SyscallInvocationParams,
22 pub is_root: bool,
24}
25
26impl Debug for InterruptionHolder {
27 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
28 write!(f, "runtime resume error")
29 }
30}
31
32impl Display for InterruptionHolder {
33 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
34 write!(f, "runtime resume error")
35 }
36}
37
38pub fn syscall_exec_handler(
40 caller: &mut impl StoreTr<RuntimeContext>,
41 params: &[Value],
42 _result: &mut [Value],
43) -> Result<(), TrapCode> {
44 let remaining_fuel = caller.remaining_fuel().unwrap_or(u64::MAX);
45 let (hash32_ptr, input_ptr, input_len, fuel16_ptr, state) = (
46 params[0].i32().unwrap() as usize,
47 params[1].i32().unwrap() as usize,
48 params[2].i32().unwrap() as usize,
49 params[3].i32().unwrap() as usize,
50 params[4].i32().unwrap() as u32,
51 );
52 let fuel_limit = if fuel16_ptr > 0 {
54 let mut fuel_buffer = [0u8; 16];
55 caller.memory_read(fuel16_ptr, &mut fuel_buffer)?;
56 let fuel_limit = LittleEndian::read_i64(&fuel_buffer[..8]) as u64;
57 let _fuel_refund = LittleEndian::read_i64(&fuel_buffer[8..]);
58 if fuel_limit > 0 {
59 min(fuel_limit, remaining_fuel)
60 } else {
61 0
62 }
63 } else {
64 remaining_fuel
65 };
66 let mut code_hash = [0u8; 32];
67 caller.memory_read(hash32_ptr, &mut code_hash)?;
68 let code_hash = B256::from(code_hash);
69 let is_root = caller.data().call_depth == 0;
70 let params = SyscallInvocationParams {
71 code_hash,
72 input: input_ptr..(input_ptr + input_len),
73 fuel_limit,
74 state,
75 fuel16_ptr: fuel16_ptr as u32,
76 };
77 caller.data_mut().resumable_context = Some(InterruptionHolder { params, is_root });
79 Err(TrapCode::InterruptionCalled)
80}
81
82pub fn syscall_exec_continue(
84 _caller: &mut impl StoreTr<RuntimeContext>,
85 _context: &InterruptionHolder,
86) -> (u64, i64, i32) {
87 unimplemented!("runtime: not supported until we finish zkVM");
88 }
100
101pub fn syscall_exec_impl<I: Into<BytecodeOrHash>>(
103 ctx: &mut RuntimeContext,
104 code_hash: I,
105 input: Cow<'_, [u8]>,
106 fuel_limit: u64,
107 state: u32,
108) -> (u64, i64, i32) {
109 if ctx.call_depth >= CALL_STACK_LIMIT {
111 return (fuel_limit, 0, ExitCode::CallDepthOverflow.into_i32());
112 }
113 let ctx2 = RuntimeContext::default()
115 .with_fuel_limit(fuel_limit)
116 .with_input(input.into_owned())
117 .with_state(state)
118 .with_call_depth(ctx.call_depth + 1);
119
120 let result = default_runtime_executor().execute(code_hash.into(), ctx2);
121 ctx.execution_result.return_data = result.output;
122 (result.fuel_consumed, result.fuel_refunded, result.exit_code)
123}