1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
// Copyright 2021-2023 Protocol Labs
// SPDX-License-Identifier: Apache-2.0, MIT
use cid::Cid;
use derive_more::{Deref, DerefMut};
use fvm_ipld_blockstore::Blockstore;
use fvm_shared::clock::ChainEpoch;
use fvm_shared::econ::TokenAmount;
use fvm_shared::version::NetworkVersion;
use fvm_shared::ActorID;
use num_traits::Zero;

use crate::externs::Externs;
use crate::gas::{price_list_by_network_version, PriceList};
use crate::kernel::Result;
use crate::state_tree::StateTree;

mod default;

pub use default::DefaultMachine;
use fvm_shared::chainid::ChainID;

pub mod limiter;
mod manifest;

pub use manifest::Manifest;

use self::limiter::MemoryLimiter;

mod boxed;

pub const REWARD_ACTOR_ID: ActorID = 2;

/// Distinguished Account actor that is the destination of all burnt funds.
pub const BURNT_FUNDS_ACTOR_ID: ActorID = 99;

/// The Machine is the top-level object of the FVM.
///
/// The Machine operates at a concrete network version and epoch, over an
/// initial state root, all of which must be specified at instantiation time.
///
/// It is instantiated by the node with concrete Blockstore and Externs
/// implementations.
///
/// The Machine is designed to be used in conjunction with the Executor, which
/// is bound to a concrete Machine and is in charge of facilitating message
/// execution.
pub trait Machine: 'static {
    type Blockstore: Blockstore;
    type Externs: Externs;
    type Limiter: MemoryLimiter;

    /// Returns a reference to the machine's blockstore.
    fn blockstore(&self) -> &Self::Blockstore;

    /// Returns a reference to the machine context: static information about the current execution
    /// context.
    fn context(&self) -> &MachineContext;

    /// Returns a reference to all "node" supplied APIs.
    fn externs(&self) -> &Self::Externs;

    /// Returns the builtin actor index.
    fn builtin_actors(&self) -> &Manifest;

    /// Returns an immutable reference to the state tree.
    fn state_tree(&self) -> &StateTree<Self::Blockstore>;

    /// Returns a mutable reference to the state tree.
    fn state_tree_mut(&mut self) -> &mut StateTree<Self::Blockstore>;

    /// Flushes the state-tree and returns the new root CID.
    fn flush(&mut self) -> Result<Cid> {
        self.state_tree_mut().flush()
    }

    /// Consumes the machine and returns the owned blockstore.
    fn into_store(self) -> Self::Blockstore;

    /// Returns a generated ID of a machine
    fn machine_id(&self) -> &str;

    /// Creates a new limiter to track the resources of a message execution.
    fn new_limiter(&self) -> Self::Limiter;
}

/// Network-level settings. Except when testing locally, changing any of these likely requires a
/// network upgrade.
#[derive(Debug, Clone)]
pub struct NetworkConfig {
    /// The network version at epoch
    pub network_version: NetworkVersion,

    /// The Chain ID of the network.
    ///
    /// DEFAULT: 0 (Invalid)
    pub chain_id: ChainID,

    /// The maximum call depth.
    ///
    /// DEFAULT: 1024
    pub max_call_depth: u32,

    /// The maximum number of elements on wasm stack
    /// DEFAULT: 64Ki (512KiB of u64 elements)
    pub max_wasm_stack: u32,

    /// Maximum size of memory of any Wasm instance, ie. each level of the recursion, in bytes.
    ///
    /// DEFAULT: 512MiB
    pub max_inst_memory_bytes: u64,

    /// Maximum size of memory used during the entire (recursive) message execution. This currently
    /// includes Wasm memories and table elements and will eventually be extended to include IPLD
    /// blocks and actor code.
    ///
    /// DEFAULT: 2GiB
    pub max_memory_bytes: u64,

    /// The maximum blocks size that can be created in the FVM.
    ///
    /// DEFAULT: 1MiB
    pub max_block_size: usize,

    /// An override for builtin-actors. If specified, this should be the CID of a builtin-actors
    /// "manifest".
    ///
    /// DEFAULT: `None`
    pub builtin_actors_override: Option<Cid>,

