Skip to content

Commit

Permalink
Basic unit tests for ProveReplicaUpdate3 (#1394)
Browse files Browse the repository at this point in the history
  • Loading branch information
anorth committed Jan 22, 2024
1 parent 5de9cae commit c1aa98f
Show file tree
Hide file tree
Showing 5 changed files with 522 additions and 242 deletions.
29 changes: 14 additions & 15 deletions actors/miner/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1020,7 +1020,7 @@ impl Actor {

// Validate parameters.
rt.validate_immediate_caller_is(
info.control_addresses.iter().chain(&[info.owner, info.worker]),
info.control_addresses.iter().chain(&[info.worker, info.owner]),
)?;
if params.sector_proofs.is_empty() == params.aggregate_proof.is_empty() {
return Err(actor_error!(
Expand Down Expand Up @@ -1129,7 +1129,7 @@ impl Actor {
}
let proven_batch = proven_batch_gen.gen();

// Activate data and compute CommD.
// Activate data.
let data_activation_inputs: Vec<SectorPiecesActivationInput> = proven_manifests
.iter()
.map(|(update, info)| SectorPiecesActivationInput {
Expand Down Expand Up @@ -1830,7 +1830,7 @@ impl Actor {
sector_expiry: precommit.info.expiration,
sector_number: precommit.info.sector_number,
sector_type: precommit.info.seal_proof,
expected_commd: Some(precommit.info.unsealed_cid.clone()),
expected_commd: Some(precommit.info.unsealed_cid.clone()), // Check CommD
}
})
.collect();
Expand Down Expand Up @@ -5353,25 +5353,26 @@ struct ReplicaUpdateActivatedData {

// Activates data pieces by claiming allocations with the verified registry.
// Pieces are grouped by sector and succeed or fail in sector groups.
// Activation inputs specify an expected CommD for the sector,
// against which the CommD computed from the pieces is checked.
// If an activation input specifies an expected CommD for the sector, a CommD
// is calculated from the pieces and must match.
// This method never returns CommDs in the output type; either the caller provided
// them and they are correct, or the caller did not provide anything that needs checking.
fn activate_sectors_pieces(
rt: &impl Runtime,
activation_inputs: Vec<SectorPiecesActivationInput>,
all_or_nothing: bool,
) -> Result<(BatchReturn, Vec<DataActivationOutput>), ActorError> {
// Get a flattened list of verified claims for all activated sectors
let mut verified_claims = Vec::new();
let mut computed_commds = Vec::new();
let mut unverified_spaces = Vec::new();
for activation_info in activation_inputs {
let computed_commd = unsealed_cid_from_pieces(
rt,
&activation_info.piece_manifests,
activation_info.sector_type,
)?;
// Check a declared CommD matches that computed from the data.
if let Some(declared_commd) = activation_info.expected_commd {
let computed_commd = unsealed_cid_from_pieces(
rt,
&activation_info.piece_manifests,
activation_info.sector_type,
)?;
if !declared_commd.eq(&computed_commd) {
return Err(actor_error!(
illegal_argument,
Expand All @@ -5382,7 +5383,6 @@ fn activate_sectors_pieces(
));
}
}
computed_commds.push(computed_commd);

let mut sector_claims = vec![];
let mut unverified_space = BigInt::zero();
Expand Down Expand Up @@ -5417,12 +5417,11 @@ fn activate_sectors_pieces(
let activation_outputs = claim_res
.sector_claims
.iter()
.zip(claim_res.sector_results.successes(&computed_commds))
.zip(claim_res.sector_results.successes(&unverified_spaces))
.map(|((sector_claim, computed_commd), unverified_space)| DataActivationOutput {
.map(|(sector_claim, unverified_space)| DataActivationOutput {
unverified_space: unverified_space.clone(),
verified_space: sector_claim.claimed_space.clone(),
unsealed_cid: computed_commd.0,
unsealed_cid: None,
})
.collect();

Expand Down
5 changes: 3 additions & 2 deletions actors/miner/tests/miner_actor_test_precommit_batch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,8 @@ mod miner_actor_precommit_batch {
SectorDeals, VerifyDealsForActivationParams, VerifyDealsForActivationReturn,
};
use fil_actor_miner::{
new_deadline_info_from_offset_and_epoch, Actor, Method, PreCommitSectorBatchParams2,
new_deadline_info_from_offset_and_epoch, Actor, CompactCommD, Method,
PreCommitSectorBatchParams2,
};
use fil_actors_runtime::{STORAGE_MARKET_ACTOR_ADDR, STORAGE_POWER_ACTOR_ADDR};
use fvm_ipld_encoding::ipld_block::IpldBlock;
Expand Down Expand Up @@ -332,7 +333,7 @@ mod miner_actor_precommit_batch {
precommit_epoch - 1,
sector_expiration,
vec![1],
Some(make_piece_cid(&[1])),
CompactCommD::new(Some(make_piece_cid(&[1]))),
);
let sectors = vec![sector];
{
Expand Down
165 changes: 165 additions & 0 deletions actors/miner/tests/prove_replica_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
use fvm_ipld_blockstore::Blockstore;
use fvm_shared::deal::DealID;
use fvm_shared::sector::{SectorNumber, StoragePower};
use fvm_shared::{bigint::Zero, clock::ChainEpoch, econ::TokenAmount, ActorID};

use fil_actor_miner::ext::verifreg::AllocationID;
use fil_actor_miner::ProveReplicaUpdates3Return;
use fil_actor_miner::{
CompactCommD, PieceActivationManifest, SectorOnChainInfo, SectorPreCommitInfo,
SectorPreCommitOnChainInfo, SectorUpdateManifest, State,
};
use fil_actors_runtime::test_utils::{make_sealed_cid, MockRuntime};
use fil_actors_runtime::{runtime::Runtime, BatchReturn, DealWeight, EPOCHS_IN_DAY};
use util::*;

mod util;

const DEFAULT_SECTOR_EXPIRATION_DAYS: ChainEpoch = 220;

#[test]
fn prove_basic_updates() {
let h = ActorHarness::new_with_options(HarnessOptions::default());
let rt = h.new_runtime();
rt.set_balance(BIG_BALANCE.clone());
let client_id: ActorID = 1000;

h.construct_and_verify(&rt);

// Onboard a batch of empty sectors.
rt.set_epoch(1);
let sector_expiry = *rt.epoch.borrow() + DEFAULT_SECTOR_EXPIRATION_DAYS * EPOCHS_IN_DAY;
let first_sector_number = 100;
let sector_count = 4;
let sectors = onboard_empty_sectors(&rt, &h, sector_expiry, first_sector_number, sector_count);
let snos = sectors.iter().map(|s| s.sector_number).collect::<Vec<_>>();

// Update them in batch, each with a single piece.
let st: State = h.get_state(&rt);
let store = rt.store();
let piece_size = h.sector_size as u64;
let sector_updates = vec![
make_update_manifest(&st, store, &sectors[0], &[(piece_size, 0, 0, 0)]), // No alloc or deal
make_update_manifest(&st, store, &sectors[1], &[(piece_size, client_id, 1000, 0)]), // Just an alloc
make_update_manifest(&st, store, &sectors[2], &[(piece_size, 0, 0, 2000)]), // Just a deal
make_update_manifest(&st, store, &sectors[3], &[(piece_size, client_id, 1001, 2001)]), // Alloc and deal
];

let result = h.prove_replica_updates3_batch(&rt, &sector_updates, true, true).unwrap();
assert_eq!(
ProveReplicaUpdates3Return { activation_results: BatchReturn::ok(sectors.len() as u32) },
result
);

let duration = sector_expiry - *rt.epoch.borrow();
let expected_weight = DealWeight::from(piece_size) * duration;
let raw_power = StoragePower::from(h.sector_size as u64);
let verified_power = &raw_power * 10;
let raw_pledge = h.initial_pledge_for_power(&rt, &raw_power);
let verified_pledge = h.initial_pledge_for_power(&rt, &verified_power);

// Sector 0: Even though there's no "deal", the data weight is set.
verify_weights(&rt, &h, snos[0], &expected_weight, &DealWeight::zero(), &raw_pledge);
// Sector 1: With an allocation, the verified weight is set instead.
verify_weights(&rt, &h, snos[1], &DealWeight::zero(), &expected_weight, &verified_pledge);
// Sector 2: Deal weight is set.
verify_weights(&rt, &h, snos[2], &expected_weight, &DealWeight::zero(), &raw_pledge);
// Sector 3: Deal doesn't make a difference to verified weight only set.
verify_weights(&rt, &h, snos[3], &DealWeight::zero(), &expected_weight, &verified_pledge);
}

fn onboard_empty_sectors(
rt: &MockRuntime,
h: &ActorHarness,
expiration: ChainEpoch,
first_sector_number: SectorNumber,
count: usize,
) -> Vec<SectorOnChainInfo> {
let precommit_epoch = *rt.epoch.borrow();

// Precommit the sectors.
let precommits =
make_empty_precommits(h, first_sector_number, precommit_epoch - 1, expiration, count);
h.pre_commit_sector_batch_v2(rt, &precommits, true, &TokenAmount::zero()).unwrap();
let precommits: Vec<SectorPreCommitOnChainInfo> =
precommits.iter().map(|sector| h.get_precommit(rt, sector.sector_number)).collect();

// Prove the sectors.
// Note: migrate this to ProveCommitSectors2 (batch) when the harness supports it.
rt.set_epoch(precommit_epoch + rt.policy.pre_commit_challenge_delay + 1);
let sectors: Vec<SectorOnChainInfo> = precommits
.iter()
.map(|pc| {
h.prove_commit_sector_and_confirm(
rt,
pc,
h.make_prove_commit_params(pc.info.sector_number),
ProveCommitConfig::default(),
)
.unwrap()
})
.collect();

// Window PoST to activate the sectors, a pre-requisite for upgrading.
h.advance_and_submit_posts(rt, &sectors);
sectors
}

fn make_empty_precommits(
h: &ActorHarness,
first_sector_number: SectorNumber,
challenge: ChainEpoch,
expiration: ChainEpoch,
count: usize,
) -> Vec<SectorPreCommitInfo> {
(0..count)
.map(|i| {
let sector_number = first_sector_number + i as u64;
h.make_pre_commit_params_v2(
sector_number,
challenge,
expiration,
vec![],
CompactCommD::empty(),
)
})
.collect()
}

fn make_update_manifest(
st: &State,
store: &impl Blockstore,
sector: &SectorOnChainInfo,
piece_specs: &[(u64, ActorID, AllocationID, DealID)],
) -> SectorUpdateManifest {
let (deadline, partition) = st.find_sector(store, sector.sector_number).unwrap();
let new_sealed_cid = make_sealed_cid(format!("sealed{}", sector.sector_number).as_bytes());
let pieces: Vec<PieceActivationManifest> = piece_specs
.iter()
.enumerate()
.map(|(i, (sz, client, alloc, deal))| make_piece_manifest(i, *sz, *client, *alloc, *deal))
.collect();
SectorUpdateManifest {
sector: sector.sector_number,
deadline,
partition,
new_sealed_cid,
pieces,
}
}

fn verify_weights(
rt: &MockRuntime,
h: &ActorHarness,
sno: SectorNumber,
data_weight: &DealWeight,
verified_weight: &DealWeight,
pledge: &TokenAmount,
) {
let s = h.get_sector(rt, sno);
// Deal IDs are deprecated and never set.
assert!(s.deal_ids.is_empty());
assert_eq!(data_weight, &s.deal_weight);
assert_eq!(verified_weight, &s.verified_deal_weight);
assert_eq!(pledge, &s.initial_pledge);
}
Loading

0 comments on commit c1aa98f

Please sign in to comment.