Skip to content

Commit 59445da

Browse files
committed
common: Introduce DisplayAmount
Introduce a version of `DecimalAmount` that has equality comparison so it can be easily used in error types. See doc comments for more details.
1 parent 249040f commit 59445da

File tree

3 files changed

+82
-10
lines changed

3 files changed

+82
-10
lines changed

common/src/primitives/decimal_amount.rs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,70 @@ pub enum ParseError {
188188
IntParse(#[from] std::num::ParseIntError),
189189
}
190190

191+
/// Just like [DecimalAmount] but useful in error types, picking a different set of trade-offs.
192+
///
193+
/// While [DecimalAmount] is intended to be used as a type to serialize/deserialize amounts to/from
194+
/// a string, [DisplayAmount] is for printing only. It has an equality comparison (comparing the
195+
/// string representation). To prevent the result of the comparison from affecting subsequent
196+
/// [Amount] calculations, there is no easy way of converting `DisplayAmount` to `Amount`.
197+
///
198+
/// To further encourage debuggability, we only provide the `from_amount_full` constructor for
199+
/// converting from `Amount` while `from_amount_minimal` is omitted. The full variant keeps all the
200+
/// trailing zeros, making it possible to see the amount both in coin/token units and in atoms.
201+
///
202+
/// This is most useful in error types where we want to display the amount and subsequently compare
203+
/// the errors for equality in tests.
204+
#[derive(Clone, Copy)]
205+
pub struct DisplayAmount(DecimalAmount);
206+
207+
impl DisplayAmount {
208+
/// Convert from [DecimalAmount]
209+
pub const fn from_decimal_amount(value: DecimalAmount) -> Self {
210+
Self(value)
211+
}
212+
213+
/// Convert from integer with no decimals
214+
pub const fn from_uint_integral(number: u128) -> Self {
215+
Self(DecimalAmount::from_uint_integral(number))
216+
}
217+
218+
/// Convert from integer, interpreting the last N digits as the fractional part
219+
pub const fn from_uint_decimal(mantissa: UnsignedIntType, decimals: u8) -> Self {
220+
Self(DecimalAmount::from_uint_decimal(mantissa, decimals))
221+
}
222+
223+
/// Convert from [Amount], keeping all decimal digits
224+
pub const fn from_amount_full(amount: Amount, decimals: u8) -> Self {
225+
Self(DecimalAmount::from_amount_full(amount, decimals))
226+
}
227+
}
228+
229+
impl std::cmp::PartialEq for DisplayAmount {
230+
fn eq(&self, other: &Self) -> bool {
231+
self.0.is_same(&other.0)
232+
}
233+
}
234+
235+
impl std::cmp::Eq for DisplayAmount {}
236+
237+
impl From<DecimalAmount> for DisplayAmount {
238+
fn from(value: DecimalAmount) -> Self {
239+
Self::from_decimal_amount(value)
240+
}
241+
}
242+
243+
impl std::fmt::Display for DisplayAmount {
244+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
245+
self.0.fmt(f)
246+
}
247+
}
248+
249+
impl std::fmt::Debug for DisplayAmount {
250+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
251+
self.0.fmt(f)
252+
}
253+
}
254+
191255
#[cfg(test)]
192256
mod test {
193257
use super::*;

mempool/src/error/mod.rs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use thiserror::Error;
2222

2323
use common::{
2424
chain::{GenBlock, Transaction},
25-
primitives::{Id, H256},
25+
primitives::{decimal_amount::DisplayAmount, Id, H256},
2626
};
2727

2828
use crate::pool::fee::Fee;
@@ -77,12 +77,18 @@ pub enum MempoolPolicyError {
7777
TransactionFeeLowerThanConflictsWithDescendants,
7878
#[error("Underflow in computing transaction's additional fees.")]
7979
AdditionalFeesUnderflow,
80-
#[error("Transaction does not pay sufficient fees to be relayed (tx_fee: {tx_fee:?}, min_relay_fee: {min_relay_fee:?}).")]
81-
InsufficientFeesToRelay { tx_fee: Fee, min_relay_fee: Fee },
80+
#[error("Transaction does not pay sufficient fees to be relayed (tx_fee: {tx_fee}, min_relay_fee: {min_relay_fee}).")]
81+
InsufficientFeesToRelay {
82+
tx_fee: DisplayAmount,
83+
min_relay_fee: DisplayAmount,
84+
},
8285
#[error("Replacement transaction does not pay enough for its bandwidth.")]
8386
InsufficientFeesToRelayRBF,
84-
#[error("Rolling fee threshold not met.")]
85-
RollingFeeThresholdNotMet { minimum_fee: Fee, tx_fee: Fee },
87+
#[error("Rolling fee threshold not met (fee is {tx_fee}, minimum {minimum_fee}).")]
88+
RollingFeeThresholdNotMet {
89+
minimum_fee: DisplayAmount,
90+
tx_fee: DisplayAmount,
91+
},
8692
#[error("Overflow encountered while computing fee with ancestors")]
8793
AncestorFeeOverflow,
8894
#[error("Overflow encountered while updating ancestor fee.")]

mempool/src/pool/mod.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ use common::{
3535
block::timestamp::BlockTimestamp, Block, ChainConfig, GenBlock, SignedTransaction,
3636
Transaction,
3737
},
38-
primitives::{amount::Amount, time::Time, BlockHeight, Id},
38+
primitives::{amount::Amount, decimal_amount::DisplayAmount, time::Time, BlockHeight, Id},
3939
time_getter::TimeGetter,
4040
};
4141
use logging::log;
@@ -529,14 +529,15 @@ impl<M: MemoryUsageEstimator> Mempool<M> {
529529
}
530530

531531
fn pays_minimum_mempool_fee(&self, tx: &TxEntryWithFee) -> Result<(), MempoolPolicyError> {
532+
let decimals = self.chain_config.coin_decimals();
532533
let tx_fee = tx.fee();
533534
let minimum_fee = self.get_update_minimum_mempool_fee(tx.transaction())?;
534535
log::debug!("pays_minimum_mempool_fee tx_fee = {tx_fee:?}, minimum_fee = {minimum_fee:?}");
535536
ensure!(
536537
tx_fee >= minimum_fee,
537538
MempoolPolicyError::RollingFeeThresholdNotMet {
538-
minimum_fee,
539-
tx_fee,
539+
minimum_fee: DisplayAmount::from_amount_full(minimum_fee.into(), decimals),
540+
tx_fee: DisplayAmount::from_amount_full(tx_fee.into(), decimals),
540541
}
541542
);
542543
Ok(())
@@ -558,14 +559,15 @@ impl<M: MemoryUsageEstimator> Mempool<M> {
558559
}
559560

560561
fn pays_minimum_relay_fees(&self, tx: &TxEntryWithFee) -> Result<(), MempoolPolicyError> {
562+
let decimals = self.chain_config.coin_decimals();
561563
let tx_fee = tx.fee();
562564
let min_relay_fee = self.get_minimum_relay_fee(tx.transaction())?;
563565
log::debug!("tx_fee: {:?}, min_relay_fee: {:?}", tx_fee, min_relay_fee);
564566
ensure!(
565567
tx_fee >= min_relay_fee,
566568
MempoolPolicyError::InsufficientFeesToRelay {
567-
tx_fee,
568-
min_relay_fee
569+
tx_fee: DisplayAmount::from_amount_full(tx_fee.into(), decimals),
570+
min_relay_fee: DisplayAmount::from_amount_full(min_relay_fee.into(), decimals),
569571
}
570572
);
571573
Ok(())

0 commit comments

Comments
 (0)