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