Skip to content

Commit

Permalink
fip-0100: update the daily sector fee on extension when zero
Browse files Browse the repository at this point in the history
When, on extension, we encounter a legacy sector with a zero fee, update
it based on the current circulating supply.
  • Loading branch information
Stebalien committed Feb 19, 2025
1 parent 45ca648 commit 3c02c1e
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 12 deletions.
29 changes: 18 additions & 11 deletions actors/miner/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2299,6 +2299,7 @@ impl Actor {
let curr_epoch = rt.curr_epoch();
let reward_stats = &request_current_epoch_block_reward(rt)?;
let power_stats = &request_current_total_power(rt)?;
let circulating_supply = rt.total_fil_circ_supply();

/* Loop over sectors and do extension */
let (power_delta, pledge_delta) = rt.transaction(|state: &mut State, rt| {
Expand Down Expand Up @@ -2347,6 +2348,7 @@ impl Actor {

let mut deadline_power_delta = PowerPair::zero();
let mut deadline_pledge_delta = TokenAmount::zero();
let mut deadline_daily_fee_delta = TokenAmount::zero();

// Group modified partitions by epoch to which they are extended. Duplicates are ok.
let mut partitions_by_new_epoch = BTreeMap::<ChainEpoch, Vec<u64>>::new();
Expand Down Expand Up @@ -2376,6 +2378,7 @@ impl Actor {
extend_sector_committment_legacy(
rt.policy(),
curr_epoch,
&circulating_supply,
decl.new_expiration,
sector,
)
Expand All @@ -2390,6 +2393,7 @@ impl Actor {
curr_epoch,
reward_stats,
power_stats,
&circulating_supply,
decl.new_expiration,
sector,
info.sector_size,
Expand Down Expand Up @@ -2426,15 +2430,7 @@ impl Actor {

deadline_power_delta += &partition_power_delta;
deadline_pledge_delta += &partition_pledge_delta; // expected to be zero, see note below.

// daily_fee should not change when replacing sectors with updated versions of themselves
if partition_daily_fee_delta != TokenAmount::zero() {
return Err(actor_error!(
illegal_state,
"unexpected daily fee change when extenting sectors at {:?}",
key
));
}
deadline_daily_fee_delta += &partition_daily_fee_delta; // non-zero when extending legacy sectors

partitions.set(decl.partition, partition).map_err(|e| {
e.downcast_default(
Expand All @@ -2457,6 +2453,7 @@ impl Actor {
}

deadline.live_power += &deadline_power_delta;
deadline.daily_fee += &deadline_daily_fee_delta;

power_delta += &deadline_power_delta;
pledge_delta += &deadline_pledge_delta;
Expand Down Expand Up @@ -3772,6 +3769,7 @@ fn extend_sector_committment(
curr_epoch: ChainEpoch,
reward_stats: &ThisEpochRewardReturn,
power_stats: &ext::power::CurrentTotalPowerReturn,
circulating_supply: &TokenAmount,
new_expiration: ChainEpoch,
sector: &SectorOnChainInfo,
sector_size: SectorSize,
Expand All @@ -3780,7 +3778,7 @@ fn extend_sector_committment(
validate_extended_expiration(policy, curr_epoch, new_expiration, sector)?;

// all simple_qa_power sectors with VerifiedDealWeight > 0 MUST check all claims
if sector.flags.contains(SectorOnChainInfoFlags::SIMPLE_QA_POWER) {
let mut sector = if sector.flags.contains(SectorOnChainInfoFlags::SIMPLE_QA_POWER) {
extend_simple_qap_sector(
policy,
new_expiration,
Expand All @@ -3793,12 +3791,17 @@ fn extend_sector_committment(
)
} else {
extend_non_simple_qap_sector(new_expiration, curr_epoch, sector)
}?;
if sector.daily_fee.is_zero() {
sector.daily_fee = daily_proof_fee(policy, circulating_supply)
}
Ok(sector)
}

fn extend_sector_committment_legacy(
policy: &Policy,
curr_epoch: ChainEpoch,
circulating_supply: &TokenAmount,
new_expiration: ChainEpoch,
sector: &SectorOnChainInfo,
) -> Result<SectorOnChainInfo, ActorError> {
Expand All @@ -3814,7 +3817,11 @@ fn extend_sector_committment_legacy(
sector.sector_number
));
}
extend_non_simple_qap_sector(new_expiration, curr_epoch, sector)
let mut sector = extend_non_simple_qap_sector(new_expiration, curr_epoch, sector)?;
if sector.daily_fee.is_zero() {
sector.daily_fee = daily_proof_fee(policy, circulating_supply)
}
Ok(sector)
}

fn validate_extended_expiration(
Expand Down
59 changes: 58 additions & 1 deletion actors/miner/tests/extend_sector_expiration_test.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use fil_actor_market::ActivatedDeal;
use fil_actor_miner::ext::verifreg::Claim as FILPlusClaim;
use fil_actor_miner::{
power_for_sector, seal_proof_sector_maximum_lifetime, ExpirationExtension,
daily_proof_fee, power_for_sector, seal_proof_sector_maximum_lifetime, ExpirationExtension,
ExpirationExtension2, ExtendSectorExpiration2Params, ExtendSectorExpirationParams,
PoStPartition, SectorClaim, SectorOnChainInfo, State,
};
Expand All @@ -14,13 +14,15 @@ use fil_actors_runtime::{
};
use fvm_ipld_bitfield::BitField;
use fvm_shared::deal::DealID;
use fvm_shared::econ::TokenAmount;
use fvm_shared::{
address::Address,
clock::ChainEpoch,
error::ExitCode,
sector::{RegisteredSealProof, SectorNumber},
ActorID,
};
use num_traits::Zero;
use std::collections::HashMap;

mod util;
Expand Down Expand Up @@ -197,12 +199,18 @@ fn updates_expiration_with_valid_params(v2: bool) {
}],
};

// Change the circulating supply so we can detect fee changes (that shouldn't happen).
rt.set_circulating_supply(rt.total_fil_circ_supply() * 2);

h.extend_sectors_versioned(&rt, params, v2).unwrap();

// assert sector expiration is set to the new value
let new_sector = h.get_sector(&rt, old_sector.sector_number);
assert_eq!(new_expiration, new_sector.expiration);

// assert that the fee hasn't changed
assert_eq!(old_sector.daily_fee, new_sector.daily_fee);

let quant = state.quant_spec_for_deadline(rt.policy(), deadline_index);

// assert that new expiration exists
Expand All @@ -220,6 +228,55 @@ fn updates_expiration_with_valid_params(v2: bool) {
h.check_state(&rt);
}

#[test_case(false; "v1")]
#[test_case(true; "v2")]
fn updates_expiration_and_daily_fee(v2: bool) {
let (mut h, rt) = setup();

h.construct_and_verify(&rt);
rt.set_circulating_supply(TokenAmount::zero());
let old_sector =
h.commit_and_prove_sectors(&rt, 1, DEFAULT_SECTOR_EXPIRATION as u64, Vec::new(), true)[0]
.to_owned();
assert_eq!(
old_sector.daily_fee,
TokenAmount::zero(),
"expected sector's daily fee to be zero because the circulating supply is zero"
);
h.advance_and_submit_posts(&rt, &vec![old_sector.clone()]);

let state: State = rt.get_state();

let (deadline_index, partition_index) =
state.find_sector(rt.store(), old_sector.sector_number).unwrap();

let extension = 42 * rt.policy().wpost_proving_period;
let new_expiration = old_sector.expiration + extension;

let params = ExtendSectorExpirationParams {
extensions: vec![ExpirationExtension {
deadline: deadline_index,
partition: partition_index,
sectors: make_bitfield(&[old_sector.sector_number]),
new_expiration,
}],
};

let new_circulating_supply = TokenAmount::from_whole(500_000_000);
rt.set_circulating_supply(new_circulating_supply.clone());
h.extend_sectors_versioned(&rt, params, v2).unwrap();

// assert sector expiration is set to the new value
let new_sector = h.get_sector(&rt, old_sector.sector_number);
assert_eq!(new_expiration, new_sector.expiration);

// Assert that we've now applied the expected fee.
let expected_fee = daily_proof_fee(rt.policy(), &new_circulating_supply);
assert_eq!(expected_fee, new_sector.daily_fee);

h.check_state(&rt);
}

#[test_case(false; "v1")]
#[test_case(true; "v2")]
fn updates_many_sectors(v2: bool) {
Expand Down

0 comments on commit 3c02c1e

Please sign in to comment.