monero_interface/
provides_fee_rates.rs1use core::future::Future;
2use alloc::vec::Vec;
3use std_shims::io;
4
5use zeroize::Zeroize;
6
7use monero_oxide::io::read_u64;
8
9use crate::InterfaceError;
10
11#[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)]
15pub enum FeePriority {
16 Unimportant,
18 Normal,
20 Elevated,
22 Priority,
24 Custom {
26 priority: u32,
28 },
29}
30
31impl FeePriority {
34 pub fn to_u32(&self) -> u32 {
36 match self {
37 FeePriority::Unimportant => 1,
38 FeePriority::Normal => 2,
39 FeePriority::Elevated => 3,
40 FeePriority::Priority => 4,
41 FeePriority::Custom { priority, .. } => *priority,
42 }
43 }
44}
45
46#[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)]
50pub struct FeeRate {
51 per_weight: u64,
53 mask: u64,
55}
56
57impl FeeRate {
58 pub fn new(per_weight: u64, mask: u64) -> Option<FeeRate> {
62 if (per_weight == 0) || (mask == 0) {
63 None?;
64 }
65 Some(FeeRate { per_weight, mask })
66 }
67
68 pub fn write(&self, w: &mut impl io::Write) -> io::Result<()> {
73 w.write_all(&self.per_weight.to_le_bytes())?;
74 w.write_all(&self.mask.to_le_bytes())
75 }
76
77 pub fn serialize(&self) -> Vec<u8> {
82 let mut res = Vec::with_capacity(16);
83 self.write(&mut res).expect("write failed but <Vec as io::Write> doesn't fail");
84 res
85 }
86
87 pub fn per_weight(&self) -> u64 {
89 self.per_weight
90 }
91
92 pub fn read(r: &mut impl io::Read) -> io::Result<FeeRate> {
97 let per_weight = read_u64(r)?;
98 let mask = read_u64(r)?;
99 FeeRate::new(per_weight, mask).ok_or_else(|| io::Error::other("fee rate was invalid"))
100 }
101
102 pub fn calculate_fee_from_weight(&self, weight: usize) -> u64 {
106 let fee =
107 self.per_weight * u64::try_from(weight).expect("couldn't convert weight (usize) to u64");
108 fee.div_ceil(self.mask) * self.mask
109 }
110
111 pub fn calculate_weight_from_fee(&self, fee: u64) -> Option<usize> {
115 usize::try_from(fee / self.per_weight).ok()
116 }
117}
118
119#[derive(Clone, PartialEq, Eq, Debug, thiserror::Error)]
121pub enum FeeError {
122 #[error("interface error ({0})")]
124 InterfaceError(InterfaceError),
125 #[error("invalid fee")]
127 InvalidFee,
128 #[error("invalid fee priority")]
130 InvalidFeePriority,
131}
132
133impl From<InterfaceError> for FeeError {
134 fn from(err: InterfaceError) -> Self {
135 Self::InterfaceError(err)
136 }
137}
138
139pub trait ProvidesUnvalidatedFeeRates: Sync {
141 fn fee_rate(
147 &self,
148 priority: FeePriority,
149 ) -> impl Send + Future<Output = Result<FeeRate, FeeError>>;
150}
151
152pub trait ProvidesFeeRates: Sync {
154 fn fee_rate(
158 &self,
159 priority: FeePriority,
160 max_per_weight: u64,
161 ) -> impl Send + Future<Output = Result<FeeRate, FeeError>>;
162}
163
164impl<P: ProvidesUnvalidatedFeeRates> ProvidesFeeRates for P {
165 fn fee_rate(
166 &self,
167 priority: FeePriority,
168 max_per_weight: u64,
169 ) -> impl Send + Future<Output = Result<FeeRate, FeeError>> {
170 async move {
171 let fee_rate = <P as ProvidesUnvalidatedFeeRates>::fee_rate(self, priority).await?;
172 if fee_rate.per_weight > max_per_weight {
173 Err(FeeError::InvalidFee)?;
174 }
175 Ok(fee_rate)
176 }
177 }
178}