Skip to content

Commit

Permalink
WIP: Use vest_funds instead of the new create_deposit state to manage…
Browse files Browse the repository at this point in the history
… create miner deposit
  • Loading branch information
tediou5 committed Jan 6, 2025
1 parent be3d556 commit 9e9a059
Show file tree
Hide file tree
Showing 14 changed files with 201 additions and 532 deletions.
82 changes: 57 additions & 25 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 @@ -155,7 +155,6 @@ pub enum Method {
GetVestingFundsExported = frc42_dispatch::method_hash!("GetVestingFunds"),
GetPeerIDExported = frc42_dispatch::method_hash!("GetPeerID"),
GetMultiaddrsExported = frc42_dispatch::method_hash!("GetMultiaddrs"),
LockCreateMinerDepositExported = frc42_dispatch::method_hash!("LockCreateMinerDeposit"),
}

pub const SECTOR_CONTENT_CHANGED: MethodNum = frc42_dispatch::method_hash!("SectorContentChanged");
Expand All @@ -181,6 +180,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 +246,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 @@ -311,12 +321,7 @@ impl Actor {
let vesting_funds = state
.load_vesting_funds(rt.store())
.map_err(|e| actor_error!(illegal_state, "failed to load vesting funds: {}", e))?;
let mut ret = vesting_funds.funds.into_iter().map(|v| (v.epoch, v.amount)).collect_vec();

// add create miner deposit into vest table
if let Some(CreateMinerDeposit { amount, epoch }) = &state.create_miner_deposit {
ret.push((*epoch, amount.clone()));
}
let ret = vesting_funds.funds.into_iter().map(|v| (v.epoch, v.amount)).collect_vec();

Ok(GetVestingFundsReturn { vesting_funds: ret })
}
Expand Down Expand Up @@ -3425,20 +3430,6 @@ impl Actor {
state.check_balance_invariants(&rt.current_balance()).map_err(balance_invariants_broken)?;
Ok(())
}

/// Lock the create miner deposit for 180 days.
/// See FIP-0077, https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0077.md
fn lock_create_miner_deposit(
rt: &impl Runtime,
params: LockCreateMinerDepositParams,
) -> Result<(), ActorError> {
rt.validate_immediate_caller_is(std::iter::once(&STORAGE_POWER_ACTOR_ADDR))?;
rt.transaction(|st: &mut State, rt| {
st.add_create_miner_deposit(params.amount, rt.curr_epoch());

Ok(())
})
}
}

#[derive(Debug, PartialEq, Clone)]
Expand Down Expand Up @@ -4973,7 +4964,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 @@ -5378,6 +5368,49 @@ 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 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,
};

/// 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(), &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,
);
Ok(sector_initial_pledge * sector_number)
}

pub struct SectorPiecesActivationInput {
pub piece_manifests: Vec<PieceActivationManifest>,
pub sector_expiry: ChainEpoch,
Expand Down Expand Up @@ -5766,7 +5799,6 @@ impl ActorCode for Actor {
GetMultiaddrsExported => get_multiaddresses,
ProveCommitSectors3 => prove_commit_sectors3,
ProveReplicaUpdates3 => prove_replica_updates3,
LockCreateMinerDepositExported => lock_create_miner_deposit,
}
}

Expand Down
63 changes: 3 additions & 60 deletions actors/miner/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,6 @@ pub struct State {
/// Sum of initial pledge requirements of all active sectors.
pub initial_pledge: TokenAmount,

/// amount of create miner depoist and when it should be unlocked.
pub create_miner_deposit: Option<CreateMinerDeposit>,

/// Sectors that have been pre-committed but not yet proven.
/// Map, HAMT<SectorNumber, SectorPreCommitOnChainInfo>
pub pre_committed_sectors: Cid,
Expand Down Expand Up @@ -192,7 +189,6 @@ impl State {
early_terminations: BitField::new(),
deadline_cron_active: false,
pre_committed_sectors_cleanup: empty_precommits_cleanup_array,
create_miner_deposit: None,
})
}

