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
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
// Copyright 2021-2023 Protocol Labs
// SPDX-License-Identifier: Apache-2.0, MIT
use ambassador::delegatable_trait;
use fvm_shared::event::StampedEvent;

use crate::call_manager::CallManager;
use crate::machine::limiter::MemoryLimiter;
use crate::machine::Machine;
use crate::syscalls::Linker;

mod blocks;
mod error;
mod hash;

pub mod default;
pub mod filecoin;

pub use blocks::{Block, BlockId, BlockRegistry, BlockStat};
pub use error::{ClassifyResult, Context, ExecutionError, Result, SyscallError};
pub use hash::SupportedHashes;

pub struct CallResult {
    pub block_id: BlockId,
    pub block_stat: BlockStat,
    pub exit_code: ExitCode,
}

/// The "kernel" implements the FVM interface as presented to the actors. It:
///
/// - Manages the Actor's state.
/// - Tracks and charges for IPLD & syscall-specific gas.
///
/// Actors may call into the kernel via the syscalls defined in the [`syscalls`][crate::syscalls]
/// module.
pub trait Kernel: SyscallHandler<Self> + 'static {
    /// The [`Kernel`]'s [`CallManager`] is
    type CallManager: CallManager;
    /// The [`Kernel`]'s memory allocation tracker.
    type Limiter: MemoryLimiter;

    /// Consume the [`Kernel`] and return the underlying [`CallManager`] and [`BlockRegistry`].
    fn into_inner(self) -> (Self::CallManager, BlockRegistry)
    where
        Self: Sized;

    /// Construct a new [`Kernel`] from the given [`CallManager`].
    ///
    /// - `caller` is the ID of the _immediate_ caller.
    /// - `actor_id` is the ID of _this_ actor.
    /// - `method` is the method that has been invoked.
    /// - `value_received` is value received due to the current call.
    /// - `blocks` is the initial block registry (should already contain the parameters).
    #[allow(clippy::too_many_arguments)]
    fn new(
        mgr: Self::CallManager,
        blocks: BlockRegistry,
        caller: ActorID,
        actor_id: ActorID,
        method: MethodNum,
        value_received: TokenAmount,
        read_only: bool,
    ) -> Self
    where
        Self: Sized;

    /// The kernel's underlying "machine".
    fn machine(&self) -> &<Self::CallManager as CallManager>::Machine;

    /// Give access to the limiter of the underlying call manager.
    fn limiter_mut(&mut self) -> &mut Self::Limiter;

    /// Returns the remaining gas for the transaction.
    fn gas_available(&self) -> Gas;

    /// ChargeGas charges specified amount of `gas` for execution.
    /// `name` provides information about gas charging point.
    fn charge_gas(&self, name: &str, compute: Gas) -> Result<GasTimer>;
}

pub trait SyscallHandler<K>: Sized {
    fn link_syscalls(linker: &mut Linker<K>) -> anyhow::Result<()>;
}

/// Network-related operations.
#[delegatable_trait]
pub trait NetworkOps {
    /// Network information (epoch, version, etc.).
    fn network_context(&self) -> Result<NetworkContext>;

    /// The CID of the tipset at the specified epoch.
    fn tipset_cid(&self, epoch: ChainEpoch) -> Result<Cid>;
}

/// Accessors to query attributes of the incoming message.
#[delegatable_trait]
pub trait MessageOps {
    /// Message information.
    fn msg_context(&self) -> Result<MessageContext>;
}

/// The actor calling operations.
#[delegatable_trait]
pub trait SendOps<K: Kernel = Self> {
    /// Sends a message to another actor.
    /// The method type parameter K is the type of the kernel to instantiate for
    /// the receiving actor. This is necessary to support wrapping a kernel, so the outer
    /// kernel can specify its Self as the receiver's kernel type, rather than the wrapped
    /// kernel specifying its Self.
    /// This method is part of the Kernel trait so it can refer to the Self::CallManager
    /// associated type necessary to constrain K.
    fn send(
        &mut self,
        recipient: &Address,
        method: u64,
        params: BlockId,
        value: &TokenAmount,
        gas_limit: Option<Gas>,
        flags: SendFlags,
    ) -> Result<CallResult>;
}

/// The actor upgrade operations.
#[delegatable_trait]
pub trait UpgradeOps<K: Kernel = Self> {
    /// Upgrades the running actor to the specified code CID.
    fn upgrade_actor(&mut self, new_code_cid: Cid, params_id: BlockId) -> Result<CallResult>;
}

