@@ -14,6 +14,7 @@ use fil_actors_runtime::{
14
14
} ;
15
15
use fvm_ipld_bitfield:: BitField ;
16
16
use fvm_shared:: econ:: TokenAmount ;
17
+ use fvm_shared:: sector:: RegisteredSealProof ;
17
18
use fvm_shared:: { clock:: ChainEpoch , error:: ExitCode } ;
18
19
use num_traits:: Zero ;
19
20
@@ -23,11 +24,13 @@ use util::*;
23
24
const PERIOD_OFFSET : ChainEpoch = 100 ;
24
25
25
26
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 ) ;
27
30
let rt = h. new_runtime ( ) ;
28
- h. construct_and_verify ( & rt) ;
29
- rt. balance . replace ( BIG_BALANCE . clone ( ) ) ;
30
31
32
+ rt. balance . replace ( BIG_BALANCE . clone ( ) ) ;
33
+ h. construct_and_verify ( & rt) ;
31
34
( h, rt)
32
35
}
33
36
@@ -631,3 +634,112 @@ fn dispute_after_move() {
631
634
h. dispute_window_post ( & rt, & dest_deadline, 0 , & sectors_info, Some ( expected_result) ) ;
632
635
}
633
636
}
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