Expand Down Expand Up @@ -761,22 +757,11 @@ impl State {
Ok(())
}

// Return true when the miner actor needs to continue scheduling deadline crons
pub fn continue_deadline_cron_without_create_miner_deposit(&self) -> bool {
!self.pre_commit_deposits.is_zero()
|| !self.initial_pledge.is_zero()
|| !self.locked_funds.is_zero()
}

// Return true when the miner actor needs to continue scheduling deadline crons
pub fn continue_deadline_cron(&self) -> bool {
!self.pre_commit_deposits.is_zero()
|| !self.initial_pledge.is_zero()
|| !self.locked_funds.is_zero()
|| !self
.create_miner_deposit
.as_ref()
.map_or_else(|| true, |deposit| deposit.amount.is_zero())
}

//
Expand Down Expand Up @@ -820,15 +805,6 @@ impl State {
}
}

// Unlocked after 180 days.
pub fn add_create_miner_deposit(&mut self, amount: TokenAmount, curr_epoch: ChainEpoch) {
let deposit = CreateMinerDeposit {
amount,
epoch: (180 * fil_actors_runtime::EPOCHS_IN_DAY) + curr_epoch,
};
self.create_miner_deposit = Some(deposit);
}

/// First vests and unlocks the vested funds AND then locks the given funds in the vesting table.
pub fn add_locked_funds<BS: Blockstore>(
&mut self,
Expand All @@ -854,13 +830,6 @@ impl State {
));
}

// unlock create miner deposit
if let Some(depoist) = &self.create_miner_deposit {
if depoist.epoch <= current_epoch {
self.create_miner_deposit.take();
}
}