/// The IPLD subset of the kernel.
#[delegatable_trait]
pub trait IpldBlockOps {
    /// Open a block.
    ///
    /// This method will fail if the requested block isn't reachable.
    fn block_open(&mut self, cid: &Cid) -> Result<(BlockId, BlockStat)>;

    /// Create a new block.
    ///
    /// This method will fail if the block is too large (SPEC_AUDIT), the codec is not allowed
    /// (SPEC_AUDIT), the block references unreachable blocks, or the block contains too many links
    /// (SPEC_AUDIT).
    fn block_create(&mut self, codec: u64, data: &[u8]) -> Result<BlockId>;

    /// Computes a CID for a block.
    ///
    /// This is the only way to add a new block to the "reachable" set.
    ///
    /// This method will fail if the block handle is invalid.
    fn block_link(&mut self, id: BlockId, hash_fun: u64, hash_len: u32) -> Result<Cid>;

    /// Read data from a block.
    ///
    /// This method will fail if the block handle is invalid.
    fn block_read(&self, id: BlockId, offset: u32, buf: &mut [u8]) -> Result<i32>;

    /// Returns the blocks codec & size.
    ///
    /// This method will fail if the block handle is invalid.
    fn block_stat(&self, id: BlockId) -> Result<BlockStat>;
}

/// Actor state access and manipulation.
/// Depends on BlockOps to read and write blocks in the state tree.
#[delegatable_trait]
pub trait SelfOps: IpldBlockOps {
    /// Get the state root.
    fn root(&mut self) -> Result<Cid>;

    /// Update the state-root.
    ///
    /// This method will fail if the new state-root isn't reachable.
    fn set_root(&mut self, root: Cid) -> Result<()>;

    /// The balance of the receiver.
    fn current_balance(&self) -> Result<TokenAmount>;

    /// Deletes the executing actor from the state tree, burning any remaining balance if requested.
    fn self_destruct(&mut self, burn_unspent: bool) -> Result<()>;
}

/// Actors operations whose scope of action is actors other than the calling
/// actor. The calling actor's state may be consulted to resolve some.
#[delegatable_trait]
pub trait ActorOps {
    /// Resolves an address of any protocol to an ID address (via the Init actor's table).
    /// This allows resolution of externally-provided SECP, BLS, or actor addresses to the canonical form.
    /// If the argument is an ID address it is returned directly.
    fn resolve_address(&self, address: &Address) -> Result<ActorID>;

    /// Looks up the "delegated" (f4) address of the specified actor, if any.
    fn lookup_delegated_address(&self, actor_id: ActorID) -> Result<Option<Address>>;

    /// Look up the code CID of an actor.
    fn get_actor_code_cid(&self, id: ActorID) -> Result<Cid>;

    /// Computes an address for a new actor. The returned address is intended to uniquely refer to
    /// the actor even in the event of a chain re-org (whereas an ID-address might refer to a
    /// different actor after messages are re-ordered).
    /// Always an ActorExec address.
    fn next_actor_address(&self) -> Result<Address>;

    /// Creates an actor with given `code_cid`, `actor_id`, `delegated_address` (if specified),
    /// and an empty state.
    fn create_actor(
        &mut self,
        code_cid: Cid,
        actor_id: ActorID,
        delegated_address: Option<Address>,
    ) -> Result<()>;

    fn install_actor(&mut self, code_cid: Cid) -> Result<()>;

    /// Returns the actor's "type" (if builitin) or 0 (if not).
    fn get_builtin_actor_type(&self, code_cid: &Cid) -> Result<u32>;

    /// Returns the CodeCID for the supplied built-in actor type.
    fn get_code_cid_for_type(&self, typ: u32) -> Result<Cid>;

    /// Returns the balance associated with an actor id
    fn balance_of(&self, actor_id: ActorID) -> Result<TokenAmount>;
}

/// Cryptographic primitives provided by the kernel.
#[delegatable_trait]
pub trait CryptoOps {
    /// Verifies that a signature is valid for an address and plaintext.
    #[cfg(feature = "verify-signature")]
    fn verify_signature(
        &self,
        sig_type: SignatureType,
        signature: &[u8],
        signer: &Address,
        plaintext: &[u8],
    ) -> Result<bool>;

