Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an integration test for testing new syscall using custom kernel #1959

Merged
merged 1 commit into from
Jan 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ ahash = "0.8.3"
itertools = "0.11.0"
once_cell = "1.18.0"
unsigned-varint = "0.7.2"
ambassador = "0.3.5"

# dev/tools/tests
criterion = "0.5.1"
Expand Down
2 changes: 1 addition & 1 deletion fvm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ once_cell = { workspace = true }
minstant = { workspace = true }
blake2b_simd = { workspace = true }
byteorder = { workspace = true }
ambassador = { workspace = true }
derive_more = "0.99.17"
replace_with = "0.1.7"
filecoin-proofs-api = { version = "16", default-features = false }
Expand All @@ -44,7 +45,6 @@ num_cpus = "1.15.0"
fvm-wasm-instrument = "0.4.0"
yastl = "0.1.2"
static_assertions = "1.1.0"
ambassador = "0.3.5"

[dev-dependencies]
pretty_assertions = "1.3.0"
Expand Down
2 changes: 2 additions & 0 deletions testing/integration/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ fvm_shared = { workspace = true, features = ["testing"] }
fvm_ipld_car = { workspace = true }
fvm_ipld_blockstore = { workspace = true }
fvm_ipld_encoding = { workspace = true }
fvm_sdk = { workspace = true }

anyhow = { workspace = true }
cid = { workspace = true }
Expand All @@ -26,6 +27,7 @@ rand_chacha = { workspace = true }
serde = { workspace = true }
serde_tuple = { workspace = true }
thiserror = { workspace = true }
ambassador = { workspace = true }
wasmtime = { workspace = true, default-features = false, features = ["cranelift", "parallel-compilation"] }

[dev-dependencies]
Expand Down
201 changes: 201 additions & 0 deletions testing/integration/src/custom_kernel/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
// Copyright 2021-2023 Protocol Labs
// SPDX-License-Identifier: Apache-2.0, MIT
use fvm::call_manager::CallManager;
use fvm::gas::Gas;
use fvm::kernel::filecoin::{DefaultFilecoinKernel, FilecoinKernel};
use fvm::kernel::prelude::*;
use fvm::kernel::Result;
use fvm::kernel::{
ActorOps, CryptoOps, DebugOps, EventOps, IpldBlockOps, MessageOps, NetworkOps, RandomnessOps,
SelfOps, SendOps, SyscallHandler, UpgradeOps,
};
use fvm::syscalls::Linker;
use fvm_shared::clock::ChainEpoch;
use fvm_shared::consensus::ConsensusFault;
use fvm_shared::piece::PieceInfo;
use fvm_shared::randomness::RANDOMNESS_LENGTH;
use fvm_shared::sector::{
AggregateSealVerifyProofAndInfos, RegisteredSealProof, ReplicaUpdateInfo, SealVerifyInfo,
};
use fvm_shared::sys::out::network::NetworkContext;
use fvm_shared::sys::out::vm::MessageContext;
use fvm_shared::{address::Address, econ::TokenAmount, ActorID, MethodNum};

use ambassador::Delegate;
use cid::Cid;

// we define a single custom syscall which simply doubles the input
pub trait CustomKernel: Kernel {
fn my_custom_syscall(&self, doubleme: i32) -> Result<i32>;
}

// our custom kernel extends the filecoin kernel
#[derive(Delegate)]
#[delegate(IpldBlockOps, where = "C: CallManager")]
#[delegate(ActorOps, where = "C: CallManager")]
#[delegate(CryptoOps, where = "C: CallManager")]
#[delegate(DebugOps, where = "C: CallManager")]
#[delegate(EventOps, where = "C: CallManager")]
#[delegate(MessageOps, where = "C: CallManager")]
#[delegate(NetworkOps, where = "C: CallManager")]
#[delegate(RandomnessOps, where = "C: CallManager")]
#[delegate(SelfOps, where = "C: CallManager")]
#[delegate(SendOps<K>, generics = "K", where = "K: CustomKernel")]
#[delegate(UpgradeOps<K>, generics = "K", where = "K: CustomKernel")]
pub struct DefaultCustomKernel<C>(pub DefaultFilecoinKernel<C>);

impl<C> CustomKernel for DefaultCustomKernel<C>
where
C: CallManager,
DefaultCustomKernel<C>: Kernel,
{
fn my_custom_syscall(&self, doubleme: i32) -> Result<i32> {
Ok(doubleme * 2)
}
}

