mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-08 12:19:24 +00:00
Add dedicated error for when amounts aren't representable within a u64
Fixes the issue where _inputs_ could still overflow u64::MAX and cause a panic.
This commit is contained in:
@@ -177,6 +177,17 @@ pub enum SendError {
|
|||||||
/// The created transaction was too large.
|
/// The created transaction was too large.
|
||||||
#[cfg_attr(feature = "std", error("too large of a transaction"))]
|
#[cfg_attr(feature = "std", error("too large of a transaction"))]
|
||||||
TooLargeTransaction,
|
TooLargeTransaction,
|
||||||
|
/// The transactions' amounts could not be represented within a `u64`.
|
||||||
|
#[cfg_attr(
|
||||||
|
feature = "std",
|
||||||
|
error("transaction amounts exceed u64::MAX (in {in_amount}, out {out_amount})")
|
||||||
|
)]
|
||||||
|
AmountsUnrepresentable {
|
||||||
|
/// The amount in (via inputs).
|
||||||
|
in_amount: u128,
|
||||||
|
/// The amount which would be out (between outputs and the fee).
|
||||||
|
out_amount: u128,
|
||||||
|
},
|
||||||
/// This transaction could not pay for itself.
|
/// This transaction could not pay for itself.
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "std",
|
feature = "std",
|
||||||
@@ -300,24 +311,35 @@ impl SignableTransaction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Make sure we have enough funds
|
// Make sure we have enough funds
|
||||||
let in_amount = self.inputs.iter().map(|input| input.commitment().amount).sum::<u64>();
|
let weight;
|
||||||
let payments_amount = self
|
{
|
||||||
|
let in_amount: u128 =
|
||||||
|
self.inputs.iter().map(|input| u128::from(input.commitment().amount)).sum();
|
||||||
|
let payments_amount: u128 = self
|
||||||
.payments
|
.payments
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|payment| match payment {
|
.filter_map(|payment| match payment {
|
||||||
InternalPayment::Payment(_, amount) => Some(*amount),
|
InternalPayment::Payment(_, amount) => Some(u128::from(*amount)),
|
||||||
InternalPayment::Change(_) => None,
|
InternalPayment::Change(_) => None,
|
||||||
})
|
})
|
||||||
.try_fold(0, u64::checked_add);
|
.sum();
|
||||||
let payments_amount = payments_amount.ok_or(SendError::TooManyOutputs)?;
|
let necessary_fee;
|
||||||
let (weight, necessary_fee) = self.weight_and_necessary_fee();
|
(weight, necessary_fee) = self.weight_and_necessary_fee();
|
||||||
if payments_amount.checked_add(necessary_fee).is_none_or(|total_out| in_amount < total_out) {
|
let out_amount = payments_amount + u128::from(necessary_fee);
|
||||||
|
let in_out_amount = u64::try_from(in_amount)
|
||||||
|
.and_then(|in_amount| u64::try_from(out_amount).map(|out_amount| (in_amount, out_amount)));
|
||||||
|
let Ok((in_amount, out_amount)) = in_out_amount else {
|
||||||
|
Err(SendError::AmountsUnrepresentable { in_amount, out_amount })?
|
||||||
|
};
|
||||||
|
if in_amount < out_amount {
|
||||||
Err(SendError::NotEnoughFunds {
|
Err(SendError::NotEnoughFunds {
|
||||||
inputs: in_amount,
|
inputs: in_amount,
|
||||||
outputs: payments_amount,
|
outputs: u64::try_from(payments_amount)
|
||||||
|
.expect("total out fit within u64 but not part of total out"),
|
||||||
necessary_fee: Some(necessary_fee),
|
necessary_fee: Some(necessary_fee),
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// The limit is half the no-penalty block size
|
// The limit is half the no-penalty block size
|
||||||
// https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454
|
// https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454
|
||||||
|
|||||||
@@ -390,6 +390,8 @@ impl Monero {
|
|||||||
MakeSignableTransactionResult::SignableTransaction(signable)
|
MakeSignableTransactionResult::SignableTransaction(signable)
|
||||||
}
|
}
|
||||||
})),
|
})),
|
||||||
|
// AmountsUnrepresentable is unreachable on Monero without 100% of the supply before tail
|
||||||
|
// emission or fundamental corruption
|
||||||
Err(e) => match e {
|
Err(e) => match e {
|
||||||
SendError::UnsupportedRctType => {
|
SendError::UnsupportedRctType => {
|
||||||
panic!("trying to use an RctType unsupported by monero-wallet")
|
panic!("trying to use an RctType unsupported by monero-wallet")
|
||||||
@@ -398,6 +400,7 @@ impl Monero {
|
|||||||
SendError::InvalidDecoyQuantity |
|
SendError::InvalidDecoyQuantity |
|
||||||
SendError::NoOutputs |
|
SendError::NoOutputs |
|
||||||
SendError::TooManyOutputs |
|
SendError::TooManyOutputs |
|
||||||
|
SendError::AmountsUnrepresentable { .. } |
|
||||||
SendError::NoChange |
|
SendError::NoChange |
|
||||||
SendError::TooMuchArbitraryData |
|
SendError::TooMuchArbitraryData |
|
||||||
SendError::TooLargeTransaction |
|
SendError::TooLargeTransaction |
|
||||||
|
|||||||
Reference in New Issue
Block a user