    /// Verifies a BLS aggregate signature. In the case where there is one signer/signed plaintext,
    /// this is equivalent to verifying a non-aggregated BLS signature.
    ///
    /// Returns:
    /// - `Ok(true)` on a valid signature.
    /// - `Ok(false)` on an invalid signature or if the signature or public keys' bytes represent an
    ///    invalid curve point.
    /// - `Err(IllegalArgument)` if `pub_keys.len() != plaintexts.len()`.
    fn verify_bls_aggregate(
        &self,
        aggregate_sig: &[u8; fvm_shared::crypto::signature::BLS_SIG_LEN],
        pub_keys: &[[u8; fvm_shared::crypto::signature::BLS_PUB_LEN]],
        plaintexts_concat: &[u8],
        plaintext_lens: &[u32],
    ) -> Result<bool>;

    /// Given a message hash and its signature, recovers the public key of the signer.
    fn recover_secp_public_key(
        &self,
        hash: &[u8; SECP_SIG_MESSAGE_HASH_SIZE],
        signature: &[u8; SECP_SIG_LEN],
    ) -> Result<[u8; SECP_PUB_LEN]>;

    /// Hashes input `data_in` using with the specified hash function, writing the output to
    /// `digest_out`, returning the size of the digest written to `digest_out`. If `digest_out` is
    /// to small to fit the entire digest, it will be truncated. If too large, the leftover space
    /// will not be overwritten.
    fn hash(&self, code: u64, data: &[u8]) -> Result<Multihash>;
}

/// Randomness queries.
#[delegatable_trait]
pub trait RandomnessOps {
    /// Randomness returns a (pseudo)random byte array drawing from the latest
    /// ticket chain from a given epoch.
    /// This randomness is fork dependant but also biasable because of this.
    fn get_randomness_from_tickets(
        &self,
        rand_epoch: ChainEpoch,
    ) -> Result<[u8; RANDOMNESS_LENGTH]>;

    /// Randomness returns a (pseudo)random byte array drawing from the latest
    /// beacon from a given epoch.
    /// This randomness is not tied to any fork of the chain, and is unbiasable.
    fn get_randomness_from_beacon(&self, rand_epoch: ChainEpoch)
        -> Result<[u8; RANDOMNESS_LENGTH]>;
}

/// Debugging APIs.
#[delegatable_trait]
pub trait DebugOps {
    /// Log a message.
    fn log(&self, msg: String);

    /// Returns whether debug mode is enabled.
    fn debug_enabled(&self) -> bool;

    /// Store an artifact.
    /// Returns error on malformed name, returns Ok and logs the error on system/os errors.
    fn store_artifact(&self, name: &str, data: &[u8]) -> Result<()>;
}

/// Eventing APIs.
#[delegatable_trait]
pub trait EventOps {
    /// Records an event emitted throughout execution.
    fn emit_event(
        &mut self,
        event_headers: &[fvm_shared::sys::EventEntry],
        raw_key: &[u8],
        raw_val: &[u8],
    ) -> Result<()>;
}

/// Import this module (with a glob) if you're implementing a kernel, _especially_ if you want to
/// use ambassador to delegate the implementation.
pub mod prelude {
    pub use super::{
        ambassador_impl_ActorOps, ambassador_impl_CryptoOps, ambassador_impl_DebugOps,
        ambassador_impl_EventOps, ambassador_impl_IpldBlockOps, ambassador_impl_MessageOps,
        ambassador_impl_NetworkOps, ambassador_impl_RandomnessOps, ambassador_impl_SelfOps,
        ambassador_impl_SendOps, ambassador_impl_UpgradeOps,
    };
    pub use super::{
        ActorOps, CryptoOps, DebugOps, EventOps, IpldBlockOps, MessageOps, NetworkOps,
        RandomnessOps, SelfOps, SendOps, UpgradeOps,
    };
    pub use super::{Block, BlockId, BlockRegistry, BlockStat, CallResult, Kernel, SyscallHandler};
    pub use crate::gas::{Gas, GasTimer, PriceList};
    pub use ambassador::Delegate;
    pub use cid::Cid;
    pub use fvm_shared::address::Address;
    pub use fvm_shared::clock::ChainEpoch;
    pub use fvm_shared::crypto::signature::{
        SignatureType, SECP_PUB_LEN, SECP_SIG_LEN, SECP_SIG_MESSAGE_HASH_SIZE,
    };
    pub use fvm_shared::econ::TokenAmount;
    pub use fvm_shared::error::ExitCode;
    pub use fvm_shared::randomness::RANDOMNESS_LENGTH;
    pub use fvm_shared::sys::out::network::NetworkContext;
    pub use fvm_shared::sys::out::vm::MessageContext;
    pub use fvm_shared::sys::SendFlags;
    pub use fvm_shared::version::NetworkVersion;
    pub use fvm_shared::{ActorID, MethodNum};
    pub use multihash::Multihash;
}

use prelude::*;