Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
fridrik01 committed Nov 15, 2023
1 parent 0731f70 commit 378adb5
Show file tree
Hide file tree
Showing 5 changed files with 195 additions and 115 deletions.
10 changes: 7 additions & 3 deletions fvm/src/engine/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ use crate::machine::limiter::MemoryLimiter;
use crate::machine::{Machine, NetworkConfig};
use crate::syscalls::error::Abort;
use crate::syscalls::{
bind_syscalls, charge_for_exec, charge_for_init, record_init_time, update_gas_available,
InvocationData,
charge_for_exec, charge_for_init, record_init_time, update_gas_available, InvocationData,
};
use crate::Kernel;

Expand Down Expand Up @@ -517,7 +516,12 @@ impl Engine {
let mut linker: Linker<InvocationData<K>> = Linker::new(&self.inner.engine);
linker.allow_shadowing(true);

bind_syscalls(&mut linker).map_err(Abort::Fatal)?;
store
.data()
.kernel
.bind_syscalls(&mut linker)
.map_err(Abort::Fatal)?;

Box::new(Cache { linker })
})
.downcast_mut()
Expand Down
36 changes: 29 additions & 7 deletions fvm/src/kernel/default.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,24 +53,46 @@ const MAX_ARTIFACT_NAME_LEN: usize = 256;
#[cfg(feature = "testing")]
const TEST_ACTOR_ALLOWED_TO_CALL_CREATE_ACTOR: ActorID = 98;

pub struct DefaultFilecoinKernel<K>(pub K)
where
K: Kernel;

impl<C> FilecoinKernel for DefaultFilecoinKernel<DefaultKernel<C>>
where
C: CallManager,
{
/// Verifies a window proof of spacetime.
fn verify_post(&self, verify_info: &WindowPoStVerifyInfo) -> Result<bool> {
let t = self
.0
.call_manager
.charge_gas(self.0.call_manager.price_list().on_verify_post(verify_info))?;

// This is especially important to catch as, otherwise, a bad "post" could be undisputable.
t.record(catch_and_log_panic("verifying post", || {
verify_post(verify_info)
}))
}
}

/// The "default" [`Kernel`] implementation.
pub struct DefaultKernel<C> {
// Fields extracted from the message, except parameters, which have been
// preloaded into the block registry.
caller: ActorID,
actor_id: ActorID,
method: MethodNum,
value_received: TokenAmount,
read_only: bool,
pub caller: ActorID,
pub actor_id: ActorID,
pub method: MethodNum,
pub value_received: TokenAmount,
pub read_only: bool,

/// The call manager for this call stack. If this kernel calls another actor, it will
/// temporarily "give" the call manager to the other kernel before re-attaching it.
call_manager: C,
pub call_manager: C,
/// Tracks block data and organizes it through index handles so it can be
/// referred to.
///
/// This does not yet reason about reachability.
blocks: BlockRegistry,
pub blocks: BlockRegistry,
}

// Even though all children traits are implemented, Rust needs to know that the
Expand Down
17 changes: 16 additions & 1 deletion fvm/src/kernel/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,25 @@ pub use error::{ClassifyResult, Context, ExecutionError, Result, SyscallError};
use fvm_shared::event::StampedEvent;
pub use hash::SupportedHashes;
use multihash::MultihashGeneric;
use wasmtime::Linker;

use crate::call_manager::CallManager;
use crate::gas::{Gas, GasTimer, PriceList};
use crate::machine::limiter::MemoryLimiter;
use crate::machine::Machine;
use crate::syscalls::InvocationData;

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

pub trait FilecoinKernel {
/// Verifies a window proof of spacetime.
fn verify_post(&self, verify_info: &WindowPoStVerifyInfo) -> Result<bool>;
}

/// The "kernel" implements the FVM interface as presented to the actors. It:
///
/// - Manages the Actor's state.
Expand All @@ -52,7 +59,8 @@ pub struct CallResult {
/// Actors may call into the kernel via the syscalls defined in the [`syscalls`][crate::syscalls]
/// module.
pub trait Kernel:
ActorOps
SyscallHandler
+ ActorOps
+ IpldBlockOps
+ CircSupplyOps
+ CryptoOps
Expand Down Expand Up @@ -115,6 +123,13 @@ pub trait Kernel:
) -> Result<CallResult>;
}

pub trait SyscallHandler {
fn bind_syscalls(
&self,
linker: &mut Linker<InvocationData<impl Kernel + 'static>>,
) -> anyhow::Result<()>;
}