impl<C> DefaultCustomKernel<C>
where
C: CallManager,
{
fn price_list(&self) -> &PriceList {
(self.0).0.call_manager.price_list()
}
}

impl<C> Kernel for DefaultCustomKernel<C>
where
C: CallManager,
{
type CallManager = C;
type Limiter = <DefaultFilecoinKernel<C> as Kernel>::Limiter;

fn into_inner(self) -> (Self::CallManager, BlockRegistry)
where
Self: Sized,
{
self.0.into_inner()
}

fn new(
mgr: C,
blocks: BlockRegistry,
caller: ActorID,
actor_id: ActorID,
method: MethodNum,
value_received: TokenAmount,
read_only: bool,
) -> Self {
DefaultCustomKernel(DefaultFilecoinKernel::new(
mgr,
blocks,
caller,
actor_id,
method,
value_received,
read_only,
))
}

fn machine(&self) -> &<Self::CallManager as CallManager>::Machine {
self.0.machine()
}

fn limiter_mut(&mut self) -> &mut Self::Limiter {
self.0.limiter_mut()
}

fn gas_available(&self) -> Gas {
self.0.gas_available()
}

fn charge_gas(&self, name: &str, compute: Gas) -> Result<GasTimer> {
self.0.charge_gas(name, compute)
}
}

impl<C> FilecoinKernel for DefaultCustomKernel<C>
where
C: CallManager,
{
fn compute_unsealed_sector_cid(
&self,
proof_type: RegisteredSealProof,
pieces: &[PieceInfo],
) -> Result<Cid> {
self.0.compute_unsealed_sector_cid(proof_type, pieces)
}

fn verify_post(&self, verify_info: &fvm_shared::sector::WindowPoStVerifyInfo) -> Result<bool> {
self.0.verify_post(verify_info)
}

// NOT forwarded
fn batch_verify_seals(&self, vis: &[SealVerifyInfo]) -> Result<Vec<bool>> {
Ok(vec![true; vis.len()])
}

// NOT forwarded
fn verify_consensus_fault(
&self,
h1: &[u8],
h2: &[u8],
extra: &[u8],
) -> Result<Option<ConsensusFault>> {
let charge = self
.price_list()
.on_verify_consensus_fault(h1.len(), h2.len(), extra.len());
let _ = self.charge_gas(&charge.name, charge.total())?;
Ok(None)
}

// NOT forwarded
fn verify_aggregate_seals(&self, agg: &AggregateSealVerifyProofAndInfos) -> Result<bool> {
let charge = self.price_list().on_verify_aggregate_seals(agg);
let _ = self.charge_gas(&charge.name, charge.total())?;
Ok(true)
}

// NOT forwarded
fn verify_replica_update(&self, rep: &ReplicaUpdateInfo) -> Result<bool> {
let charge = self.price_list().on_verify_replica_update(rep);
let _ = self.charge_gas(&charge.name, charge.total())?;
Ok(true)
}

fn total_fil_circ_supply(&self) -> Result<TokenAmount> {
self.0.total_fil_circ_supply()
}
}

impl<K> SyscallHandler<K> for DefaultCustomKernel<K::CallManager>
where
K: CustomKernel
+ FilecoinKernel
+ ActorOps
+ SendOps
+ UpgradeOps
+ IpldBlockOps
+ CryptoOps
+ DebugOps
+ EventOps
+ MessageOps
+ NetworkOps
+ RandomnessOps
+ SelfOps,
{
fn link_syscalls(linker: &mut Linker<K>) -> anyhow::Result<()> {
DefaultFilecoinKernel::<K::CallManager>::link_syscalls(linker)?;

linker.link_syscall("my_custom_kernel", "my_custom_syscall", my_custom_syscall)?;

Ok(())
}
}

pub fn my_custom_syscall(
context: fvm::syscalls::Context<'_, impl CustomKernel>,
doubleme: i32,
) -> Result<i32> {
context.kernel.my_custom_syscall(doubleme)
}
1 change: 1 addition & 0 deletions testing/integration/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// SPDX-License-Identifier: Apache-2.0, MIT
mod builtin;
pub mod bundle;
pub mod custom_kernel;
pub mod dummy;
pub mod error;
pub mod tester;
Expand Down
6 changes: 3 additions & 3 deletions testing/integration/src/tester.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use fvm::call_manager::DefaultCallManager;
use fvm::engine::EnginePool;
use fvm::executor::DefaultExecutor;
use fvm::externs::Externs;
use fvm::kernel::filecoin::DefaultFilecoinKernel;
use fvm::machine::{DefaultMachine, Machine, MachineContext, NetworkConfig};
use fvm::state_tree::{ActorState, StateTree};
use fvm::{init_actor, system_actor};
Expand All @@ -24,6 +23,7 @@ use multihash::Code;
use crate::builtin::{
fetch_builtin_code_cid, set_burnt_funds_account, set_eam_actor, set_init_actor, set_sys_actor,
};
use crate::custom_kernel::DefaultCustomKernel;
use crate::dummy::DummyExterns;
use crate::error::Error::{FailedToFlushTree, NoManifestInformation};

