1use cid::Cid;
4use fvm_ipld_encoding::{CBOR, to_vec};
5use fvm_shared::address::Address;
6use fvm_shared::econ::TokenAmount;
7use fvm_shared::error::ExitCode;
8use fvm_shared::upgrade::UpgradeInfo;
9use fvm_shared::{ActorID, METHOD_CONSTRUCTOR, MethodNum};
10
11use crate::Kernel;
12use crate::engine::Engine;
13use crate::gas::{Gas, GasCharge, GasTimer, GasTracker, PriceList};
14use crate::kernel::{self, BlockRegistry, ClassifyResult, Context, Result};
15use crate::machine::{Machine, MachineContext};
16use crate::state_tree::ActorState;
17
18pub mod backtrace;
19mod state_access_tracker;
20pub use backtrace::Backtrace;
21
22mod default;
23
24pub use default::DefaultCallManager;
25use fvm_shared::event::StampedEvent;
26
27use crate::trace::{ExecutionTrace, IpldOperation};
28
29pub const NO_DATA_BLOCK_ID: u32 = 0;
31
32pub trait CallManager: 'static {
48 type Machine: Machine;
50
51 #[allow(clippy::too_many_arguments)]
53 fn new(
54 machine: Self::Machine,
55 engine: Engine,
56 gas_limit: u64,
57 origin: ActorID,
58 origin_address: Address,
59 receiver: Option<ActorID>,
60 receiver_address: Address,
61 nonce: u64,
62 gas_premium: TokenAmount,
63 ) -> Self;
64
65 #[allow(clippy::too_many_arguments)]
68 fn call_actor<K: Kernel<CallManager = Self>>(
69 &mut self,
70 from: ActorID,
71 to: Address,
72 entrypoint: Entrypoint,
73 params: Option<kernel::Block>,
74 value: &TokenAmount,
75 gas_limit: Option<Gas>,
76 read_only: bool,
77 ) -> Result<InvocationResult>;
78
79 fn with_transaction(
81 &mut self,
82 f: impl FnOnce(&mut Self) -> Result<InvocationResult>,
83 ) -> Result<InvocationResult>;
84
85 fn finish(self) -> (Result<FinishRet>, Self::Machine);
87
88 fn machine(&self) -> &Self::Machine;
90
91 fn machine_mut(&mut self) -> &mut Self::Machine;
93
94 fn engine(&self) -> &Engine;
96
97 fn gas_tracker(&self) -> &GasTracker;
99
100 fn gas_premium(&self) -> &TokenAmount;
102
103 fn origin(&self) -> ActorID;
105
106 fn next_actor_address(&self) -> Address;
111
112 fn create_actor(
117 &mut self,
118 code_id: Cid,
119 actor_id: ActorID,
120 delegated_address: Option<Address>,
121 ) -> Result<()>;
122
123 fn get_call_stack(&self) -> &[(ActorID, &'static str)];
125
126 fn resolve_address(&self, address: &Address) -> Result<Option<ActorID>>;
128
129 fn set_actor(&mut self, id: ActorID, state: ActorState) -> Result<()>;
132
133 fn get_actor(&self, id: ActorID) -> Result<Option<ActorState>>;
135
136 fn delete_actor(&mut self, id: ActorID) -> Result<()>;
138
139 fn transfer(&mut self, from: ActorID, to: ActorID, value: &TokenAmount) -> Result<()>;
141
142 fn nonce(&self) -> u64;
144
145 fn invocation_count(&self) -> u64;
147
148 fn price_list(&self) -> &PriceList {
150 self.machine().context().price_list
151 }
152
153 fn context(&self) -> &MachineContext {
155 self.machine().context()
156 }
157
158 fn blockstore(&self) -> &<Self::Machine as Machine>::Blockstore {
160 self.machine().blockstore()
161 }
162
163 fn externs(&self) -> &<Self::Machine as Machine>::Externs {
165 self.machine().externs()
166 }
167
168 fn charge_gas(&self, charge: GasCharge) -> Result<GasTimer> {
170 self.gas_tracker().apply_charge(charge)
171 }
172
173 fn limiter_mut(&mut self) -> &mut <Self::Machine as Machine>::Limiter;
175
176 fn append_event(&mut self, evt: StampedEvent);
178
179 fn log(&mut self, msg: String);
181
182 fn trace_ipld(&mut self, op: IpldOperation, cid: Cid, size: usize);
183}
184
185#[derive(Clone, Debug)]
187pub struct InvocationResult {
188 pub exit_code: ExitCode,
190 pub value: Option<kernel::Block>,
192}
193
194impl Default for InvocationResult {
195 fn default() -> Self {
196 Self {
197 value: None,
198 exit_code: ExitCode::OK,
199 }
200 }
201}
202
203pub struct FinishRet {
205 pub gas_used: u64,
206 pub backtrace: Backtrace,
207 pub exec_trace: ExecutionTrace,
208 pub events: Vec<StampedEvent>,
209 pub events_root: Option<Cid>,
210}
211
212#[derive(Clone, Debug, Copy)]
213pub enum Entrypoint {
214 ImplicitConstructor,
216 Invoke(MethodNum),
218 Upgrade(UpgradeInfo),
220}
221
222pub static INVOKE_FUNC_NAME: &str = "invoke";
223pub static UPGRADE_FUNC_NAME: &str = "upgrade";
224
225const METHOD_UPGRADE: MethodNum = 932083;
226
227impl std::fmt::Display for Entrypoint {
228 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
229 match self {
230 Entrypoint::ImplicitConstructor => write!(f, "implicit_constructor"),
231 Entrypoint::Invoke(method) => write!(f, "invoke({})", method),
232 Entrypoint::Upgrade(_) => write!(f, "upgrade"),
233 }
234 }
235}
236
237impl Entrypoint {
238 fn method_num(&self) -> MethodNum {
239 match self {
240 Entrypoint::ImplicitConstructor => METHOD_CONSTRUCTOR,
241 Entrypoint::Invoke(num) => *num,
242 Entrypoint::Upgrade(_) => METHOD_UPGRADE,
243 }
244 }
245
246 fn func_name(&self) -> &'static str {
247 match self {
248 Entrypoint::ImplicitConstructor | Entrypoint::Invoke(_) => INVOKE_FUNC_NAME,
249 Entrypoint::Upgrade(_) => UPGRADE_FUNC_NAME,
250 }
251 }
252
253 fn invokes(&self, method: MethodNum) -> bool {
254 match self {
255 Entrypoint::ImplicitConstructor => method == METHOD_CONSTRUCTOR,
256 Entrypoint::Invoke(num) => *num == method,
257 Entrypoint::Upgrade(_) => false,
258 }
259 }
260
261 fn into_params(self, br: &mut BlockRegistry) -> Result<Vec<wasmtime::Val>> {
262 match self {
263 Entrypoint::ImplicitConstructor | Entrypoint::Invoke(_) => Ok(Vec::new()),
264 Entrypoint::Upgrade(ui) => {
265 let ui_params = to_vec(&ui)
266 .or_fatal()
267 .context("failed to serialize upgrade params")?;
268 let block_id = br.put_reachable(kernel::Block::new(CBOR, ui_params, Vec::new()))?;
270 Ok(vec![wasmtime::Val::I32(block_id as i32)])
271 }
272 }
273 }
274}