Skip to main content

fvm/kernel/
default.rs

1// Copyright 2021-2023 Protocol Labs
2// SPDX-License-Identifier: Apache-2.0, MIT
3use std::convert::{TryFrom, TryInto};
4use std::path::PathBuf;
5
6use anyhow::{Context as _, anyhow};
7use cid::Cid;
8use fvm_ipld_blockstore::Blockstore;
9use fvm_ipld_encoding::{CBOR, IPLD_RAW};
10use fvm_shared::crypto::signature;
11use fvm_shared::error::ErrorNumber;
12use fvm_shared::event::{ActorEvent, Entry, Flags};
13use fvm_shared::sys::out::vm::ContextFlags;
14use fvm_shared::upgrade::UpgradeInfo;
15use multihash_codetable::MultihashDigest;
16
17use super::blocks::{Block, BlockRegistry};
18use super::error::Result;
19use super::hash::SupportedHashes;
20use super::*;
21use crate::call_manager::{
22    CallManager, Entrypoint, INVOKE_FUNC_NAME, InvocationResult, NO_DATA_BLOCK_ID,
23    UPGRADE_FUNC_NAME,
24};
25use crate::externs::{Chain, Rand};
26use crate::gas::GasTimer;
27use crate::init_actor::INIT_ACTOR_ID;
28use crate::machine::{BURNT_FUNDS_ACTOR_ID, MachineContext, NetworkConfig};
29use crate::state_tree::ActorState;
30use crate::trace::IpldOperation;
31use crate::{ipld, syscall_error};
32
33const BLAKE2B_256: u64 = 0xb220;
34const ENV_ARTIFACT_DIR: &str = "FVM_STORE_ARTIFACT_DIR";
35const MAX_ARTIFACT_NAME_LEN: usize = 256;
36
37#[cfg(feature = "testing")]
38const TEST_ACTOR_ALLOWED_TO_CALL_CREATE_ACTOR: ActorID = 98;
39
40/// The "default" [`Kernel`] implementation.
41pub struct DefaultKernel<C> {
42    // Fields extracted from the message, except parameters, which have been
43    // preloaded into the block registry.
44    pub caller: ActorID,
45    pub actor_id: ActorID,
46    pub method: MethodNum,
47    pub value_received: TokenAmount,
48    pub read_only: bool,
49
50    /// The call manager for this call stack. If this kernel calls another actor, it will
51    /// temporarily "give" the call manager to the other kernel before re-attaching it.
52    pub call_manager: C,
53    /// Tracks block data and organizes it through index handles so it can be
54    /// referred to.
55    ///
56    /// This does not yet reason about reachability.
57    pub blocks: BlockRegistry,
58}
59
60// Even though all children traits are implemented, Rust needs to know that the
61// supertrait is implemented too.
62impl<C> Kernel for DefaultKernel<C>
63where
64    C: CallManager,
65{
66    type CallManager = C;
67    type Limiter = <<C as CallManager>::Machine as Machine>::Limiter;
68
69    fn into_inner(self) -> (Self::CallManager, BlockRegistry)
70    where
71        Self: Sized,
72    {
73        (self.call_manager, self.blocks)
74    }
75
76    fn new(
77        mgr: C,
78        blocks: BlockRegistry,
79        caller: ActorID,
80        actor_id: ActorID,
81        method: MethodNum,
82        value_received: TokenAmount,
83        read_only: bool,
84    ) -> Self {
85        DefaultKernel {
86            call_manager: mgr,
87            blocks,
88            caller,
89            actor_id,
90            method,
91            value_received,
92            read_only,
93        }
94    }
95
96    fn machine(&self) -> &<Self::CallManager as CallManager>::Machine {
97        self.call_manager.machine()
98    }
99
100    fn limiter_mut(&mut self) -> &mut Self::Limiter {
101        self.call_manager.limiter_mut()
102    }
103
104    fn gas_available(&self) -> Gas {
105        self.call_manager.gas_tracker().gas_available()
106    }
107
108    fn charge_gas(&self, name: &str, compute: Gas) -> Result<GasTimer> {
109        self.call_manager.gas_tracker().charge_gas(name, compute)
110    }
111}
112
113impl<C> DefaultKernel<C>
114where
115    C: CallManager,
116{
117    /// Returns `Some(actor_state)` or `None` if this actor has been deleted.
118    fn get_self(&self) -> Result<Option<ActorState>> {
119        self.call_manager.get_actor(self.actor_id)
120    }
121}
122
123impl<K> SendOps<K> for DefaultKernel<K::CallManager>
124where
125    K: Kernel,
126{
127    fn send(
128        &mut self,
129        recipient: &Address,
130        method: MethodNum,
131        params_id: BlockId,
132        value: &TokenAmount,
133        gas_limit: Option<Gas>,
134        flags: SendFlags,
135    ) -> Result<CallResult> {
136        let from = self.actor_id;
137        let read_only = self.read_only || flags.read_only();
138
139        if read_only && !value.is_zero() {
140            return Err(syscall_error!(ReadOnly; "cannot transfer value when read-only").into());
141        }
142
143        // Load parameters.
144        let params = if params_id == NO_DATA_BLOCK_ID {
145            None
146        } else {
147            Some(self.blocks.get(params_id)?.clone())
148        };
149
150        // Make sure we can actually store the return block.
151        if self.blocks.is_full() {
152            return Err(syscall_error!(LimitExceeded; "cannot store return block").into());
153        }
154
155        // Send.
156        let result = self.call_manager.with_transaction(|cm| {
157            cm.call_actor::<K>(
158                from,
159                *recipient,
160                Entrypoint::Invoke(method),
161                params,
162                value,
163                gas_limit,
164                read_only,
165            )
166        })?;
167
168        // Store result and return.
169        Ok(match result {
170            InvocationResult {
171                exit_code,
172                value: Some(blk),
173            } => {
174                let block_stat = blk.stat();
175                // This can't fail because:
176                // 1. We've already charged for gas.
177                // 2. We've already checked that we have space for a return block.
178                // 3. This block has already been validated by the kernel that returned it.
179                let block_id = self
180                    .blocks
181                    .put_reachable(blk)
182                    .or_fatal()
183                    .context("failed to store a valid return value")?;
184                CallResult {
185                    block_id,
186                    block_stat,
187                    exit_code,
188                }
189            }
190            InvocationResult {
191                exit_code,
192                value: None,
193            } => CallResult {
194                block_id: NO_DATA_BLOCK_ID,
195                block_stat: BlockStat { codec: 0, size: 0 },
196                exit_code,
197            },
198        })
199    }
200}
201
202impl<K> UpgradeOps<K> for DefaultKernel<K::CallManager>
203where
204    K: Kernel,
205{
206    fn upgrade_actor(&mut self, new_code_cid: Cid, params_id: BlockId) -> Result<CallResult> {
207        if self.read_only {
208            return Err(
209                syscall_error!(ReadOnly, "upgrade_actor cannot be called while read-only").into(),
210            );
211        }
212
213        // check if this actor is already on the call stack
214        //
215        // We first find the first position of this actor on the call stack, and then make sure that
216        // no other actor appears on the call stack after 'position' (unless its a recursive upgrade
217        // call which is allowed)
218        let mut iter = self.call_manager.get_call_stack().iter();
219        let position = iter.position(|&tuple| tuple == (self.actor_id, INVOKE_FUNC_NAME));
220        if position.is_some() {
221            for tuple in iter {
222                if tuple.0 != self.actor_id || tuple.1 != UPGRADE_FUNC_NAME {
223                    return Err(syscall_error!(
224                        Forbidden,
225                        "calling upgrade on actor already on call stack is forbidden"
226                    )
227                    .into());
228                }
229            }
230        }
231
232        // Load parameters.
233        let params = if params_id == NO_DATA_BLOCK_ID {
234            None
235        } else {
236            Some(self.blocks.get(params_id)?.clone())
237        };
238
239        // Make sure we can actually store the return block.
240        if self.blocks.is_full() {
241            return Err(syscall_error!(LimitExceeded; "cannot store return block").into());
242        }
243
244        let result = self.call_manager.with_transaction(|cm| {
245            let state = cm
246                .get_actor(self.actor_id)?
247                .ok_or_else(|| syscall_error!(IllegalOperation; "actor deleted"))?;
248
249            // store the code cid of the calling actor before running the upgrade entrypoint
250            // in case it was changed (which could happen if the target upgrade entrypoint
251            // sent a message to this actor which in turn called upgrade)
252            let code = state.code;
253
254            // update the code cid of the actor to new_code_cid
255            cm.set_actor(
256                self.actor_id,
257                ActorState::new(
258                    new_code_cid,
259                    state.state,
260                    state.balance,
261                    state.sequence,
262                    None,
263                ),
264            )?;
265
266            // run the upgrade entrypoint
267            let result = cm.call_actor::<K>(
268                self.caller,
269                Address::new_id(self.actor_id),
270                Entrypoint::Upgrade(UpgradeInfo { old_code_cid: code }),
271                params,
272                &TokenAmount::from_whole(0),
273                None,
274                false,
275            )?;
276
277            Ok(result)
278        });
279
280        match result {
281            Ok(InvocationResult { exit_code, value }) => {
282                let (block_stat, block_id) = match value {
283                    None => (BlockStat { codec: 0, size: 0 }, NO_DATA_BLOCK_ID),
284                    Some(block) => (block.stat(), self.blocks.put_reachable(block)?),
285                };
286                Ok(CallResult {
287                    block_id,
288                    block_stat,
289                    exit_code,
290                })
291            }
292            Err(err) => Err(err),
293        }
294    }
295}
296
297impl<C> SelfOps for DefaultKernel<C>
298where
299    C: CallManager,
300{
301    fn root(&mut self) -> Result<Cid> {
302        let t = self
303            .call_manager
304            .charge_gas(self.call_manager.price_list().on_get_root())?;
305
306        // This can fail during normal operations if the actor has been deleted.
307        let cid = self
308            .get_self()?
309            .context("state root requested after actor deletion")
310            .or_error(ErrorNumber::IllegalOperation)?
311            .state;
312
313        self.blocks.mark_reachable(&cid);
314
315        t.stop();
316
317        Ok(cid)
318    }
319
320    fn set_root(&mut self, new: Cid) -> Result<()> {
321        if self.read_only {
322            return Err(
323                syscall_error!(ReadOnly; "cannot update the state-root while read-only").into(),
324            );
325        }
326
327        let _ = self
328            .call_manager
329            .charge_gas(self.call_manager.price_list().on_set_root())?;
330
331        if !self.blocks.is_reachable(&new) {
332            return Err(syscall_error!(NotFound; "new root cid not reachable: {new}").into());
333        }
334
335        let mut state = self
336            .call_manager
337            .get_actor(self.actor_id)?
338            .ok_or_else(|| syscall_error!(IllegalOperation; "actor deleted"))?;
339        state.state = new;
340        self.call_manager.set_actor(self.actor_id, state)?;
341        Ok(())
342    }
343
344    fn current_balance(&self) -> Result<TokenAmount> {
345        let t = self
346            .call_manager
347            .charge_gas(self.call_manager.price_list().on_self_balance())?;
348
349        // If the actor doesn't exist, it has zero balance.
350        t.record(Ok(self.get_self()?.map(|a| a.balance).unwrap_or_default()))
351    }
352
353    fn self_destruct(&mut self, burn_unspent: bool) -> Result<()> {
354        if self.read_only {
355            return Err(syscall_error!(ReadOnly; "cannot self-destruct when read-only").into());
356        }
357
358        // Idempotent: If the actor doesn't exist, this won't actually do anything. The current
359        // balance will be zero, and `delete_actor_id` will be a no-op.
360        let t = self
361            .call_manager
362            .charge_gas(self.call_manager.price_list().on_delete_actor())?;
363
364        // If there are remaining funds, burn them. We do this instead of letting the user to
365        // specify the beneficiary as:
366        //
367        // 1. This lets the user handle transfer failure cases themselves. The only way _this_ can
368        //    fail is for the caller to run out of gas.
369        // 2. If we ever decide to allow code on method 0, allowing transfers here would be
370        //    unfortunate.
371        let balance = self.current_balance()?;
372        if !balance.is_zero() {
373            if !burn_unspent {
374                return Err(
375                    syscall_error!(IllegalOperation; "self-destruct with unspent funds").into(),
376                );
377            }
378            self.call_manager
379                .transfer(self.actor_id, BURNT_FUNDS_ACTOR_ID, &balance)
380                .or_fatal()?;
381        }
382
383        // Delete the executing actor.
384        t.record(self.call_manager.delete_actor(self.actor_id))
385    }
386}
387
388impl<C> IpldBlockOps for DefaultKernel<C>
389where
390    C: CallManager,
391{
392    fn block_open(&mut self, cid: &Cid) -> Result<(BlockId, BlockStat)> {
393        let t = self
394            .call_manager
395            .charge_gas(self.call_manager.price_list().on_block_open_base())?;
396
397        if !self.blocks.is_reachable(cid) {
398            return Err(syscall_error!(NotFound; "block not reachable: {cid}").into());
399        }
400
401        let data = self
402            .call_manager
403            .blockstore()
404            .get(cid)
405            // Treat missing blocks as errors as well.
406            .and_then(|b| b.ok_or_else(|| anyhow!("missing reachable state: {}", cid)))
407            // TODO Any failures here should really be considered "super fatal". It means we're
408            // missing state and/or have a corrupted store.
409            .or_fatal()?;
410
411        t.stop();
412
413        self.call_manager
414            .trace_ipld(IpldOperation::Get, *cid, data.len());
415
416        // This can fail because we can run out of gas.
417        let children = ipld::scan_for_reachable_links(
418            cid.codec(),
419            &data,
420            self.call_manager.price_list(),
421            self.call_manager.gas_tracker(),
422        )?;
423
424        let t = self.call_manager.charge_gas(
425            self.call_manager
426                .price_list()
427                .on_block_open(data.len(), children.len()),
428        )?;
429
430        let block = Block::new(cid.codec(), data, children);
431        let stat = block.stat();
432        let id = self.blocks.put_reachable(block)?;
433        t.stop();
434        Ok((id, stat))
435    }
436
437    fn block_create(&mut self, codec: u64, data: &[u8]) -> Result<BlockId> {
438        if data.len() > self.machine().context().max_block_size {
439            return Err(syscall_error!(LimitExceeded; "blocks may not be larger than 1MiB").into());
440        }
441
442        if !ipld::ALLOWED_CODECS.contains(&codec) {
443            return Err(syscall_error!(IllegalCodec; "codec {} not allowed", codec).into());
444        }
445
446        let children = ipld::scan_for_reachable_links(
447            codec,
448            data,
449            self.call_manager.price_list(),
450            self.call_manager.gas_tracker(),
451        )?;
452
453        let t = self.call_manager.charge_gas(
454            self.call_manager
455                .price_list()
456                .on_block_create(data.len(), children.len()),
457        )?;
458
459        let blk = Block::new(codec, data, children);
460
461        t.record(Ok(self.blocks.put_check_reachable(blk)?))
462    }
463
464    fn block_link(&mut self, id: BlockId, hash_fun: u64, hash_len: u32) -> Result<Cid> {
465        if hash_fun != BLAKE2B_256 || hash_len != 32 {
466            return Err(syscall_error!(IllegalCid; "cids must be 32-byte blake2b").into());
467        }
468        let start = GasTimer::start();
469        let block = self.blocks.get(id)?;
470        let code = SupportedHashes::try_from(hash_fun)
471            .map_err(|_| syscall_error!(IllegalCid; "invalid CID codec"))?;
472
473        let t = self.call_manager.charge_gas(
474            self.call_manager
475                .price_list()
476                .on_block_link(code, block.size() as usize),
477        )?;
478
479        let hash = code.digest(block.data());
480        if u32::from(hash.size()) < hash_len {
481            return Err(syscall_error!(IllegalCid; "invalid hash length: {}", hash_len).into());
482        }
483        let k = Cid::new_v1(block.codec(), hash.truncate(hash_len as u8));
484        self.call_manager
485            .blockstore()
486            .put_keyed(&k, block.data())
487            // TODO: This is really "super fatal". It means we failed to store state, and should
488            // probably abort the entire block.
489            .or_fatal()?;
490        let size = block.data().len();
491        self.blocks.mark_reachable(&k);
492
493        t.stop_with(start);
494
495        self.call_manager.trace_ipld(IpldOperation::Put, k, size);
496
497        Ok(k)
498    }
499
500    fn block_read(&self, id: BlockId, offset: u32, buf: &mut [u8]) -> Result<i32> {
501        let tstart = GasTimer::start();
502        // First, find the end of the _logical_ buffer (taking the offset into account).
503        // This must fit into an i32.
504
505        // We perform operations as u64, because we know that the buffer length and offset must fit
506        // in a u32.
507        let end = i32::try_from((offset as u64) + (buf.len() as u64))
508            .map_err(|_| syscall_error!(IllegalArgument; "offset plus buffer length did not fit into an i32"))?;
509
510        // Then get the block.
511        let block = self.blocks.get(id)?;
512        let data = block.data();
513
514        // We start reading at this offset.
515        let start = offset as usize;
516
517        // We read (block_length - start) bytes, or until we fill the buffer.
518        let to_read = std::cmp::min(data.len().saturating_sub(start), buf.len());
519
520        // We can now _charge_, because we actually know how many bytes we need to read.
521        let t = self
522            .call_manager
523            .charge_gas(self.call_manager.price_list().on_block_read(to_read))?;
524
525        // Copy into the output buffer, but only if were're reading. If to_read == 0, start may be
526        // past the end of the block.
527        if to_read != 0 {
528            buf[..to_read].copy_from_slice(&data[start..(start + to_read)]);
529        }
530        t.stop_with(tstart);
531        // Returns the difference between the end of the block, and offset + buf.len()
532        Ok((data.len() as i32) - end)
533    }
534
535    fn block_stat(&self, id: BlockId) -> Result<BlockStat> {
536        let t = self
537            .call_manager
538            .charge_gas(self.call_manager.price_list().on_block_stat())?;
539
540        t.record(Ok(self.blocks.stat(id)?))
541    }
542}
543
544impl<C> MessageOps for DefaultKernel<C>
545where
546    C: CallManager,
547{
548    fn msg_context(&self) -> Result<MessageContext> {
549        let t = self
550            .call_manager
551            .charge_gas(self.call_manager.price_list().on_message_context())?;
552
553        let ctx = MessageContext {
554            caller: self.caller,
555            origin: self.call_manager.origin(),
556            receiver: self.actor_id,
557            method_number: self.method,
558            value_received: (&self.value_received)
559                .try_into()
560                .or_fatal()
561                .context("invalid token amount")?,
562            gas_premium: self
563                .call_manager
564                .gas_premium()
565                .try_into()
566                .or_fatal()
567                .context("invalid gas premium")?,
568            flags: if self.read_only {
569                ContextFlags::READ_ONLY
570            } else {
571                ContextFlags::empty()
572            },
573            nonce: self.call_manager.nonce(),
574        };
575        t.stop();
576        Ok(ctx)
577    }
578}
579
580impl<C> CryptoOps for DefaultKernel<C>
581where
582    C: CallManager,
583{
584    #[cfg(feature = "verify-signature")]
585    fn verify_signature(
586        &self,
587        sig_type: SignatureType,
588        signature: &[u8],
589        signer: &Address,
590        plaintext: &[u8],
591    ) -> Result<bool> {
592        use fvm_shared::address::Payload;
593        use std::panic::{self, UnwindSafe};
594
595        fn catch_and_log_panic<F: FnOnce() -> Result<R> + UnwindSafe, R>(
596            context: &str,
597            f: F,
598        ) -> Result<R> {
599            match panic::catch_unwind(f) {
600                Ok(v) => v,
601                Err(e) => {
602                    log::error!("caught panic when {}: {:?}", context, e);
603                    Err(
604                        syscall_error!(IllegalArgument; "caught panic when {}: {:?}", context, e)
605                            .into(),
606                    )
607                }
608            }
609        }
610
611        let t = self.call_manager.charge_gas(
612            self.call_manager
613                .price_list()
614                .on_verify_signature(sig_type, plaintext.len()),
615        )?;
616
617        // We only support key addresses (f1/f3). This change does not require a FIP, because no
618        // actors invoke this method with non-key addresses.
619        let signing_addr = match signer.payload() {
620            Payload::BLS(_) | Payload::Secp256k1(_) => *signer,
621            // Not a key address.
622            _ => {
623                return Err(syscall_error!(IllegalArgument; "address protocol {} not supported", signer.protocol()).into());
624            }
625        };
626
627        // Verify signature, catching errors. Signature verification can include some complicated
628        // math.
629        t.record(catch_and_log_panic("verifying signature", || {
630            Ok(signature::verify(sig_type, signature, plaintext, &signing_addr).is_ok())
631        }))
632    }
633
634    fn verify_bls_aggregate(
635        &self,
636        aggregate_sig: &[u8; signature::BLS_SIG_LEN],
637        pub_keys: &[[u8; signature::BLS_PUB_LEN]],
638        plaintexts_concat: &[u8],
639        plaintext_lens: &[u32],
640    ) -> Result<bool> {
641        let num_signers = pub_keys.len();
642
643        if num_signers != plaintext_lens.len() {
644            return Err(syscall_error!(
645                IllegalArgument;
646                "unequal numbers of bls public keys and plaintexts"
647            )
648            .into());
649        }
650
651        let t = self.call_manager.charge_gas(
652            self.call_manager
653                .price_list()
654                .on_verify_aggregate_signature(num_signers, plaintexts_concat.len()),
655        )?;
656
657        let mut offset: usize = 0;
658        let plaintexts = plaintext_lens
659            .iter()
660            .map(|&len| {
661                let start = offset;
662                offset = start
663                    .checked_add(len as usize)
664                    .context("invalid bls plaintext length")
665                    .or_illegal_argument()?;
666                plaintexts_concat
667                    .get(start..offset)
668                    .context("bls signature plaintext out of bounds")
669                    .or_illegal_argument()
670            })
671            .collect::<Result<Vec<_>>>()?;
672        if offset != plaintexts_concat.len() {
673            return Err(
674                syscall_error!(IllegalArgument; "plaintexts buffer length doesn't match").into(),
675            );
676        }
677
678        t.record(
679            signature::ops::verify_bls_aggregate(aggregate_sig, pub_keys, &plaintexts)
680                .or(Ok(false)),
681        )
682    }
683
684    fn recover_secp_public_key(
685        &self,
686        hash: &[u8; SECP_SIG_MESSAGE_HASH_SIZE],
687        signature: &[u8; SECP_SIG_LEN],
688    ) -> Result<[u8; SECP_PUB_LEN]> {
689        let t = self
690            .call_manager
691            .charge_gas(self.call_manager.price_list().on_recover_secp_public_key())?;
692
693        t.record(
694            signature::ops::recover_secp_public_key(hash, signature)
695                .or_illegal_argument()
696                .context("public key recovery failed"),
697        )
698    }
699
700    fn hash(&self, code: u64, data: &[u8]) -> Result<Multihash> {
701        let hasher = SupportedHashes::try_from(code)
702            .map_err(|err| syscall_error!(IllegalArgument; "unsupported hash code {}", err.0))?;
703
704        let t = self.call_manager.charge_gas(
705            self.call_manager
706                .price_list()
707                .on_hashing(hasher, data.len()),
708        )?;
709
710        t.record(Ok(hasher.digest(data)))
711    }
712}
713
714impl<C> NetworkOps for DefaultKernel<C>
715where
716    C: CallManager,
717{
718    fn network_context(&self) -> Result<NetworkContext> {
719        let t = self
720            .call_manager
721            .charge_gas(self.call_manager.price_list().on_network_context())?;
722
723        let MachineContext {
724            epoch,
725            timestamp,
726            base_fee,
727            network:
728                NetworkConfig {
729                    network_version,
730                    chain_id,
731                    ..
732                },
733            ..
734        } = self.call_manager.context();
735
736        let ctx = NetworkContext {
737            chain_id: (*chain_id).into(),
738            epoch: *epoch,
739            network_version: *network_version,
740            timestamp: *timestamp,
741            base_fee: base_fee
742                .try_into()
743                .or_fatal()
744                .context("base-fee exceeds u128 limit")?,
745        };
746
747        t.stop();
748        Ok(ctx)
749    }
750
751    fn tipset_cid(&self, epoch: ChainEpoch) -> Result<Cid> {
752        use std::cmp::Ordering::*;
753
754        if epoch < 0 {
755            return Err(syscall_error!(IllegalArgument; "epoch is negative").into());
756        }
757        let offset = self.call_manager.context().epoch - epoch;
758
759        // Can't lookup the current tipset CID, or a future tipset CID>
760        match offset.cmp(&0) {
761            Less => return Err(syscall_error!(IllegalArgument; "epoch {} is in the future", epoch).into()),
762            Equal => return Err(syscall_error!(IllegalArgument; "cannot lookup the tipset cid for the current epoch").into()),
763            Greater => {}
764        }
765
766        self.call_manager
767            .charge_gas(self.call_manager.price_list().on_tipset_cid(offset))?;
768
769        self.call_manager.externs().get_tipset_cid(epoch).or_fatal()
770    }
771}
772
773impl<C> RandomnessOps for DefaultKernel<C>
774where
775    C: CallManager,
776{
777    fn get_randomness_from_tickets(
778        &self,
779        rand_epoch: ChainEpoch,
780    ) -> Result<[u8; RANDOMNESS_LENGTH]> {
781        let lookback = self
782            .call_manager
783            .context()
784            .epoch
785            .checked_sub(rand_epoch)
786            .ok_or_else(|| syscall_error!(IllegalArgument; "randomness epoch {} is in the future", rand_epoch)
787            )?;
788
789        let t = self
790            .call_manager
791            .charge_gas(self.call_manager.price_list().on_get_randomness(lookback))?;
792
793        t.record(
794            self.call_manager
795                .externs()
796                .get_chain_randomness(rand_epoch)
797                .or_illegal_argument(),
798        )
799    }
800
801    fn get_randomness_from_beacon(
802        &self,
803        rand_epoch: ChainEpoch,
804    ) -> Result<[u8; RANDOMNESS_LENGTH]> {
805        let lookback = self
806            .call_manager
807            .context()
808            .epoch
809            .checked_sub(rand_epoch)
810            .ok_or_else(|| syscall_error!(IllegalArgument; "randomness epoch {} is in the future", rand_epoch))?;
811
812        let t = self
813            .call_manager
814            .charge_gas(self.call_manager.price_list().on_get_randomness(lookback))?;
815
816        t.record(
817            self.call_manager
818                .externs()
819                .get_beacon_randomness(rand_epoch)
820                .or_illegal_argument(),
821        )
822    }
823}
824
825impl<C> ActorOps for DefaultKernel<C>
826where
827    C: CallManager,
828{
829    fn resolve_address(&self, address: &Address) -> Result<ActorID> {
830        let t = self
831            .call_manager
832            .charge_gas(self.call_manager.price_list().on_resolve_address())?;
833
834        t.record(Ok(self
835            .call_manager
836            .resolve_address(address)?
837            .ok_or_else(|| syscall_error!(NotFound; "actor not found"))?))
838    }
839
840    fn get_actor_code_cid(&self, id: ActorID) -> Result<Cid> {
841        let t = self
842            .call_manager
843            .charge_gas(self.call_manager.price_list().on_get_actor_code_cid())?;
844
845        t.record(Ok(self
846            .call_manager
847            .get_actor(id)?
848            .ok_or_else(|| syscall_error!(NotFound; "actor not found"))?
849            .code))
850    }
851
852    fn next_actor_address(&self) -> Result<Address> {
853        Ok(self.call_manager.next_actor_address())
854    }
855
856    fn create_actor(
857        &mut self,
858        code_id: Cid,
859        actor_id: ActorID,
860        delegated_address: Option<Address>,
861    ) -> Result<()> {
862        let is_allowed_to_create_actor = self.actor_id == INIT_ACTOR_ID;
863
864        #[cfg(feature = "testing")]
865        let is_allowed_to_create_actor =
866            is_allowed_to_create_actor || self.actor_id == TEST_ACTOR_ALLOWED_TO_CALL_CREATE_ACTOR;
867
868        if !is_allowed_to_create_actor {
869            return Err(syscall_error!(
870                Forbidden,
871                "create_actor is restricted to InitActor. Called by {}",
872                self.actor_id
873            )
874            .into());
875        }
876
877        if self.read_only {
878            return Err(
879                syscall_error!(ReadOnly, "create_actor cannot be called while read-only").into(),
880            );
881        }
882
883        self.call_manager
884            .create_actor(code_id, actor_id, delegated_address)
885    }
886
887    fn install_actor(&mut self, code_id: Cid) -> Result<()> {
888        let start = GasTimer::start();
889
890        let size = self
891            .call_manager
892            .engine()
893            .preload_all(self.call_manager.blockstore(), &[code_id])
894            .context("failed to install actor")
895            .or_illegal_argument()?;
896
897        let t = self
898            .call_manager
899            .charge_gas(self.call_manager.price_list().on_install_actor(size))?;
900        t.stop_with(start);
901
902        self.call_manager
903            .trace_ipld(IpldOperation::Get, code_id, size);
904
905        Ok(())
906    }
907
908    fn get_builtin_actor_type(&self, code_cid: &Cid) -> Result<u32> {
909        let t = self
910            .call_manager
911            .charge_gas(self.call_manager.price_list().on_get_builtin_actor_type())?;
912
913        let id = self
914            .call_manager
915            .machine()
916            .builtin_actors()
917            .id_by_code(code_cid);
918
919        t.stop();
920        Ok(id)
921    }
922
923    fn get_code_cid_for_type(&self, typ: u32) -> Result<Cid> {
924        let t = self
925            .call_manager
926            .charge_gas(self.call_manager.price_list().on_get_code_cid_for_type())?;
927
928        t.record(
929            self.call_manager
930                .machine()
931                .builtin_actors()
932                .code_by_id(typ)
933                .cloned()
934                .context("tried to resolve CID of unrecognized actor type")
935                .or_illegal_argument(),
936        )
937    }
938
939    fn balance_of(&self, actor_id: ActorID) -> Result<TokenAmount> {
940        let t = self
941            .call_manager
942            .charge_gas(self.call_manager.price_list().on_balance_of())?;
943
944        Ok(t.record(self.call_manager.get_actor(actor_id))?
945            .ok_or_else(|| syscall_error!(NotFound; "actor not found"))?
946            .balance)
947    }
948
949    fn lookup_delegated_address(&self, actor_id: ActorID) -> Result<Option<Address>> {
950        let t = self
951            .call_manager
952            .charge_gas(self.call_manager.price_list().on_lookup_delegated_address())?;
953
954        Ok(t.record(self.call_manager.get_actor(actor_id))?
955            .ok_or_else(|| syscall_error!(NotFound; "actor not found"))?
956            .delegated_address)
957    }
958}
959
960impl<C> DebugOps for DefaultKernel<C>
961where
962    C: CallManager,
963{
964    fn log(&mut self, msg: String) {
965        self.call_manager.log(msg)
966    }
967
968    fn debug_enabled(&self) -> bool {
969        self.call_manager.context().actor_debugging
970    }
971
972    fn store_artifact(&self, name: &str, data: &[u8]) -> Result<()> {
973        // Ensure well formed artifact name
974        {
975            if name.len() > MAX_ARTIFACT_NAME_LEN {
976                Err("debug artifact name should not exceed 256 bytes")
977            } else if name.chars().any(std::path::is_separator) {
978                Err("debug artifact name should not include any path separators")
979            } else if name
980                .chars()
981                .next()
982                .ok_or("debug artifact name should be at least one character")
983                .or_error(fvm_shared::error::ErrorNumber::IllegalArgument)?
984                == '.'
985            {
986                Err("debug artifact name should not start with a decimal '.'")
987            } else {
988                Ok(())
989            }
990        }
991        .or_error(fvm_shared::error::ErrorNumber::IllegalArgument)?;
992
993        // Write to disk
994        if let Ok(dir) = std::env::var(ENV_ARTIFACT_DIR).as_deref() {
995            let dir: PathBuf = [
996                dir,
997                self.call_manager.machine().machine_id(),
998                &self.call_manager.origin().to_string(),
999                &self.call_manager.nonce().to_string(),
1000                &self.actor_id.to_string(),
1001                &self.call_manager.invocation_count().to_string(),
1002            ]
1003            .iter()
1004            .collect();
1005
1006            if let Err(e) = std::fs::create_dir_all(dir.clone()) {
1007                log::error!("failed to make directory to store debug artifacts {}", e);
1008            } else if let Err(e) = std::fs::write(dir.join(name), data) {
1009                log::error!("failed to store debug artifact {}", e)
1010            } else {
1011                log::info!("wrote artifact: {} to {:?}", name, dir);
1012            }
1013        } else {
1014            log::error!(
1015                "store_artifact was ignored, env var {} was not set",
1016                ENV_ARTIFACT_DIR
1017            )
1018        }
1019        Ok(())
1020    }
1021}
1022
1023impl<C> EventOps for DefaultKernel<C>
1024where
1025    C: CallManager,
1026{
1027    fn emit_event(
1028        &mut self,
1029        event_headers: &[fvm_shared::sys::EventEntry],
1030        event_keys: &[u8],
1031        event_values: &[u8],
1032    ) -> Result<()> {
1033        const MAX_NR_ENTRIES: usize = 255;
1034        const MAX_KEY_LEN: usize = 31;
1035        const MAX_TOTAL_VALUES_LEN: usize = 8 << 10;
1036
1037        if self.read_only {
1038            return Err(syscall_error!(ReadOnly; "cannot emit events while read-only").into());
1039        }
1040
1041        let t = self
1042            .call_manager
1043            .charge_gas(self.call_manager.price_list().on_actor_event(
1044                event_headers.len(),
1045                event_keys.len(),
1046                event_values.len(),
1047            ))?;
1048
1049        if event_headers.len() > MAX_NR_ENTRIES {
1050            return Err(syscall_error!(LimitExceeded; "event exceeded max entries: {} > {MAX_NR_ENTRIES}", event_headers.len()).into());
1051        }
1052
1053        if event_values.len() > MAX_TOTAL_VALUES_LEN {
1054            return Err(syscall_error!(LimitExceeded; "total event value lengths exceeded the max size: {} > {MAX_TOTAL_VALUES_LEN}", event_values.len()).into());
1055        }
1056
1057        // We validate utf8 all at once for better performance.
1058        let event_keys = std::str::from_utf8(event_keys)
1059            .context("invalid event key")
1060            .or_illegal_argument()?;
1061
1062        let mut key_offset: usize = 0;
1063        let mut val_offset: usize = 0;
1064
1065        let mut entries: Vec<Entry> = Vec::with_capacity(event_headers.len());
1066        for header in event_headers {
1067            // make sure that the fixed parsed values are within bounds before we do any allocation
1068            let flags = header.flags;
1069            if Flags::from_bits(flags.bits()).is_none() {
1070                return Err(
1071                    syscall_error!(IllegalArgument; "event flags are invalid: {}", flags.bits())
1072                        .into(),
1073                );
1074            }
1075
1076            if header.key_len > MAX_KEY_LEN as u32 {
1077                let tmp = header.key_len;
1078                return Err(syscall_error!(LimitExceeded; "event key exceeded max size: {} > {MAX_KEY_LEN}", tmp).into());
1079            }
1080
1081            // We check this here purely to detect/prevent integer overflows below. That's why we
1082            // return IllegalArgument, not LimitExceeded.
1083            if header.val_len > MAX_TOTAL_VALUES_LEN as u32 {
1084                return Err(
1085                    syscall_error!(IllegalArgument; "event entry value out of range").into(),
1086                );
1087            }
1088
1089            // parse the variable sized fields from the raw_key/raw_val buffers
1090            let key = &event_keys
1091                .get(key_offset..key_offset + header.key_len as usize)
1092                .context("event entry key out of range")
1093                .or_illegal_argument()?;
1094
1095            let value = &event_values
1096                .get(val_offset..val_offset + header.val_len as usize)
1097                .context("event entry value out of range")
1098                .or_illegal_argument()?;
1099
1100            // Check the codec. We currently only allow IPLD_RAW or CBOR.
1101            if header.codec != IPLD_RAW && header.codec != CBOR {
1102                let tmp = header.codec;
1103                return Err(
1104                    syscall_error!(IllegalCodec; "event codec must be IPLD_RAW or CBOR, was: {}", tmp)
1105                        .into(),
1106                );
1107            }
1108
1109            // we have all we need to construct a new Entry
1110            let entry = Entry {
1111                flags: header.flags,
1112                key: key.to_string(),
1113                codec: header.codec,
1114                value: value.to_vec(),
1115            };
1116
1117            // shift the key/value offsets
1118            key_offset += header.key_len as usize;
1119            val_offset += header.val_len as usize;
1120
1121            entries.push(entry);
1122        }
1123
1124        if key_offset != event_keys.len() {
1125            return Err(syscall_error!(IllegalArgument;
1126                "event key buffer length is too large: {} < {}",
1127                key_offset,
1128                event_keys.len()
1129            )
1130            .into());
1131        }
1132
1133        if val_offset != event_values.len() {
1134            return Err(syscall_error!(IllegalArgument;
1135                "event value buffer length is too large: {} < {}",
1136                val_offset,
1137                event_values.len()
1138            )
1139            .into());
1140        }
1141
1142        let actor_evt = ActorEvent::from(entries);
1143
1144        let stamped_evt = StampedEvent::new(self.actor_id, actor_evt);
1145        // Enable this when performing gas calibration to measure the cost of serializing early.
1146        #[cfg(feature = "gas_calibration")]
1147        let _ = fvm_ipld_encoding::to_vec(&stamped_evt).unwrap();
1148
1149        self.call_manager.append_event(stamped_evt);
1150
1151        t.stop();
1152
1153        Ok(())
1154    }
1155}