|
1 | 1 | use fil_actor_miner::{ |
2 | 2 | pledge_penalty_for_continued_fault, pledge_penalty_for_termination, power_for_sector, |
3 | | - qa_power_for_sector, Actor, CronEventPayload, DeferredCronEventParams, MaxTerminationFeeParams, |
4 | | - MaxTerminationFeeReturn, Method, SectorOnChainInfo, State, TerminateSectorsParams, |
5 | | - TerminationDeclaration, CRON_EVENT_PROCESS_EARLY_TERMINATIONS, |
6 | | - TERM_FEE_MAX_FAULT_FEE_MULTIPLE_DENOM, TERM_FEE_MAX_FAULT_FEE_MULTIPLE_NUM, |
7 | | - TERM_FEE_PLEDGE_MULTIPLE_DENOM, TERM_FEE_PLEDGE_MULTIPLE_NUM, |
| 3 | + qa_power_for_sector, Actor, CronEventPayload, DeferredCronEventParams, ExpirationExtension2, |
| 4 | + ExtendSectorExpiration2Params, MaxTerminationFeeParams, MaxTerminationFeeReturn, Method, |
| 5 | + SectorOnChainInfo, State, TerminateSectorsParams, TerminationDeclaration, |
| 6 | + CRON_EVENT_PROCESS_EARLY_TERMINATIONS, TERM_FEE_MAX_FAULT_FEE_MULTIPLE_DENOM, |
| 7 | + TERM_FEE_MAX_FAULT_FEE_MULTIPLE_NUM, TERM_FEE_PLEDGE_MULTIPLE_DENOM, |
| 8 | + TERM_FEE_PLEDGE_MULTIPLE_NUM, |
8 | 9 | }; |
9 | 10 | use fil_actors_runtime::{ |
| 11 | + reward::FilterEstimate, |
10 | 12 | runtime::Runtime, |
11 | 13 | test_utils::{expect_abort_contains_message, MockRuntime, ACCOUNT_ACTOR_CODE_ID}, |
12 | | - BURNT_FUNDS_ACTOR_ADDR, STORAGE_MARKET_ACTOR_ADDR, STORAGE_POWER_ACTOR_ADDR, SYSTEM_ACTOR_ADDR, |
| 14 | + BatchReturn, BURNT_FUNDS_ACTOR_ADDR, STORAGE_MARKET_ACTOR_ADDR, STORAGE_POWER_ACTOR_ADDR, |
| 15 | + SYSTEM_ACTOR_ADDR, |
13 | 16 | }; |
14 | 17 | use fvm_ipld_bitfield::BitField; |
15 | 18 | use fvm_shared::{ |
16 | | - econ::TokenAmount, error::ExitCode, sector::StoragePower, MethodNum, METHOD_SEND, |
| 19 | + bigint::BigInt, econ::TokenAmount, error::ExitCode, sector::StoragePower, MethodNum, |
| 20 | + METHOD_SEND, |
17 | 21 | }; |
18 | 22 | use std::collections::HashMap; |
19 | 23 |
|
@@ -47,32 +51,72 @@ fn setup() -> (ActorHarness, MockRuntime) { |
47 | 51 | } |
48 | 52 |
|
49 | 53 | #[test] |
50 | | -fn removes_sector_with_correct_accounting() { |
| 54 | +fn removes_sectors_with_correct_accounting() { |
51 | 55 | let (mut h, rt) = setup(); |
52 | 56 |
|
53 | | - let sector_info = |
54 | | - h.commit_and_prove_sectors(&rt, 1, DEFAULT_SECTOR_EXPIRATION, Vec::new(), true); |
| 57 | + // set the reward such that our termination fees don't bottom out at the fault fee multiple and |
| 58 | + // instead invoke the duration multipler so we can also test that |
| 59 | + h.epoch_reward_smooth = FilterEstimate::new(BigInt::from(1e12 as u64), BigInt::zero()); |
55 | 60 |
|
56 | | - assert_eq!(sector_info.len(), 1); |
57 | | - h.advance_and_submit_posts(&rt, §or_info); |
58 | | - let sector = sector_info.into_iter().next().unwrap(); |
| 61 | + // 3 sectors: one left alone, one that we'll extend and one that we'll update, they should all |
| 62 | + // have the same termination fee |
| 63 | + let sectors = h.commit_and_prove_sectors(&rt, 3, DEFAULT_SECTOR_EXPIRATION, Vec::new(), true); |
| 64 | + assert_eq!(sectors.len(), 3); |
| 65 | + |
| 66 | + // advance enough to make the duration component of the termination fee large enough to not hit |
| 67 | + // the minimum bound |
| 68 | + for _ in 0..40 { |
| 69 | + h.advance_and_submit_posts(&rt, §ors); |
| 70 | + } |
| 71 | + |
| 72 | + // extend the second sector, shouldn't affect the termination fee |
| 73 | + let state: State = rt.get_state(); |
| 74 | + let (deadline_index, partition_index) = |
| 75 | + state.find_sector(rt.store(), sectors[1].sector_number).unwrap(); |
| 76 | + let extension = 42 * rt.policy.wpost_proving_period; |
| 77 | + let new_expiration = sectors[1].expiration + extension; |
| 78 | + let params = ExtendSectorExpiration2Params { |
| 79 | + extensions: vec![ExpirationExtension2 { |
| 80 | + deadline: deadline_index, |
| 81 | + partition: partition_index, |
| 82 | + sectors: make_bitfield(&[sectors[1].sector_number]), |
| 83 | + sectors_with_claims: vec![], |
| 84 | + new_expiration, |
| 85 | + }], |
| 86 | + }; |
| 87 | + h.extend_sectors2(&rt, params, HashMap::new()).unwrap(); |
| 88 | + |
| 89 | + // update the third sector with no pieces, should not affect the termination fee |
| 90 | + let updates = make_update_manifest(&rt.get_state(), rt.store(), sectors[2].sector_number, &[]); // No pieces |
| 91 | + let (result, _, _) = h |
| 92 | + .prove_replica_updates3_batch( |
| 93 | + &rt, |
| 94 | + &[updates], |
| 95 | + true, |
| 96 | + true, |
| 97 | + ProveReplicaUpdatesConfig::default(), |
| 98 | + ) |
| 99 | + .unwrap(); |
| 100 | + assert_eq!(BatchReturn::of(&[ExitCode::OK; 1]), result.activation_results); |
59 | 101 |
|
60 | 102 | // A miner will pay the minimum of termination fee and locked funds. Add some locked funds to ensure |
61 | 103 | // correct fee calculation is used. |
62 | 104 | h.apply_rewards(&rt, BIG_REWARDS.clone(), TokenAmount::zero()); |
63 | 105 | let state: State = rt.get_state(); |
64 | 106 | let initial_locked_funds = state.locked_funds; |
65 | 107 |
|
66 | | - let expected_fee = calc_expected_fee_for_termination(&h, &rt, §or); |
| 108 | + // fee for all sectors is the same, so we can just use the first one |
| 109 | + let expected_fee = calc_expected_fee_for_termination(&h, &rt, §ors[0]) * 3; |
67 | 110 |
|
68 | | - let sectors = bitfield_from_slice(&[sector.sector_number]); |
69 | | - h.terminate_sectors(&rt, §ors, expected_fee.clone()); |
| 111 | + let bf = bitfield_from_slice(§ors.iter().map(|s| s.sector_number).collect::<Vec<u64>>()); |
| 112 | + h.terminate_sectors(&rt, &bf, expected_fee.clone()); |
70 | 113 |
|
71 | 114 | // expect sector to be marked as terminated and the early termination queue to be empty (having been fully processed) |
72 | 115 | let state: State = rt.get_state(); |
73 | | - let (_, mut partition) = h.find_sector(&rt, sector.sector_number); |
74 | | - let terminated = partition.terminated.get(sector.sector_number); |
75 | | - assert!(terminated); |
| 116 | + let (_, mut partition) = h.find_sector(&rt, sectors[0].sector_number); |
| 117 | + for s in §ors { |
| 118 | + assert!(partition.terminated.get(s.sector_number)); |
| 119 | + } |
76 | 120 |
|
77 | 121 | let (result, _) = partition.pop_early_terminations(rt.store(), 1000).unwrap(); |
78 | 122 | assert!(result.is_empty()); |
|
0 commit comments