Skip to content

Commit 181dc2e

Browse files
committed
add test
1 parent 3eac91e commit 181dc2e

File tree

2 files changed

+367
-3
lines changed

2 files changed

+367
-3
lines changed
+337
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,337 @@
1+
use fil_actor_miner::{
2+
deadline_available_for_compaction, deadline_available_for_optimistic_post_dispute,
3+
new_deadline_info, DeadlineInfo,
4+
};
5+
use fil_actors_runtime::{
6+
runtime::{DomainSeparationTag, RuntimePolicy},
7+
test_utils::{expect_abort_contains_message, MockRuntime},
8+
};
9+
use fvm_ipld_bitfield::BitField;
10+
use fvm_ipld_encoding::RawBytes;
11+
use fvm_shared::randomness::Randomness;
12+
use fvm_shared::{clock::ChainEpoch, error::ExitCode};
13+
14+
mod util;
15+
use util::*;
16+
const PERIOD_OFFSET: ChainEpoch = 100;
17+
18+
fn setup() -> (ActorHarness, MockRuntime) {
19+
let h = ActorHarness::new(PERIOD_OFFSET);
20+
let rt = h.new_runtime();
21+
h.construct_and_verify(&rt);
22+
rt.balance.replace(BIG_BALANCE.clone());
23+
24+
(h, rt)
25+
}
26+
27+
// returns the nearest epoch such that synchronous post verification is required
28+
fn nearest_unsafe_epoch(rt: &MockRuntime, h: &ActorHarness, from_deadline_id: u64) -> i64 {
29+
let current_ddl = h.current_deadline(rt);
30+
31+
for i in *rt.epoch.borrow().. {
32+
if !deadline_available_for_compaction(
33+
&rt.policy,
34+
current_ddl.period_start,
35+
from_deadline_id,
36+
i,
37+
) && deadline_available_for_optimistic_post_dispute(
38+
&rt.policy,
39+
current_ddl.period_start,
40+
from_deadline_id,
41+
i,
42+
) {
43+
return i;
44+
}
45+
}
46+
47+
panic!("impossible path");
48+
}
49+
50+
// returns the nearest epoch such that no synchronous post verification is necessary
51+
fn nearest_safe_epoch(rt: &MockRuntime, h: &ActorHarness, from_deadline_id: u64) -> i64 {
52+
let current_ddl = h.current_deadline(rt);
53+
54+
for i in *rt.epoch.borrow().. {
55+
if deadline_available_for_compaction(
56+
&rt.policy,
57+
current_ddl.period_start,
58+
from_deadline_id,
59+
i,
60+
) {
61+
return i;
62+
}
63+
}
64+
65+
panic!("impossible path");
66+
}
67+
68+
// returns the farthest deadline from current that satisfies deadline_available_for_move
69+
fn farthest_possible_to_deadline(
70+
rt: &MockRuntime,
71+
from_deadline_id: u64,
72+
current_deadline: DeadlineInfo,
73+
) -> u64 {
74+
assert!(from_deadline_id != current_deadline.index, "can't move nearer when the gap is 0");
75+
76+
if current_deadline.index < from_deadline_id {
77+
// the deadline distance can only be nearer
78+
for i in (current_deadline.index..(from_deadline_id)).rev() {
79+
if deadline_available_for_compaction(
80+
&rt.policy,
81+
current_deadline.period_start,
82+
i,
83+
*rt.epoch.borrow(),
84+
) {
85+
return i;
86+
}
87+
}
88+
} else {
89+
for i in (0..(from_deadline_id)).rev() {
90+
if deadline_available_for_compaction(
91+
&rt.policy,
92+
current_deadline.period_start,
93+
i,
94+
*rt.epoch.borrow(),
95+
) {
96+
return i;
97+
}
98+
}
99+
100+
for i in (current_deadline.index..rt.policy.wpost_period_deadlines).rev() {
101+
if deadline_available_for_compaction(
102+
&rt.policy,
103+
current_deadline.period_start,
104+
i,
105+
*rt.epoch.borrow(),
106+
) {
107+
return i;
108+
}
109+
}
110+
}
111+
112+
panic!("no candidate to_deadline");
113+
}
114+
115+
#[test]
116+
fn fail_to_move_partitions_with_faults_from_safe_epoch() {
117+
let (mut h, rt) = setup();
118+
rt.set_epoch(200);
119+
120+
// create 2 sectors in partition 0
121+
let sectors_info = h.commit_and_prove_sectors(
122+
&rt,
123+
2,
124+
DEFAULT_SECTOR_EXPIRATION,
125+
vec![vec![10], vec![20]],
126+
true,
127+
);
128+
h.advance_and_submit_posts(&rt, &sectors_info);
129+
130+
// fault sector 1
131+
h.declare_faults(&rt, &sectors_info[0..1]);
132+
133+
let partition_id = 0;
134+
let from_deadline_id = 0;
135+
136+
h.advance_to_epoch_with_cron(&rt, nearest_safe_epoch(&rt, &h, from_deadline_id));
137+
138+
let to_deadline_id =
139+
farthest_possible_to_deadline(&rt, from_deadline_id, h.current_deadline(&rt));
140+
141+
let result = h.move_partitions(
142+
&rt,
143+
from_deadline_id,
144+
to_deadline_id,
145+
bitfield_from_slice(&[partition_id]),
146+
|| {},
147+
);
148+
expect_abort_contains_message(
149+
ExitCode::USR_ILLEGAL_ARGUMENT,
150+
"cannot remove partition 0: has faults",
151+
result,
152+
);
153+
154+
h.check_state(&rt);
155+
}
156+
157+
#[test]
158+
fn fail_to_move_partitions_with_faults_from_unsafe_epoch() {
159+
let (mut h, rt) = setup();
160+
rt.set_epoch(200);
161+
162+
// create 2 sectors in partition 0
163+
let sectors_info = h.commit_and_prove_sectors(
164+
&rt,
165+
2,
166+
DEFAULT_SECTOR_EXPIRATION,
167+
vec![vec![10], vec![20]],
168+
true,
169+
);
170+
h.advance_and_submit_posts(&rt, &sectors_info);
171+
172+
// fault sector 1
173+
h.declare_faults(&rt, &sectors_info[0..1]);
174+
175+
let partition_id = 0;
176+
let from_deadline_id = 0;
177+
178+
h.advance_to_epoch_with_cron(&rt, nearest_unsafe_epoch(&rt, &h, from_deadline_id));
179+
180+
let to_deadline_id =
181+
farthest_possible_to_deadline(&rt, from_deadline_id, h.current_deadline(&rt));
182+
183+
let result = h.move_partitions(
184+
&rt,
185+
from_deadline_id,
186+
to_deadline_id,
187+
bitfield_from_slice(&[partition_id]),
188+
|| {
189+
let current_deadline = h.current_deadline(&rt);
190+
191+
let from_deadline = new_deadline_info(
192+
rt.policy(),
193+
if current_deadline.index < from_deadline_id {
194+
current_deadline.period_start - rt.policy().wpost_proving_period
195+
} else {
196+
current_deadline.period_start
197+
},
198+
from_deadline_id,
199+
*rt.epoch.borrow(),
200+
);
201+
202+
let from_ddl = h.get_deadline(&rt, from_deadline_id);
203+
204+
let entropy = RawBytes::serialize(h.receiver).unwrap();
205+
rt.expect_get_randomness_from_beacon(
206+
DomainSeparationTag::WindowedPoStChallengeSeed,
207+
from_deadline.challenge,
208+
entropy.to_vec(),
209+
TEST_RANDOMNESS_ARRAY_FROM_ONE,
210+
);
211+
212+
let post = h.get_submitted_proof(&rt, &from_ddl, 0);
213+
214+
let all_ignored = BitField::new();
215+
let vi = h.make_window_post_verify_info(
216+
&sectors_info,
217+
&all_ignored,
218+
sectors_info[1].clone(),
219+
Randomness(TEST_RANDOMNESS_ARRAY_FROM_ONE.into()),
220+
post.proofs,
221+
);
222+
rt.expect_verify_post(vi, ExitCode::OK);
223+
},
224+
);
225+
expect_abort_contains_message(
226+
ExitCode::USR_ILLEGAL_ARGUMENT,
227+
"cannot remove partition 0: has faults",
228+
result,
229+
);
230+
231+
h.check_state(&rt);
232+
}
233+
234+
#[test]
235+
fn ok_to_move_partitions_from_safe_epoch() {
236+
let (mut h, rt) = setup();
237+
rt.set_epoch(200);
238+
239+
// create 2 sectors in partition 0
240+
let sectors_info = h.commit_and_prove_sectors(
241+
&rt,
242+
2,
243+
DEFAULT_SECTOR_EXPIRATION,
244+
vec![vec![10], vec![20]],
245+
true,
246+
);
247+
h.advance_and_submit_posts(&rt, &sectors_info);
248+
249+
let from_deadline_id = 0;
250+
251+
h.advance_to_epoch_with_cron(&rt, nearest_safe_epoch(&rt, &h, from_deadline_id));
252+
253+
let partition_id = 0;
254+
let to_deadline_id =
255+
farthest_possible_to_deadline(&rt, from_deadline_id, h.current_deadline(&rt));
256+
257+
let result = h.move_partitions(
258+
&rt,
259+
from_deadline_id,
260+
to_deadline_id,
261+
bitfield_from_slice(&[partition_id]),
262+
|| {},
263+
);
264+
assert!(result.is_ok());
265+
266+
h.check_state(&rt);
267+
}
268+
269+
#[test]
270+
fn ok_to_move_partitions_from_unsafe_epoch() {
271+
let (mut h, rt) = setup();
272+
rt.set_epoch(200);
273+
274+
// create 2 sectors in partition 0
275+
let sectors_info = h.commit_and_prove_sectors(
276+
&rt,
277+
2,
278+
DEFAULT_SECTOR_EXPIRATION,
279+
vec![vec![10], vec![20]],
280+
true,
281+
);
282+
h.advance_and_submit_posts(&rt, &sectors_info);
283+
284+
let from_deadline_id = 0;
285+
286+
h.advance_to_epoch_with_cron(&rt, nearest_unsafe_epoch(&rt, &h, from_deadline_id));
287+
288+
let partition_id = 0;
289+
let to_deadline_id =
290+
farthest_possible_to_deadline(&rt, from_deadline_id, h.current_deadline(&rt));
291+
292+
let result = h.move_partitions(
293+
&rt,
294+
from_deadline_id,
295+
to_deadline_id,
296+
bitfield_from_slice(&[partition_id]),
297+
|| {
298+
let current_deadline = h.current_deadline(&rt);
299+
300+
let from_deadline = new_deadline_info(
301+
rt.policy(),
302+
if current_deadline.index < from_deadline_id {
303+
current_deadline.period_start - rt.policy().wpost_proving_period
304+
} else {
305+
current_deadline.period_start
306+
},
307+
from_deadline_id,
308+
*rt.epoch.borrow(),
309+
);
310+
311+
let from_ddl = h.get_deadline(&rt, from_deadline_id);
312+
313+
let entropy = RawBytes::serialize(h.receiver).unwrap();
314+
rt.expect_get_randomness_from_beacon(
315+
DomainSeparationTag::WindowedPoStChallengeSeed,
316+
from_deadline.challenge,
317+
entropy.to_vec(),
318+
TEST_RANDOMNESS_ARRAY_FROM_ONE,
319+
);
320+
321+
let post = h.get_submitted_proof(&rt, &from_ddl, 0);
322+
323+
let all_ignored = BitField::new();
324+
let vi = h.make_window_post_verify_info(
325+
&sectors_info,
326+
&all_ignored,
327+
sectors_info[1].clone(),
328+
Randomness(TEST_RANDOMNESS_ARRAY_FROM_ONE.into()),
329+
post.proofs,
330+
);
331+
rt.expect_verify_post(vi, ExitCode::OK);
332+
},
333+
);
334+
assert!(result.is_ok());
335+
336+
h.check_state(&rt);
337+
}

