Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: move partitions #8

Open
wants to merge 59 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
924722e
init
zhiqiangxu Jun 25, 2023
da95dbb
avoid recompute current_deadline
zhiqiangxu Jun 25, 2023
e502709
treat empty bitfield as all
zhiqiangxu Jun 26, 2023
eaf5370
rm useless quote
zhiqiangxu Jun 26, 2023
2fa9693
add verify
zhiqiangxu Jun 27, 2023
8725420
combine option1 & option2
zhiqiangxu Jun 28, 2023
d534373
fix
zhiqiangxu Jun 28, 2023
36caece
fix
zhiqiangxu Jun 28, 2023
badb691
nit
zhiqiangxu Jun 28, 2023
fd39aac
mod error
zhiqiangxu Jun 28, 2023
daab781
nit
zhiqiangxu Jun 28, 2023
0271369
fmt
zhiqiangxu Jun 28, 2023
c046cc6
fix ci
zhiqiangxu Jun 28, 2023
3eac91e
fix bug
zhiqiangxu Jul 3, 2023
181dc2e
add test
zhiqiangxu Jul 4, 2023
8eb2243
add more test
zhiqiangxu Jul 5, 2023
394ea44
Merge remote-tracking branch 'origin/master' into feature/move_partit…
zhiqiangxu Jul 11, 2023
d1fdb0f
partial fix for review
zhiqiangxu Jul 18, 2023
0804565
Merge remote-tracking branch 'origin/master' into feature/move_partit…
zhiqiangxu Jul 19, 2023
0353a28
adjust test
zhiqiangxu Jul 19, 2023
bc9e6a1
use .context_code
zhiqiangxu Jul 19, 2023
c1d88a2
fix for test
zhiqiangxu Jul 19, 2023
37d7d03
disallow empty partitions
zhiqiangxu Jul 19, 2023
89bcb74
refactor deadline_available_for_move
zhiqiangxu Jul 19, 2023
79ab15d
fix for clippy
zhiqiangxu Jul 19, 2023
39d6447
minor opt
zhiqiangxu Jul 19, 2023
0bd0611
only verify_windowed_post once
zhiqiangxu Jul 20, 2023
c01b54c
mod error msg
zhiqiangxu Jul 24, 2023
ccdb45f
1. verify_window_post batch by batch
zhiqiangxu Jul 25, 2023
b775fa8
fix ci
zhiqiangxu Jul 25, 2023
a5290cc
mod check for epoch
zhiqiangxu Jul 25, 2023
bf13558
partial review fix
zhiqiangxu Aug 2, 2023
9195aa1
Merge remote-tracking branch 'origin/master' into feature/move_partit…
zhiqiangxu Aug 2, 2023
70fd5fe
adjust test
zhiqiangxu Aug 2, 2023
511e170
refactor with Partition::adjust_for_move
zhiqiangxu Aug 2, 2023
d16077c
share the language with FIP
zhiqiangxu Aug 30, 2023
9ed53b8
deadline_available_for_move => ensure_deadline_available_for_move
zhiqiangxu Aug 30, 2023
15d5ac1
add some doc comment
zhiqiangxu Aug 30, 2023
5744223
more renaming
zhiqiangxu Aug 30, 2023
e8f0a22
more renaming
zhiqiangxu Aug 30, 2023
194b7cd
Merge remote-tracking branch 'origin/master' into feature/move_partit…
zhiqiangxu Aug 30, 2023
5e400d2
rename + merge master
zhiqiangxu Aug 30, 2023
c1159c5
mod wording
zhiqiangxu Aug 30, 2023
cb5e3c4
fix test
zhiqiangxu Aug 30, 2023
faa4873
renaming in test
zhiqiangxu Aug 31, 2023
7bc1156
apply alex's idea of not re-quantizing at all.
zhiqiangxu Sep 19, 2023
f7b7bd7
1. forbid moving when there're early terminations
zhiqiangxu Sep 22, 2023
3b25fdc
rm anyhow::Ok
zhiqiangxu Sep 22, 2023
f3ddb23
Merge branch 'master' into feature/move_partition_verify
zhiqiangxu Sep 23, 2023
9c8517a
minor optimization by observing that partition `faulty_power` should …
zhiqiangxu Sep 23, 2023
3c6a374
adjust find_sectors_by_expiration for not re-quantizing
zhiqiangxu Sep 25, 2023
271e3c0
add test
zhiqiangxu Sep 26, 2023
d2202ab
fix for review
zhiqiangxu Sep 26, 2023
d276241
add a comment about not re-quantizing when moving expirations_epochs
zhiqiangxu Sep 26, 2023
b2dc66c
minor optimization
zhiqiangxu Sep 27, 2023
fcc4cc0
avoid scanning the same range twice
zhiqiangxu Sep 28, 2023
7619065
1. review fix
zhiqiangxu Sep 28, 2023
6e91261
fix comment
zhiqiangxu Sep 28, 2023
9964257
use with_context_code
zhiqiangxu Sep 29, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions actors/miner/src/deadlines.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,26 @@ pub fn deadline_available_for_compaction(
)
}

