From f46d4dc4cbd631a506ef70a5a198275f1d96339d Mon Sep 17 00:00:00 2001 From: Alex Su <7680266+alexytsu@users.noreply.github.com> Date: Thu, 10 Aug 2023 11:17:44 +1000 Subject: [PATCH] Reverse import of fil_actors_runtime and vm_api (#1359) * amend actor type to match fvm impl * reverse builtin <-> runtime dependency * hide testing utils behind feature flag --- Cargo.lock | 4 +- integration_tests/Cargo.toml | 2 +- integration_tests/src/tests/init_test.rs | 4 +- runtime/Cargo.toml | 1 + runtime/src/runtime/builtins.rs | 51 +------------- runtime/src/runtime/mod.rs | 42 +---------- test_vm/src/lib.rs | 29 ++++---- test_vm/src/messaging.rs | 6 +- test_vm/tests/test_vm_test.rs | 8 +-- vm_api/Cargo.toml | 7 +- vm_api/src/builtin.rs | 50 +++++++++++++ vm_api/src/lib.rs | 89 +++++++++++++++++++----- 12 files changed, 161 insertions(+), 132 deletions(-) create mode 100644 vm_api/src/builtin.rs diff --git a/Cargo.lock b/Cargo.lock index a34121525..b6f77ce3d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1824,6 +1824,7 @@ dependencies = [ "sha2 0.10.7", "thiserror", "unsigned-varint", + "vm_api", ] [[package]] @@ -4396,11 +4397,12 @@ version = "1.0.0" dependencies = [ "anyhow", "cid 0.10.1", - "fil_actors_runtime", "fvm_ipld_blockstore 0.2.0", "fvm_ipld_encoding 0.4.0", "fvm_ipld_hamt", "fvm_shared", + "num-derive", + "num-traits", "rand", "rand_chacha", "serde", diff --git a/integration_tests/Cargo.toml b/integration_tests/Cargo.toml index dede91021..3883e6dc7 100644 --- a/integration_tests/Cargo.toml +++ b/integration_tests/Cargo.toml @@ -29,7 +29,7 @@ fil_actor_evm = { workspace = true } fil_actor_eam = { workspace = true } fil_actor_ethaccount = { workspace = true } fil_actors_evm_shared = { workspace = true } -vm_api = { workspace = true } +vm_api = { workspace = true, features = ["testing"] } anyhow = { workspace = true } bimap = { workspace = true } diff --git a/integration_tests/src/tests/init_test.rs b/integration_tests/src/tests/init_test.rs index 5a59432cb..c4dff7c58 100644 --- a/integration_tests/src/tests/init_test.rs +++ b/integration_tests/src/tests/init_test.rs @@ -7,7 +7,7 @@ use fil_actors_runtime::{ }; use fvm_shared::{address::Address, econ::TokenAmount, error::ExitCode, METHOD_SEND}; use num_traits::Zero; -use vm_api::{actor, util::serialize_ok, VM}; +use vm_api::{new_actor, util::serialize_ok, VM}; use crate::{FIRST_TEST_USER_ADDR, TEST_FAUCET_ADDR}; @@ -22,7 +22,7 @@ pub fn placeholder_deploy_test(v: &dyn VM) { // Create a "fake" eam. v.set_actor( &EAM_ACTOR_ADDR, - actor(*EAM_ACTOR_CODE_ID, EMPTY_ARR_CID, 0, TokenAmount::zero(), None), + new_actor(*EAM_ACTOR_CODE_ID, EMPTY_ARR_CID, 0, TokenAmount::zero(), None), ); // Create a placeholder. diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index b7426cca7..ddc9c6c4d 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -33,6 +33,7 @@ serde = { workspace = true } serde_repr = { workspace = true } thiserror = { workspace = true } unsigned-varint = { workspace = true } +vm_api = { workspace = true } # A fake-proofs dependency but... we can't select on that feature here because we enable it from # build.rs. diff --git a/runtime/src/runtime/builtins.rs b/runtime/src/runtime/builtins.rs index 0279349e6..2e379fe01 100644 --- a/runtime/src/runtime/builtins.rs +++ b/runtime/src/runtime/builtins.rs @@ -1,50 +1 @@ -use num_derive::FromPrimitive; - -/// Identifies the builtin actor types for usage with the -/// actor::resolve_builtin_actor_type syscall. -/// Note that there is a mirror of this enum in the FVM SDK src/actors/builtins.rs. -/// These must be kept in sync for the syscall to work correctly, without either side -/// importing the other. -#[derive(PartialEq, Eq, Clone, Copy, PartialOrd, Ord, FromPrimitive, Debug)] -#[repr(i32)] -pub enum Type { - System = 1, - Init = 2, - Cron = 3, - Account = 4, - Power = 5, - Miner = 6, - Market = 7, - PaymentChannel = 8, - Multisig = 9, - Reward = 10, - VerifiedRegistry = 11, - DataCap = 12, - Placeholder = 13, - EVM = 14, - EAM = 15, - EthAccount = 16, -} - -impl Type { - pub fn name(&self) -> &'static str { - match *self { - Type::System => "system", - Type::Init => "init", - Type::Cron => "cron", - Type::Account => "account", - Type::Power => "storagepower", - Type::Miner => "storageminer", - Type::Market => "storagemarket", - Type::PaymentChannel => "paymentchannel", - Type::Multisig => "multisig", - Type::Reward => "reward", - Type::VerifiedRegistry => "verifiedregistry", - Type::DataCap => "datacap", - Type::Placeholder => "placeholder", - Type::EVM => "evm", - Type::EAM => "eam", - Type::EthAccount => "ethaccount", - } - } -} +pub use vm_api::builtin::Type; diff --git a/runtime/src/runtime/mod.rs b/runtime/src/runtime/mod.rs index 8db350ce6..69f78344e 100644 --- a/runtime/src/runtime/mod.rs +++ b/runtime/src/runtime/mod.rs @@ -7,16 +7,10 @@ use fvm_ipld_encoding::CborStore; use fvm_shared::address::Address; use fvm_shared::clock::ChainEpoch; use fvm_shared::consensus::ConsensusFault; -use fvm_shared::crypto::hash::SupportedHashes; -use fvm_shared::crypto::signature::{ - Signature, SECP_PUB_LEN, SECP_SIG_LEN, SECP_SIG_MESSAGE_HASH_SIZE, -}; use fvm_shared::econ::TokenAmount; -use fvm_shared::piece::PieceInfo; use fvm_shared::randomness::RANDOMNESS_LENGTH; use fvm_shared::sector::{ - AggregateSealVerifyProofAndInfos, RegisteredSealProof, ReplicaUpdateInfo, SealVerifyInfo, - WindowPoStVerifyInfo, + AggregateSealVerifyProofAndInfos, ReplicaUpdateInfo, SealVerifyInfo, WindowPoStVerifyInfo, }; use fvm_shared::version::NetworkVersion; use fvm_shared::{ActorID, MethodNum, Response}; @@ -49,6 +43,7 @@ use fvm_ipld_encoding::ipld_block::IpldBlock; use fvm_shared::chainid::ChainID; use fvm_shared::event::ActorEvent; use fvm_shared::sys::SendFlags; +pub use vm_api::Primitives; /// Runtime is the VM's internal runtime object. /// this is everything that is accessible to actors, beyond parameters. @@ -280,39 +275,6 @@ pub trait MessageInfo { fn gas_premium(&self) -> TokenAmount; } -/// Pure functions implemented as primitives by the runtime. -pub trait Primitives { - /// Hashes input data using blake2b with 256 bit output. - fn hash_blake2b(&self, data: &[u8]) -> [u8; 32]; - - /// Hashes input data using a supported hash function. - fn hash(&self, hasher: SupportedHashes, data: &[u8]) -> Vec; - - /// Hashes input into a 64 byte buffer - fn hash_64(&self, hasher: SupportedHashes, data: &[u8]) -> ([u8; 64], usize); - - /// Computes an unsealed sector CID (CommD) from its constituent piece CIDs (CommPs) and sizes. - fn compute_unsealed_sector_cid( - &self, - proof_type: RegisteredSealProof, - pieces: &[PieceInfo], - ) -> Result; - - /// Verifies that a signature is valid for an address and plaintext. - fn verify_signature( - &self, - signature: &Signature, - signer: &Address, - plaintext: &[u8], - ) -> Result<(), anyhow::Error>; - - fn recover_secp_public_key( - &self, - hash: &[u8; SECP_SIG_MESSAGE_HASH_SIZE], - signature: &[u8; SECP_SIG_LEN], - ) -> Result<[u8; SECP_PUB_LEN], anyhow::Error>; -} - /// filcrypto verification primitives provided by the runtime pub trait Verifier { /// Verifies a sector seal proof. diff --git a/test_vm/src/lib.rs b/test_vm/src/lib.rs index 46ab9d8c5..3a350a490 100644 --- a/test_vm/src/lib.rs +++ b/test_vm/src/lib.rs @@ -39,7 +39,7 @@ use serde::ser; use std::cell::{RefCell, RefMut}; use std::collections::{BTreeMap, HashMap}; use vm_api::trace::InvocationTrace; -use vm_api::{actor, ActorState, MessageResult, VMError, VM}; +use vm_api::{new_actor, ActorState, MessageResult, VMError, VM}; use vm_api::util::{get_state, serialize_ok}; @@ -95,14 +95,17 @@ where let sys_st = SystemState::new(store).unwrap(); let sys_head = v.put_store(&sys_st); let sys_value = faucet_total.clone(); // delegate faucet funds to system so we can construct faucet by sending to bls addr - v.set_actor(&SYSTEM_ACTOR_ADDR, actor(*SYSTEM_ACTOR_CODE_ID, sys_head, 0, sys_value, None)); + v.set_actor( + &SYSTEM_ACTOR_ADDR, + new_actor(*SYSTEM_ACTOR_CODE_ID, sys_head, 0, sys_value, None), + ); // init let init_st = InitState::new(store, "integration-test".to_string()).unwrap(); let init_head = v.put_store(&init_st); v.set_actor( &INIT_ACTOR_ADDR, - actor(*INIT_ACTOR_CODE_ID, init_head, 0, TokenAmount::zero(), None), + new_actor(*INIT_ACTOR_CODE_ID, init_head, 0, TokenAmount::zero(), None), ); // reward @@ -110,7 +113,7 @@ where let reward_head = v.put_store(&RewardState::new(StoragePower::zero())); v.set_actor( &REWARD_ACTOR_ADDR, - actor(*REWARD_ACTOR_CODE_ID, reward_head, 0, reward_total, None), + new_actor(*REWARD_ACTOR_CODE_ID, reward_head, 0, reward_total, None), ); // cron @@ -127,21 +130,21 @@ where let cron_head = v.put_store(&CronState { entries: builtin_entries }); v.set_actor( &CRON_ACTOR_ADDR, - actor(*CRON_ACTOR_CODE_ID, cron_head, 0, TokenAmount::zero(), None), + new_actor(*CRON_ACTOR_CODE_ID, cron_head, 0, TokenAmount::zero(), None), ); // power let power_head = v.put_store(&PowerState::new(&v.store).unwrap()); v.set_actor( &STORAGE_POWER_ACTOR_ADDR, - actor(*POWER_ACTOR_CODE_ID, power_head, 0, TokenAmount::zero(), None), + new_actor(*POWER_ACTOR_CODE_ID, power_head, 0, TokenAmount::zero(), None), ); // market let market_head = v.put_store(&MarketState::new(&v.store).unwrap()); v.set_actor( &STORAGE_MARKET_ACTOR_ADDR, - actor(*MARKET_ACTOR_CODE_ID, market_head, 0, TokenAmount::zero(), None), + new_actor(*MARKET_ACTOR_CODE_ID, market_head, 0, TokenAmount::zero(), None), ); // verifreg @@ -190,13 +193,13 @@ where let verifreg_head = v.put_store(&VerifRegState::new(&v.store, root_msig_addr).unwrap()); v.set_actor( &VERIFIED_REGISTRY_ACTOR_ADDR, - actor(*VERIFREG_ACTOR_CODE_ID, verifreg_head, 0, TokenAmount::zero(), None), + new_actor(*VERIFREG_ACTOR_CODE_ID, verifreg_head, 0, TokenAmount::zero(), None), ); // Ethereum Address Manager v.set_actor( &EAM_ACTOR_ADDR, - actor(*EAM_ACTOR_CODE_ID, EMPTY_ARR_CID, 0, TokenAmount::zero(), None), + new_actor(*EAM_ACTOR_CODE_ID, EMPTY_ARR_CID, 0, TokenAmount::zero(), None), ); // datacap @@ -204,14 +207,14 @@ where v.put_store(&DataCapState::new(&v.store, VERIFIED_REGISTRY_ACTOR_ADDR).unwrap()); v.set_actor( &DATACAP_TOKEN_ACTOR_ADDR, - actor(*DATACAP_TOKEN_ACTOR_CODE_ID, datacap_head, 0, TokenAmount::zero(), None), + new_actor(*DATACAP_TOKEN_ACTOR_CODE_ID, datacap_head, 0, TokenAmount::zero(), None), ); // burnt funds let burnt_funds_head = v.put_store(&AccountState { address: BURNT_FUNDS_ACTOR_ADDR }); v.set_actor( &BURNT_FUNDS_ACTOR_ADDR, - actor(*ACCOUNT_ACTOR_CODE_ID, burnt_funds_head, 0, TokenAmount::zero(), None), + new_actor(*ACCOUNT_ACTOR_CODE_ID, burnt_funds_head, 0, TokenAmount::zero(), None), ); // create a faucet with 1 billion FIL for setting up test accounts @@ -294,8 +297,8 @@ where ) -> Result { let from_id = &self.resolve_id_address(from).unwrap(); let mut a = self.actor(from_id).unwrap(); - let call_seq = a.call_seq; - a.call_seq = call_seq + 1; + let call_seq = a.sequence; + a.sequence = call_seq + 1; // EthAccount abstractions turns Placeholders into EthAccounts if a.code == *PLACEHOLDER_ACTOR_CODE_ID { a.code = *ETHACCOUNT_ACTOR_CODE_ID; diff --git a/test_vm/src/messaging.rs b/test_vm/src/messaging.rs index b144f7f9b..d2c82051b 100644 --- a/test_vm/src/messaging.rs +++ b/test_vm/src/messaging.rs @@ -61,7 +61,7 @@ use serde::Serialize; use std::cell::{RefCell, RefMut}; use vm_api::trace::InvocationTrace; use vm_api::util::get_state; -use vm_api::{actor, ActorState, VM}; +use vm_api::{new_actor, ActorState, VM}; use std::ops::Add; @@ -334,7 +334,7 @@ where act.code = code_id; act } - None => actor(code_id, EMPTY_ARR_CID, 0, TokenAmount::zero(), predictable_address), + None => new_actor(code_id, EMPTY_ARR_CID, 0, TokenAmount::zero(), predictable_address), _ => { return Err(actor_error!(forbidden; "attempt to create new actor at existing address {}", addr)); @@ -489,7 +489,7 @@ where } fn lookup_delegated_address(&self, id: ActorID) -> Option
{ - self.v.actor(&Address::new_id(id)).and_then(|act| act.predictable_address) + self.v.actor(&Address::new_id(id)).and_then(|act| act.delegated_address) } fn send( diff --git a/test_vm/tests/test_vm_test.rs b/test_vm/tests/test_vm_test.rs index f895b91a8..4d2241cbc 100644 --- a/test_vm/tests/test_vm_test.rs +++ b/test_vm/tests/test_vm_test.rs @@ -12,7 +12,7 @@ use fvm_shared::METHOD_SEND; use num_traits::Zero; use test_vm::{TestVM, FIRST_TEST_USER_ADDR, TEST_FAUCET_ADDR}; use vm_api::util::{get_state, pk_addrs_from}; -use vm_api::{actor, VM}; +use vm_api::{new_actor, VM}; #[test] fn state_control() { @@ -22,7 +22,7 @@ fn state_control() { let addr2 = Address::new_id(2222); // set actor - let a1 = actor( + let a1 = new_actor( *ACCOUNT_ACTOR_CODE_ID, make_identity_cid(b"a1-head"), 42, @@ -34,7 +34,7 @@ fn state_control() { assert_eq!(out, a1); let check = v.checkpoint(); - let a2 = actor( + let a2 = new_actor( *PAYCH_ACTOR_CODE_ID, make_identity_cid(b"a2-head"), 88, @@ -64,7 +64,7 @@ fn assert_account_actor( ) { let act = v.actor(&addr).unwrap(); let st: AccountState = get_state(v, &addr).unwrap(); - assert_eq!(exp_call_seq, act.call_seq); + assert_eq!(exp_call_seq, act.sequence); assert_eq!(*ACCOUNT_ACTOR_CODE_ID, act.code); assert_eq!(exp_bal, act.balance); assert_eq!(exp_pk_addr, st.address); diff --git a/vm_api/Cargo.toml b/vm_api/Cargo.toml index b151b5ae9..ccd36b110 100644 --- a/vm_api/Cargo.toml +++ b/vm_api/Cargo.toml @@ -11,15 +11,18 @@ publish = false [lib] [dependencies] -fil_actors_runtime = { workspace = true, features = [ "test_utils" ] } - anyhow = { workspace = true } cid = { workspace = true } fvm_ipld_blockstore = { workspace = true } fvm_ipld_encoding = { workspace = true } fvm_ipld_hamt = { workspace = true } fvm_shared = { workspace = true } +num-derive = { workspace = true } +num-traits = { workspace = true } rand = { workspace = true } rand_chacha = { workspace = true } serde = { workspace = true } +[features] +testing = [] + diff --git a/vm_api/src/builtin.rs b/vm_api/src/builtin.rs new file mode 100644 index 000000000..0279349e6 --- /dev/null +++ b/vm_api/src/builtin.rs @@ -0,0 +1,50 @@ +use num_derive::FromPrimitive; + +/// Identifies the builtin actor types for usage with the +/// actor::resolve_builtin_actor_type syscall. +/// Note that there is a mirror of this enum in the FVM SDK src/actors/builtins.rs. +/// These must be kept in sync for the syscall to work correctly, without either side +/// importing the other. +#[derive(PartialEq, Eq, Clone, Copy, PartialOrd, Ord, FromPrimitive, Debug)] +#[repr(i32)] +pub enum Type { + System = 1, + Init = 2, + Cron = 3, + Account = 4, + Power = 5, + Miner = 6, + Market = 7, + PaymentChannel = 8, + Multisig = 9, + Reward = 10, + VerifiedRegistry = 11, + DataCap = 12, + Placeholder = 13, + EVM = 14, + EAM = 15, + EthAccount = 16, +} + +impl Type { + pub fn name(&self) -> &'static str { + match *self { + Type::System => "system", + Type::Init => "init", + Type::Cron => "cron", + Type::Account => "account", + Type::Power => "storagepower", + Type::Miner => "storageminer", + Type::Market => "storagemarket", + Type::PaymentChannel => "paymentchannel", + Type::Multisig => "multisig", + Type::Reward => "reward", + Type::VerifiedRegistry => "verifiedregistry", + Type::DataCap => "datacap", + Type::Placeholder => "placeholder", + Type::EVM => "evm", + Type::EAM => "eam", + Type::EthAccount => "ethaccount", + } + } +} diff --git a/vm_api/src/lib.rs b/vm_api/src/lib.rs index 180e6776e..ce9bbced4 100644 --- a/vm_api/src/lib.rs +++ b/vm_api/src/lib.rs @@ -1,24 +1,34 @@ use std::collections::BTreeMap; use cid::Cid; -// TODO: drop the dependency on fil_actors_runtime and have a suitable replacement abstraction here -// https://github.com/filecoin-project/builtin-actors/issues/1344 -pub use fil_actors_runtime::runtime::{builtins::Type, Primitives}; use fvm_ipld_blockstore::Blockstore; use fvm_ipld_encoding::{ ipld_block::IpldBlock, tuple::{serde_tuple, Deserialize_tuple, Serialize_tuple}, }; use fvm_shared::{ - address::Address, clock::ChainEpoch, econ::TokenAmount, error::ExitCode, MethodNum, + address::Address, + clock::ChainEpoch, + crypto::{ + hash::SupportedHashes, + signature::{Signature, SECP_PUB_LEN, SECP_SIG_LEN, SECP_SIG_MESSAGE_HASH_SIZE}, + }, + econ::TokenAmount, + error::ExitCode, + piece::PieceInfo, + sector::RegisteredSealProof, + MethodNum, }; -pub mod trace; +use builtin::*; +pub use error::*; use trace::*; -pub mod util; +pub mod builtin; mod error; -pub use error::*; +pub mod trace; +#[cfg(feature = "testing")] +pub mod util; /// An abstract VM that is injected into integration tests pub trait VM { @@ -82,28 +92,75 @@ pub trait VM { fn state_root(&self) -> Cid; } +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct MessageResult { + pub code: ExitCode, + pub message: String, + pub ret: Option, +} + +// Duplicates an internal FVM type (fvm::state_tree::ActorState) that cannot be depended on here #[derive(Serialize_tuple, Deserialize_tuple, Clone, PartialEq, Eq, Debug)] pub struct ActorState { + /// Link to code for the actor. pub code: Cid, + /// Link to the state of the actor. pub state: Cid, - pub call_seq: u64, + /// Sequence of the actor. + pub sequence: u64, + /// Tokens available to the actor. pub balance: TokenAmount, - pub predictable_address: Option
, + /// The actor's "delegated" address, if assigned. + /// + /// This field is set on actor creation and never modified. + pub delegated_address: Option
, } -pub fn actor( +pub fn new_actor( code: Cid, head: Cid, call_seq_num: u64, balance: TokenAmount, predictable_address: Option
, ) -> ActorState { - ActorState { code, state: head, call_seq: call_seq_num, balance, predictable_address } + ActorState { + code, + state: head, + sequence: call_seq_num, + balance, + delegated_address: predictable_address, + } } -#[derive(Clone, PartialEq, Eq, Debug)] -pub struct MessageResult { - pub code: ExitCode, - pub message: String, - pub ret: Option, +/// Pure functions implemented as primitives by the runtime. +pub trait Primitives { + /// Hashes input data using blake2b with 256 bit output. + fn hash_blake2b(&self, data: &[u8]) -> [u8; 32]; + + /// Hashes input data using a supported hash function. + fn hash(&self, hasher: SupportedHashes, data: &[u8]) -> Vec; + + /// Hashes input into a 64 byte buffer + fn hash_64(&self, hasher: SupportedHashes, data: &[u8]) -> ([u8; 64], usize); + + /// Computes an unsealed sector CID (CommD) from its constituent piece CIDs (CommPs) and sizes. + fn compute_unsealed_sector_cid( + &self, + proof_type: RegisteredSealProof, + pieces: &[PieceInfo], + ) -> Result; + + /// Verifies that a signature is valid for an address and plaintext. + fn verify_signature( + &self, + signature: &Signature, + signer: &Address, + plaintext: &[u8], + ) -> Result<(), anyhow::Error>; + + fn recover_secp_public_key( + &self, + hash: &[u8; SECP_SIG_MESSAGE_HASH_SIZE], + signature: &[u8; SECP_SIG_LEN], + ) -> Result<[u8; SECP_PUB_LEN], anyhow::Error>; }