diff --git a/actors/market/src/state.rs b/actors/market/src/state.rs index 46067c8c3..f66d36f2c 100644 --- a/actors/market/src/state.rs +++ b/actors/market/src/state.rs @@ -708,7 +708,7 @@ impl State { Ok(()) } - fn load_provider_sectors(&self, store: BS) -> Result, ActorError> + pub fn load_provider_sectors(&self, store: BS) -> Result, ActorError> where BS: Blockstore, { @@ -1128,7 +1128,7 @@ where .context_code(ExitCode::USR_ILLEGAL_STATE, "failed to lookup pending deal") } -fn load_provider_sector_deals( +pub fn load_provider_sector_deals( store: BS, provider_sectors: &ProviderSectorsMap, provider: &Address, diff --git a/actors/miner/src/lib.rs b/actors/miner/src/lib.rs index 0641424fb..6de326abc 100644 --- a/actors/miner/src/lib.rs +++ b/actors/miner/src/lib.rs @@ -5370,8 +5370,11 @@ fn activate_sectors_pieces( rt, &activation_info.piece_manifests, activation_info.sector_type, - )?; - if !declared_commd.eq(&computed_commd) { + )? + .get_cid(activation_info.sector_type)?; + // A declared zero CommD might be compact or fully computed, + // so normalize to the computed value before checking. + if !declared_commd.get_cid(activation_info.sector_type)?.eq(&computed_commd) { return Err(actor_error!( illegal_argument, "unsealed CID does not match pieces for sector {}, computed {:?} declared {:?}", diff --git a/integration_tests/src/expects.rs b/integration_tests/src/expects.rs index 9097a436b..c30e99267 100644 --- a/integration_tests/src/expects.rs +++ b/integration_tests/src/expects.rs @@ -23,8 +23,9 @@ use fil_actor_miner::{IsControllingAddressParam, PowerPair}; use fil_actor_power::{UpdateClaimedPowerParams, UpdatePledgeTotalParams}; use fil_actor_verifreg::GetClaimsParams; use fil_actors_runtime::{ - BURNT_FUNDS_ACTOR_ADDR, REWARD_ACTOR_ADDR, STORAGE_MARKET_ACTOR_ADDR, STORAGE_POWER_ACTOR_ADDR, - STORAGE_POWER_ACTOR_ID, VERIFIED_REGISTRY_ACTOR_ADDR, + BURNT_FUNDS_ACTOR_ADDR, DATACAP_TOKEN_ACTOR_ADDR, DATACAP_TOKEN_ACTOR_ID, REWARD_ACTOR_ADDR, + STORAGE_MARKET_ACTOR_ADDR, STORAGE_POWER_ACTOR_ADDR, STORAGE_POWER_ACTOR_ID, + VERIFIED_REGISTRY_ACTOR_ADDR, VERIFIED_REGISTRY_ACTOR_ID, }; use vm_api::trace::ExpectInvocation; @@ -208,6 +209,47 @@ impl Expect { ..Default::default() } } + pub fn datacap_transfer_to_verifreg( + from: ActorID, + amount: TokenAmount, + operator_data: RawBytes, + burn: bool, + ) -> ExpectInvocation { + let payload = IpldBlock::serialize_cbor(&FRC46TokenReceived { + from, + to: VERIFIED_REGISTRY_ACTOR_ADDR.id().unwrap(), + operator: from, + amount: amount.clone(), + operator_data, + token_data: RawBytes::default(), + }) + .unwrap(); + let burn_invocs = if burn { + vec![Expect::frc46_burn(VERIFIED_REGISTRY_ACTOR_ID, DATACAP_TOKEN_ACTOR_ADDR, amount)] + } else { + vec![] + }; + ExpectInvocation { + from, + to: DATACAP_TOKEN_ACTOR_ADDR, + method: fil_actor_datacap::Method::TransferExported as u64, + subinvocs: Some(vec![ExpectInvocation { + from: DATACAP_TOKEN_ACTOR_ID, + to: VERIFIED_REGISTRY_ACTOR_ADDR, + method: fil_actor_verifreg::Method::UniversalReceiverHook as u64, + params: Some( + IpldBlock::serialize_cbor(&UniversalReceiverParams { + type_: FRC46_TOKEN_TYPE, + payload: payload.unwrap().data.into(), + }) + .unwrap(), + ), + subinvocs: Some(burn_invocs), + ..Default::default() + }]), + ..Default::default() + } + } pub fn verifreg_get_claims( from: ActorID, miner: ActorID, diff --git a/integration_tests/src/tests/mod.rs b/integration_tests/src/tests/mod.rs index 9bb0c699a..8e6b243c8 100644 --- a/integration_tests/src/tests/mod.rs +++ b/integration_tests/src/tests/mod.rs @@ -36,3 +36,5 @@ mod verifreg_remove_datacap_test; pub use verifreg_remove_datacap_test::*; mod withdraw_balance_test; pub use withdraw_balance_test::*; +mod prove_commit2_test; +pub use prove_commit2_test::*; diff --git a/integration_tests/src/tests/prove_commit2_test.rs b/integration_tests/src/tests/prove_commit2_test.rs new file mode 100644 index 000000000..5457434a0 --- /dev/null +++ b/integration_tests/src/tests/prove_commit2_test.rs @@ -0,0 +1,356 @@ +use fvm_ipld_encoding::ipld_block::IpldBlock; +use fvm_ipld_encoding::RawBytes; +use fvm_shared::bigint::BigInt; +use fvm_shared::clock::ChainEpoch; +use fvm_shared::deal::DealID; +use fvm_shared::econ::TokenAmount; +use fvm_shared::piece::{PaddedPieceSize, PieceInfo}; +use fvm_shared::sector::{RegisteredSealProof, SectorNumber, StoragePower}; +use num_traits::Zero; + +use fil_actor_market::Method as MarketMethod; +use fil_actor_miner::{ + max_prove_commit_duration, CompactCommD, DataActivationNotification, PieceActivationManifest, + PieceChange, ProveCommitSectors2Params, SectorActivationManifest, SectorChanges, + SectorContentChangedParams, +}; +use fil_actor_miner::{Method as MinerMethod, VerifiedAllocationKey}; +use fil_actor_verifreg::{ + AllocationClaim, AllocationRequest, ClaimAllocationsParams, Method as VerifregMethod, + SectorAllocationClaims, +}; +use fil_actors_runtime::cbor::serialize; +use fil_actors_runtime::runtime::Policy; +use fil_actors_runtime::test_utils::make_piece_cid; +use fil_actors_runtime::{ + EPOCHS_IN_DAY, EPOCHS_IN_YEAR, STORAGE_MARKET_ACTOR_ADDR, VERIFIED_REGISTRY_ACTOR_ADDR, +}; +use vm_api::trace::ExpectInvocation; +use vm_api::util::apply_ok; +use vm_api::VM; + +use crate::deals::{DealBatcher, DealOptions}; +use crate::expects::Expect; +use crate::util::{ + advance_by_deadline_to_epoch, create_accounts, create_miner, datacap_create_allocations, + market_add_balance, market_list_deals, market_list_sectors_deals, precommit_sectors_v2, + sector_info, verifreg_add_client, verifreg_add_verifier, verifreg_list_claims, + PrecommitMetadata, +}; + +pub fn prove_commit_sectors2_test(v: &dyn VM) { + let policy = Policy::default(); + let addrs = create_accounts(v, 3, &TokenAmount::from_whole(10_000)); + let seal_proof = RegisteredSealProof::StackedDRG32GiBV1P1; + let sector_size = seal_proof.sector_size().unwrap(); + let (owner, worker, verifier, client) = (addrs[0], addrs[0], addrs[1], addrs[2]); + let worker_id = worker.id().unwrap(); + let client_id = client.id().unwrap(); + let (maddr, _) = create_miner( + v, + &owner, + &worker, + seal_proof.registered_window_post_proof().unwrap(), + &TokenAmount::from_whole(8_000), + ); + let miner_id = maddr.id().unwrap(); + let full_piece_size = PaddedPieceSize(sector_size as u64); + let half_piece_size = PaddedPieceSize(sector_size as u64 / 2); + + // Register verifier and verified clients + let datacap = StoragePower::from(32_u128 << 40); + verifreg_add_verifier(v, &verifier, &datacap * 2); + verifreg_add_client(v, &verifier, &client, datacap); + + // Publish two verified allocations for half a sector each. + let claim_term_min = 2 * EPOCHS_IN_YEAR; + let claim_term_max = claim_term_min + 90 * EPOCHS_IN_DAY; + let allocs = vec![ + AllocationRequest { + provider: miner_id, + data: make_piece_cid(b"s2p1"), + size: half_piece_size, + term_min: claim_term_min, + term_max: claim_term_max, + expiration: 30 * EPOCHS_IN_DAY, + }, + AllocationRequest { + provider: miner_id, + data: make_piece_cid(b"s2p2"), + size: half_piece_size, + term_min: claim_term_min, + term_max: claim_term_max, + expiration: 30 * EPOCHS_IN_DAY, + }, + ]; + let alloc_ids_s2 = datacap_create_allocations(v, &client, &allocs); + + // Publish a full-size deal + let market_collateral = TokenAmount::from_whole(100); + market_add_balance(v, &worker, &maddr, &market_collateral); + market_add_balance(v, &client, &client, &market_collateral); + let deal_start = v.epoch() + max_prove_commit_duration(&Policy::default(), seal_proof).unwrap(); + let opts = DealOptions { deal_start, piece_size: full_piece_size, ..DealOptions::default() }; + let mut batcher = DealBatcher::new(v, opts); + batcher.stage_with_label(client, maddr, "s3p1".to_string()); + let deal_ids_s3 = batcher.publish_ok(worker).ids; + + // Publish a half-size verified deal. + // This creates a verified allocation automatically. + let opts = DealOptions { + deal_start, + piece_size: half_piece_size, + verified: true, + deal_lifetime: claim_term_min, // The implicit claim term must fit sector life + ..DealOptions::default() + }; + let mut batcher = DealBatcher::new(v, opts); + batcher.stage_with_label(client, maddr, "s4p1".to_string()); + let deal_ids_s4 = batcher.publish_ok(worker).ids; + let alloc_ids_s4 = vec![alloc_ids_s2[alloc_ids_s2.len() - 1] + 1]; + + // Onboard a batch of sectors with a mix of data pieces, claims, and deals. + let first_sector_number: SectorNumber = 100; + let manifests = vec![ + // Sector 0: no pieces (CC sector) + SectorActivationManifest { sector_number: first_sector_number, pieces: vec![] }, + // Sector 1: one piece, no claim or deal. + SectorActivationManifest { + sector_number: first_sector_number + 1, + pieces: vec![PieceActivationManifest { + cid: make_piece_cid(b"s1p1"), + size: full_piece_size, + verified_allocation_key: None, + notify: vec![], + }], + }, + // Sector 2: two pieces for verified claims. + SectorActivationManifest { + sector_number: first_sector_number + 2, + pieces: allocs + .iter() + .enumerate() + .map(|(i, alloc)| PieceActivationManifest { + cid: alloc.data, + size: alloc.size, + verified_allocation_key: Some(VerifiedAllocationKey { + client: client_id, + id: alloc_ids_s2[i], + }), + notify: vec![], + }) + .collect(), + }, + // Sector 3: a full-size, unverified deal + SectorActivationManifest { + sector_number: first_sector_number + 3, + pieces: vec![PieceActivationManifest { + cid: make_piece_cid(b"s3p1"), + size: full_piece_size, + verified_allocation_key: None, + notify: vec![DataActivationNotification { + address: STORAGE_MARKET_ACTOR_ADDR, + payload: serialize(&deal_ids_s3[0], "dealid").unwrap(), + }], + }], + }, + // Sector 4: a half-sized, verified deal, and implicit empty space + SectorActivationManifest { + sector_number: first_sector_number + 4, + pieces: vec![PieceActivationManifest { + cid: make_piece_cid(b"s4p1"), + size: half_piece_size, + verified_allocation_key: Some(VerifiedAllocationKey { + client: client_id, + id: alloc_ids_s4[0], + }), + notify: vec![DataActivationNotification { + address: STORAGE_MARKET_ACTOR_ADDR, + payload: serialize(&deal_ids_s4[0], "deal id").unwrap(), + }], + }], + }, + ]; + + let meta: Vec = manifests + .iter() + .map(|sector| { + let pis: Vec = + sector.pieces.iter().map(|p| PieceInfo { size: p.size, cid: p.cid }).collect(); + let commd = v.primitives().compute_unsealed_sector_cid(seal_proof, &pis).unwrap(); + PrecommitMetadata { deals: vec![], commd: CompactCommD::of(commd) } + }) + .collect(); + let sector_expiry = v.epoch() + claim_term_min + 60 * EPOCHS_IN_DAY; + precommit_sectors_v2( + v, + meta.len(), + meta.len(), + meta, + &worker, + &maddr, + seal_proof, + first_sector_number, + true, + Some(sector_expiry), + ); + + let activation_epoch = v.epoch() + policy.pre_commit_challenge_delay + 1; + advance_by_deadline_to_epoch(v, &maddr, activation_epoch); + + // Prove-commit + let proofs = vec![RawBytes::new(vec![1, 2, 3, 4]); manifests.len()]; + let params = ProveCommitSectors2Params { + sector_activations: manifests.clone(), + sector_proofs: proofs, + aggregate_proof: RawBytes::default(), + require_activation_success: true, + require_notification_success: true, + }; + apply_ok( + v, + &worker, + &maddr, + &TokenAmount::zero(), + MinerMethod::ProveCommitSectors2 as u64, + Some(params.clone()), + ); + ExpectInvocation { + from: worker_id, + to: maddr, + method: MinerMethod::ProveCommitSectors2 as u64, + params: Some(IpldBlock::serialize_cbor(¶ms).unwrap()), + subinvocs: Some(vec![ + // Verified claims + ExpectInvocation { + from: miner_id, + to: VERIFIED_REGISTRY_ACTOR_ADDR, + method: VerifregMethod::ClaimAllocations as u64, + params: Some( + IpldBlock::serialize_cbor(&ClaimAllocationsParams { + sectors: vec![ + no_claims(first_sector_number, sector_expiry), + no_claims(first_sector_number + 1, sector_expiry), + SectorAllocationClaims { + sector: first_sector_number + 2, + expiry: sector_expiry, + claims: vec![ + AllocationClaim { + client: client_id, + allocation_id: alloc_ids_s2[0], + data: allocs[0].data, + size: allocs[0].size, + }, + AllocationClaim { + client: client_id, + allocation_id: alloc_ids_s2[1], + data: allocs[1].data, + size: allocs[1].size, + }, + ], + }, + no_claims(first_sector_number + 3, sector_expiry), + SectorAllocationClaims { + sector: first_sector_number + 4, + expiry: sector_expiry, + claims: vec![AllocationClaim { + client: client_id, + allocation_id: alloc_ids_s4[0], + data: make_piece_cid(b"s4p1"), + size: half_piece_size, + }], + }, + ], + all_or_nothing: true, + }) + .unwrap(), + ), + ..Default::default() + }, + Expect::reward_this_epoch(miner_id), + Expect::power_current_total(miner_id), + Expect::power_update_pledge(miner_id, None), + // Market notifications. + ExpectInvocation { + from: miner_id, + to: STORAGE_MARKET_ACTOR_ADDR, + method: MarketMethod::SectorContentChangedExported as u64, + params: Some( + IpldBlock::serialize_cbor(&SectorContentChangedParams { + sectors: vec![ + SectorChanges { + sector: first_sector_number + 3, + minimum_commitment_epoch: sector_expiry, + added: vec![piece_change(b"s3p1", full_piece_size, &deal_ids_s3)], + }, + SectorChanges { + sector: first_sector_number + 4, + minimum_commitment_epoch: sector_expiry, + added: vec![piece_change(b"s4p1", half_piece_size, &deal_ids_s4)], + }, + ], + }) + .unwrap(), + ), + value: Some(TokenAmount::zero()), + subinvocs: Some(vec![]), + ..Default::default() + }, + ]), + ..Default::default() + } + .matches(v.take_invocations().last().unwrap()); + + // Checks on sector state. + let sectors = + manifests.iter().map(|m| sector_info(v, &maddr, m.sector_number)).collect::>(); + for sector in §ors { + assert_eq!(activation_epoch, sector.activation); + assert_eq!(activation_epoch, sector.power_base_epoch); + assert!(sector.simple_qa_power); + assert!(sector.deprecated_deal_ids.is_empty()); + } + let full_sector_weight = + BigInt::from(full_piece_size.0 * (sector_expiry - activation_epoch) as u64); + assert_eq!(BigInt::zero(), sectors[0].deal_weight); + assert_eq!(BigInt::zero(), sectors[0].verified_deal_weight); + assert_eq!(full_sector_weight, sectors[1].deal_weight); + assert_eq!(BigInt::zero(), sectors[1].verified_deal_weight); + assert_eq!(BigInt::zero(), sectors[2].deal_weight); + assert_eq!(full_sector_weight, sectors[2].verified_deal_weight); + assert_eq!(full_sector_weight, sectors[3].deal_weight); + assert_eq!(BigInt::zero(), sectors[3].verified_deal_weight); + assert_eq!(BigInt::zero(), sectors[4].deal_weight); + assert_eq!(full_sector_weight / 2, sectors[4].verified_deal_weight); + + // Brief checks on state consistency between actors. + let claims = verifreg_list_claims(v, miner_id); + assert_eq!(claims.len(), 3); + assert_eq!(first_sector_number + 2, claims[&alloc_ids_s2[0]].sector); + assert_eq!(first_sector_number + 2, claims[&alloc_ids_s2[1]].sector); + assert_eq!(first_sector_number + 4, claims[&alloc_ids_s4[0]].sector); + + let deals = market_list_deals(v); + assert_eq!(deals.len(), 2); + assert_eq!(maddr, deals[&deal_ids_s3[0]].0.provider); + assert_eq!(first_sector_number + 3, deals[&deal_ids_s3[0]].1.unwrap().sector_number); + assert_eq!(maddr, deals[&deal_ids_s4[0]].0.provider); + assert_eq!(first_sector_number + 4, deals[&deal_ids_s4[0]].1.unwrap().sector_number); + + let sector_deals = market_list_sectors_deals(v, &maddr); + assert_eq!(sector_deals.len(), 2); + assert_eq!(deal_ids_s3, sector_deals[&(first_sector_number + 3)]); + assert_eq!(deal_ids_s4, sector_deals[&(first_sector_number + 4)]); +} + +fn no_claims(sector: SectorNumber, expiry: ChainEpoch) -> SectorAllocationClaims { + SectorAllocationClaims { sector, expiry, claims: vec![] } +} + +fn piece_change(cid_seed: &[u8], piece_size: PaddedPieceSize, deal_ids: &[DealID]) -> PieceChange { + PieceChange { + data: make_piece_cid(cid_seed), + size: piece_size, + payload: serialize(&deal_ids[0], "deal id").unwrap(), + } +} diff --git a/integration_tests/src/util/mod.rs b/integration_tests/src/util/mod.rs index aee64a4e5..68162fe3d 100644 --- a/integration_tests/src/util/mod.rs +++ b/integration_tests/src/util/mod.rs @@ -1,9 +1,9 @@ -use fil_actor_market::State as MarketState; +use fil_actor_market::{load_provider_sector_deals, DealProposal, DealState, State as MarketState}; use fil_actor_power::State as PowerState; use fil_actor_reward::State as RewardState; use fil_actors_runtime::{ - runtime::Policy, MessageAccumulator, REWARD_ACTOR_ADDR, STORAGE_MARKET_ACTOR_ADDR, - STORAGE_POWER_ACTOR_ADDR, + parse_uint_key, runtime::Policy, MessageAccumulator, REWARD_ACTOR_ADDR, + STORAGE_MARKET_ACTOR_ADDR, STORAGE_POWER_ACTOR_ADDR, VERIFIED_REGISTRY_ACTOR_ADDR, }; use fvm_ipld_bitfield::BitField; use fvm_ipld_encoding::{CborStore, RawBytes}; @@ -11,13 +11,15 @@ use fvm_shared::address::Address; use fvm_shared::deal::DealID; use fvm_shared::econ::TokenAmount; use fvm_shared::sector::SectorNumber; -use fvm_shared::METHOD_SEND; +use fvm_shared::{ActorID, METHOD_SEND}; +use std::collections::HashMap; use fil_actor_miner::ext::verifreg::AllocationID; use fil_actor_miner::{ new_deadline_info_from_offset_and_epoch, Deadline, DeadlineInfo, GetBeneficiaryReturn, Method as MinerMethod, MinerInfo, PowerPair, SectorOnChainInfo, State as MinerState, }; +use fil_actor_verifreg::{Claim, ClaimID, State as VerifregState}; use fil_builtin_actors_state::check::{check_state_invariants, Tree}; use num_traits::Zero; use regex::Regex; @@ -156,6 +158,54 @@ pub fn market_pending_deal_allocations(v: &dyn VM, deals: &[DealID]) -> Vec HashMap)> { + let st: MarketState = get_state(v, &STORAGE_MARKET_ACTOR_ADDR).unwrap(); + let bs = &DynBlockstore::wrap(v.blockstore()); + let proposals = st.load_proposals(bs).unwrap(); + let states = st.load_deal_states(bs).unwrap(); + let mut found: HashMap)> = HashMap::new(); + proposals + .for_each(|i, p| { + let state = states.get(i).unwrap().cloned(); + found.insert(i, (p.clone(), state)); + Ok(()) + }) + .unwrap(); + found +} + +pub fn market_list_sectors_deals( + v: &dyn VM, + provider: &Address, +) -> HashMap> { + let st: MarketState = get_state(v, &STORAGE_MARKET_ACTOR_ADDR).unwrap(); + let bs = &DynBlockstore::wrap(v.blockstore()); + let sectors = st.load_provider_sectors(bs).unwrap(); + let sector_deals = load_provider_sector_deals(bs, §ors, provider).unwrap(); + let mut found: HashMap> = HashMap::new(); + sector_deals + .for_each(|sno, deal_ids| { + found.insert(sno, deal_ids.deals.clone()); + Ok(()) + }) + .unwrap(); + found +} + +pub fn verifreg_list_claims(v: &dyn VM, provider: ActorID) -> HashMap { + let st: VerifregState = get_state(v, &VERIFIED_REGISTRY_ACTOR_ADDR).unwrap(); + let bs = &DynBlockstore::wrap(v.blockstore()); + let mut claims = st.load_claims(bs).unwrap(); + let mut found: HashMap = HashMap::new(); + claims + .for_each_in(provider, |id, claim| { + found.insert(parse_uint_key(id).unwrap(), claim.clone()); + Ok(()) + }) + .unwrap(); + found +} + pub fn make_bitfield(bits: &[u64]) -> BitField { BitField::try_from_bits(bits.iter().copied()).unwrap() } diff --git a/integration_tests/src/util/workflows.rs b/integration_tests/src/util/workflows.rs index 65332116a..d2380683a 100644 --- a/integration_tests/src/util/workflows.rs +++ b/integration_tests/src/util/workflows.rs @@ -2,8 +2,8 @@ use std::cmp::min; use frc46_token::receiver::FRC46TokenReceived; use frc46_token::receiver::FRC46_TOKEN_TYPE; -use frc46_token::token::types::TransferFromParams; use frc46_token::token::types::TransferParams; +use frc46_token::token::types::{TransferFromParams, TransferReturn}; use fvm_actor_utils::receiver::UniversalReceiverParams; use fvm_ipld_bitfield::BitField; use fvm_ipld_blockstore::Blockstore; @@ -28,6 +28,7 @@ use num_traits::Zero; use fil_actor_cron::Method as CronMethod; use fil_actor_datacap::Method as DataCapMethod; +use fil_actor_market::ext::verifreg::AllocationsResponse; use fil_actor_market::{ ClientDealProposal, DealProposal, Label, Method as MarketMethod, PublishStorageDealsParams, PublishStorageDealsReturn, SectorDeals, State as MarketState, MARKET_NOTIFY_DEAL_METHOD, @@ -877,6 +878,44 @@ pub fn datacap_get_balance(v: &dyn VM, address: &Address) -> TokenAmount { deserialize(&ret, "balance of return value").unwrap() } +pub fn datacap_create_allocations( + v: &dyn VM, + client: &Address, + reqs: &[AllocationRequest], +) -> Vec { + let payload = AllocationRequests { allocations: reqs.to_vec(), extensions: vec![] }; + let token_amount = TokenAmount::from_whole(reqs.iter().map(|r| r.size.0).sum::()); + let operator_data = serialize(&payload, "allocation requests").unwrap(); + let transfer_params = TransferParams { + to: VERIFIED_REGISTRY_ACTOR_ADDR, + amount: token_amount.clone(), + operator_data: operator_data.clone(), + }; + + let client_id = v.resolve_id_address(client).unwrap().id().unwrap(); + let tfer_result: TransferReturn = apply_ok( + v, + client, + &DATACAP_TOKEN_ACTOR_ADDR, + &TokenAmount::zero(), + DataCapMethod::TransferExported as u64, + Some(transfer_params), + ) + .deserialize() + .unwrap(); + let alloc_response: AllocationsResponse = tfer_result.recipient_data.deserialize().unwrap(); + + Expect::datacap_transfer_to_verifreg( + client_id, + token_amount, + operator_data, + false, // No burn + ) + .matches(v.take_invocations().last().unwrap()); + + alloc_response.new_allocations +} + pub fn datacap_extend_claim( v: &dyn VM, client: &Address, @@ -911,41 +950,12 @@ pub fn datacap_extend_claim( Some(transfer_params), ); - ExpectInvocation { - from: client_id, - to: DATACAP_TOKEN_ACTOR_ADDR, - method: DataCapMethod::TransferExported as u64, - subinvocs: Some(vec![ExpectInvocation { - from: DATACAP_TOKEN_ACTOR_ID, - to: VERIFIED_REGISTRY_ACTOR_ADDR, - method: VerifregMethod::UniversalReceiverHook as u64, - params: Some( - IpldBlock::serialize_cbor(&UniversalReceiverParams { - type_: FRC46_TOKEN_TYPE, - payload: serialize( - &FRC46TokenReceived { - from: client.id().unwrap(), - to: VERIFIED_REGISTRY_ACTOR_ADDR.id().unwrap(), - operator: client.id().unwrap(), - amount: token_amount.clone(), - operator_data, - token_data: RawBytes::default(), - }, - "token received params", - ) - .unwrap(), - }) - .unwrap(), - ), - subinvocs: Some(vec![Expect::frc46_burn( - VERIFIED_REGISTRY_ACTOR_ID, - DATACAP_TOKEN_ACTOR_ADDR, - token_amount, - )]), - ..Default::default() - }]), - ..Default::default() - } + Expect::datacap_transfer_to_verifreg( + client_id, + token_amount, + operator_data, + true, // Burn + ) .matches(v.take_invocations().last().unwrap()); } diff --git a/test_vm/src/fakes.rs b/test_vm/src/fakes.rs index ba59d7109..b558fe6c6 100644 --- a/test_vm/src/fakes.rs +++ b/test_vm/src/fakes.rs @@ -2,6 +2,7 @@ use anyhow::anyhow; use cid::multihash::Code; use cid::multihash::MultihashDigest; use cid::Cid; +use fil_actor_miner::CompactCommD; use fvm_shared::address::{Address, SECP_PUB_LEN}; use fvm_shared::crypto::hash::SupportedHashes; use fvm_shared::crypto::signature::{Signature, SECP_SIG_LEN, SECP_SIG_MESSAGE_HASH_SIZE}; @@ -44,6 +45,9 @@ impl Primitives for FakePrimitives { proof_type: RegisteredSealProof, pieces: &[PieceInfo], ) -> Result { + if pieces.is_empty() { + return Ok(CompactCommD::empty().get_cid(proof_type).unwrap()); + } // Construct a buffer that depends on all the input data. let mut buf: Vec = Vec::new(); let ptv: i64 = proof_type.into(); diff --git a/test_vm/tests/prove_commit2_test.rs b/test_vm/tests/prove_commit2_test.rs new file mode 100644 index 000000000..368ed3b81 --- /dev/null +++ b/test_vm/tests/prove_commit2_test.rs @@ -0,0 +1,10 @@ +use fil_actors_integration_tests::tests::prove_commit_sectors2_test; +use fvm_ipld_blockstore::MemoryBlockstore; +use test_vm::TestVM; + +#[test] +fn prove_commit_sectors2() { + let store = MemoryBlockstore::new(); + let v = TestVM::::new_with_singletons(&store); + prove_commit_sectors2_test(&v); +}