solana/program-runtime/src/prioritization_fee.rs

205 lines
5.8 KiB
Rust

/// There are 10^6 micro-lamports in one lamport
const MICRO_LAMPORTS_PER_LAMPORT: u64 = 1_000_000;
type MicroLamports = u128;
pub enum PrioritizationFeeType {
ComputeUnitPrice(u64),
Deprecated(u64),
}
#[derive(Default, Debug, PartialEq, Eq)]
pub struct PrioritizationFeeDetails {
fee: u64,
priority: u64,
}
impl PrioritizationFeeDetails {
pub fn new(fee_type: PrioritizationFeeType, compute_unit_limit: u64) -> Self {
match fee_type {
PrioritizationFeeType::Deprecated(fee) => {
let priority = if compute_unit_limit == 0 {
0
} else {
let micro_lamport_fee: MicroLamports =
(fee as u128).saturating_mul(MICRO_LAMPORTS_PER_LAMPORT as u128);
let priority = micro_lamport_fee.saturating_div(compute_unit_limit as u128);
u64::try_from(priority).unwrap_or(u64::MAX)
};
Self { fee, priority }
}
PrioritizationFeeType::ComputeUnitPrice(cu_price) => {
let fee = {
let micro_lamport_fee: MicroLamports =
(cu_price as u128).saturating_mul(compute_unit_limit as u128);
let fee = micro_lamport_fee
.saturating_add(MICRO_LAMPORTS_PER_LAMPORT.saturating_sub(1) as u128)
.saturating_div(MICRO_LAMPORTS_PER_LAMPORT as u128);
u64::try_from(fee).unwrap_or(u64::MAX)
};
Self {
fee,
priority: cu_price,
}
}
}
}
pub fn get_fee(&self) -> u64 {
self.fee
}
pub fn get_priority(&self) -> u64 {
self.priority
}
}
#[cfg(test)]
mod test {
use super::{PrioritizationFeeDetails as FeeDetails, PrioritizationFeeType as FeeType, *};
#[test]
fn test_new_with_no_fee() {
for compute_units in [0, 1, MICRO_LAMPORTS_PER_LAMPORT, u64::MAX] {
assert_eq!(
FeeDetails::new(FeeType::ComputeUnitPrice(0), compute_units),
FeeDetails::default(),
);
assert_eq!(
FeeDetails::new(FeeType::Deprecated(0), compute_units),
FeeDetails::default(),
);
}
}
#[test]
fn test_new_with_compute_unit_price() {
assert_eq!(
FeeDetails::new(FeeType::ComputeUnitPrice(MICRO_LAMPORTS_PER_LAMPORT - 1), 1),
FeeDetails {
fee: 1,
priority: MICRO_LAMPORTS_PER_LAMPORT - 1,
},
"should round up (<1.0) lamport fee to 1 lamport"
);
assert_eq!(
FeeDetails::new(FeeType::ComputeUnitPrice(MICRO_LAMPORTS_PER_LAMPORT), 1),
FeeDetails {
fee: 1,
priority: MICRO_LAMPORTS_PER_LAMPORT,
},
);
assert_eq!(
FeeDetails::new(FeeType::ComputeUnitPrice(MICRO_LAMPORTS_PER_LAMPORT + 1), 1),
FeeDetails {
fee: 2,
priority: MICRO_LAMPORTS_PER_LAMPORT + 1,
},
"should round up (>1.0) lamport fee to 2 lamports"
);
assert_eq!(
FeeDetails::new(FeeType::ComputeUnitPrice(200), 100_000),
FeeDetails {
fee: 20,
priority: 200,
},
);
assert_eq!(
FeeDetails::new(
FeeType::ComputeUnitPrice(MICRO_LAMPORTS_PER_LAMPORT),
u64::MAX
),
FeeDetails {
fee: u64::MAX,
priority: MICRO_LAMPORTS_PER_LAMPORT,
},
);
assert_eq!(
FeeDetails::new(FeeType::ComputeUnitPrice(u64::MAX), u64::MAX),
FeeDetails {
fee: u64::MAX,
priority: u64::MAX,
},
);
}
#[test]
fn test_new_with_deprecated_fee() {
assert_eq!(
FeeDetails::new(FeeType::Deprecated(1), MICRO_LAMPORTS_PER_LAMPORT / 2 - 1),
FeeDetails {
fee: 1,
priority: 2,
},
"should round down fee rate of (>2.0) to priority value 1"
);
assert_eq!(
FeeDetails::new(FeeType::Deprecated(1), MICRO_LAMPORTS_PER_LAMPORT / 2),
FeeDetails {
fee: 1,
priority: 2,
},
);
assert_eq!(
FeeDetails::new(FeeType::Deprecated(1), MICRO_LAMPORTS_PER_LAMPORT / 2 + 1),
FeeDetails {
fee: 1,
priority: 1,
},
"should round down fee rate of (<2.0) to priority value 1"
);
assert_eq!(
FeeDetails::new(FeeType::Deprecated(1), MICRO_LAMPORTS_PER_LAMPORT),
FeeDetails {
fee: 1,
priority: 1,
},
);
assert_eq!(
FeeDetails::new(FeeType::Deprecated(42), 42 * MICRO_LAMPORTS_PER_LAMPORT),
FeeDetails {
fee: 42,
priority: 1,
},
);
assert_eq!(
FeeDetails::new(FeeType::Deprecated(420), 42 * MICRO_LAMPORTS_PER_LAMPORT),
FeeDetails {
fee: 420,
priority: 10,
},
);
assert_eq!(
FeeDetails::new(
FeeType::Deprecated(u64::MAX),
2 * MICRO_LAMPORTS_PER_LAMPORT
),
FeeDetails {
fee: u64::MAX,
priority: u64::MAX / 2,
},
);
assert_eq!(
FeeDetails::new(FeeType::Deprecated(u64::MAX), u64::MAX),
FeeDetails {
fee: u64::MAX,
priority: MICRO_LAMPORTS_PER_LAMPORT,
},
);
}
}