fluentbase_runtime/runtime.rs
1//! Execution mode dispatcher for rWasm-based runtimes.
2//!
3//! This module defines a thin abstraction over different execution backends
4//! (contract vs system runtimes). The goal is to provide a uniform interface
5//! for driving execution, memory access, fuel accounting and context handling,
6//! while allowing the underlying runtime to differ.
7//!
8//! From the executor’s point of view, `ExecutionMode` behaves like a tagged
9//! union with identical operational semantics.
10
11use crate::RuntimeContext;
12use rwasm::TrapCode;
13
14mod contract_runtime;
15pub use contract_runtime::ContractRuntime;
16
17mod system_runtime;
18pub use system_runtime::SystemRuntime;
19
20/// Represents the active execution mode.
21///
22/// Execution can happen either in a *contract* context (user-deployed code)
23/// or in a *system* context (privileged runtimes, precompiles, delegated VMs).
24///
25/// Both modes expose the same operational surface:
26/// execution control, memory access, fuel accounting, and context access.
27/// This enum acts as a dynamic dispatcher between them.
28#[allow(clippy::large_enum_variant)]
29pub enum ExecutionMode {
30 /// Contract-level execution runtime.
31 ///
32 /// Used for regular smart contracts executed in a constrained,
33 /// user-controlled environment.
34 Contract(ContractRuntime),
35
36 /// System-level execution runtime.
37 ///
38 /// Used for privileged or delegated runtimes (e.g., EVM/SVM/Wasm system
39 /// runtimes) that may have different invariants or capabilities.
40 System(SystemRuntime),
41}
42
43impl ExecutionMode {
44 /// Executes the runtime until it either finishes or traps.
45 ///
46 /// This is the initial entry point for execution. Any runtime-specific
47 /// exit conditions (normal return, trap, host call) are translated
48 /// into a `TrapCode` if execution cannot continue.
49 pub fn execute(&mut self) -> Result<(), TrapCode> {
50 match self {
51 ExecutionMode::Contract(runtime) => runtime.execute(),
52 ExecutionMode::System(runtime) => runtime.execute(),
53 }
54 }
55
56 /// Resumes execution after an external interruption.
57 ///
58 /// Typically used after handling a host call or delegated execution,
59 /// passing back the exit code and the amount of fuel consumed by
60 /// the external component.
61 pub fn resume(&mut self, exit_code: i32, fuel_consumed: u64) -> Result<(), TrapCode> {
62 match self {
63 ExecutionMode::Contract(runtime) => runtime.resume(exit_code, fuel_consumed),
64 ExecutionMode::System(runtime) => runtime.resume(exit_code, fuel_consumed),
65 }
66 }
67
68 /// Writes data into the runtime linear memory.
69 ///
70 /// The write is bounds-checked according to the runtime’s memory model.
71 /// Any violation (out-of-bounds, unmapped memory, etc.) results in a trap.
72 pub fn memory_write(&mut self, offset: usize, data: &[u8]) -> Result<(), TrapCode> {
73 match self {
74 ExecutionMode::Contract(runtime) => runtime.memory_write(offset, data),
75 ExecutionMode::System(runtime) => runtime.memory_write(offset, data),
76 }
77 }
78
79 /// Reads data from the runtime linear memory.
80 ///
81 /// The provided buffer is filled with bytes starting at `offset`.
82 /// Traps if the read exceeds the accessible memory range.
83 pub fn memory_read(&mut self, offset: usize, buffer: &mut [u8]) -> Result<(), TrapCode> {
84 match self {
85 ExecutionMode::Contract(runtime) => runtime.memory_read(offset, buffer),
86 ExecutionMode::System(runtime) => runtime.memory_read(offset, buffer),
87 }
88 }
89
90 /// Returns the remaining execution fuel, if fuel metering is enabled.
91 ///
92 /// Some runtimes may choose not to expose fuel accounting; in that case
93 /// `None` is returned.
94 pub fn remaining_fuel(&self) -> Option<u64> {
95 match self {
96 ExecutionMode::Contract(runtime) => runtime.remaining_fuel(),
97 ExecutionMode::System(runtime) => runtime.remaining_fuel(),
98 }
99 }
100
101 /// Provides mutable access to the underlying `RuntimeContext`.
102 ///
103 /// This is the only sanctioned way to mutate execution context shared
104 /// between the executor and the runtime (e.g., call depth, logs, gas
105 /// accounting, environment data).
106 ///
107 /// The closure-based API prevents leaking mutable references outside
108 /// the execution boundary.
109 pub fn context_mut(&mut self) -> &mut RuntimeContext {
110 match self {
111 ExecutionMode::Contract(runtime) => runtime.context_mut(),
112 ExecutionMode::System(runtime) => runtime.context_mut(),
113 }
114 }
115
116 /// Provides immutable access to the underlying `RuntimeContext`.
117 ///
118 /// Intended for inspection and read-only queries without allowing
119 /// mutation of consensus-critical state.
120 pub fn context(&self) -> &RuntimeContext {
121 match self {
122 ExecutionMode::Contract(runtime) => runtime.context(),
123 ExecutionMode::System(runtime) => runtime.context(),
124 }
125 }
126}