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::*;