Skip to content

Commit

Permalink
feat(miner): no batch fee in PCD & lower batch balancer to 2
Browse files Browse the repository at this point in the history
  • Loading branch information
rvagg committed Jan 14, 2025
1 parent b4ed8cf commit 7a4c822
Show file tree
Hide file tree
Showing 9 changed files with 65 additions and 319 deletions.
13 changes: 0 additions & 13 deletions actors/miner/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1586,19 +1586,6 @@ impl Actor {
let mut fee_to_burn = TokenAmount::zero();
let mut needs_cron = false;
rt.transaction(|state: &mut State, rt| {
// Aggregate fee applies only when batching.
if sectors.len() > 1 {
let aggregate_fee = aggregate_pre_commit_network_fee(sectors.len(), &rt.base_fee());
// AggregateFee applied to fee debt to consolidate burn with outstanding debts
state.apply_penalty(&aggregate_fee)
.map_err(|e| {
actor_error!(
illegal_state,
"failed to apply penalty: {}",
e
)
})?;
}
// available balance already accounts for fee debt so it is correct to call
// this before RepayDebts. We would have to
// subtract fee debt explicitly if we called this after.
Expand Down
10 changes: 1 addition & 9 deletions actors/miner/src/monies.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ pub mod detail {
use super::*;

lazy_static! {
pub static ref BATCH_BALANCER: TokenAmount = TokenAmount::from_nano(5);
pub static ref BATCH_BALANCER: TokenAmount = TokenAmount::from_nano(2);
}

// BR but zero values are clamped at 1 attofil
Expand Down Expand Up @@ -328,7 +328,6 @@ const BATCH_DISCOUNT_DENOM: u32 = 20;

lazy_static! {
static ref ESTIMATED_SINGLE_PROVE_COMMIT_GAS_USAGE: BigInt = BigInt::from(49299973);
static ref ESTIMATED_SINGLE_PRE_COMMIT_GAS_USAGE: BigInt = BigInt::from(16433324);
}

pub fn aggregate_prove_commit_network_fee(
Expand All @@ -338,13 +337,6 @@ pub fn aggregate_prove_commit_network_fee(
aggregate_network_fee(aggregate_size, &ESTIMATED_SINGLE_PROVE_COMMIT_GAS_USAGE, base_fee)
}

pub fn aggregate_pre_commit_network_fee(
aggregate_size: usize,
base_fee: &TokenAmount,
) -> TokenAmount {
aggregate_network_fee(aggregate_size, &ESTIMATED_SINGLE_PRE_COMMIT_GAS_USAGE, base_fee)
}

pub fn aggregate_network_fee(
aggregate_size: usize,
gas_usage: &BigInt,
Expand Down
91 changes: 32 additions & 59 deletions actors/miner/tests/aggregate_network_fee_test.rs
Original file line number Diff line number Diff line change
@@ -1,89 +1,62 @@
use fil_actor_miner::aggregate_prove_commit_network_fee;
use fil_actor_miner::detail::BATCH_BALANCER;
use fil_actor_miner::{aggregate_pre_commit_network_fee, aggregate_prove_commit_network_fee};
use fvm_shared::econ::TokenAmount;
use num_traits::zero;

#[test]
fn constant_fee_per_sector_when_base_fee_is_below_5_nfil() {
for fee_func in [aggregate_prove_commit_network_fee, aggregate_pre_commit_network_fee] {
let one_sector_fee = fee_func(1, &zero());
let ten_sector_fee = fee_func(10, &zero());
assert_eq!(&one_sector_fee * 10, ten_sector_fee);
fn constant_fee_per_sector_when_base_fee_is_below_batch_balancer() {
let one_sector_fee = aggregate_prove_commit_network_fee(1, &zero());
let ten_sector_fee = aggregate_prove_commit_network_fee(10, &zero());
assert_eq!(&one_sector_fee * 10, ten_sector_fee);

let forty_sector_fee = fee_func(40, &TokenAmount::from_nano(1));
assert_eq!(&one_sector_fee * 40, forty_sector_fee);
let forty_sector_fee = aggregate_prove_commit_network_fee(40, &TokenAmount::from_nano(1));
assert_eq!(&one_sector_fee * 40, forty_sector_fee);

let two_hundred_sector_fee = fee_func(200, &TokenAmount::from_nano(3));
assert_eq!(one_sector_fee * 200, two_hundred_sector_fee);
}
let two_hundred_sector_fee =
aggregate_prove_commit_network_fee(200, &TokenAmount::from_nano(2));
assert_eq!(one_sector_fee * 200, two_hundred_sector_fee);
}

#[test]
fn fee_increases_if_basefee_crosses_threshold() {
for fee_func in [aggregate_prove_commit_network_fee, aggregate_pre_commit_network_fee] {
let at_no_base_fee = fee_func(10, &zero());
let at_balance_minus_one_base_fee =
fee_func(10, &(&*BATCH_BALANCER - TokenAmount::from_atto(1)));
let at_balance_base_fee = fee_func(10, &BATCH_BALANCER);
let at_balance_plus_one_base_fee =
fee_func(10, &(&*BATCH_BALANCER + TokenAmount::from_nano(1)));
let at_balance_plus_two_base_fee =
fee_func(10, &(&*BATCH_BALANCER + TokenAmount::from_nano(2)));
let at_balance_times_two_base = fee_func(10, &(2 * &*BATCH_BALANCER));

assert_eq!(at_no_base_fee, at_balance_minus_one_base_fee);
assert_eq!(at_no_base_fee, at_balance_base_fee);
assert!(at_balance_base_fee < at_balance_plus_one_base_fee);
assert!(at_balance_plus_one_base_fee < at_balance_plus_two_base_fee);
assert_eq!(at_balance_times_two_base, 2 * at_balance_base_fee);
}
let at_no_base_fee = aggregate_prove_commit_network_fee(10, &zero());
let at_balance_minus_one_base_fee =
aggregate_prove_commit_network_fee(10, &(&*BATCH_BALANCER - TokenAmount::from_atto(1)));
let at_balance_base_fee = aggregate_prove_commit_network_fee(10, &BATCH_BALANCER);
let at_balance_plus_one_base_fee =
aggregate_prove_commit_network_fee(10, &(&*BATCH_BALANCER + TokenAmount::from_nano(1)));
let at_balance_plus_two_base_fee =
aggregate_prove_commit_network_fee(10, &(&*BATCH_BALANCER + TokenAmount::from_nano(2)));
let at_balance_times_two_base = aggregate_prove_commit_network_fee(10, &(2 * &*BATCH_BALANCER));

assert_eq!(at_no_base_fee, at_balance_minus_one_base_fee);
assert_eq!(at_no_base_fee, at_balance_base_fee);
assert!(at_balance_base_fee < at_balance_plus_one_base_fee);
assert!(at_balance_plus_one_base_fee < at_balance_plus_two_base_fee);
assert_eq!(at_balance_times_two_base, 2 * at_balance_base_fee);
}

#[test]
fn regression_tests() {
let magic_number = 65733297;
let magic_number = 49299973;
let fee = |aggregate_size, base_fee_multiplier| {
aggregate_prove_commit_network_fee(
aggregate_size,
&TokenAmount::from_nano(base_fee_multiplier),
) + aggregate_pre_commit_network_fee(
aggregate_size,
&TokenAmount::from_nano(base_fee_multiplier),
)
};

// (5/20) * x * 10 = (5/2) * x
let expected = (TokenAmount::from_nano(5) * magic_number).div_floor(2);
// Under batch balancer (2), so these two are the same:
// 2/20 * x * 10 = (2/2) * x = x
let expected = TokenAmount::from_nano(magic_number);
assert_eq!(expected, fee(10, 0));
assert_eq!(expected, fee(10, 1));

let expected = TokenAmount::from_nano(25) * magic_number;
// 3/20 * x * 100 = 15 * x
let expected = TokenAmount::from_nano(15) * magic_number;
assert_eq!(expected, fee(100, 3));

// 6/20 * x * 100 = 30 * x
let expected = TokenAmount::from_nano(30) * magic_number;
assert_eq!(expected, fee(100, 6));
}

#[test]
fn split_25_75() {
// check 25/75% split up to uFIL precision
let one_micro_fil = TokenAmount::from_nano(1000);

for base_fee_multiplier in [0, 5, 20] {
for aggregate_size in [13, 303] {
let fee_pre = aggregate_pre_commit_network_fee(
aggregate_size,
&TokenAmount::from_nano(base_fee_multiplier),
)
.atto()
/ one_micro_fil.atto();
let fee_prove = aggregate_prove_commit_network_fee(
aggregate_size,
&TokenAmount::from_nano(base_fee_multiplier),
)
.atto()
/ one_micro_fil.atto();
assert_eq!(fee_prove, 3 * fee_pre);
}
}
}
184 changes: 5 additions & 179 deletions actors/miner/tests/batch_method_network_fees_test.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
use std::collections::HashMap;

use fil_actor_miner::{
aggregate_pre_commit_network_fee, aggregate_prove_commit_network_fee,
pre_commit_deposit_for_power, qa_power_max, PreCommitSectorBatchParams, State,
aggregate_prove_commit_network_fee, pre_commit_deposit_for_power, qa_power_max,
PreCommitSectorBatchParams, State,
};
use fil_actors_runtime::test_utils::{expect_abort, expect_abort_contains_message};
use fil_actors_runtime::test_utils::expect_abort;
use fvm_ipld_bitfield::BitField;
use fvm_shared::{clock::ChainEpoch, econ::TokenAmount, error::ExitCode};
use lazy_static::lazy_static;
Expand Down Expand Up @@ -67,166 +65,6 @@ fn insufficient_funds_for_aggregated_prove_commit_network_fee() {
rt.reset();
}

#[test]
fn insufficient_funds_for_batch_precommit_network_fee() {
let actor = ActorHarness::new(*PERIOD_OFFSET);
let rt = actor.new_runtime();
rt.set_balance(BIG_BALANCE.clone());
let precommit_epoch = *PERIOD_OFFSET + 1;
rt.set_epoch(precommit_epoch);
actor.construct_and_verify(&rt);
let dl_info = actor.deadline(&rt);
// something on deadline boundary but > 180 days
let expiration =
dl_info.period_end() + rt.policy.wpost_proving_period * DEFAULT_SECTOR_EXPIRATION as i64;

let mut precommits = Vec::new();
let mut sector_nos_bf = BitField::new();
for i in 0..4 {
sector_nos_bf.set(i);
let precommit = actor.make_pre_commit_params(i, precommit_epoch - 1, expiration, vec![]);
precommits.push(precommit);
}

// set base fee extremely high so AggregateProveCommitNetworkFee is > 1000 FIL. Set balance to 1000 FIL to easily cover PCD but not network fee
let balance = TokenAmount::from_whole(1000);
rt.set_balance(balance.clone());
let base_fee = TokenAmount::from_atto(10u64.pow(16));
rt.base_fee.replace(base_fee.clone());
assert!(aggregate_pre_commit_network_fee(precommits.len(), &base_fee) > balance);

let res = actor.pre_commit_sector_batch(
&rt,
PreCommitSectorBatchParams { sectors: precommits },
&PreCommitBatchConfig { first_for_miner: true, ..Default::default() },
&base_fee,
);

// state untouched
let state: State = rt.get_state();
assert!(state.pre_commit_deposits.is_zero());
let expirations = actor.collect_precommit_expirations(&rt, &state);
assert_eq!(HashMap::new(), expirations);

expect_abort_contains_message(
ExitCode::USR_INSUFFICIENT_FUNDS,
"unlocked balance can not repay fee debt",
res,
);
rt.reset();
}

#[test]
fn insufficient_funds_for_batch_precommit_in_combination_of_fee_debt_and_network_fee() {
let actor = ActorHarness::new(*PERIOD_OFFSET);
let rt = actor.new_runtime();
rt.set_balance(BIG_BALANCE.clone());
let precommit_epoch = *PERIOD_OFFSET + 1;
rt.set_epoch(precommit_epoch);
actor.construct_and_verify(&rt);
let dl_info = actor.deadline(&rt);
// something on deadline boundary but > 180 days
let expiration =
dl_info.period_end() + rt.policy.wpost_proving_period * DEFAULT_SECTOR_EXPIRATION as i64;

let mut precommits = Vec::new();
let mut sector_nos_bf = BitField::new();
for i in 0..4 {
sector_nos_bf.set(i);
let precommit = actor.make_pre_commit_params(i, precommit_epoch - 1, expiration, vec![]);
precommits.push(precommit);
}

// set base fee extremely high so AggregateProveCommitNetworkFee is > 1000 FIL. Set balance to 1000 FIL to easily cover PCD but not network fee
let base_fee = TokenAmount::from_atto(10u64.pow(16));
rt.base_fee.replace(base_fee.clone());
let net_fee = aggregate_pre_commit_network_fee(precommits.len(), &base_fee);

// setup miner to have fee debt equal to net fee
let mut state: State = rt.get_state();
state.fee_debt = net_fee.clone();
rt.replace_state(&state);

// give miner almost enough balance to pay both
let balance = (2 * net_fee) - TokenAmount::from_atto(1);
rt.set_balance(balance);

let res = actor.pre_commit_sector_batch(
&rt,
PreCommitSectorBatchParams { sectors: precommits },
&PreCommitBatchConfig { first_for_miner: true, ..Default::default() },
&base_fee,
);

// state untouched
let state: State = rt.get_state();
assert!(state.pre_commit_deposits.is_zero());
let expirations = actor.collect_precommit_expirations(&rt, &state);
assert_eq!(HashMap::new(), expirations);

expect_abort_contains_message(
ExitCode::USR_INSUFFICIENT_FUNDS,
"unlocked balance can not repay fee debt",
res,
);
rt.reset();
}

#[test]
fn enough_funds_for_fee_debt_and_network_fee_but_not_for_pcd() {
let actor = ActorHarness::new(*PERIOD_OFFSET);
let rt = actor.new_runtime();
rt.set_balance(BIG_BALANCE.clone());
let precommit_epoch = *PERIOD_OFFSET + 1;
rt.set_epoch(precommit_epoch);
actor.construct_and_verify(&rt);
let dl_info = actor.deadline(&rt);
// something on deadline boundary but > 180 days
let expiration =
dl_info.period_end() + rt.policy.wpost_proving_period * DEFAULT_SECTOR_EXPIRATION as i64;

let mut precommits = Vec::new();
let mut sector_nos_bf = BitField::new();
for i in 0..4 {
sector_nos_bf.set(i);
let precommit = actor.make_pre_commit_params(i, precommit_epoch - 1, expiration, vec![]);
precommits.push(precommit);
}

// set base fee and fee debt high
let base_fee = TokenAmount::from_atto(10u64.pow(16));
rt.base_fee.replace(base_fee.clone());
let net_fee = aggregate_pre_commit_network_fee(precommits.len(), &base_fee);
// setup miner to have feed debt equal to net fee
let mut state: State = rt.get_state();
state.fee_debt = net_fee.clone();
rt.replace_state(&state);

// give miner enough balance to pay both but not any extra for pcd
let balance = 2 * net_fee;
rt.set_balance(balance);

let res = actor.pre_commit_sector_batch(
&rt,
PreCommitSectorBatchParams { sectors: precommits },
&PreCommitBatchConfig { first_for_miner: true, ..Default::default() },
&base_fee,
);

expect_abort_contains_message(
ExitCode::USR_INSUFFICIENT_FUNDS,
"insufficient funds 0.0 for pre-commit deposit",
res,
);
rt.reset();

// state untouched
let state: State = rt.get_state();
assert!(state.pre_commit_deposits.is_zero());
let expirations = actor.collect_precommit_expirations(&rt, &state);
assert_eq!(HashMap::new(), expirations);
}

#[test]
fn enough_funds_for_everything() {
let actor = ActorHarness::new(*PERIOD_OFFSET);
Expand All @@ -248,32 +86,20 @@ fn enough_funds_for_everything() {
precommits.push(precommit);
}

// set base fee extremely high so AggregateProveCommitNetworkFee is > 1000 FIL. Set balance to 1000 FIL to easily cover PCD but not network fee
let base_fee = TokenAmount::from_atto(10u64.pow(16));
rt.base_fee.replace(base_fee.clone());
let net_fee = aggregate_pre_commit_network_fee(precommits.len(), &base_fee);

// setup miner to have fee debt equal to net fee
let mut state: State = rt.get_state();
state.fee_debt = net_fee.clone();
rt.replace_state(&state);

// give miner enough balance to pay both and pcd
let mut balance = 2 * net_fee;
// give miner enough balance to pay pcd
let expected_deposit = pre_commit_deposit_for_power(
&actor.epoch_reward_smooth,
&actor.epoch_qa_power_smooth,
&qa_power_max(actor.sector_size),
) * precommits.len();
balance += expected_deposit.clone();
let balance = expected_deposit.clone();
rt.set_balance(balance);

actor
.pre_commit_sector_batch(
&rt,
PreCommitSectorBatchParams { sectors: precommits },
&PreCommitBatchConfig { first_for_miner: true, ..Default::default() },
&base_fee,
)
.unwrap();

Expand Down
Loading

0 comments on commit 7a4c822

Please sign in to comment.