Skip to content

Commit 09d50ad

Browse files
arajasekzhiqiangxu
andauthored
fix: miner: move partitions with expired/terminated sectors (#1455)
* 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 <[email protected]>
1 parent 1e50065 commit 09d50ad

File tree

2 files changed

+118
-6
lines changed

2 files changed

+118
-6
lines changed

actors/miner/src/deadline_state.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,16 +145,16 @@ impl Deadlines {
145145

146146
let dest_partition_idx = first_dest_partition_idx + i as u64;
147147

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

151151
// start updating orig/dest `Deadline` here
152152

153153
orig_deadline.total_sectors -= sector_count;
154-
orig_deadline.live_sectors -= sector_count;
154+
orig_deadline.live_sectors -= live_sector_count;
155155

156156
dest_deadline.total_sectors += sector_count;
157-
dest_deadline.live_sectors += sector_count;
157+
dest_deadline.live_sectors += live_sector_count;
158158

159159
orig_partitions.set(orig_partition_idx, Partition::new(store)?)?;
160160
dest_partitions.set(dest_partition_idx, moving_partition)?;

actors/miner/tests/move_partitions_test.rs

Lines changed: 115 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use fil_actors_runtime::{
1414
};
1515
use fvm_ipld_bitfield::BitField;
1616
use fvm_shared::econ::TokenAmount;
17+
use fvm_shared::sector::RegisteredSealProof;
1718
use fvm_shared::{clock::ChainEpoch, error::ExitCode};
1819
use num_traits::Zero;
1920

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

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

32+
rt.balance.replace(BIG_BALANCE.clone());
33+
h.construct_and_verify(&rt);
3134
(h, rt)
3235
}
3336

@@ -631,3 +634,112 @@ fn dispute_after_move() {
631634
h.dispute_window_post(&rt, &dest_deadline, 0, &sectors_info, Some(expected_result));
632635
}
633636
}
637+
638+
#[test]
639+
fn dispute_remaining_partition_after_move() {
640+
let (mut h, rt) = setup();
641+
642+
// Commit more sectors than fit in one partition in every eligible deadline, overflowing to a second partition.
643+
let sectors_to_commit = (rt.policy.wpost_period_deadlines - 2) * h.partition_size + 1;
644+
let sectors_info = h.commit_and_prove_sectors(
645+
&rt,
646+
sectors_to_commit as usize,
647+
DEFAULT_SECTOR_EXPIRATION,
648+
vec![],
649+
true,
650+
);
651+
h.advance_and_submit_posts(&rt, &sectors_info);
652+
653+
let last_sector = sectors_info.last().unwrap();
654+
let st = h.get_state(&rt);
655+
656+
let (orig_deadline_id, partition_id) =
657+
st.find_sector(&rt.store, last_sector.sector_number).unwrap();
658+
assert_eq!(partition_id, 1);
659+
660+
// move a partition from a deadline that still needs WindowPoST verification.
661+
662+
// at this moment, the current and next deadlines are empty, orig_deadline_id has 2 partitions, and all other deadlines have 1 partition.
663+
let target_sectors = &[
664+
&sectors_info[0..h.partition_size as usize], /* these belong to partition 0 */
665+
vec![last_sector.clone()].as_slice(), /* these belong to partition 1 */
666+
]
667+
.concat();
668+
// after this call, current epoch will automatically be advanced to `nearest_unsafe_epoch(&rt, &h, orig_deadline_id)`
669+
h.advance_and_submit_posts(&rt, target_sectors);
670+
671+
let dest_deadline_id =
672+
farthest_possible_to_deadline(&rt, orig_deadline_id, h.current_deadline(&rt));
673+
674+
// move the second partition
675+
let result = h.move_partitions(
676+
&rt,
677+
orig_deadline_id,
678+
dest_deadline_id,
679+
bitfield_from_slice(&[partition_id]),
680+
target_sectors,
681+
);
682+
assert!(result.is_ok());
683+
684+
let st = h.get_state(&rt);
685+
let (dl_idx, _) = st.find_sector(&rt.store, last_sector.sector_number).unwrap();
686+
assert!(dl_idx == dest_deadline_id);
687+
688+
h.check_state(&rt);
689+
690+
// Dispute the first partition in the original deadline
691+
{
692+
let orig_deadline =
693+
nearest_occured_deadline_info(rt.policy(), &h.current_deadline(&rt), orig_deadline_id);
694+
695+
// Check that a failed dispute is ok. A successful dispute is impossible because the Window PoST was synchronously validated when the partition was moved.
696+
h.dispute_window_post(&rt, &orig_deadline, 0, target_sectors, None);
697+
}
698+
}
699+
700+
#[test]
701+
fn move_partition_with_terminated_sector() {
702+
let (mut h, rt) = setup();
703+
704+
// create 2 sectors in partition 0
705+
let sectors_info = h.commit_and_prove_sectors(
706+
&rt,
707+
2,
708+
DEFAULT_SECTOR_EXPIRATION,
709+
vec![vec![10], vec![20]],
710+
true,
711+
);
712+
h.advance_and_submit_posts(&rt, &sectors_info);
713+
714+
// terminate 1 sector
715+
{
716+
// A miner will pay the minimum of termination fee and locked funds. Add some locked funds to ensure
717+
// correct fee calculation is used.
718+
h.apply_rewards(&rt, BIG_REWARDS.clone(), TokenAmount::zero());
719+
720+
let expected_fee = calc_expected_fee_for_termination(&h, &rt, sectors_info[1].clone());
721+
722+
let sectors = bitfield_from_slice(&[sectors_info[1].sector_number]);
723+
h.terminate_sectors(&rt, &sectors, expected_fee);
724+
}
725+
726+
let st = h.get_state(&rt);
727+
let (orig_deadline_id, partition_id) =
728+
st.find_sector(&rt.store, sectors_info[0].sector_number).unwrap();
729+
730+
h.advance_to_epoch_with_cron(&rt, nearest_safe_epoch(&rt, &h, orig_deadline_id));
731+
732+
let dest_deadline_id =
733+
farthest_possible_to_deadline(&rt, orig_deadline_id, h.current_deadline(&rt));
734+
735+
let result = h.move_partitions(
736+
&rt,
737+
orig_deadline_id,
738+
dest_deadline_id,
739+
bitfield_from_slice(&[partition_id]),
740+
&[],
741+
);
742+
assert!(result.is_ok());
743+
744+
h.check_state(&rt);
745+
}

0 commit comments

Comments
 (0)