1use super::utils::structured;
5use super::*;
6use crate::interpreter::{ExecutionContext, IMPLICIT_MESSAGE_GAS_LIMIT, VM, VMTrace};
7use crate::message::{MessageRead as _, MessageReadWrite as _};
8use crate::rpc::state::{ApiInvocResult, MessageGasCost};
9use crate::shim::executor::ApplyRet;
10use crate::shim::message::{METHOD_SEND, Message};
11use crate::state_migration::run_state_migrations;
12use std::time::Duration;
13use tracing::instrument;
14
15impl StateManager {
16 #[instrument(skip(self))]
18 pub fn call_blocking(
19 &self,
20 msg: &Message,
21 tipset: Option<Tipset>,
22 ) -> Result<ApiInvocResult, Error> {
23 let mut msg = msg.clone();
24 let chain_config = self.chain_config();
25
26 let tipset = if let Some(ts) = tipset {
27 if ts.epoch() > 0 {
28 let parent = self
31 .chain_index()
32 .load_required_tipset(ts.parents())
33 .map_err(Error::other)?;
34 if let Some(epoch) =
35 chain_config.expensive_fork_between(parent.epoch(), ts.epoch() + 1)
36 {
37 return Err(Error::ExpensiveFork { epoch });
38 }
39 }
40 ts
41 } else {
42 let mut heaviest_ts = self.heaviest_tipset();
44 while heaviest_ts.epoch() > 0 {
45 let parent = self
46 .chain_index()
47 .load_required_tipset(heaviest_ts.parents())
48 .map_err(Error::other)?;
49 if !chain_config.has_expensive_fork_between(parent.epoch(), heaviest_ts.epoch() + 1)
50 {
51 break;
52 }
53 heaviest_ts = parent;
54 }
55 heaviest_ts
56 };
57
58 let state_cid = *tipset.parent_state();
59
60 let state_cid = match run_state_migrations(
62 tipset.epoch(),
63 self.chain_config(),
64 self.db(),
65 &state_cid,
66 ) {
67 Ok(Some(new_state)) => new_state,
68 Ok(None) => state_cid,
69 Err(e) => return Err(Error::other(e)),
70 };
71
72 let height = tipset.epoch();
73 let mut vm = VM::new(
74 ExecutionContext {
75 heaviest_tipset: tipset.shallow_clone(),
76 state_tree_root: state_cid,
77 epoch: height,
78 rand: Box::new(self.chain_rand(tipset.shallow_clone())),
79 base_fee: tipset.block_headers().first().parent_base_fee.clone(),
80 circ_supply: self.genesis_info().get_vm_circulating_supply(
81 height,
82 self.db(),
83 &state_cid,
84 )?,
85 chain_config: self.chain_config().shallow_clone(),
86 chain_index: self.chain_index().shallow_clone(),
87 timestamp: tipset.min_timestamp(),
88 },
89 &self.engine,
90 VMTrace::Traced,
91 )?;
92
93 let tipset_messages = self
94 .chain_store()
95 .messages_for_tipset(&tipset)
96 .map_err(|err| Error::Other(err.to_string()))?;
97
98 let prior_messsages = tipset_messages
99 .iter()
100 .filter(|ts_msg| ts_msg.message().from() == msg.from());
101
102 for m in prior_messsages {
103 vm.apply_message(m)?;
104 }
105
106 let state_cid = vm.flush()?;
109
110 let state = StateTree::new_from_root(self.db(), &state_cid)?;
111
112 let from_actor = state
113 .get_actor(&msg.from())?
114 .ok_or_else(|| anyhow::anyhow!("actor not found"))?;
115 msg.set_sequence(from_actor.sequence);
116
117 msg.gas_limit = IMPLICIT_MESSAGE_GAS_LIMIT as u64;
119
120 let (apply_ret, duration) = vm.apply_implicit_message(&msg)?;
121
122 let msg_cid = msg.cid();
123 Ok(ApiInvocResult {
124 msg,
125 msg_rct: Some(apply_ret.msg_receipt()),
126 msg_cid,
127 error: apply_ret.failure_info().unwrap_or_default(),
128 duration: duration.as_nanos().clamp(0, u128::from(u64::MAX)) as u64,
129 gas_cost: MessageGasCost::default(),
130 execution_trace: structured::parse_events(apply_ret.exec_trace()).unwrap_or_default(),
131 })
132 }
133
134 pub async fn call(
137 &self,
138 message: Arc<Message>,
139 tipset: Option<Tipset>,
140 ) -> Result<ApiInvocResult, Error> {
141 let this = self.shallow_clone();
142 tokio::task::spawn_blocking(move || this.call_blocking(&message, tipset)).await?
143 }
144
145 pub async fn apply_on_state_with_gas(
146 &self,
147 tipset: Option<&Tipset>,
148 msg: &Message,
149 vm_flush: VMFlush,
150 vm_trace: VMTrace,
151 sender_validation: SenderValidation,
152 ) -> anyhow::Result<(ApiInvocResult, Option<Cid>)> {
153 let ts = tipset.map_or_else(|| self.heaviest_tipset(), Tipset::shallow_clone);
154
155 let from_protocol = match sender_validation {
156 SenderValidation::Skip => msg.from.protocol(),
157 SenderValidation::Enforce => self
158 .resolve_to_deterministic_address(msg.from, &ts)
159 .await
160 .context("could not resolve key")?
161 .protocol(),
162 };
163 let chain_msg = ChainMessage::for_gas_estimation(msg.clone(), from_protocol);
164
165 let (apply_ret, duration, state_root) = self
166 .call_with_gas(
167 chain_msg,
168 Default::default(),
169 Some(ts),
170 vm_flush,
171 vm_trace,
172 sender_validation,
173 )
174 .await?;
175
176 let msg_rct = Some(apply_ret.msg_receipt());
177 let error = apply_ret.failure_info().unwrap_or_default();
178 Ok((
179 ApiInvocResult {
180 msg_cid: msg.cid(),
181 msg: msg.clone(),
182 msg_rct,
183 error,
184 duration: duration.as_nanos().clamp(0, u128::from(u64::MAX)) as u64,
185 gas_cost: MessageGasCost::default(),
186 execution_trace: structured::parse_events(apply_ret.into_exec_trace())
187 .unwrap_or_default(),
188 },
189 state_root,
190 ))
191 }
192
193 pub async fn call_with_gas(
196 &self,
197 mut message: ChainMessage,
198 prior_messages: Arc<Vec<ChainMessage>>,
199 tipset: Option<Tipset>,
200 vm_flush: VMFlush,
201 vm_trace: VMTrace,
202 sender_validation: SenderValidation,
203 ) -> Result<(ApplyRet, Duration, Option<Cid>), Error> {
204 let ts = tipset.unwrap_or_else(|| self.heaviest_tipset());
205 let TipsetState { state_root, .. } = self
206 .load_tipset_state(&ts)
207 .await
208 .map_err(|e| Error::Other(format!("Could not load tipset state: {e:#}")))?;
209 let chain_rand = self.chain_rand(ts.clone());
210
211 let epoch = ts.epoch() + 1;
214 let this = self.shallow_clone();
215 tokio::task::spawn_blocking(move || {
216 let (ret, duration, state_cid) = stacker::grow(64 << 20, || -> Result<_, Error> {
219 let mut vm = VM::new(
220 ExecutionContext {
221 heaviest_tipset: ts.clone(),
222 state_tree_root: state_root,
223 epoch,
224 rand: Box::new(chain_rand),
225 base_fee: ts.block_headers().first().parent_base_fee.clone(),
226 circ_supply: this.genesis_info().get_vm_circulating_supply(
227 epoch,
228 this.chain_index().db(),
229 &state_root,
230 )?,
231 chain_config: this.chain_config().shallow_clone(),
232 chain_index: this.chain_index().shallow_clone(),
233 timestamp: ts.min_timestamp(),
234 },
235 &this.engine,
236 vm_trace,
237 )?;
238
239 for msg in prior_messages.iter() {
240 vm.apply_message(msg)?;
241 }
242
243 let (from_actor, apply) =
244 sender_for_simulation(&mut vm, message.from(), sender_validation)?;
245 message.set_sequence(from_actor.sequence);
246 let (ret, duration) = match apply {
247 SenderApply::Implicit => vm.apply_implicit_message(message.message())?,
250 SenderApply::Explicit => vm.apply_message(&message)?,
253 };
254 let state_root = match vm_flush {
255 VMFlush::Flush => Some(vm.flush()?),
256 VMFlush::Skip => None,
257 };
258 Ok((ret, duration, state_root))
259 })?;
260
261 Ok((ret, duration, state_cid))
262 })
263 .await?
264 }
265}
266
267#[derive(Debug, Copy, Clone, PartialEq, Eq)]
268enum SenderApply {
269 Explicit,
270 Implicit,
271}
272
273fn sender_for_simulation(
280 vm: &mut VM,
281 from: Address,
282 sender_validation: SenderValidation,
283) -> Result<(ActorState, SenderApply), Error> {
284 match (
285 vm.get_actor(&from)
286 .map_err(|e| Error::Other(format!("Could not get actor from state: {e:#}")))?,
287 sender_validation,
288 ) {
289 (Some(actor), SenderValidation::Enforce) => Ok((actor, SenderApply::Explicit)),
290 (Some(actor), SenderValidation::Skip) => Ok((actor, SenderApply::Implicit)),
291 (None, SenderValidation::Enforce) => Err(Error::SenderValidationFailed(format!(
292 "sender {from} not found on chain"
293 ))),
294 (None, SenderValidation::Skip) => {
295 let (create_ret, _) = vm.apply_implicit_message(&placeholder_send(from))?;
296 let exit_code = create_ret.msg_receipt().exit_code();
297 if !exit_code.is_success() {
298 return Err(Error::Other(format!(
299 "failed to create ephemeral sender placeholder {from} (exit={exit_code}): {}",
300 create_ret.failure_info().unwrap_or_default()
301 )));
302 }
303 let actor = vm
304 .get_actor(&from)
305 .map_err(|e| Error::Other(format!("Could not get placeholder actor: {e:#}")))?
306 .ok_or_else(|| {
307 Error::Other(format!(
308 "ephemeral sender placeholder {from} missing after creation"
309 ))
310 })?;
311 Ok((actor, SenderApply::Explicit))
312 }
313 }
314}
315
316fn placeholder_send(to: Address) -> Message {
317 Message {
318 from: Address::SYSTEM_ACTOR,
319 to,
320 method_num: METHOD_SEND,
321 gas_limit: IMPLICIT_MESSAGE_GAS_LIMIT as u64,
322 ..Default::default()
323 }
324}