diff --git a/fendermint/vm/interpreter/src/fvm/state/exec.rs b/fendermint/vm/interpreter/src/fvm/state/exec.rs index a45c2f83..784c0af4 100644 --- a/fendermint/vm/interpreter/src/fvm/state/exec.rs +++ b/fendermint/vm/interpreter/src/fvm/state/exec.rs @@ -13,7 +13,6 @@ use fvm::{ state_tree::StateTree, DefaultKernel, }; -use fvm::kernel::filecoin::DefaultFilecoinKernel; use fvm_ipld_blockstore::Blockstore; use fvm_ipld_encoding::RawBytes; use fvm_shared::{ @@ -79,13 +78,15 @@ pub struct FvmUpdatableParams { pub type MachineBlockstore = as Machine>::Blockstore; +use crate::fvm::state::mycustomkernel::DefaultCustomKernel; + /// A state we create for the execution of all the messages in a block. pub struct FvmExecState where DB: Blockstore + 'static, { executor: - DefaultExecutor>>>>, + DefaultExecutor>>>>, /// Hash of the block currently being executed. For queries and checks this is empty. /// diff --git a/fendermint/vm/interpreter/src/fvm/state/mod.rs b/fendermint/vm/interpreter/src/fvm/state/mod.rs index 9f8f7b0a..562d5a7c 100644 --- a/fendermint/vm/interpreter/src/fvm/state/mod.rs +++ b/fendermint/vm/interpreter/src/fvm/state/mod.rs @@ -8,6 +8,7 @@ mod genesis; pub mod ipc; mod query; pub mod snapshot; +pub mod mycustomkernel; use std::sync::Arc; diff --git a/fendermint/vm/interpreter/src/fvm/state/mycustomkernel.rs b/fendermint/vm/interpreter/src/fvm/state/mycustomkernel.rs new file mode 100644 index 00000000..6eb4b909 --- /dev/null +++ b/fendermint/vm/interpreter/src/fvm/state/mycustomkernel.rs @@ -0,0 +1,171 @@ +// Copyright 2021-2023 Protocol Labs +// SPDX-License-Identifier: Apache-2.0, MIT + + +use fvm::gas::GasTimer; +use fvm::gas::PriceList; +use fvm::kernel::*; +use fvm::syscalls::InvocationData; +use fvm::syscalls::bind::BindSyscall; +use fvm::call_manager::CallManager; +use fvm::gas::Gas; +use fvm::{ + DefaultKernel, ambassador_impl_IpldBlockOps, ambassador_impl_ActorOps, ambassador_impl_CircSupplyOps, ambassador_impl_CryptoOps, ambassador_impl_DebugOps, ambassador_impl_EventOps, ambassador_impl_GasOps, ambassador_impl_MessageOps, ambassador_impl_NetworkOps, ambassador_impl_RandomnessOps, ambassador_impl_SelfOps, ambassador_impl_LimiterOps +}; + +use fvm_shared::{address::Address, econ::TokenAmount, ActorID, MethodNum, sys::SendFlags}; +use fvm_shared::crypto::signature::*; +use fvm_shared::sys::out::vm::MessageContext; +use fvm_shared::sys::out::network::NetworkContext; +use fvm_shared::clock::ChainEpoch; +use fvm_shared::randomness::RANDOMNESS_LENGTH; + +use multihash::MultihashGeneric; +use cid::Cid; + +use wasmtime::Linker; +use ambassador::Delegate; + +// define the custom kernel syscall here +pub trait CustomKernel: Kernel { + fn my_custom_syscall(&self) -> Result<()>; +} + +#[derive(Delegate)] +#[delegate(IpldBlockOps)] +#[delegate(ActorOps)] +#[delegate(CircSupplyOps)] +#[delegate(CryptoOps)] +#[delegate(DebugOps)] +#[delegate(EventOps)] +#[delegate(GasOps)] +#[delegate(MessageOps)] +#[delegate(NetworkOps)] +#[delegate(RandomnessOps)] +#[delegate(SelfOps)] +#[delegate(LimiterOps)] +// we define the implementation of the custom kernel here. We use ambassador to delegate most of the existing syscalls to the default kernel +pub struct DefaultCustomKernel(pub K) +where + K: Kernel; + +// we need to implement the custom kernel trait for the default custom kernel +impl CustomKernel for DefaultCustomKernel> +where + C: CallManager, + DefaultCustomKernel>: Kernel, +{ + fn my_custom_syscall(&self) -> Result<()> { + // TODO: Implement the kernel syscall here. + Ok(()) + } +} + +// we need to implement the kernel trait for the default custom kernel, here we simply delegate to the default kernel +impl Kernel for DefaultCustomKernel> +where + C: CallManager, +{ + type CallManager = C; + + fn into_inner(self) -> (Self::CallManager, BlockRegistry) + where + Self: Sized, + { + self.0.into_inner() + } + + fn machine(&self) -> &::Machine { + self.0.machine() + } + + fn send>( + &mut self, + recipient: &Address, + method: u64, + params: BlockId, + value: &TokenAmount, + gas_limit: Option, + flags: SendFlags, + ) -> Result { + self.0 + .send::(recipient, method, params, value, gas_limit, flags) + } + + fn upgrade_actor>( + &mut self, + new_code_cid: Cid, + params_id: BlockId, + ) -> Result { + self.0.upgrade_actor::(new_code_cid, params_id) + } + + fn new( + mgr: C, + blocks: BlockRegistry, + caller: ActorID, + actor_id: ActorID, + method: MethodNum, + value_received: TokenAmount, + read_only: bool, + ) -> Self { + DefaultCustomKernel(DefaultKernel::new( + mgr, + blocks, + caller, + actor_id, + method, + value_received, + read_only, + )) + } +} + +// we need to implement the syscall handler for the default custom kernel which binds our syscalls to the wasmtime linker +impl SyscallHandler>> + for DefaultCustomKernel> +where + C: CallManager, +{ + fn bind_syscalls( + &self, + linker: &mut Linker>>>, + ) -> anyhow::Result<()> { + self.0.bind_syscalls(linker)?; + + // Now bind our custom syscalls + linker.bind( + "my_custom_kernel", + "my_custom_syscall", + my_custom_syscall, + )?; + + Ok(()) + } +} + +// this is the actual syscall implementation as registered in bind_syscalls +pub fn my_custom_syscall(context: fvm::syscalls::Context<'_, impl CustomKernel>) -> Result<()> { + context + .kernel + .my_custom_syscall()?; + Ok(()) +} + +pub mod sdk { + // This is the direct sdk call the wasm actor calls + pub fn my_custom_syscall() { + unsafe { + sys::my_custom_syscall().unwrap(); + } + } + + pub mod sys { + use fvm_sdk::fvm_syscalls; + + fvm_syscalls!{ + module = "my_custom_kernel"; + pub fn my_custom_syscall() -> Result<()>; + } + } +}