add fee burning (#4818)
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
use crate::message::Message;
|
||||
use crate::timing::{DEFAULT_NUM_TICKS_PER_SECOND, DEFAULT_TICKS_PER_SLOT};
|
||||
use log::*;
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Debug, Default)]
|
||||
#[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct FeeCalculator {
|
||||
// The current cost of a signature This amount may increase/decrease over time based on
|
||||
@@ -19,6 +20,28 @@ pub struct FeeCalculator {
|
||||
|
||||
pub min_lamports_per_signature: u64,
|
||||
pub max_lamports_per_signature: u64,
|
||||
|
||||
// What portion of collected fees are to be destroyed, percentage-wise
|
||||
pub burn_percent: u8,
|
||||
}
|
||||
|
||||
/// TODO: determine good values for these
|
||||
pub const DEFAULT_TARGET_LAMPORTS_PER_SIGNATURE: u64 = 42;
|
||||
pub const DEFAULT_TARGET_SIGNATURES_PER_SLOT: usize =
|
||||
710_000 * DEFAULT_TICKS_PER_SLOT as usize / DEFAULT_NUM_TICKS_PER_SECOND as usize;
|
||||
pub const DEFAULT_BURN_PERCENT: u8 = 50;
|
||||
|
||||
impl Default for FeeCalculator {
|
||||
fn default() -> Self {
|
||||
FeeCalculator {
|
||||
lamports_per_signature: 0,
|
||||
target_lamports_per_signature: DEFAULT_TARGET_LAMPORTS_PER_SIGNATURE,
|
||||
target_signatures_per_slot: DEFAULT_TARGET_SIGNATURES_PER_SLOT,
|
||||
min_lamports_per_signature: 0,
|
||||
max_lamports_per_signature: 0,
|
||||
burn_percent: DEFAULT_BURN_PERCENT,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FeeCalculator {
|
||||
@@ -26,6 +49,7 @@ impl FeeCalculator {
|
||||
let base_fee_calculator = Self {
|
||||
target_lamports_per_signature,
|
||||
lamports_per_signature: target_lamports_per_signature,
|
||||
target_signatures_per_slot: 0,
|
||||
..FeeCalculator::default()
|
||||
};
|
||||
|
||||
@@ -48,15 +72,14 @@ impl FeeCalculator {
|
||||
me.max_lamports_per_signature = me.target_lamports_per_signature * 10;
|
||||
|
||||
// What the cluster should charge at `latest_signatures_per_slot`
|
||||
let desired_lamports_per_signature = std::cmp::min(
|
||||
me.max_lamports_per_signature,
|
||||
std::cmp::max(
|
||||
me.min_lamports_per_signature,
|
||||
me.target_lamports_per_signature
|
||||
* std::cmp::min(latest_signatures_per_slot, std::u32::MAX as usize) as u64
|
||||
/ me.target_signatures_per_slot as u64,
|
||||
),
|
||||
);
|
||||
let desired_lamports_per_signature =
|
||||
me.max_lamports_per_signature
|
||||
.min(me.min_lamports_per_signature.max(
|
||||
me.target_lamports_per_signature
|
||||
* std::cmp::min(latest_signatures_per_slot, std::u32::MAX as usize)
|
||||
as u64
|
||||
/ me.target_signatures_per_slot as u64,
|
||||
));
|
||||
|
||||
trace!(
|
||||
"desired_lamports_per_signature: {}",
|
||||
@@ -82,13 +105,11 @@ impl FeeCalculator {
|
||||
gap_adjust
|
||||
);
|
||||
|
||||
me.lamports_per_signature = std::cmp::min(
|
||||
me.max_lamports_per_signature,
|
||||
std::cmp::max(
|
||||
me.min_lamports_per_signature,
|
||||
(base_fee_calculator.lamports_per_signature as i64 + gap_adjust) as u64,
|
||||
),
|
||||
);
|
||||
me.lamports_per_signature =
|
||||
me.max_lamports_per_signature
|
||||
.min(me.min_lamports_per_signature.max(
|
||||
(base_fee_calculator.lamports_per_signature as i64 + gap_adjust) as u64,
|
||||
));
|
||||
}
|
||||
} else {
|
||||
me.lamports_per_signature = base_fee_calculator.target_lamports_per_signature;
|
||||
@@ -105,6 +126,11 @@ impl FeeCalculator {
|
||||
pub fn calculate_fee(&self, message: &Message) -> u64 {
|
||||
self.lamports_per_signature * u64::from(message.header.num_required_signatures)
|
||||
}
|
||||
|
||||
/// calculate unburned fee from a fee total
|
||||
pub fn burn(&self, fees: u64) -> u64 {
|
||||
fees * u64::from(100 - self.burn_percent) / 100
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -113,6 +139,19 @@ mod tests {
|
||||
use crate::pubkey::Pubkey;
|
||||
use crate::system_instruction;
|
||||
|
||||
#[test]
|
||||
fn test_fee_calculator_burn() {
|
||||
let mut fee_calculator = FeeCalculator::default();
|
||||
|
||||
assert_eq!(fee_calculator.burn(2), 1);
|
||||
|
||||
fee_calculator.burn_percent = 0;
|
||||
|
||||
assert_eq!(fee_calculator.burn(2), 2);
|
||||
fee_calculator.burn_percent = 100;
|
||||
assert_eq!(fee_calculator.burn(2), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fee_calculator_calculate_fee() {
|
||||
// Default: no fee.
|
||||
@@ -140,18 +179,24 @@ mod tests {
|
||||
fn test_fee_calculator_derived_default() {
|
||||
solana_logger::setup();
|
||||
|
||||
let mut f0 = FeeCalculator::default();
|
||||
assert_eq!(f0.target_signatures_per_slot, 0);
|
||||
assert_eq!(f0.target_lamports_per_signature, 0);
|
||||
let f0 = FeeCalculator::default();
|
||||
assert_eq!(
|
||||
f0.target_signatures_per_slot,
|
||||
DEFAULT_TARGET_SIGNATURES_PER_SLOT
|
||||
);
|
||||
assert_eq!(
|
||||
f0.target_lamports_per_signature,
|
||||
DEFAULT_TARGET_LAMPORTS_PER_SIGNATURE
|
||||
);
|
||||
assert_eq!(f0.lamports_per_signature, 0);
|
||||
f0.target_lamports_per_signature = 42;
|
||||
|
||||
let f1 = FeeCalculator::new_derived(&f0, 4242);
|
||||
assert_eq!(f1.target_signatures_per_slot, 0);
|
||||
let f1 = FeeCalculator::new_derived(&f0, DEFAULT_TARGET_SIGNATURES_PER_SLOT);
|
||||
assert_eq!(
|
||||
f1.target_signatures_per_slot,
|
||||
DEFAULT_TARGET_SIGNATURES_PER_SLOT
|
||||
);
|
||||
assert_eq!(f1.target_lamports_per_signature, 42);
|
||||
assert_eq!(f1.lamports_per_signature, 42);
|
||||
assert_eq!(f1.min_lamports_per_signature, 42);
|
||||
assert_eq!(f1.max_lamports_per_signature, 42);
|
||||
assert_eq!(f1.lamports_per_signature, 21); // min
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -164,27 +209,54 @@ mod tests {
|
||||
f = FeeCalculator::new_derived(&f, 0);
|
||||
|
||||
// Ramp fees up
|
||||
while f.lamports_per_signature < f.max_lamports_per_signature {
|
||||
let mut count = 0;
|
||||
loop {
|
||||
let last_lamports_per_signature = f.lamports_per_signature;
|
||||
|
||||
f = FeeCalculator::new_derived(&f, std::usize::MAX);
|
||||
info!("[up] f.lamports_per_signature={}", f.lamports_per_signature);
|
||||
|
||||
// some maximum target reached
|
||||
if f.lamports_per_signature == last_lamports_per_signature {
|
||||
break;
|
||||
}
|
||||
// shouldn't take more than 1000 steps to get to minimum
|
||||
assert!(count < 1000);
|
||||
count += 1;
|
||||
}
|
||||
|
||||
// Ramp fees down
|
||||
while f.lamports_per_signature > f.min_lamports_per_signature {
|
||||
let mut count = 0;
|
||||
loop {
|
||||
let last_lamports_per_signature = f.lamports_per_signature;
|
||||
f = FeeCalculator::new_derived(&f, 0);
|
||||
|
||||
info!(
|
||||
"[down] f.lamports_per_signature={}",
|
||||
f.lamports_per_signature
|
||||
);
|
||||
|
||||
// some minimum target reached
|
||||
if f.lamports_per_signature == last_lamports_per_signature {
|
||||
break;
|
||||
}
|
||||
|
||||
// shouldn't take more than 1000 steps to get to minimum
|
||||
assert!(count < 1000);
|
||||
count += 1;
|
||||
}
|
||||
|
||||
// Arrive at target rate
|
||||
let mut count = 0;
|
||||
while f.lamports_per_signature != f.target_lamports_per_signature {
|
||||
f = FeeCalculator::new_derived(&f, f.target_signatures_per_slot);
|
||||
info!(
|
||||
"[target] f.lamports_per_signature={}",
|
||||
f.lamports_per_signature
|
||||
);
|
||||
// shouldn't take more than 100 steps to get to target
|
||||
assert!(count < 100);
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -130,16 +130,16 @@ impl Builder {
|
||||
self.genesis_block.ticks_per_slot = ticks_per_slot;
|
||||
self
|
||||
}
|
||||
pub fn poh_config(mut self, poh_config: &PohConfig) -> Self {
|
||||
self.genesis_block.poh_config = poh_config.clone();
|
||||
pub fn poh_config(mut self, poh_config: PohConfig) -> Self {
|
||||
self.genesis_block.poh_config = poh_config;
|
||||
self
|
||||
}
|
||||
pub fn fee_calculator(mut self, fee_calculator: &FeeCalculator) -> Self {
|
||||
self.genesis_block.fee_calculator = fee_calculator.clone();
|
||||
pub fn fee_calculator(mut self, fee_calculator: FeeCalculator) -> Self {
|
||||
self.genesis_block.fee_calculator = fee_calculator;
|
||||
self
|
||||
}
|
||||
pub fn inflation(mut self, inflation: &Inflation) -> Self {
|
||||
self.genesis_block.inflation = inflation.clone();
|
||||
pub fn inflation(mut self, inflation: Inflation) -> Self {
|
||||
self.genesis_block.inflation = inflation;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user