Skip to content

Commit

Permalink
injectable extern behaviour
Browse files Browse the repository at this point in the history
  • Loading branch information
alexytsu committed Oct 30, 2023
1 parent 5aee49e commit 71025f3
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 50 deletions.
4 changes: 2 additions & 2 deletions actors/miner/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ pub use deadlines::*;
pub use expiration_queue::*;
use fil_actors_runtime::cbor::{serialize, serialize_vec};
use fil_actors_runtime::runtime::builtins::Type;
use fil_actors_runtime::runtime::{ActorCode, DomainSeparationTag, Policy, Runtime};
use fil_actors_runtime::runtime::{ActorCode, DomainSeparationTag, Policy, Runtime, Verifier};
use fil_actors_runtime::{
actor_dispatch, actor_error, deserialize_block, extract_send_result, ActorContext,
ActorDowncast, ActorError, AsActorError, BatchReturn, BatchReturnGen, BURNT_FUNDS_ACTOR_ADDR,
Expand Down Expand Up @@ -1054,7 +1054,7 @@ impl Actor {
let quant = state.quant_spec_for_deadline(rt.policy(), dl_idx);

for update in &decls_by_deadline[&dl_idx] {
rt.verify_replica_update(&update.proof_inputs).with_context_code(
Verifier::verify_replica_update(rt, &update.proof_inputs).with_context_code(
ExitCode::USR_ILLEGAL_ARGUMENT,
|| {
format!(
Expand Down
4 changes: 2 additions & 2 deletions integration_tests/src/tests/multisig_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ pub fn proposal_hash_test(v: &dyn VM) {
params: RawBytes::default(),
};

let wrong_hash = compute_proposal_hash(&wrong_tx, v.primitives()).unwrap();
let wrong_hash = compute_proposal_hash(&wrong_tx, &*v.primitives()).unwrap();

let wrong_approval_params = TxnIDParams { id: TxnID(0), proposal_hash: wrong_hash.to_vec() };
apply_code(
Expand All @@ -80,7 +80,7 @@ pub fn proposal_hash_test(v: &dyn VM) {
params: RawBytes::default(),
};

let correct_hash = compute_proposal_hash(&correct_tx, v.primitives()).unwrap();
let correct_hash = compute_proposal_hash(&correct_tx, &*v.primitives()).unwrap();

let correct_approval_params =
TxnIDParams { id: TxnID(0), proposal_hash: correct_hash.to_vec() };
Expand Down
32 changes: 18 additions & 14 deletions runtime/src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1367,6 +1367,23 @@ impl Primitives for MockRuntime {
fn hash_64(&self, hasher: SupportedHashes, data: &[u8]) -> ([u8; 64], usize) {
(*self.hash_func)(hasher, data)
}

fn verify_replica_update(&self, replica: &ReplicaUpdateInfo) -> Result<(), anyhow::Error> {
let exp = self
.expectations
.borrow_mut()
.expect_replica_verify
.take()
.expect("unexpected call to verify replica update");
assert_eq!(exp.input.update_proof_type, replica.update_proof_type, "mismatched proof type");
assert_eq!(exp.input.new_sealed_cid, replica.new_sealed_cid, "mismatched new sealed CID");
assert_eq!(exp.input.old_sealed_cid, replica.old_sealed_cid, "mismatched old sealed CID");
assert_eq!(
exp.input.new_unsealed_cid, replica.new_unsealed_cid,
"mismatched new unsealed CID"
);
exp.result
}
}

impl Verifier for MockRuntime {
Expand Down Expand Up @@ -1472,20 +1489,7 @@ impl Verifier for MockRuntime {
}

fn verify_replica_update(&self, replica: &ReplicaUpdateInfo) -> anyhow::Result<()> {
let exp = self
.expectations
.borrow_mut()
.expect_replica_verify
.take()
.expect("unexpected call to verify replica update");
assert_eq!(exp.input.update_proof_type, replica.update_proof_type, "mismatched proof type");
assert_eq!(exp.input.new_sealed_cid, replica.new_sealed_cid, "mismatched new sealed CID");
assert_eq!(exp.input.old_sealed_cid, replica.old_sealed_cid, "mismatched old sealed CID");
assert_eq!(
exp.input.new_unsealed_cid, replica.new_unsealed_cid,
"mismatched new unsealed CID"
);
exp.result
Primitives::verify_replica_update(self, replica)
}
}

Expand Down
30 changes: 24 additions & 6 deletions test_vm/src/fakes.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,34 @@
use anyhow::anyhow;
use anyhow::Error;
use cid::multihash::Code;
use cid::multihash::MultihashDigest;
use cid::Cid;
use fil_actors_runtime::runtime::Verifier;
use fvm_shared::address::{Address, SECP_PUB_LEN};
use fvm_shared::consensus::ConsensusFault;
use fvm_shared::crypto::hash::SupportedHashes;
use fvm_shared::crypto::signature::{Signature, SECP_SIG_LEN, SECP_SIG_MESSAGE_HASH_SIZE};
use fvm_shared::piece::PieceInfo;
use fvm_shared::sector::AggregateSealVerifyProofAndInfos;
use fvm_shared::sector::RegisteredSealProof;
use fvm_shared::sector::ReplicaUpdateInfo;
use fvm_shared::sector::SealVerifyInfo;
use fvm_shared::sector::WindowPoStVerifyInfo;
use fvm_shared::sector::WindowPoStVerifyInfo;
use integer_encoding::VarInt;

use fil_actors_runtime::runtime::Primitives;
use fil_actors_runtime::test_utils::{make_piece_cid, recover_secp_public_key};

// Fake implementation of runtime primitives.
// Struct members can be added here to provide configurable functionality.
pub struct FakePrimitives {}
use crate::TEST_VM_INVALID_POST;

/// Fake implementation of runtime primitives.
#[derive(Default, Clone)]
#[allow(clippy::type_complexity)]
pub struct FakePrimitives {
pub verify_signature_override: Option<fn(&Signature, &Address, &[u8]) -> Result<(), Error>>,
pub verify_replica_update: Option<fn(&ReplicaUpdateInfo) -> Result<(), Error>>,
}

impl Primitives for FakePrimitives {
fn hash_blake2b(&self, data: &[u8]) -> [u8; 32] {
Expand Down Expand Up @@ -43,7 +57,7 @@ impl Primitives for FakePrimitives {
&self,
proof_type: RegisteredSealProof,
pieces: &[PieceInfo],
) -> Result<Cid, anyhow::Error> {
) -> Result<Cid, Error> {
// Construct a buffer that depends on all the input data.
let mut buf: Vec<u8> = Vec::new();
let ptv: i64 = proof_type.into();
Expand All @@ -60,7 +74,11 @@ impl Primitives for FakePrimitives {
signature: &Signature,
_signer: &Address,
plaintext: &[u8],
) -> Result<(), anyhow::Error> {
) -> Result<(), Error> {
if self.verify_signature_override.is_some() {
return (self.verify_signature_override.unwrap())(signature, _signer, plaintext);
}

if signature.bytes != plaintext {
return Err(anyhow::format_err!(
"invalid signature (mock sig validation expects siggy bytes to be equal to plaintext)"
Expand All @@ -73,7 +91,7 @@ impl Primitives for FakePrimitives {
&self,
hash: &[u8; SECP_SIG_MESSAGE_HASH_SIZE],
signature: &[u8; SECP_SIG_LEN],
) -> Result<[u8; SECP_PUB_LEN], anyhow::Error> {
) -> Result<[u8; SECP_PUB_LEN], Error> {
recover_secp_public_key(hash, signature).map_err(|_| anyhow!("failed to recover pubkey"))
}
}
29 changes: 24 additions & 5 deletions test_vm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::fakes::FakePrimitives;

use cid::multihash::Code;
use cid::Cid;
use fakes::FakeVerifier;
use fil_actor_account::State as AccountState;
use fil_actor_cron::{Entry as CronEntry, State as CronState};
use fil_actor_datacap::State as DataCapState;
Expand All @@ -13,7 +14,7 @@ use fil_actor_system::State as SystemState;
use fil_actor_verifreg::State as VerifRegState;
use fil_actors_runtime::cbor::serialize;
use fil_actors_runtime::runtime::builtins::Type;
use fil_actors_runtime::runtime::{Policy, Primitives, EMPTY_ARR_CID};
use fil_actors_runtime::runtime::{Policy, Primitives, Verifier, EMPTY_ARR_CID};
use fil_actors_runtime::test_blockstores::MemoryBlockstore;
use fil_actors_runtime::{test_utils::*, DEFAULT_HAMT_CONFIG};
use fil_actors_runtime::{Map, DATACAP_TOKEN_ACTOR_ADDR};
Expand Down Expand Up @@ -51,7 +52,7 @@ pub use messaging::*;

/// An in-memory rust-execution VM for testing builtin-actors that yields sensible stack traces and debug info
pub struct TestVM {
pub primitives: FakePrimitives,
pub primitives: RefCell<FakePrimitives>,
pub store: Rc<MemoryBlockstore>,
pub state_root: RefCell<Cid>,
actors_dirty: RefCell<bool>,
Expand All @@ -75,7 +76,7 @@ impl TestVM {
);

TestVM {
primitives: FakePrimitives {},
primitives: RefCell::new(FakePrimitives::default()),
store,
state_root: RefCell::new(actors.flush().unwrap()),
circulating_supply: RefCell::new(TokenAmount::zero()),
Expand Down Expand Up @@ -390,8 +391,8 @@ impl VM for TestVM {
self.actors_dirty.replace(true);
}

fn primitives(&self) -> &dyn Primitives {
&self.primitives
fn primitives(&self) -> Box<dyn Primitives> {
Box::new(self.primitives.borrow().clone())
}

fn actor_manifest(&self) -> BTreeMap<Cid, Type> {
Expand Down Expand Up @@ -448,4 +449,22 @@ impl VM for TestVM {
fn set_initial_state_root(&self, state_root: Cid) {
self.state_root.replace(state_root);
}

fn override_verify_signature(
&self,
verify_signature: fn(
&fvm_shared::crypto::signature::Signature,
&Address,
&[u8],
) -> Result<(), anyhow::Error>,
) {
self.primitives.borrow_mut().verify_signature_override = Some(verify_signature);
}

fn override_verifiy_replica_update(
&self,
verify_replica_update: fn(&ReplicaUpdateInfo) -> Result<(), anyhow::Error>,
) {
self.primitives.borrow_mut().verify_replica_update = Some(verify_replica_update);
}
}
26 changes: 10 additions & 16 deletions test_vm/src/messaging.rs
Original file line number Diff line number Diff line change
Expand Up @@ -653,47 +653,41 @@ impl Primitives for InvocationCtx<'_> {
signer: &Address,
plaintext: &[u8],
) -> Result<(), anyhow::Error> {
self.v.primitives.verify_signature(signature, signer, plaintext)
self.v.primitives().verify_signature(signature, signer, plaintext)
}

fn hash_blake2b(&self, data: &[u8]) -> [u8; 32] {
self.v.primitives.hash_blake2b(data)
self.v.primitives().hash_blake2b(data)
}

fn compute_unsealed_sector_cid(
&self,
proof_type: RegisteredSealProof,
pieces: &[PieceInfo],
) -> Result<Cid, anyhow::Error> {
self.v.primitives.compute_unsealed_sector_cid(proof_type, pieces)
self.v.primitives().compute_unsealed_sector_cid(proof_type, pieces)
}

fn hash(&self, hasher: SupportedHashes, data: &[u8]) -> Vec<u8> {
self.v.primitives.hash(hasher, data)
self.v.primitives().hash(hasher, data)
}

fn hash_64(&self, hasher: SupportedHashes, data: &[u8]) -> ([u8; 64], usize) {
self.v.primitives.hash_64(hasher, data)
self.v.primitives().hash_64(hasher, data)
}

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> {
self.v.primitives.recover_secp_public_key(hash, signature)
self.v.primitives().recover_secp_public_key(hash, signature)
}
}

impl Verifier for InvocationCtx<'_> {
fn verify_post(&self, verify_info: &WindowPoStVerifyInfo) -> Result<(), anyhow::Error> {
for proof in &verify_info.proofs {
if proof.proof_bytes.eq(&TEST_VM_INVALID_POST.as_bytes().to_vec()) {
return Err(anyhow!("invalid proof"));
}
}

Ok(())
self.v.verifiier().verify_post(verify_info)
}

fn verify_consensus_fault(
Expand All @@ -702,7 +696,7 @@ impl Verifier for InvocationCtx<'_> {
_h2: &[u8],
_extra: &[u8],
) -> Result<Option<ConsensusFault>, anyhow::Error> {
Ok(None)
self.v.verifiier().borrow().ver
}

fn batch_verify_seals(&self, batch: &[SealVerifyInfo]) -> anyhow::Result<Vec<bool>> {
Expand All @@ -716,8 +710,8 @@ impl Verifier for InvocationCtx<'_> {
Ok(())
}

fn verify_replica_update(&self, _replica: &ReplicaUpdateInfo) -> Result<(), anyhow::Error> {
Ok(())
fn verify_replica_update(&self, replica: &ReplicaUpdateInfo) -> Result<(), anyhow::Error> {
self.v.primitives().verify_replica_update(replica)
}
}

Expand Down
21 changes: 16 additions & 5 deletions vm_api/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::collections::BTreeMap;

use anyhow::Error;
use cid::Cid;
use fvm_ipld_blockstore::Blockstore;
use fvm_ipld_encoding::{
Expand All @@ -16,7 +17,7 @@ use fvm_shared::{
econ::TokenAmount,
error::ExitCode,
piece::PieceInfo,
sector::RegisteredSealProof,
sector::{RegisteredSealProof, ReplicaUpdateInfo},
MethodNum,
};

Expand Down Expand Up @@ -71,14 +72,16 @@ pub trait VM {
fn take_invocations(&self) -> Vec<InvocationTrace>;

/// Provides access to VM primitives
fn primitives(&self) -> &dyn Primitives;
fn primitives(&self) -> Box<dyn Primitives>;

/// Return a map of actor code CIDs to their corresponding types
fn actor_manifest(&self) -> BTreeMap<Cid, Type>;

/// Returns a map of all actor addresses to their corresponding states
fn actor_states(&self) -> BTreeMap<Address, ActorState>;

// Overridable constants and extern behaviour

/// Get the current chain epoch
fn epoch(&self) -> ChainEpoch;

Expand Down Expand Up @@ -108,6 +111,12 @@ pub trait VM {

/// Set the initial state root of the block
fn set_initial_state_root(&self, state_root: Cid);

// Override the signature verification behaviour
fn override_verify_signature(
&self,
verify_signature: fn(&Signature, &Address, &[u8]) -> Result<(), Error>,
);
}

#[derive(Clone, PartialEq, Eq, Debug)]
Expand Down Expand Up @@ -160,19 +169,21 @@ pub trait Primitives {
&self,
proof_type: RegisteredSealProof,
pieces: &[PieceInfo],
) -> Result<Cid, anyhow::Error>;
) -> Result<Cid, Error>;

/// Verifies that a signature is valid for an address and plaintext.
fn verify_signature(
&self,
signature: &Signature,
signer: &Address,
plaintext: &[u8],
) -> Result<(), anyhow::Error>;
) -> Result<(), 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>;
) -> Result<[u8; SECP_PUB_LEN], Error>;

fn verify_replica_update(&self, replica: &ReplicaUpdateInfo) -> Result<(), Error>;
}

0 comments on commit 71025f3

Please sign in to comment.