Skip to content

Commit

Permalink
feat(FIP-0077): add create miner deposit
Browse files Browse the repository at this point in the history
  • Loading branch information
tediou5 committed Jan 7, 2025
1 parent b4ed8cf commit 5e08d67
Show file tree
Hide file tree
Showing 17 changed files with 355 additions and 59 deletions.
65 changes: 62 additions & 3 deletions actors/miner/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ pub use expiration_queue::*;
use fil_actors_runtime::cbor::{serialize, serialize_vec};
use fil_actors_runtime::reward::{FilterEstimate, ThisEpochRewardReturn};
use fil_actors_runtime::runtime::builtins::Type;
use fil_actors_runtime::runtime::policy_constants::MAX_SECTOR_NUMBER;
use fil_actors_runtime::runtime::policy_constants::{MAX_SECTOR_NUMBER, MINIMUM_CONSENSUS_POWER};
use fil_actors_runtime::runtime::{ActorCode, DomainSeparationTag, Policy, Runtime};
use fil_actors_runtime::{
actor_dispatch, actor_error, deserialize_block, extract_send_result, util, ActorContext,
Expand Down Expand Up @@ -181,6 +181,14 @@ impl Actor {
check_peer_info(rt.policy(), &params.peer_id, &params.multi_addresses)?;
check_valid_post_proof_type(rt.policy(), params.window_post_proof_type)?;

let balance = rt.current_balance();
let deposit = calculate_create_miner_deposit(rt, params.network_qap)?;
if balance < deposit {
return Err(actor_error!(insufficient_funds;
"not enough balance to lock for create miner deposit: \
sent balance {} < deposit {}", balance.atto(), deposit.atto()));
}

let owner = rt.resolve_address(&params.owner).ok_or_else(|| {
actor_error!(illegal_argument, "unable to resolve owner address: {}", params.owner)
})?;
Expand Down Expand Up @@ -239,7 +247,10 @@ impl Actor {
e.downcast_default(ExitCode::USR_ILLEGAL_STATE, "failed to construct illegal state")
})?;

let st = State::new(policy, rt.store(), info_cid, period_start, deadline_idx)?;
let store = rt.store();
let mut st = State::new(policy, store, info_cid, period_start, deadline_idx)?;
st.add_locked_funds(store, rt.curr_epoch(), &deposit, &REWARD_VESTING_SPEC)
.map_err(|e| actor_error!(illegal_state, e))?;
rt.create(&st)?;
Ok(())
}
Expand Down Expand Up @@ -312,6 +323,7 @@ impl Actor {
.load_vesting_funds(rt.store())
.map_err(|e| actor_error!(illegal_state, "failed to load vesting funds: {}", e))?;
let ret = vesting_funds.funds.into_iter().map(|v| (v.epoch, v.amount)).collect_vec();

Ok(GetVestingFundsReturn { vesting_funds: ret })
}

Expand Down Expand Up @@ -756,6 +768,7 @@ impl Actor {

Ok(())
}

/// Checks state of the corresponding sector pre-commitments and verifies aggregate proof of replication
/// of these sectors. If valid, the sectors' deals are activated, sectors are assigned a deadline and charged pledge
/// and precommit state is removed.
Expand Down Expand Up @@ -5240,7 +5253,6 @@ fn resolve_worker_address(rt: &impl Runtime, raw: Address) -> Result<ActorID, Ac
}

fn burn_funds(rt: &impl Runtime, amount: TokenAmount) -> Result<(), ActorError> {
log::debug!("storage provder {} burning {}", rt.message().receiver(), amount);
if amount.is_positive() {
extract_send_result(rt.send_simple(&BURNT_FUNDS_ACTOR_ADDR, METHOD_SEND, None, amount))?;
}
Expand Down Expand Up @@ -5642,6 +5654,53 @@ fn activate_new_sector_infos(
Ok(())
}

/// Calculate create miner deposit by MINIMUM_CONSENSUS_POWER x StateMinerInitialPledgeCollateral
/// See FIP-0077, https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0077.md
pub fn calculate_create_miner_deposit(
rt: &impl Runtime,
network_qap: FilterEstimate,
) -> Result<TokenAmount, ActorError> {
// set network pledge inputs
let rew = request_current_epoch_block_reward(rt)?;
let pwr = request_current_total_power(rt)?;
let circulating_supply = rt.total_fil_circ_supply();
let pledge_inputs = NetworkPledgeInputs {
network_qap,
network_baseline: rew.this_epoch_baseline_power,
circulating_supply,
epoch_reward: rew.this_epoch_reward_smoothed,
epochs_since_ramp_start: rt.curr_epoch() - pwr.ramp_start_epoch,
ramp_duration_epochs: pwr.ramp_duration_epochs,
};

/// set sector size with min power
#[cfg(feature = "min-power-2k")]
let sector_size = SectorSize::_2KiB;
#[cfg(feature = "min-power-2g")]
let sector_size = SectorSize::_8MiB;
#[cfg(feature = "min-power-32g")]
let sector_size = SectorSize::_512MiB;
#[cfg(not(any(
feature = "min-power-2k",
feature = "min-power-2g",
feature = "min-power-32g"
)))]
let sector_size = SectorSize::_32GiB;