// 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 @@ -957,20 +926,12 @@ impl State {
store: &BS,
current_epoch: ChainEpoch,
) -> anyhow::Result<TokenAmount> {
let mut amount_unlocked = TokenAmount::zero();
if let Some(depoist) = &self.create_miner_deposit {
if depoist.epoch <= current_epoch {
amount_unlocked += &depoist.amount;
self.create_miner_deposit.take();
}
}

if self.locked_funds.is_zero() {
return Ok(TokenAmount::zero());
}

let mut vesting_funds = self.load_vesting_funds(store)?;
amount_unlocked += vesting_funds.unlock_vested_funds(current_epoch);
let amount_unlocked = vesting_funds.unlock_vested_funds(current_epoch);
self.locked_funds -= &amount_unlocked;
if self.locked_funds.is_negative() {
return Err(anyhow!(
Expand Down Expand Up @@ -999,13 +960,9 @@ impl State {

/// Unclaimed funds that are not locked -- includes funds used to cover initial pledge requirement.
pub fn get_unlocked_balance(&self, actor_balance: &TokenAmount) -> anyhow::Result<TokenAmount> {
let mut unlocked_balance =
let unlocked_balance =
actor_balance - &self.locked_funds - &self.pre_commit_deposits - &self.initial_pledge;

if let Some(depoist) = &self.create_miner_deposit {
unlocked_balance -= &depoist.amount;
}

if unlocked_balance.is_negative() {
return Err(anyhow!("negative unlocked balance {}", unlocked_balance));
}
Expand Down Expand Up @@ -1036,15 +993,8 @@ impl State {
return Err(anyhow!("fee debt is negative: {}", self.fee_debt));
}

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

if let Some(CreateMinerDeposit { amount, .. }) = &self.create_miner_deposit {
if amount.is_negative() {
return Err(anyhow!("create miner deposit is negative: {}", amount));
}

min_balance += amount;
}
if balance < &min_balance {
return Err(anyhow!("fee debt is negative: {}", self.fee_debt));
}
Expand Down Expand Up @@ -1239,13 +1189,6 @@ impl State {
}
}

#[derive(Serialize_tuple, Deserialize_tuple, Clone, Debug)]
pub struct CreateMinerDeposit {
pub amount: TokenAmount,
/// when to unlock
pub epoch: ChainEpoch,
}

pub struct AdvanceDeadlineResult {
pub pledge_delta: TokenAmount,
pub power_delta: PowerPair,
Expand Down
13 changes: 2 additions & 11 deletions actors/miner/src/testing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,11 +248,6 @@ fn check_miner_balances<BS: Blockstore>(
balance: &TokenAmount,
acc: &MessageAccumulator,
) {
let create_deposit = state
.create_miner_deposit
.as_ref()
.map_or_else(|| TokenAmount::zero(), |deposit| deposit.amount.clone());

acc.require(
!balance.is_negative(),
format!("miner actor balance is less than zero: {balance}"),
Expand All @@ -273,11 +268,7 @@ fn check_miner_balances<BS: Blockstore>(
!state.fee_debt.is_negative(),
format!("miner fee debt is less than zero: {}", state.fee_debt),
);
acc.require(
!create_deposit.is_negative(),
format!("create miner deposit is less than zero: {}", create_deposit),
);
acc.require(!(balance - &state.locked_funds - &state.pre_commit_deposits - &state.initial_pledge - &create_deposit).is_negative(), format!("miner balance {balance} is less than sum of locked funds ({}), precommit deposit ({}), initial pledge ({}) and create miner deposit ({})", state.locked_funds, state.pre_commit_deposits, state.initial_pledge, create_deposit));
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 Expand Up @@ -315,7 +306,7 @@ fn check_miner_balances<BS: Blockstore>(
);

// non zero funds implies that DeadlineCronActive is true
if state.continue_deadline_cron_without_create_miner_deposit() {
if state.continue_deadline_cron() {
acc.require(state.deadline_cron_active, "DeadlineCronActive == false when IP+PCD+LF > 0");
}
}
Expand Down
1 change: 1 addition & 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
12 changes: 1 addition & 11 deletions actors/miner/tests/apply_rewards.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,6 @@ fn funds_vest() {
let rt = h.new_runtime();
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());

// Lock some funds with AddLockedFund
let amt = TokenAmount::from_atto(600_000);
Expand Down Expand Up @@ -115,14 +108,13 @@ fn penalty_is_partially_burnt_and_stored_as_fee_debt() {
let st = h.get_state(&rt);
assert!(st.fee_debt.is_zero());

let amt = rt.get_balance();
let amt = BIG_BALANCE.clone();
let penalty = &amt * 3;
let reward = amt.clone();

// manually update actor balance to include the added funds on reward message
let new_balance = &reward + &amt;
rt.set_balance(new_balance);

rt.set_caller(*REWARD_ACTOR_CODE_ID, REWARD_ACTOR_ADDR);
rt.expect_validate_caller_addr(vec![REWARD_ACTOR_ADDR]);

Expand Down Expand Up @@ -163,8 +155,6 @@ fn rewards_pay_back_fee_debt() {
h.construct_and_verify(&rt);
let mut st = h.get_state(&rt);

assert!(st.locked_funds.is_zero());

let amt = rt.get_balance();
let available_before = h.get_available_balance(&rt).unwrap();
assert!(available_before.is_positive());
Expand Down
4 changes: 2 additions & 2 deletions actors/miner/tests/deadline_cron.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ fn cron_on_inactive_state() {
h.construct_and_verify(&rt);

let st = h.get_state(&rt);
assert_eq!(PERIOD_OFFSET - rt.policy.wpost_proving_period, st.proving_period_start);
assert!(!st.continue_deadline_cron_without_create_miner_deposit());
assert!(!st.continue_deadline_cron());

assert_eq!(PERIOD_OFFSET - rt.policy.wpost_proving_period, st.proving_period_start);
// cron does nothing and does not enroll another cron
let deadline = h.deadline(&rt);
rt.set_epoch(deadline.last());
Expand Down
Loading

0 comments on commit 9e9a059

Please sign in to comment.