Skip to main content

fvm/kernel/
mod.rs

1// Copyright 2021-2023 Protocol Labs
2// SPDX-License-Identifier: Apache-2.0, MIT
3use ambassador::delegatable_trait;
4use fvm_shared::event::StampedEvent;
5
6use crate::call_manager::CallManager;
7use crate::machine::Machine;
8use crate::machine::limiter::MemoryLimiter;
9use crate::syscalls::Linker;
10
11mod blocks;
12mod error;
13mod hash;
14
15pub mod default;
16pub mod filecoin;
17
18pub use blocks::{Block, BlockId, BlockRegistry, BlockStat};
19pub use error::{ClassifyResult, Context, ExecutionError, Result, SyscallError};
20pub use hash::SupportedHashes;
21
22pub struct CallResult {
23    pub block_id: BlockId,
24    pub block_stat: BlockStat,
25    pub exit_code: ExitCode,
26}
27
28/// The "kernel" implements the FVM interface as presented to the actors. It:
29///
30/// - Manages the Actor's state.
31/// - Tracks and charges for IPLD & syscall-specific gas.
32///
33/// Actors may call into the kernel via the syscalls defined in the [`syscalls`][crate::syscalls]
34/// module.
35pub trait Kernel: SyscallHandler<Self> + 'static {
36    /// The [`Kernel`]'s [`CallManager`] is
37    type CallManager: CallManager;
38    /// The [`Kernel`]'s memory allocation tracker.
39    type Limiter: MemoryLimiter;
40
41    /// Consume the [`Kernel`] and return the underlying [`CallManager`] and [`BlockRegistry`].
42    fn into_inner(self) -> (Self::CallManager, BlockRegistry)
43    where
44        Self: Sized;
45
46    /// Construct a new [`Kernel`] from the given [`CallManager`].
47    ///
48    /// - `caller` is the ID of the _immediate_ caller.
49    /// - `actor_id` is the ID of _this_ actor.
50    /// - `method` is the method that has been invoked.
51    /// - `value_received` is value received due to the current call.
52    /// - `blocks` is the initial block registry (should already contain the parameters).
53    #[allow(clippy::too_many_arguments)]
54    fn new(
55        mgr: Self::CallManager,
56        blocks: BlockRegistry,
57        caller: ActorID,
58        actor_id: ActorID,
59        method: MethodNum,
60        value_received: TokenAmount,
61        read_only: bool,
62    ) -> Self
63    where
64        Self: Sized;
65
66    /// The kernel's underlying "machine".
67    fn machine(&self) -> &<Self::CallManager as CallManager>::Machine;
68
69    /// Give access to the limiter of the underlying call manager.
70    fn limiter_mut(&mut self) -> &mut Self::Limiter;
71
72    /// Returns the remaining gas for the transaction.
73    fn gas_available(&self) -> Gas;
74
75    /// ChargeGas charges specified amount of `gas` for execution.
76    /// `name` provides information about gas charging point.
77    fn charge_gas(&self, name: &str, compute: Gas) -> Result<GasTimer>;
78}
79
80pub trait SyscallHandler<K>: Sized {
81    fn link_syscalls(linker: &mut Linker<K>) -> anyhow::Result<()>;
82}
83
84/// Network-related operations.
85#[delegatable_trait]
86pub trait NetworkOps {
87    /// Network information (epoch, version, etc.).
88    fn network_context(&self) -> Result<NetworkContext>;
89
90    /// The CID of the tipset at the specified epoch.
91    fn tipset_cid(&self, epoch: ChainEpoch) -> Result<Cid>;
92}
93
94/// Accessors to query attributes of the incoming message.
95#[delegatable_trait]
96pub trait MessageOps {
97    /// Message information.
98    fn msg_context(&self) -> Result<MessageContext>;
99}
100
101/// The actor calling operations.
102#[delegatable_trait]
103pub trait SendOps<K: Kernel = Self> {
104    /// Sends a message to another actor.
105    /// The method type parameter K is the type of the kernel to instantiate for
106    /// the receiving actor. This is necessary to support wrapping a kernel, so the outer
107    /// kernel can specify its Self as the receiver's kernel type, rather than the wrapped
108    /// kernel specifying its Self.
109    /// This method is part of the Kernel trait so it can refer to the Self::CallManager
110    /// associated type necessary to constrain K.
111    fn send(
112        &mut self,
113        recipient: &Address,
114        method: u64,
115        params: BlockId,
116        value: &TokenAmount,
117        gas_limit: Option<Gas>,
118        flags: SendFlags,
119    ) -> Result<CallResult>;
120}
121
122/// The actor upgrade operations.
123#[delegatable_trait]
124pub trait UpgradeOps<K: Kernel = Self> {
125    /// Upgrades the running actor to the specified code CID.
126    fn upgrade_actor(&mut self, new_code_cid: Cid, params_id: BlockId) -> Result<CallResult>;
127}
128
129/// The IPLD subset of the kernel.
130#[delegatable_trait]
131pub trait IpldBlockOps {
132    /// Open a block.
133    ///
134    /// This method will fail if the requested block isn't reachable.
135    fn block_open(&mut self, cid: &Cid) -> Result<(BlockId, BlockStat)>;
136
137    /// Create a new block.
138    ///
139    /// This method will fail if the block is too large (SPEC_AUDIT), the codec is not allowed
140    /// (SPEC_AUDIT), the block references unreachable blocks, or the block contains too many links
141    /// (SPEC_AUDIT).
142    fn block_create(&mut self, codec: u64, data: &[u8]) -> Result<BlockId>;
143
144    /// Computes a CID for a block.
145    ///
146    /// This is the only way to add a new block to the "reachable" set.
147    ///
148    /// This method will fail if the block handle is invalid.
149    fn block_link(&mut self, id: BlockId, hash_fun: u64, hash_len: u32) -> Result<Cid>;
150
151    /// Read data from a block.
152    ///
153    /// This method will fail if the block handle is invalid.
154    fn block_read(&self, id: BlockId, offset: u32, buf: &mut [u8]) -> Result<i32>;
155
156    /// Returns the blocks codec & size.
157    ///
158    /// This method will fail if the block handle is invalid.
159    fn block_stat(&self, id: BlockId) -> Result<BlockStat>;
160}
161
162/// Actor state access and manipulation.
163/// Depends on BlockOps to read and write blocks in the state tree.
164#[delegatable_trait]
165pub trait SelfOps: IpldBlockOps {
166    /// Get the state root.
167    fn root(&mut self) -> Result<Cid>;
168
169    /// Update the state-root.
170    ///
171    /// This method will fail if the new state-root isn't reachable.
172    fn set_root(&mut self, root: Cid) -> Result<()>;
173
174    /// The balance of the receiver.
175    fn current_balance(&self) -> Result<TokenAmount>;
176
177    /// Deletes the executing actor from the state tree, burning any remaining balance if requested.
178    fn self_destruct(&mut self, burn_unspent: bool) -> Result<()>;
179}
180
181/// Actors operations whose scope of action is actors other than the calling
182/// actor. The calling actor's state may be consulted to resolve some.
183#[delegatable_trait]
184pub trait ActorOps {
185    /// Resolves an address of any protocol to an ID address (via the Init actor's table).
186    /// This allows resolution of externally-provided SECP, BLS, or actor addresses to the canonical form.
187    /// If the argument is an ID address it is returned directly.
188    fn resolve_address(&self, address: &Address) -> Result<ActorID>;
189
190    /// Looks up the "delegated" (f4) address of the specified actor, if any.
191    fn lookup_delegated_address(&self, actor_id: ActorID) -> Result<Option<Address>>;
192
193    /// Look up the code CID of an actor.
194    fn get_actor_code_cid(&self, id: ActorID) -> Result<Cid>;
195
196    /// Computes an address for a new actor. The returned address is intended to uniquely refer to
197    /// the actor even in the event of a chain re-org (whereas an ID-address might refer to a
198    /// different actor after messages are re-ordered).
199    /// Always an ActorExec address.
200    fn next_actor_address(&self) -> Result<Address>;
201
202    /// Creates an actor with given `code_cid`, `actor_id`, `delegated_address` (if specified),
203    /// and an empty state.
204    fn create_actor(
205        &mut self,
206        code_cid: Cid,
207        actor_id: ActorID,
208        delegated_address: Option<Address>,
209    ) -> Result<()>;
210
211    fn install_actor(&mut self, code_cid: Cid) -> Result<()>;
212
213    /// Returns the actor's "type" (if builitin) or 0 (if not).
214    fn get_builtin_actor_type(&self, code_cid: &Cid) -> Result<u32>;
215
216    /// Returns the CodeCID for the supplied built-in actor type.
217    fn get_code_cid_for_type(&self, typ: u32) -> Result<Cid>;
218
219    /// Returns the balance associated with an actor id
220    fn balance_of(&self, actor_id: ActorID) -> Result<TokenAmount>;
221}
222
223/// Cryptographic primitives provided by the kernel.
224#[delegatable_trait]
225pub trait CryptoOps {
226    /// Verifies that a signature is valid for an address and plaintext.
227    #[cfg(feature = "verify-signature")]
228    fn verify_signature(
229        &self,
230        sig_type: SignatureType,
231        signature: &[u8],
232        signer: &Address,
233        plaintext: &[u8],
234    ) -> Result<bool>;
235
236    /// Verifies a BLS aggregate signature. In the case where there is one signer/signed plaintext,
237    /// this is equivalent to verifying a non-aggregated BLS signature.
238    ///
239    /// Returns:
240    /// - `Ok(true)` on a valid signature.
241    /// - `Ok(false)` on an invalid signature or if the signature or public keys' bytes represent an
242    ///    invalid curve point.
243    /// - `Err(IllegalArgument)` if `pub_keys.len() != plaintexts.len()`.
244    fn verify_bls_aggregate(
245        &self,
246        aggregate_sig: &[u8; fvm_shared::crypto::signature::BLS_SIG_LEN],
247        pub_keys: &[[u8; fvm_shared::crypto::signature::BLS_PUB_LEN]],
248        plaintexts_concat: &[u8],
249        plaintext_lens: &[u32],
250    ) -> Result<bool>;
251
252    /// Given a message hash and its signature, recovers the public key of the signer.
253    fn recover_secp_public_key(
254        &self,
255        hash: &[u8; SECP_SIG_MESSAGE_HASH_SIZE],
256        signature: &[u8; SECP_SIG_LEN],
257    ) -> Result<[u8; SECP_PUB_LEN]>;
258
259    /// Hashes input `data_in` using with the specified hash function, writing the output to
260    /// `digest_out`, returning the size of the digest written to `digest_out`. If `digest_out` is
261    /// to small to fit the entire digest, it will be truncated. If too large, the leftover space
262    /// will not be overwritten.
263    fn hash(&self, code: u64, data: &[u8]) -> Result<Multihash>;
264}
265
266/// Randomness queries.
267#[delegatable_trait]
268pub trait RandomnessOps {
269    /// Randomness returns a (pseudo)random byte array drawing from the latest
270    /// ticket chain from a given epoch.
271    /// This randomness is fork dependant but also biasable because of this.
272    fn get_randomness_from_tickets(
273        &self,
274        rand_epoch: ChainEpoch,
275    ) -> Result<[u8; RANDOMNESS_LENGTH]>;
276
277    /// Randomness returns a (pseudo)random byte array drawing from the latest
278    /// beacon from a given epoch.
279    /// This randomness is not tied to any fork of the chain, and is unbiasable.
280    fn get_randomness_from_beacon(&self, rand_epoch: ChainEpoch)
281    -> Result<[u8; RANDOMNESS_LENGTH]>;
282}
283
284/// Debugging APIs.
285#[delegatable_trait]
286pub trait DebugOps {
287    /// Log a message.
288    fn log(&mut self, msg: String);
289
290    /// Returns whether debug mode is enabled.
291    fn debug_enabled(&self) -> bool;
292
293    /// Store an artifact.
294    /// Returns error on malformed name, returns Ok and logs the error on system/os errors.
295    fn store_artifact(&self, name: &str, data: &[u8]) -> Result<()>;
296}
297
298/// Eventing APIs.
299#[delegatable_trait]
300pub trait EventOps {
301    /// Records an event emitted throughout execution.
302    fn emit_event(
303        &mut self,
304        event_headers: &[fvm_shared::sys::EventEntry],
305        raw_key: &[u8],
306        raw_val: &[u8],
307    ) -> Result<()>;
308}
309
310/// Import this module (with a glob) if you're implementing a kernel, _especially_ if you want to
311/// use ambassador to delegate the implementation.
312pub mod prelude {
313    pub use super::{
314        ActorOps, CryptoOps, DebugOps, EventOps, IpldBlockOps, MessageOps, NetworkOps,
315        RandomnessOps, SelfOps, SendOps, UpgradeOps,
316    };
317    pub use super::{Block, BlockId, BlockRegistry, BlockStat, CallResult, Kernel, SyscallHandler};
318    pub use super::{
319        ambassador_impl_ActorOps, ambassador_impl_CryptoOps, ambassador_impl_DebugOps,
320        ambassador_impl_EventOps, ambassador_impl_IpldBlockOps, ambassador_impl_MessageOps,
321        ambassador_impl_NetworkOps, ambassador_impl_RandomnessOps, ambassador_impl_SelfOps,
322        ambassador_impl_SendOps, ambassador_impl_UpgradeOps,
323    };
324    pub use crate::gas::{Gas, GasTimer, PriceList};
325    pub use ambassador::Delegate;
326    pub use fvm_shared::address::Address;
327    pub use fvm_shared::clock::ChainEpoch;
328    pub use fvm_shared::crypto::signature::{
329        SECP_PUB_LEN, SECP_SIG_LEN, SECP_SIG_MESSAGE_HASH_SIZE, SignatureType,
330    };
331    pub use fvm_shared::econ::TokenAmount;
332    pub use fvm_shared::error::ExitCode;
333    pub use fvm_shared::randomness::RANDOMNESS_LENGTH;
334    pub use fvm_shared::sys::SendFlags;
335    pub use fvm_shared::sys::out::network::NetworkContext;
336    pub use fvm_shared::sys::out::vm::MessageContext;
337    pub use fvm_shared::version::NetworkVersion;
338    pub use fvm_shared::{ActorID, MethodNum};
339
340    pub use cid::Cid;
341    pub type Multihash = cid::multihash::Multihash<64>;
342}
343
344use prelude::*;