    /// Enable actor debugging.
    ///
    /// DEFAULT: `false`
    pub actor_debugging: bool,

    /// The price list.
    ///
    /// DEFAULT: The price-list for the current network version.
    pub price_list: &'static PriceList,

    /// Actor redirects for debug execution
    pub actor_redirect: Vec<(Cid, Cid)>,
}

impl NetworkConfig {
    /// Create a new network config for the given network version.
    pub fn new(network_version: NetworkVersion) -> Self {
        NetworkConfig {
            chain_id: ChainID::from(0u64),
            network_version,
            max_call_depth: 1024,
            max_wasm_stack: 2048,
            max_inst_memory_bytes: 512 * (1 << 20),
            max_memory_bytes: 2 * (1 << 30),
            actor_debugging: false,
            builtin_actors_override: None,
            price_list: price_list_by_network_version(network_version),
            actor_redirect: vec![],
            max_block_size: 1 << 20,
        }
    }

    /// Enable actor debugging. This is a consensus-critical option (affects gas usage) so it should
    /// only be enabled for local testing or as a network-wide parameter.
    pub fn enable_actor_debugging(&mut self) -> &mut Self {
        self.actor_debugging = true;
        self
    }

    /// Override actors with the specific manifest. This is primarily useful for testing, or
    /// networks prior to NV16 (where the actor's "manifest" isn't specified on-chain).
    pub fn override_actors(&mut self, manifest: Cid) -> &mut Self {
        self.builtin_actors_override = Some(manifest);
        self
    }

    /// Set actor redirects for debug execution
    pub fn redirect_actors(&mut self, actor_redirect: Vec<(Cid, Cid)>) -> &mut Self {
        self.actor_redirect = actor_redirect;
        self
    }

    /// Create a ['MachineContext'] for a given epoch, timestamp, and initial state.
    pub fn for_epoch(
        &self,
        epoch: ChainEpoch,
        timestamp: u64,
        initial_state: Cid,
    ) -> MachineContext {
        MachineContext {
            network: self.clone(),
            base_fee: TokenAmount::zero(),
            epoch,
            timestamp,
            initial_state_root: initial_state,
            circ_supply: fvm_shared::TOTAL_FILECOIN.clone(),
            tracing: false,
        }
    }

    /// Set Chain ID of the network.
    pub fn chain_id(&mut self, id: ChainID) -> &mut Self {
        self.chain_id = id;
        self
    }
}

/// Per-epoch machine context.
#[derive(Clone, Debug, Deref, DerefMut)]
pub struct MachineContext {
    /// Network-level settings.
    #[deref]
    #[deref_mut]
    pub network: NetworkConfig,

    /// The current epoch
    ///
    /// Default: 0
    pub epoch: ChainEpoch,

    /// The UNIX timestamp (in seconds) of the current tipset
    ///
    /// Default: 0
    pub timestamp: u64,

    /// The base fee that's in effect when the Machine runs.
    ///
    /// Default: 0.
    pub base_fee: TokenAmount,

    /// The initial state root on which this block is based.
    pub initial_state_root: Cid,

    /// v15 and onwards: The amount of FIL that has vested from genesis actors.
    /// v14 and earlier: The amount of FIL that has vested from genesis msigs
    /// (the remainder of the circ supply must be calculated by the FVM)
    ///
    /// DEFAULT: Total FIL supply (likely not what you want).
    pub circ_supply: TokenAmount,

    /// Whether or not to produce execution traces in the returned result.
    /// Not consensus-critical, but has a performance impact.
    pub tracing: bool,
}

impl MachineContext {
    /// Sets [`MachineContext::base_fee`].
    pub fn set_base_fee(&mut self, amt: TokenAmount) -> &mut Self {
        self.base_fee = amt;
        self
    }

    /// Set [`MachineContext::circ_supply`].
    pub fn set_circulating_supply(&mut self, amt: TokenAmount) -> &mut Self {
        self.circ_supply = amt;
        self
    }

    /// Enable execution traces. [`MachineContext::tracing`].
    pub fn enable_tracing(&mut self) -> &mut Self {
        self.tracing = true;
        self
    }
}