fvm/executor/
mod.rs

1// Copyright 2021-2023 Protocol Labs
2// SPDX-License-Identifier: Apache-2.0, MIT
3mod default;
4mod threaded;
5
6use std::fmt::Display;
7
8use cid::Cid;
9pub use default::DefaultExecutor;
10use fvm_ipld_encoding::RawBytes;
11use fvm_shared::econ::TokenAmount;
12use fvm_shared::error::ExitCode;
13use fvm_shared::event::StampedEvent;
14use fvm_shared::message::Message;
15use fvm_shared::receipt::Receipt;
16use num_traits::Zero;
17pub use threaded::ThreadedExecutor;
18
19use crate::call_manager::Backtrace;
20use crate::trace::ExecutionTrace;
21use crate::Kernel;
22
23/// An executor executes messages on the underlying machine/kernel. It's responsible for:
24///
25/// 1. Validating messages (nonce, sender, etc).
26/// 2. Creating message receipts.
27/// 3. Charging message inclusion gas, overestimation gas, miner tip, etc.
28pub trait Executor {
29    /// The [`Kernel`] on which messages will be applied. We specify a [`Kernel`] here, not a
30    /// [`Machine`](crate::machine::Machine), because the [`Kernel`] implies the
31    /// [`Machine`](crate::machine::Machine).
32    type Kernel: Kernel;
33
34    /// This is the entrypoint to execute a message.
35    ///
36    /// NOTE: The "raw length" is the length of the message as it appears on-chain and is used to
37    /// charge message inclusion gas.
38    fn execute_message(
39        &mut self,
40        msg: Message,
41        apply_kind: ApplyKind,
42        raw_length: usize,
43    ) -> anyhow::Result<ApplyRet>;
44
45    /// Flushes the state-tree, returning the new root CID.
46    fn flush(&mut self) -> anyhow::Result<Cid>;
47}
48
49/// A description of some failure encountered when applying a message.
50#[derive(Debug, Clone)]
51pub enum ApplyFailure {
52    /// The backtrace from a message failure.
53    MessageBacktrace(Backtrace),
54    /// A message describing a pre-validation failure.
55    PreValidation(String),
56}
57
58impl Display for ApplyFailure {
59    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
60        match self {
61            ApplyFailure::MessageBacktrace(bt) => {
62                writeln!(f, "message failed with backtrace:")?;
63                write!(f, "{}", bt)?;
64            }
65            ApplyFailure::PreValidation(msg) => {
66                writeln!(f, "pre-validation failed: {}", msg)?;
67            }
68        }
69        Ok(())
70    }
71}
72
73/// Apply message return data.
74#[derive(Clone, Debug)]
75pub struct ApplyRet {
76    /// Message receipt for the transaction. This data is stored on chain.
77    pub msg_receipt: Receipt,
78    /// Gas penalty from transaction, if any.
79    pub penalty: TokenAmount,
80    /// Tip given to miner from message.
81    pub miner_tip: TokenAmount,
82
83    // Gas stuffs
84    pub base_fee_burn: TokenAmount,
85    pub over_estimation_burn: TokenAmount,
86    pub refund: TokenAmount,
87    pub gas_refund: u64,
88    pub gas_burned: u64,
89
90    /// Additional failure information for debugging, if any.
91    pub failure_info: Option<ApplyFailure>,
92    /// Execution trace information, for debugging.
93    pub exec_trace: ExecutionTrace,
94    /// Events generated while applying the message.
95    pub events: Vec<StampedEvent>,
96}
97
98impl ApplyRet {
99    #[inline]
100    pub fn prevalidation_fail(
101        code: ExitCode,
102        message: impl Into<String>,
103        miner_penalty: TokenAmount,
104    ) -> ApplyRet {
105        ApplyRet {
106            msg_receipt: Receipt {
107                exit_code: code,
108                return_data: RawBytes::default(),
109                gas_used: 0,
110                events_root: None,
111            },
112            penalty: miner_penalty,
113            miner_tip: TokenAmount::zero(),
114            base_fee_burn: TokenAmount::zero(),
115            over_estimation_burn: TokenAmount::zero(),
116            refund: TokenAmount::zero(),
117            gas_refund: 0,
118            gas_burned: 0,
119            failure_info: Some(ApplyFailure::PreValidation(message.into())),
120            exec_trace: vec![],
121            events: vec![],
122        }
123    }
124}
125
126/// The kind of message being applied:
127///
128/// 1. Explicit messages may only come from account actors and charge the sending account for gas
129/// consumed.
130/// 2. Implicit messages may come from any actor, ignore the nonce, and charge no gas (but still
131/// account for it).
132#[derive(Eq, PartialEq, Copy, Clone, Debug)]
133pub enum ApplyKind {
134    Explicit,
135    Implicit,
136}