let sector_number = MINIMUM_CONSENSUS_POWER / sector_size as i64;
let power = qa_power_for_weight(sector_size, MIN_SECTOR_EXPIRATION, &BigInt::zero());
let sector_initial_pledge = initial_pledge_for_power(
&power,
&pledge_inputs.network_baseline,
&pledge_inputs.epoch_reward,
&pledge_inputs.network_qap,
&pledge_inputs.circulating_supply,
pledge_inputs.epochs_since_ramp_start,
pledge_inputs.ramp_duration_epochs,
);
Ok(sector_initial_pledge * sector_number)
}

pub struct SectorPiecesActivationInput {
pub piece_manifests: Vec<PieceActivationManifest>,
pub sector_expiry: ChainEpoch,
Expand Down
5 changes: 5 additions & 0 deletions actors/miner/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ impl State {
pub fn deadline_info(&self, policy: &Policy, current_epoch: ChainEpoch) -> DeadlineInfo {
new_deadline_info_from_offset_and_epoch(policy, self.proving_period_start, current_epoch)
}

// Returns deadline calculations for the state recorded proving period and deadline.
// This is out of date if the a miner does not have an active miner cron
pub fn recorded_deadline_info(
Expand Down Expand Up @@ -877,6 +878,7 @@ impl State {
amount_unlocked
));
}

// add locked funds now
vesting_funds.add_locked_funds(current_epoch, vesting_sum, self.proving_period_start, spec);
self.locked_funds += vesting_sum;
Expand Down Expand Up @@ -937,6 +939,7 @@ impl State {

Ok(std::mem::take(&mut self.fee_debt))
}

/// Unlocks an amount of funds that have *not yet vested*, if possible.
/// The soonest-vesting entries are unlocked first.
/// Returns the amount actually unlocked.
Expand Down Expand Up @@ -1008,6 +1011,7 @@ impl State {
pub fn get_unlocked_balance(&self, actor_balance: &TokenAmount) -> anyhow::Result<TokenAmount> {
let unlocked_balance =
actor_balance - &self.locked_funds - &self.pre_commit_deposits - &self.initial_pledge;

if unlocked_balance.is_negative() {
return Err(anyhow!("negative unlocked balance {}", unlocked_balance));
}
Expand Down Expand Up @@ -1039,6 +1043,7 @@ impl State {
}

let min_balance = &self.pre_commit_deposits + &self.locked_funds + &self.initial_pledge;

if balance < &min_balance {
return Err(anyhow!("fee debt is negative: {}", self.fee_debt));
}
Expand Down
2 changes: 1 addition & 1 deletion actors/miner/src/testing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ fn check_miner_balances<BS: Blockstore>(
format!("miner fee debt is less than zero: {}", state.fee_debt),
);

acc.require(!(balance - &state.locked_funds - &state.pre_commit_deposits - &state.initial_pledge).is_negative(), format!("miner balance {balance} is less than sum of locked funds ({}), precommit deposit ({}) and initial pledge ({})", state.locked_funds, state.pre_commit_deposits, state.initial_pledge));
acc.require(!(balance - &state.locked_funds - &state.pre_commit_deposits - &state.initial_pledge).is_negative(), format!("miner balance {balance} is less than sum of locked funds ({}), precommit deposit ({}), initial pledge ({})", state.locked_funds, state.pre_commit_deposits, state.initial_pledge));

// locked funds must be sum of vesting table and vesting table payments must be quantized
let mut vesting_sum = TokenAmount::zero();
Expand Down
6 changes: 6 additions & 0 deletions actors/miner/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ pub struct MinerConstructorParams {
#[serde(with = "strict_bytes")]
pub peer_id: Vec<u8>,
pub multi_addresses: Vec<BytesDe>,
pub network_qap: FilterEstimate,
}

#[derive(Serialize_tuple, Deserialize_tuple)]
Expand Down Expand Up @@ -105,6 +106,11 @@ pub struct DeferredCronEventParams {
pub quality_adj_power_smoothed: FilterEstimate,
}

#[derive(Serialize_tuple, Deserialize_tuple)]
pub struct LockCreateMinerDepositParams {
pub amount: TokenAmount,
}

#[derive(Serialize_tuple, Deserialize_tuple)]
pub struct PoStPartition {
/// Partitions are numbered per-deadline, from zero.
Expand Down
18 changes: 18 additions & 0 deletions actors/miner/tests/aggregate_prove_commit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ const DEFAULT_SECTOR_EXPIRATION: ChainEpoch = 220;
fn valid_precommits_then_aggregate_provecommit() {
let period_offset = ChainEpoch::from(100);

println!("#0");

let actor = ActorHarness::new(period_offset);
let rt = actor.new_runtime();
rt.add_balance(BIG_BALANCE.clone());
Expand All @@ -29,6 +31,8 @@ fn valid_precommits_then_aggregate_provecommit() {
actor.construct_and_verify(&rt);
let dl_info = actor.deadline(&rt);

println!("#1");

// make a good commitment for the proof to target

let prove_commit_epoch = precommit_epoch + rt.policy.pre_commit_challenge_delay + 1;
Expand All @@ -51,6 +55,8 @@ fn valid_precommits_then_aggregate_provecommit() {
precommits.push(precommit);
}

println!("#2");

// run prove commit logic
rt.set_epoch(prove_commit_epoch);
rt.set_balance(TokenAmount::from_whole(1000));
Expand All @@ -63,6 +69,8 @@ fn valid_precommits_then_aggregate_provecommit() {
);
}

println!("#3");

actor
.prove_commit_aggregate_sector(
&rt,
Expand All @@ -73,13 +81,17 @@ fn valid_precommits_then_aggregate_provecommit() {
)
.unwrap();

println!("#4");

// expect precommits to have been removed
let st = actor.get_state(&rt);

for sector_no in sector_nos_bf.iter() {
assert!(!actor.has_precommit(&rt, sector_no));
}

println!("#5");

// expect deposit to have been transferred to initial pledges
assert!(st.pre_commit_deposits.is_zero());

Expand Down Expand Up @@ -107,6 +119,8 @@ fn valid_precommits_then_aggregate_provecommit() {
let ten_sectors_initial_pledge = BigInt::from(10i32) * expected_initial_pledge.clone();
assert_eq!(ten_sectors_initial_pledge, st.initial_pledge);

println!("#6");

// expect new onchain sector
for sector_no in sector_nos_bf.iter() {
let sector = actor.get_sector(&rt, sector_no);
Expand All @@ -127,6 +141,8 @@ fn valid_precommits_then_aggregate_provecommit() {
assert_eq!(0, pidx);
}

println!("#7");

let sector_power = PowerPair::new(BigInt::from(actor.sector_size as i64), qa_power);
let ten_sectors_power = PowerPair::new(
BigInt::from(10u32) * sector_power.raw,
Expand Down Expand Up @@ -158,6 +174,8 @@ fn valid_precommits_then_aggregate_provecommit() {
assert_eq!(PowerPair::zero(), partition.faulty_power);
assert_eq!(PowerPair::zero(), partition.recovering_power);

println!("#8");

let p_queue = actor.collect_partition_expirations(&rt, &partition);
let entry = p_queue.get(&quantized_expiration).cloned().unwrap();
assert_eq!(entry.on_time_sectors, sector_nos_bf);
Expand Down
2 changes: 0 additions & 2 deletions actors/miner/tests/apply_rewards.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,7 @@ fn funds_vest() {
rt.set_balance(BIG_BALANCE.clone());
h.construct_and_verify(&rt);
let st = h.get_state(&rt);

let vesting_funds = st.load_vesting_funds(&rt.store).unwrap();

// Nothing vesting to start
assert!(vesting_funds.funds.is_empty());
assert!(st.locked_funds.is_zero());
Expand Down
Loading

0 comments on commit 5e08d67

Please sign in to comment.