/// Network-related operations.
pub trait NetworkOps {
/// Network information (epoch, version, etc.).
Expand Down
231 changes: 127 additions & 104 deletions fvm/src/syscalls/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ use anyhow::{anyhow, Context as _};
use num_traits::Zero;
use wasmtime::{AsContextMut, ExternType, Global, Linker, Memory, Module, Val};

use crate::call_manager::backtrace;
use crate::call_manager::{backtrace, CallManager};
use crate::gas::{Gas, GasInstant, GasTimer};
use crate::kernel::ExecutionError;
use crate::kernel::default::DefaultFilecoinKernel;
use crate::kernel::{ExecutionError, SyscallHandler};
use crate::machine::limiter::MemoryLimiter;
use crate::Kernel;
use crate::{DefaultKernel, Kernel};

pub(crate) mod error;

Expand Down Expand Up @@ -233,107 +234,129 @@ fn min_table_elements(module: &Module) -> Option<u32> {
use self::bind::BindSyscall;
use self::error::Abort;

// Binds the syscall handlers so they can handle invocations
// from the actor code.
pub fn bind_syscalls(
linker: &mut Linker<InvocationData<impl Kernel + 'static>>,
) -> anyhow::Result<()> {
linker.bind("vm", "exit", vm::exit)?;
linker.bind("vm", "message_context", vm::message_context)?;

linker.bind(
"network",
"total_fil_circ_supply",
network::total_fil_circ_supply,
)?;
linker.bind("network", "context", network::context)?;
linker.bind("network", "tipset_cid", network::tipset_cid)?;

linker.bind("ipld", "block_open", ipld::block_open)?;
linker.bind("ipld", "block_create", ipld::block_create)?;
linker.bind("ipld", "block_read", ipld::block_read)?;
linker.bind("ipld", "block_stat", ipld::block_stat)?;
linker.bind("ipld", "block_link", ipld::block_link)?;

linker.bind("self", "root", sself::root)?;
linker.bind("self", "set_root", sself::set_root)?;
linker.bind("self", "current_balance", sself::current_balance)?;
linker.bind("self", "self_destruct", sself::self_destruct)?;

linker.bind("actor", "resolve_address", actor::resolve_address)?;
linker.bind(
"actor",
"lookup_delegated_address",
actor::lookup_delegated_address,
)?;
linker.bind("actor", "get_actor_code_cid", actor::get_actor_code_cid)?;
linker.bind("actor", "next_actor_address", actor::next_actor_address)?;
linker.bind("actor", "create_actor", actor::create_actor)?;
if cfg!(feature = "upgrade-actor") {
// We disable/enable with the feature, but we always compile this code to ensure we don't
// accidentally break it.
linker.bind("actor", "upgrade_actor", actor::upgrade_actor)?;
impl<C> SyscallHandler for DefaultKernel<C>
where
C: CallManager,
{
fn bind_syscalls(
&self,
linker: &mut Linker<InvocationData<impl Kernel + 'static>>,
) -> anyhow::Result<()> {
linker.bind("vm", "exit", vm::exit)?;
linker.bind("vm", "message_context", vm::message_context)?;

linker.bind(
"network",
"total_fil_circ_supply",
network::total_fil_circ_supply,
)?;
linker.bind("network", "context", network::context)?;
linker.bind("network", "tipset_cid", network::tipset_cid)?;

linker.bind("ipld", "block_open", ipld::block_open)?;
linker.bind("ipld", "block_create", ipld::block_create)?;
linker.bind("ipld", "block_read", ipld::block_read)?;
linker.bind("ipld", "block_stat", ipld::block_stat)?;
linker.bind("ipld", "block_link", ipld::block_link)?;

linker.bind("self", "root", sself::root)?;
linker.bind("self", "set_root", sself::set_root)?;
linker.bind("self", "current_balance", sself::current_balance)?;
linker.bind("self", "self_destruct", sself::self_destruct)?;

linker.bind("actor", "resolve_address", actor::resolve_address)?;
linker.bind(
"actor",
"lookup_delegated_address",
actor::lookup_delegated_address,
)?;
linker.bind("actor", "get_actor_code_cid", actor::get_actor_code_cid)?;
linker.bind("actor", "next_actor_address", actor::next_actor_address)?;
linker.bind("actor", "create_actor", actor::create_actor)?;
if cfg!(feature = "upgrade-actor") {
// We disable/enable with the feature, but we always compile this code to ensure we don't
// accidentally break it.
linker.bind("actor", "upgrade_actor", actor::upgrade_actor)?;
}
linker.bind(
"actor",
"get_builtin_actor_type",
actor::get_builtin_actor_type,
)?;
linker.bind(
"actor",
"get_code_cid_for_type",
actor::get_code_cid_for_type,
)?;
linker.bind("actor", "balance_of", actor::balance_of)?;

// Only wire this syscall when M2 native is enabled.
#[cfg(feature = "m2-native")]
linker.bind("actor", "install_actor", actor::install_actor)?;

linker.bind("crypto", "verify_signature", crypto::verify_signature)?;
linker.bind(
"crypto",
"recover_secp_public_key",
crypto::recover_secp_public_key,
)?;
linker.bind("crypto", "hash", crypto::hash)?;
linker.bind("crypto", "verify_post", crypto::verify_post)?;
linker.bind(
"crypto",
"compute_unsealed_sector_cid",
crypto::compute_unsealed_sector_cid,
)?;
linker.bind(
"crypto",
"verify_consensus_fault",
crypto::verify_consensus_fault,
)?;
linker.bind(
"crypto",
"verify_aggregate_seals",
crypto::verify_aggregate_seals,
)?;
linker.bind(
"crypto",
"verify_replica_update",
crypto::verify_replica_update,
)?;
linker.bind("crypto", "batch_verify_seals", crypto::batch_verify_seals)?;

linker.bind("event", "emit_event", event::emit_event)?;

linker.bind("rand", "get_chain_randomness", rand::get_chain_randomness)?;
linker.bind("rand", "get_beacon_randomness", rand::get_beacon_randomness)?;

linker.bind("gas", "charge", gas::charge_gas)?;
linker.bind("gas", "available", gas::available)?;

// Ok, this singled-out syscall should probably be in another category.
linker.bind("send", "send", send::send)?;

linker.bind("debug", "log", debug::log)?;
linker.bind("debug", "enabled", debug::enabled)?;
linker.bind("debug", "store_artifact", debug::store_artifact)?;

Ok(())
}
linker.bind(
"actor",
"get_builtin_actor_type",
actor::get_builtin_actor_type,
)?;
linker.bind(
"actor",
"get_code_cid_for_type",
actor::get_code_cid_for_type,
)?;
linker.bind("actor", "balance_of", actor::balance_of)?;

// Only wire this syscall when M2 native is enabled.
#[cfg(feature = "m2-native")]
linker.bind("actor", "install_actor", actor::install_actor)?;

linker.bind("crypto", "verify_signature", crypto::verify_signature)?;
linker.bind(
"crypto",
"recover_secp_public_key",
crypto::recover_secp_public_key,
)?;
linker.bind("crypto", "hash", crypto::hash)?;
linker.bind("crypto", "verify_post", crypto::verify_post)?;
linker.bind(
"crypto",
"compute_unsealed_sector_cid",
crypto::compute_unsealed_sector_cid,
)?;
linker.bind(
"crypto",
"verify_consensus_fault",
crypto::verify_consensus_fault,
)?;
linker.bind(
"crypto",
"verify_aggregate_seals",
crypto::verify_aggregate_seals,
)?;
linker.bind(
"crypto",
"verify_replica_update",
crypto::verify_replica_update,
)?;
linker.bind("crypto", "batch_verify_seals", crypto::batch_verify_seals)?;

linker.bind("event", "emit_event", event::emit_event)?;

linker.bind("rand", "get_chain_randomness", rand::get_chain_randomness)?;
linker.bind("rand", "get_beacon_randomness", rand::get_beacon_randomness)?;

linker.bind("gas", "charge", gas::charge_gas)?;
linker.bind("gas", "available", gas::available)?;

// Ok, this singled-out syscall should probably be in another category.
linker.bind("send", "send", send::send)?;

linker.bind("debug", "log", debug::log)?;
linker.bind("debug", "enabled", debug::enabled)?;
linker.bind("debug", "store_artifact", debug::store_artifact)?;
}

Ok(())
impl<K> SyscallHandler for DefaultFilecoinKernel<K>
where
K: Kernel,
{
fn bind_syscalls(
&self,
linker: &mut Linker<InvocationData<impl Kernel + 'static>>,
) -> anyhow::Result<()> {
// Bind the default syscalls.
self.0.bind_syscalls(linker)?;

// Now bind the crypto syscalls.
linker.bind("crypto", "verify_post", crypto::verify_post)?;

Ok(())
}
}
Loading

0 comments on commit 378adb5

Please sign in to comment.