// the distance between from_deadline and to_deadline clockwise in deadline unit.
fn deadline_distance(policy: &Policy, from_deadline: u64, to_deadline: u64) -> u64 {
if to_deadline > from_deadline {
to_deadline - from_deadline
} else {
policy.wpost_period_deadlines - from_deadline + to_deadline

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if to_deadline > from_deadline {
to_deadline - from_deadline
} else {
policy.wpost_period_deadlines - from_deadline + to_deadline
if to_deadline >= from_deadline {
to_deadline - from_deadline
} else {
policy.wpost_period_deadlines - from_deadline + to_deadline

The distance should be 0~47.
And, this change makes the function deadline_available_for_move more reasonable. It will automatically return false if currDeadline=fromDeadline

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, fixed!

}
}

// only allow moving to a nearer deadline from current one
pub fn deadline_available_for_move(
policy: &Policy,
from_deadline: u64,
to_deadline: u64,
current_deadline: u64,
) -> bool {
deadline_distance(policy, current_deadline, to_deadline)
< deadline_distance(policy, current_deadline, from_deadline)
}

// Determine current period start and deadline index directly from current epoch and
// the offset implied by the proving period. This works correctly even for the state
// of a miner actor without an active deadline cron
Expand Down
293 changes: 293 additions & 0 deletions actors/miner/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ pub enum Method {
ChangeBeneficiary = 30,
GetBeneficiary = 31,
ExtendSectorExpiration2 = 32,
MovePartitions = 33,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

类似下面,用exported方法

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CompactPartitions 也没用exported,这里的规范是什么?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

相当于hash一个方法数出来

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

frc42规范是这样的

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个知道,我指的是什么情况需要用exported方法?因为CompactPartitions也没用。貌似exported方法的好处是可以从evm调,暂时应该还没这个需求。

// Method numbers derived from FRC-0042 standards
ChangeWorkerAddressExported = frc42_dispatch::method_hash!("ChangeWorkerAddress"),
ChangePeerIDExported = frc42_dispatch::method_hash!("ChangePeerID"),
Expand Down Expand Up @@ -2995,6 +2996,297 @@ impl Actor {
Ok(())
}

fn move_partitions(
rt: &impl Runtime,
mut params: MovePartitionsParams,
) -> Result<(), ActorError> {
let policy = rt.policy();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

可以挪到第一个条件下面

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

if params.from_deadline == params.to_deadline {
return Err(actor_error!(illegal_argument, "from_deadline == to_deadline"));
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be deleted if we fail it when !deadline_available_for_move earlier (before the transaction handling).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as reply for deadline_available_for_move

if params.from_deadline >= policy.wpost_period_deadlines
|| params.to_deadline >= policy.wpost_period_deadlines
{
return Err(actor_error!(
illegal_argument,
"invalid deadline {}",
if params.from_deadline >= policy.wpost_period_deadlines {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

直接返回from/to就行了,用户自行判断

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

params.from_deadline
} else {
params.to_deadline
}
));
}

let partitions = &mut params.partitions;

rt.transaction(|state: &mut State, rt| {
let info = get_miner_info(rt.store(), state)?;

rt.validate_immediate_caller_is(&[info.worker, info.owner])?;

let store = rt.store();
let current_deadline = state.deadline_info(policy, rt.curr_epoch());
let mut deadlines =
state.load_deadlines(store).map_err(|e| e.wrap("failed to load deadlines"))?;

// only try to do synchronous Window Post verification if from_deadline doesn't satisfy deadline_available_for_compaction
if !deadline_available_for_compaction(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

建议把这些检查都封装到move里面,这里调一下move函数,函数有点太长了,deadline_available_for_compaction最后也抽到deadline_available_for_move里面,毕竟还是两个功能,现在可以套用,以后不一定可以套用。

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

主要是verify_windowed_post篇幅比较长,另外2处verify_windowed_post也是这个风格,先跟风下-_-b

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里两个check后续的处理不一样,所以没法合成一个判断。

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

还是说指的是to_deadline的deadline_available_for_compaction判断?那个倒是可以跟deadline_available_for_move合并,不过错误消息要改下

policy,
current_deadline.period_start,
params.from_deadline,
rt.curr_epoch(),
) {
// the heavy path: try to do synchronous Window Post verification

// current deadline must be in the dispute window to satisfy the condition of synchronous Window POST verification
if !deadline_available_for_optimistic_post_dispute(
policy,
current_deadline.period_start,
params.from_deadline,
rt.curr_epoch(),
) {
return Err(actor_error!(
forbidden,
"cannot move from deadline {} when !deadline_available_for_compaction && !deadline_available_for_optimistic_post_dispute",
params.from_deadline
));
}


let dl_current = deadlines
.load_deadline(policy, rt.store(), params.from_deadline)
.map_err(|e| {
e.downcast_default(ExitCode::USR_ILLEGAL_STATE, "failed to load deadline")
})?;

let proofs_snapshot =
dl_current.optimistic_proofs_snapshot_amt(store).map_err(|e| {
e.downcast_default(
ExitCode::USR_ILLEGAL_STATE,
"failed to load proofs snapshot",
)
})?;

let partitions_snapshot =
dl_current.partitions_snapshot_amt(store).map_err(|e| {
e.downcast_default(
ExitCode::USR_ILLEGAL_STATE,
"failed to load partitions snapshot",
)
})?;

// Load sectors for the dispute.
let sectors =
Sectors::load(rt.store(), &dl_current.sectors_snapshot).map_err(|e| {
e.downcast_default(
ExitCode::USR_ILLEGAL_STATE,
"failed to load sectors array",
)
})?;

proofs_snapshot
.for_each(|_, window_proof| {
let mut all_sectors =
Vec::<BitField>::with_capacity(window_proof.partitions.len() as usize);
let mut all_ignored =
Vec::<BitField>::with_capacity(window_proof.partitions.len() as usize);

for partition_idx in window_proof.partitions.iter() {
let partition = partitions_snapshot
.get(partition_idx)
.map_err(|e| {
e.downcast_default(
ExitCode::USR_ILLEGAL_STATE,
"failed to load partitions snapshot for proof",
)
})?
.ok_or_else(|| {
actor_error!(
illegal_state,
"failed to load partitions snapshot for proof"
)
})?;
all_sectors.push(partition.sectors.clone());
all_ignored.push(partition.terminated.clone());
// fail early since remove_partitions will fail when there're faults anyway.
if !partition.faults.is_empty() {
return Err(anyhow::anyhow!("unable to do synchronous Window POST verification while there're faults in from deadline {}",
params.from_deadline
));
}
}

// Load sector infos for proof, substituting a known-good sector for known-faulty sectors.
// Note: this is slightly sub-optimal, loading info for the recovering sectors again after they were already
// loaded above.
let sector_infos = sectors
.load_for_proof(
&BitField::union(&all_sectors),
&BitField::union(&all_ignored),
)
.map_err(|e| {
e.downcast_default(
ExitCode::USR_ILLEGAL_STATE,
"failed to load sectors for post verification",
)
})?;
if !verify_windowed_post(
rt,
current_deadline.challenge,
&sector_infos,
window_proof.proofs.clone(),
)
.map_err(|e| e.wrap("window post failed"))?
{
return Err(actor_error!(
illegal_argument,
"invalid post was submitted"
)
.into());
}
Ok(())
})
.map_err(|e| {
e.downcast_default(ExitCode::USR_ILLEGAL_STATE, "while removing partitions")
})?;
}

if !deadline_available_for_compaction(
policy,
current_deadline.period_start,
params.to_deadline,
rt.curr_epoch(),
) {
return Err(actor_error!(
forbidden,
"cannot move to deadline {} during its challenge window, \
or the prior challenge window,
or before {} epochs have passed since its last challenge window ended",
params.to_deadline,
policy.wpost_dispute_window
));
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this still required if we had done the verification of PoSt?

Copy link
Author

@zhiqiangxu zhiqiangxu Jun 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We only do the verification of from_deadline, but not to_deadline.

It's obviously forbidden to change deadline partitions during deadline window and challenge window, not so sure about whether it's possible to allow modifications to the partition during the dispute window though. But the original compact_partitions function doesn't allow it during dispute window, so I followed its decision.


if !deadline_available_for_move(
policy,
params.from_deadline,
params.to_deadline,
current_deadline.index,
) {
return Err(actor_error!(
forbidden,
"cannot move to a deadline which is further from current deadline"
));
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we move this before the transaction handling?
I would think it is better if it can fail faster.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, seems not , because current_deadline depends on state, which is only available in the transaction.


let from_quant = state.quant_spec_for_deadline(policy, params.from_deadline);
let to_quant = state.quant_spec_for_deadline(policy, params.to_deadline);

let mut from_deadline =
deadlines.load_deadline(policy, store, params.from_deadline).map_err(|e| {
e.downcast_default(
ExitCode::USR_ILLEGAL_STATE,
format!("failed to load deadline {}", params.from_deadline),
)
})?;
let mut to_deadline =
deadlines.load_deadline(policy, store, params.to_deadline).map_err(|e| {
e.downcast_default(
ExitCode::USR_ILLEGAL_STATE,
format!("failed to load deadline {}", params.to_deadline),
)
})?;

if partitions.len() == 0 {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个条件检查可以挪到前面么

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0等于全是吗

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

挪到let mut from_deadlinelet mut to_deadline之间?感觉没啥必要

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

可以上面定义的变量拿到这里吗,定义和使用贴近一点。

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

对的,0等于全

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

可以上面定义的变量拿到这里吗,定义和使用贴近一点。

这些变量下面也要用到。

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

           let partitions = &mut params.partitions;
            if partitions.len() == 0 {

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

let partitions_amt = from_deadline.partitions_amt(rt.store()).map_err(|e| {
e.downcast_default(
ExitCode::USR_ILLEGAL_STATE,
format!("failed to load partitions for deadline {}", params.from_deadline),
)
})?;

for partition_idx in 0..partitions_amt.count() {
partitions.set(partition_idx);
}
}

let (live, dead, removed_power) =
from_deadline.remove_partitions(store, partitions, from_quant).map_err(|e| {
hunjixin marked this conversation as resolved.
Show resolved Hide resolved
e.downcast_default(
ExitCode::USR_ILLEGAL_STATE,
format!(
"failed to remove partitions from deadline {}",
params.from_deadline
),
)
})?;

state.delete_sectors(store, &dead).map_err(|e| {
e.downcast_default(ExitCode::USR_ILLEGAL_STATE, "failed to delete dead sectors")
})?;

let sectors = state.load_sector_infos(store, &live).map_err(|e| {
e.downcast_default(ExitCode::USR_ILLEGAL_STATE, "failed to load moved sectors")
})?;
let proven = true;
let added_power = to_deadline
.add_sectors(
store,
info.window_post_partition_sectors,
proven,
&sectors,
info.sector_size,
to_quant,
)
.map_err(|e| {
e.downcast_default(
ExitCode::USR_ILLEGAL_STATE,
"failed to add back moved sectors",
)
})?;

if removed_power != added_power {
return Err(actor_error!(
illegal_state,
"power changed when compacting partitions: was {:?}, is now {:?}",
removed_power,
added_power
));
}

deadlines
.update_deadline(policy, store, params.from_deadline, &from_deadline)
.map_err(|e| {
e.downcast_default(
ExitCode::USR_ILLEGAL_STATE,
format!("failed to update deadline {}", params.from_deadline),
)
})?;
deadlines.update_deadline(policy, store, params.to_deadline, &to_deadline).map_err(
|e| {
e.downcast_default(
ExitCode::USR_ILLEGAL_STATE,
format!("failed to update deadline {}", params.to_deadline),
)
},
)?;

state.save_deadlines(store, deadlines).map_err(|e| {
e.downcast_default(
ExitCode::USR_ILLEGAL_STATE,
format!(
"failed to save deadline when move_partitions from {} to {}",
params.from_deadline, params.to_deadline
),
)
})?;

Ok(())
})?;

Ok(())
}
/// Compacts sector number allocations to reduce the size of the allocated sector
/// number bitfield.
///
Expand Down Expand Up @@ -5113,6 +5405,7 @@ impl ActorCode for Actor {
ConfirmSectorProofsValid => confirm_sector_proofs_valid,
ChangeMultiaddrs|ChangeMultiaddrsExported => change_multiaddresses,
CompactPartitions => compact_partitions,
MovePartitions => move_partitions,
CompactSectorNumbers => compact_sector_numbers,
ConfirmChangeWorkerAddress|ConfirmChangeWorkerAddressExported => confirm_change_worker_address,
RepayDebt|RepayDebtExported => repay_debt,
Expand Down
7 changes: 7 additions & 0 deletions actors/miner/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,13 @@ pub struct CompactPartitionsParams {
pub partitions: BitField,
}

#[derive(Serialize_tuple, Deserialize_tuple)]
pub struct MovePartitionsParams {
pub from_deadline: u64,
pub to_deadline: u64,
pub partitions: BitField,
}

#[derive(Serialize_tuple, Deserialize_tuple)]
pub struct CompactSectorNumbersParams {
pub mask_sector_numbers: BitField,
Expand Down