diff --git a/actors/runtime/src/runtime/mod.rs b/actors/runtime/src/runtime/mod.rs index 837f06ea0..97acf008d 100644 --- a/actors/runtime/src/runtime/mod.rs +++ b/actors/runtime/src/runtime/mod.rs @@ -21,6 +21,7 @@ use fvm_shared::{ActorID, MethodNum}; pub use self::actor_code::*; use crate::ActorError; + mod actor_code; #[cfg(feature = "runtime-wasm")] diff --git a/actors/runtime/src/test_utils.rs b/actors/runtime/src/test_utils.rs index 732c3a222..a2a3d673d 100644 --- a/actors/runtime/src/test_utils.rs +++ b/actors/runtime/src/test_utils.rs @@ -156,6 +156,7 @@ pub struct ExpectCreateActor { pub code_id: Cid, pub actor_id: ActorID, } + #[derive(Clone, Debug)] pub struct ExpectedMessage { pub to: Address, @@ -594,8 +595,8 @@ impl Runtime for MockRuntime { .unwrap(); assert!(expected_msg.to == to && expected_msg.method == method && expected_msg.params == params && expected_msg.value == value, - "expectedMessage being sent does not match expectation.\nMessage -\t to: {:?} method: {:?} value: {:?} params: {:?}\nExpected -\t {:?}", - to, method, value, params, expected_msg); + "expectedMessage being sent does not match expectation.\nMessage -\t to: {:?} method: {:?} value: {:?} params: {:?}\nExpected -\t {:?}", + to, method, value, params, expected_msg); { let mut balance = self.balance.borrow_mut(); diff --git a/fvm/src/externs/mod.rs b/fvm/src/externs/mod.rs index 440262285..6ddc61c59 100644 --- a/fvm/src/externs/mod.rs +++ b/fvm/src/externs/mod.rs @@ -14,7 +14,7 @@ pub trait Consensus { h1: &[u8], h2: &[u8], extra: &[u8], - ) -> anyhow::Result>; + ) -> anyhow::Result<(Option, i64)>; } /// Randomness provider trait diff --git a/fvm/src/kernel/default.rs b/fvm/src/kernel/default.rs index 465b5fc79..a8bab96b9 100644 --- a/fvm/src/kernel/default.rs +++ b/fvm/src/kernel/default.rs @@ -14,6 +14,7 @@ use fvm_shared::blockstore::{Blockstore, CborStore}; use fvm_shared::commcid::{ cid_to_data_commitment_v1, cid_to_replica_commitment_v1, data_commitment_v1_to_cid, }; +use fvm_shared::consensus::ConsensusFault; use fvm_shared::econ::TokenAmount; use fvm_shared::encoding::{blake2b_256, bytes_32, to_vec, RawBytes}; use fvm_shared::error::ErrorNumber; @@ -534,11 +535,14 @@ where // This syscall cannot be resolved inside the FVM, so we need to traverse // the node boundary through an extern. - self.call_manager + let (fault, gas) = self + .call_manager .externs() .verify_consensus_fault(h1, h2, extra) - .or_illegal_argument() - .context("fault not verified") + .or_illegal_argument()?; + self.call_manager + .charge_gas(GasCharge::new("verify_consensus_fault_accesses", gas, 0))?; + Ok(fault) } fn batch_verify_seals(&mut self, vis: &[SealVerifyInfo]) -> Result> { @@ -571,7 +575,7 @@ where false } } - }, + } Err(e) => { log::error!("seal verify internal fail (miner: {}) (err: {:?})", seal.sector_id.miner, e); false diff --git a/fvm/src/kernel/mod.rs b/fvm/src/kernel/mod.rs index 8f55e3aec..0970daddb 100644 --- a/fvm/src/kernel/mod.rs +++ b/fvm/src/kernel/mod.rs @@ -19,6 +19,7 @@ mod blocks; pub mod default; mod error; + pub use error::{ClassifyResult, Context, ExecutionError, Result, SyscallError}; use crate::call_manager::{CallManager, InvocationResult}; diff --git a/fvm/src/lib.rs b/fvm/src/lib.rs index e30e73411..8c7190730 100644 --- a/fvm/src/lib.rs +++ b/fvm/src/lib.rs @@ -68,6 +68,7 @@ mod test { struct DummyExterns; impl Externs for DummyExterns {} + impl Rand for DummyExterns { fn get_chain_randomness( &self, @@ -87,13 +88,14 @@ mod test { todo!() } } + impl Consensus for DummyExterns { fn verify_consensus_fault( &self, _h1: &[u8], _h2: &[u8], _extra: &[u8], - ) -> anyhow::Result> { + ) -> anyhow::Result<(Option, i64)> { todo!() } } diff --git a/fvm/src/syscalls/crypto.rs b/fvm/src/syscalls/crypto.rs index 523c465a5..8e23e107d 100644 --- a/fvm/src/syscalls/crypto.rs +++ b/fvm/src/syscalls/crypto.rs @@ -15,7 +15,7 @@ use fvm_shared::piece::PieceInfo; use fvm_shared::sector::{ AggregateSealVerifyProofAndInfos, RegisteredSealProof, SealVerifyInfo, WindowPoStVerifyInfo, }; -use fvm_shared::ActorID; +use fvm_shared::{sys, ActorID}; use wasmtime::{Caller, Trap}; use super::Context; @@ -140,42 +140,38 @@ pub fn verify_post( /// the "parent grinding fault", in which case it must be the sibling of h1 (same parent tipset) and one of the /// blocks in the parent of h2 (i.e. h2's grandparent). /// -/// Returns: -/// - The fault type (1-3) or 0 for no fault. -/// - The chain epoch at which the fault happened. -/// - The actor at fault. pub fn verify_consensus_fault( - mut context: Context<'_, impl Kernel>, + context: Context<'_, impl Kernel>, h1_off: u32, h1_len: u32, h2_off: u32, h2_len: u32, extra_off: u32, extra_len: u32, -) -> Result<(u32, ChainEpoch, ActorID)> { +) -> Result { let h1 = context.memory.try_slice(h1_off, h1_len)?; let h2 = context.memory.try_slice(h2_off, h2_len)?; let extra = context.memory.try_slice(extra_off, extra_len)?; - // TODO the extern should only signal an error in case there was an internal - // interrupting error evaluating the consensus fault. If the outcome is - // "no consensus fault was found", the extern should not error, as doing so - // would interrupt execution via the Trap (at least currently). let ret = context.kernel.verify_consensus_fault(h1, h2, extra)?; match ret { - // Consensus fault detected; return the actor as a block. - Some(fault) => Ok(( - fault.fault_type as u32, - fault.epoch, - fault + // Consensus fault detected + Some(fault) => Ok(sys::out::crypto::VerifyConsensusFault { + fault: fault.fault_type as u32, + epoch: fault.epoch, + target: fault .target .id() - .context("expected a resolved actor address") + .context("kernel returned non-id target address") .or_fatal()?, - )), + }), // No consensus fault. - None => Ok((0, 0, 0)), + None => Ok(sys::out::crypto::VerifyConsensusFault { + fault: 0, + epoch: 0, + target: 0, + }), } } diff --git a/sdk/src/crypto.rs b/sdk/src/crypto.rs index 547d28730..bf38b2bed 100644 --- a/sdk/src/crypto.rs +++ b/sdk/src/crypto.rs @@ -97,17 +97,17 @@ pub fn verify_post(info: &WindowPoStVerifyInfo) -> SyscallResult { /// The parameters are all serialized block headers. The third "extra" parameter is consulted only for /// the "parent grinding fault", in which case it must be the sibling of h1 (same parent tipset) and one of the /// blocks in the parent of h2 (i.e. h2's grandparent). -/// Returns nil and an error if the headers don't prove a fault. +/// Returns None and an error if the headers don't prove a fault. #[allow(unused)] pub fn verify_consensus_fault( h1: &[u8], h2: &[u8], extra: &[u8], ) -> SyscallResult> { - let sys::crypto::out::VerifyConsensusFault { + let fvm_shared::sys::out::crypto::VerifyConsensusFault { fault, epoch, - actor, + target, } = unsafe { sys::crypto::verify_consensus_fault( h1.as_ptr(), @@ -125,8 +125,8 @@ pub fn verify_consensus_fault( FromPrimitive::from_u32(fault).expect("received an invalid fault type from the runtime"); Ok(Some(ConsensusFault { epoch, + target: Address::new_id(target), fault_type, - target: Address::new_id(actor), })) } diff --git a/sdk/src/sys/crypto.rs b/sdk/src/sys/crypto.rs index e19cade4f..74b100e81 100644 --- a/sdk/src/sys/crypto.rs +++ b/sdk/src/sys/crypto.rs @@ -50,7 +50,7 @@ super::fvm_syscalls! { h2_len: u32, extra_off: *const u8, extra_len: u32, - ) -> Result; + ) -> Result; /// Verifies an aggregated batch of sector seal proofs. pub fn verify_aggregate_seals(agg_off: *const u8, agg_len: u32) -> Result; @@ -58,13 +58,3 @@ super::fvm_syscalls! { /// Verifies an aggregated batch of sector seal proofs. pub fn batch_verify_seals(batch_off: *const u8, batch_len: u32, result_off: *const u8) -> Result<()>; } - -/// Module containing multi-value out types of these syscalls. -pub mod out { - #[repr(C)] - pub struct VerifyConsensusFault { - pub fault: u32, - pub epoch: fvm_shared::clock::ChainEpoch, - pub actor: fvm_shared::ActorID, - } -} diff --git a/shared/src/sys/out.rs b/shared/src/sys/out.rs index 35c97af42..3121914dd 100644 --- a/shared/src/sys/out.rs +++ b/shared/src/sys/out.rs @@ -44,3 +44,15 @@ pub mod send { pub return_id: BlockId, } } + +pub mod crypto { + use crate::{ActorID, ChainEpoch}; + + #[repr(C)] + #[derive(Debug, Copy, Clone)] + pub struct VerifyConsensusFault { + pub fault: u32, + pub epoch: ChainEpoch, + pub target: ActorID, + } +} diff --git a/testing/conformance/src/externs.rs b/testing/conformance/src/externs.rs index 14424f6d7..cfed1e72d 100644 --- a/testing/conformance/src/externs.rs +++ b/testing/conformance/src/externs.rs @@ -49,7 +49,7 @@ impl Consensus for TestExterns { _h1: &[u8], _h2: &[u8], _extra: &[u8], - ) -> anyhow::Result> { + ) -> anyhow::Result<(Option, i64)> { todo!() } } diff --git a/testing/conformance/src/vm.rs b/testing/conformance/src/vm.rs index 305567e8c..8397395ab 100644 --- a/testing/conformance/src/vm.rs +++ b/testing/conformance/src/vm.rs @@ -337,6 +337,7 @@ where self.0.create_actor(code_id, actor_id) } } + impl BlockOps for TestKernel where M: Machine, @@ -367,6 +368,7 @@ where self.0.block_get(id) } } + impl CircSupplyOps for TestKernel where M: Machine, @@ -378,6 +380,7 @@ where Ok(self.1.circ_supply.clone()) } } + impl CryptoOps for TestKernel where M: Machine, @@ -447,6 +450,7 @@ where Ok(true) } } + impl DebugOps for TestKernel where M: Machine, @@ -461,6 +465,7 @@ where self.0.debug_enabled() } } + impl GasOps for TestKernel where M: Machine, @@ -471,6 +476,7 @@ where self.0.charge_gas(name, compute) } } + impl MessageOps for TestKernel where M: Machine, @@ -493,6 +499,7 @@ where self.0.msg_value_received() } } + impl NetworkOps for TestKernel where M: Machine, @@ -511,6 +518,7 @@ where self.0.network_base_fee() } } + impl RandomnessOps for TestKernel where M: Machine, @@ -537,6 +545,7 @@ where .get_randomness_from_beacon(personalization, rand_epoch, entropy) } } + impl SelfOps for TestKernel where M: Machine, @@ -559,6 +568,7 @@ where self.0.self_destruct(beneficiary) } } + impl SendOps for TestKernel where M: Machine,