Expand All @@ -36,7 +36,7 @@ lazy_static! {
pub trait Store: Blockstore + Sized + 'static {}

pub type IntegrationExecutor<B, E> =
DefaultExecutor<DefaultFilecoinKernel<DefaultCallManager<DefaultMachine<B, E>>>>;
DefaultExecutor<DefaultCustomKernel<DefaultCallManager<DefaultMachine<B, E>>>>;

pub type Account = (ActorID, Address);

Expand Down Expand Up @@ -298,7 +298,7 @@ where
let machine = DefaultMachine::new(&mc, blockstore, externs)?;

let executor = DefaultExecutor::<
DefaultFilecoinKernel<DefaultCallManager<DefaultMachine<B, E>>>,
DefaultCustomKernel<DefaultCallManager<DefaultMachine<B, E>>>,
>::new(engine, machine)?;

self.executor = Some(executor);
Expand Down
57 changes: 54 additions & 3 deletions testing/integration/tests/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ use fvm_shared::message::Message;
use fvm_shared::state::StateTreeVersion;
use fvm_shared::version::NetworkVersion;
use fvm_test_actors::wasm_bin::{
ADDRESS_ACTOR_BINARY, CREATE_ACTOR_BINARY, EXIT_DATA_ACTOR_BINARY, HELLO_WORLD_ACTOR_BINARY,
IPLD_ACTOR_BINARY, OOM_ACTOR_BINARY, READONLY_ACTOR_BINARY, SSELF_ACTOR_BINARY,
STACK_OVERFLOW_ACTOR_BINARY, SYSCALL_ACTOR_BINARY, UPGRADE_ACTOR_BINARY,
ADDRESS_ACTOR_BINARY, CREATE_ACTOR_BINARY, CUSTOM_SYSCALL_ACTOR_BINARY, EXIT_DATA_ACTOR_BINARY,
HELLO_WORLD_ACTOR_BINARY, IPLD_ACTOR_BINARY, OOM_ACTOR_BINARY, READONLY_ACTOR_BINARY,
SSELF_ACTOR_BINARY, STACK_OVERFLOW_ACTOR_BINARY, SYSCALL_ACTOR_BINARY, UPGRADE_ACTOR_BINARY,
UPGRADE_RECEIVE_ACTOR_BINARY,
};
use num_traits::Zero;
Expand Down Expand Up @@ -1108,6 +1108,57 @@ fn readonly_actor_tests() {
assert!(res.msg_receipt.events_root.is_none());
}

#[test]
fn custom_syscall() {
// Instantiate tester
let mut tester = new_tester(
NetworkVersion::V21,
StateTreeVersion::V5,
MemoryBlockstore::default(),
)
.unwrap();

let [(_sender_id, sender_address)] = tester.create_accounts().unwrap();

let wasm_bin = CUSTOM_SYSCALL_ACTOR_BINARY;

// Set actor state
let actor_state = [(); 0];
let state_cid = tester.set_state(&actor_state).unwrap();

// Set actor
let actor_address = Address::new_id(10000);

tester
.set_actor_from_bin(wasm_bin, state_cid, actor_address, TokenAmount::zero())
.unwrap();

// Instantiate machine
tester.instantiate_machine(DummyExterns).unwrap();

let executor = tester.executor.as_mut().unwrap();

let message = Message {
from: sender_address,
to: actor_address,
gas_limit: 1000000000,
method_num: 1,
sequence: 0,
value: TokenAmount::from_atto(100),
..Message::default()
};

let res = executor
.execute_message(message, ApplyKind::Explicit, 100)
.unwrap();

assert!(
res.msg_receipt.exit_code.is_success(),
"{:?}",
res.failure_info
);
}

#[test]
fn upgrade_actor_test() {
// inline function to calculate cid from address
Expand Down
Loading
Loading