Skip to main content

solana_program_runtime/
prioritization_fee.rs

1/// There are 10^6 micro-lamports in one lamport
2const MICRO_LAMPORTS_PER_LAMPORT: u64 = 1_000_000;
3
4type MicroLamports = u128;
5
6pub enum PrioritizationFeeType {
7    ComputeUnitPrice(u64),
8    Deprecated(u64),
9}
10
11#[derive(Default, Debug, PartialEq, Eq)]
12pub struct PrioritizationFeeDetails {
13    fee: u64,
14    priority: u64,
15}
16
17impl PrioritizationFeeDetails {
18    pub fn new(fee_type: PrioritizationFeeType, compute_unit_limit: u64) -> Self {
19        match fee_type {
20            PrioritizationFeeType::Deprecated(fee) => {
21                let priority = if compute_unit_limit == 0 {
22                    0
23                } else {
24                    let micro_lamport_fee: MicroLamports =
25                        (fee as u128).saturating_mul(MICRO_LAMPORTS_PER_LAMPORT as u128);
26                    let priority = micro_lamport_fee.saturating_div(compute_unit_limit as u128);
27                    u64::try_from(priority).unwrap_or(u64::MAX)
28                };
29
30                Self { fee, priority }
31            }
32            PrioritizationFeeType::ComputeUnitPrice(cu_price) => {
33                let fee = {
34                    let micro_lamport_fee: MicroLamports =
35                        (cu_price as u128).saturating_mul(compute_unit_limit as u128);
36                    let fee = micro_lamport_fee
37                        .saturating_add(MICRO_LAMPORTS_PER_LAMPORT.saturating_sub(1) as u128)
38                        .saturating_div(MICRO_LAMPORTS_PER_LAMPORT as u128);
39                    u64::try_from(fee).unwrap_or(u64::MAX)
40                };
41
42                Self {
43                    fee,
44                    priority: cu_price,
45                }
46            }
47        }
48    }
49
50    pub fn get_fee(&self) -> u64 {
51        self.fee
52    }
53
54    pub fn get_priority(&self) -> u64 {
55        self.priority
56    }
57}
58
59#[cfg(test)]
60mod test {
61    use super::{PrioritizationFeeDetails as FeeDetails, PrioritizationFeeType as FeeType, *};
62
63    #[test]
64    fn test_new_with_no_fee() {
65        for compute_units in [0, 1, MICRO_LAMPORTS_PER_LAMPORT, u64::MAX] {
66            assert_eq!(
67                FeeDetails::new(FeeType::ComputeUnitPrice(0), compute_units),
68                FeeDetails::default(),
69            );
70            assert_eq!(
71                FeeDetails::new(FeeType::Deprecated(0), compute_units),
72                FeeDetails::default(),
73            );
74        }
75    }
76
77    #[test]
78    fn test_new_with_compute_unit_price() {
79        assert_eq!(
80            FeeDetails::new(FeeType::ComputeUnitPrice(MICRO_LAMPORTS_PER_LAMPORT - 1), 1),
81            FeeDetails {
82                fee: 1,
83                priority: MICRO_LAMPORTS_PER_LAMPORT - 1,
84            },
85            "should round up (<1.0) lamport fee to 1 lamport"
86        );
87
88        assert_eq!(
89            FeeDetails::new(FeeType::ComputeUnitPrice(MICRO_LAMPORTS_PER_LAMPORT), 1),
90            FeeDetails {
91                fee: 1,
92                priority: MICRO_LAMPORTS_PER_LAMPORT,
93            },
94        );
95
96        assert_eq!(
97            FeeDetails::new(FeeType::ComputeUnitPrice(MICRO_LAMPORTS_PER_LAMPORT + 1), 1),
98            FeeDetails {
99                fee: 2,
100                priority: MICRO_LAMPORTS_PER_LAMPORT + 1,
101            },
102            "should round up (>1.0) lamport fee to 2 lamports"
103        );
104
105        assert_eq!(
106            FeeDetails::new(FeeType::ComputeUnitPrice(200), 100_000),
107            FeeDetails {
108                fee: 20,
109                priority: 200,
110            },
111        );
112
113        assert_eq!(
114            FeeDetails::new(
115                FeeType::ComputeUnitPrice(MICRO_LAMPORTS_PER_LAMPORT),
116                u64::MAX
117            ),
118            FeeDetails {
119                fee: u64::MAX,
120                priority: MICRO_LAMPORTS_PER_LAMPORT,
121            },
122        );
123
124        assert_eq!(
125            FeeDetails::new(FeeType::ComputeUnitPrice(u64::MAX), u64::MAX),
126            FeeDetails {
127                fee: u64::MAX,
128                priority: u64::MAX,
129            },
130        );
131    }
132
133    #[test]
134    fn test_new_with_deprecated_fee() {
135        assert_eq!(
136            FeeDetails::new(FeeType::Deprecated(1), MICRO_LAMPORTS_PER_LAMPORT / 2 - 1),
137            FeeDetails {
138                fee: 1,
139                priority: 2,
140            },
141            "should round down fee rate of (>2.0) to priority value 1"
142        );
143
144        assert_eq!(
145            FeeDetails::new(FeeType::Deprecated(1), MICRO_LAMPORTS_PER_LAMPORT / 2),
146            FeeDetails {
147                fee: 1,
148                priority: 2,
149            },
150        );
151
152        assert_eq!(
153            FeeDetails::new(FeeType::Deprecated(1), MICRO_LAMPORTS_PER_LAMPORT / 2 + 1),
154            FeeDetails {
155                fee: 1,
156                priority: 1,
157            },
158            "should round down fee rate of (<2.0) to priority value 1"
159        );
160
161        assert_eq!(
162            FeeDetails::new(FeeType::Deprecated(1), MICRO_LAMPORTS_PER_LAMPORT),
163            FeeDetails {
164                fee: 1,
165                priority: 1,
166            },
167        );
168
169        assert_eq!(
170            FeeDetails::new(FeeType::Deprecated(42), 42 * MICRO_LAMPORTS_PER_LAMPORT),
171            FeeDetails {
172                fee: 42,
173                priority: 1,
174            },
175        );
176
177        assert_eq!(
178            FeeDetails::new(FeeType::Deprecated(420), 42 * MICRO_LAMPORTS_PER_LAMPORT),
179            FeeDetails {
180                fee: 420,
181                priority: 10,
182            },
183        );
184
185        assert_eq!(
186            FeeDetails::new(
187                FeeType::Deprecated(u64::MAX),
188                2 * MICRO_LAMPORTS_PER_LAMPORT
189            ),
190            FeeDetails {
191                fee: u64::MAX,
192                priority: u64::MAX / 2,
193            },
194        );
195
196        assert_eq!(
197            FeeDetails::new(FeeType::Deprecated(u64::MAX), u64::MAX),
198            FeeDetails {
199                fee: u64::MAX,
200                priority: MICRO_LAMPORTS_PER_LAMPORT,
201            },
202        );
203    }
204}