diff --git a/fendermint/vm/interpreter/src/fvm/state/exec.rs b/fendermint/vm/interpreter/src/fvm/state/exec.rs index 4f8bbd28..444485f6 100644 --- a/fendermint/vm/interpreter/src/fvm/state/exec.rs +++ b/fendermint/vm/interpreter/src/fvm/state/exec.rs @@ -3,7 +3,6 @@ use cid::Cid; use fendermint_vm_genesis::PowerScale; -use fvm::kernel::filecoin::DefaultFilecoinKernel; use fvm::{ call_manager::DefaultCallManager, engine::MultiEngine, @@ -78,13 +77,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< - DefaultFilecoinKernel< + DefaultCustomKernel< DefaultKernel>>, >, >, diff --git a/fendermint/vm/interpreter/src/fvm/state/mod.rs b/fendermint/vm/interpreter/src/fvm/state/mod.rs index 9f8f7b0a..e25b6e89 100644 --- a/fendermint/vm/interpreter/src/fvm/state/mod.rs +++ b/fendermint/vm/interpreter/src/fvm/state/mod.rs @@ -6,6 +6,7 @@ mod exec; pub mod fevm; mod genesis; pub mod ipc; +pub mod mycustomkernel; mod query; pub mod snapshot; 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..106233d9 --- /dev/null +++ b/fendermint/vm/interpreter/src/fvm/state/mycustomkernel.rs @@ -0,0 +1,168 @@ +// Copyright 2021-2023 Protocol Labs +// SPDX-License-Identifier: Apache-2.0, MIT + +use fvm::call_manager::CallManager; +use fvm::gas::Gas; +use fvm::gas::GasTimer; +use fvm::gas::PriceList; +use fvm::kernel::*; +use fvm::syscalls::bind::BindSyscall; +use fvm::syscalls::InvocationData; +use fvm::{ + ambassador_impl_ActorOps, ambassador_impl_CircSupplyOps, ambassador_impl_CryptoOps, + ambassador_impl_DebugOps, ambassador_impl_EventOps, ambassador_impl_GasOps, + ambassador_impl_IpldBlockOps, ambassador_impl_LimiterOps, ambassador_impl_MessageOps, + ambassador_impl_NetworkOps, ambassador_impl_RandomnessOps, ambassador_impl_SelfOps, + DefaultKernel, +}; + +use fvm_shared::clock::ChainEpoch; +use fvm_shared::crypto::signature::*; +use fvm_shared::randomness::RANDOMNESS_LENGTH; +use fvm_shared::sys::out::network::NetworkContext; +use fvm_shared::sys::out::vm::MessageContext; +use fvm_shared::{address::Address, econ::TokenAmount, sys::SendFlags, ActorID, MethodNum}; + +use cid::Cid; +use multihash::MultihashGeneric; + +use ambassador::Delegate; +use wasmtime::Linker; + +// 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<()>; + } + } +}