Skip to content

Commit

Permalink
fix: miner: move partitions with expired/terminated sectors (#1455)
Browse files Browse the repository at this point in the history
* fix: miner: move partitions with expired/terminated sectors

* add `dispute_remaining_partition_after_move` (#1448)

* add dispute_remaining_partition_after_move

* add move_partition_with_terminated_sector

---------

Co-authored-by: zhiqiangxu <652732310@qq.com>
  • Loading branch information
arajasek and zhiqiangxu authored Oct 24, 2023
1 parent 1e50065 commit 09d50ad
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 6 deletions.
6 changes: 3 additions & 3 deletions actors/miner/src/deadline_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,16 +145,16 @@ impl Deadlines {

let dest_partition_idx = first_dest_partition_idx + i as u64;

// sector_count is both total sector count and total live sector count, since no sector is faulty here.
let sector_count = moving_partition.sectors.len();
let live_sector_count = sector_count - moving_partition.terminated.len();

// start updating orig/dest `Deadline` here

orig_deadline.total_sectors -= sector_count;
orig_deadline.live_sectors -= sector_count;
orig_deadline.live_sectors -= live_sector_count;

dest_deadline.total_sectors += sector_count;
dest_deadline.live_sectors += sector_count;
dest_deadline.live_sectors += live_sector_count;

orig_partitions.set(orig_partition_idx, Partition::new(store)?)?;
dest_partitions.set(dest_partition_idx, moving_partition)?;
Expand Down
118 changes: 115 additions & 3 deletions actors/miner/tests/move_partitions_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use fil_actors_runtime::{
};
use fvm_ipld_bitfield::BitField;
use fvm_shared::econ::TokenAmount;
use fvm_shared::sector::RegisteredSealProof;
use fvm_shared::{clock::ChainEpoch, error::ExitCode};
use num_traits::Zero;

Expand All @@ -23,11 +24,13 @@ use util::*;
const PERIOD_OFFSET: ChainEpoch = 100;

fn setup() -> (ActorHarness, MockRuntime) {
let h = ActorHarness::new(PERIOD_OFFSET);
let mut h = ActorHarness::new(PERIOD_OFFSET);
// For a small partition size, necessary for `dispute_remaining_partition_after_move`
h.set_proof_type(RegisteredSealProof::StackedDRG2KiBV1P1);
let rt = h.new_runtime();
h.construct_and_verify(&rt);
rt.balance.replace(BIG_BALANCE.clone());

rt.balance.replace(BIG_BALANCE.clone());
h.construct_and_verify(&rt);
(h, rt)
}

Expand Down Expand Up @@ -631,3 +634,112 @@ fn dispute_after_move() {
h.dispute_window_post(&rt, &dest_deadline, 0, &sectors_info, Some(expected_result));
}
}

#[test]
fn dispute_remaining_partition_after_move() {
let (mut h, rt) = setup();

// Commit more sectors than fit in one partition in every eligible deadline, overflowing to a second partition.
let sectors_to_commit = (rt.policy.wpost_period_deadlines - 2) * h.partition_size + 1;
let sectors_info = h.commit_and_prove_sectors(
&rt,
sectors_to_commit as usize,
DEFAULT_SECTOR_EXPIRATION,
vec![],
true,
);
h.advance_and_submit_posts(&rt, &sectors_info);

let last_sector = sectors_info.last().unwrap();
let st = h.get_state(&rt);

let (orig_deadline_id, partition_id) =
st.find_sector(&rt.store, last_sector.sector_number).unwrap();
assert_eq!(partition_id, 1);

// move a partition from a deadline that still needs WindowPoST verification.

// at this moment, the current and next deadlines are empty, orig_deadline_id has 2 partitions, and all other deadlines have 1 partition.
let target_sectors = &[
&sectors_info[0..h.partition_size as usize], /* these belong to partition 0 */
vec![last_sector.clone()].as_slice(), /* these belong to partition 1 */
]
.concat();
// after this call, current epoch will automatically be advanced to `nearest_unsafe_epoch(&rt, &h, orig_deadline_id)`
h.advance_and_submit_posts(&rt, target_sectors);

let dest_deadline_id =
farthest_possible_to_deadline(&rt, orig_deadline_id, h.current_deadline(&rt));

// move the second partition
let result = h.move_partitions(
&rt,
orig_deadline_id,
dest_deadline_id,
bitfield_from_slice(&[partition_id]),
target_sectors,
);
assert!(result.is_ok());

let st = h.get_state(&rt);
let (dl_idx, _) = st.find_sector(&rt.store, last_sector.sector_number).unwrap();
assert!(dl_idx == dest_deadline_id);

h.check_state(&rt);

// Dispute the first partition in the original deadline
{
let orig_deadline =
nearest_occured_deadline_info(rt.policy(), &h.current_deadline(&rt), orig_deadline_id);

// Check that a failed dispute is ok. A successful dispute is impossible because the Window PoST was synchronously validated when the partition was moved.
h.dispute_window_post(&rt, &orig_deadline, 0, target_sectors, None);
}
}

#[test]
fn move_partition_with_terminated_sector() {
let (mut h, rt) = setup();

// create 2 sectors in partition 0
let sectors_info = h.commit_and_prove_sectors(
&rt,
2,
DEFAULT_SECTOR_EXPIRATION,
vec![vec![10], vec![20]],
true,
);
h.advance_and_submit_posts(&rt, &sectors_info);

// terminate 1 sector
{
// A miner will pay the minimum of termination fee and locked funds. Add some locked funds to ensure
// correct fee calculation is used.
h.apply_rewards(&rt, BIG_REWARDS.clone(), TokenAmount::zero());

let expected_fee = calc_expected_fee_for_termination(&h, &rt, sectors_info[1].clone());

let sectors = bitfield_from_slice(&[sectors_info[1].sector_number]);
h.terminate_sectors(&rt, &sectors, expected_fee);
}

let st = h.get_state(&rt);
let (orig_deadline_id, partition_id) =
st.find_sector(&rt.store, sectors_info[0].sector_number).unwrap();

h.advance_to_epoch_with_cron(&rt, nearest_safe_epoch(&rt, &h, orig_deadline_id));

let dest_deadline_id =
farthest_possible_to_deadline(&rt, orig_deadline_id, h.current_deadline(&rt));

let result = h.move_partitions(
&rt,
orig_deadline_id,
dest_deadline_id,
bitfield_from_slice(&[partition_id]),
&[],
);
assert!(result.is_ok());

h.check_state(&rt);
}

0 comments on commit 09d50ad

Please sign in to comment.