actors/miner/tests/util.rs

+30-3
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use fil_actor_miner::{
2525
ExpirationQueue, ExpirationSet, ExtendSectorExpiration2Params, ExtendSectorExpirationParams,
2626
FaultDeclaration, GetAvailableBalanceReturn, GetBeneficiaryReturn, GetControlAddressesReturn,
2727
GetMultiaddrsReturn, GetPeerIDReturn, Method, MinerConstructorParams as ConstructorParams,
28-
MinerInfo, Partition, PendingBeneficiaryChange, PoStPartition, PowerPair,
28+
MinerInfo, MovePartitionsParams, Partition, PendingBeneficiaryChange, PoStPartition, PowerPair,
2929
PreCommitSectorBatchParams, PreCommitSectorBatchParams2, PreCommitSectorParams,
3030
ProveCommitSectorParams, RecoveryDeclaration, ReportConsensusFaultParams, SectorOnChainInfo,
3131
SectorPreCommitInfo, SectorPreCommitOnChainInfo, Sectors, State, SubmitWindowedPoStParams,
@@ -1470,7 +1470,7 @@ impl ActorHarness {
14701470
)
14711471
}
14721472

1473-
fn make_window_post_verify_info(
1473+
pub fn make_window_post_verify_info(
14741474
&self,
14751475
infos: &[SectorOnChainInfo],
14761476
all_ignored: &BitField,
@@ -1630,7 +1630,12 @@ impl ActorHarness {
16301630
rt.verify();
16311631
}
16321632

1633-
fn get_submitted_proof(&self, rt: &MockRuntime, deadline: &Deadline, idx: u64) -> WindowedPoSt {
1633+
pub fn get_submitted_proof(
1634+
&self,
1635+
rt: &MockRuntime,
1636+
deadline: &Deadline,
1637+
idx: u64,
1638+
) -> WindowedPoSt {
16341639
amt_get::<WindowedPoSt>(rt, &deadline.optimistic_post_submissions_snapshot, idx)
16351640
}
16361641

@@ -2590,6 +2595,28 @@ impl ActorHarness {
25902595
Ok(())
25912596
}
25922597

2598+
pub fn move_partitions(
2599+
&self,
2600+
rt: &MockRuntime,
2601+
from_deadline: u64,
2602+
to_deadline: u64,
2603+
partitions: BitField,
2604+
mut f: impl FnMut(),
2605+
) -> Result<(), ActorError> {
2606+
f();
2607+
2608+
let params = MovePartitionsParams { from_deadline, to_deadline, partitions };
2609+
2610+
rt.expect_validate_caller_addr(vec![self.worker, self.owner]);
2611+
rt.set_caller(*ACCOUNT_ACTOR_CODE_ID, self.worker);
2612+
2613+
rt.call::<Actor>(
2614+
Method::MovePartitions as u64,
2615+
IpldBlock::serialize_cbor(&params).unwrap(),
2616+
)?;
2617+
rt.verify();
2618+
Ok(())
2619+
}
25932620
pub fn get_info(&self, rt: &MockRuntime) -> MinerInfo {
25942621
let state: State = rt.get_state();
25952622
state.get_info(rt.store()).unwrap()

0 commit comments

Comments
 (0)