From a9e65f36d3bfdc85176aeed4ce89627b24f6efc2 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Tue, 6 Aug 2019 10:32:51 -0400 Subject: [PATCH] Check that the amount precision isn't more than the size of the amount --- src/util/amount.rs | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/util/amount.rs b/src/util/amount.rs index b0d00de9..9dbb4e9b 100644 --- a/src/util/amount.rs +++ b/src/util/amount.rs @@ -129,6 +129,11 @@ impl error::Error for ParseAmountError { } } + +fn is_too_precise(s: &str, precision: usize) -> bool { + s.contains(".") || precision >= s.len() || s.chars().rev().take(precision).any(|d| d != '0') +} + /// Parse decimal string in the given denomination into a satoshi value and a /// bool indicator for a negative amount. fn parse_signed_to_satoshi( @@ -142,8 +147,8 @@ fn parse_signed_to_satoshi( return Err(ParseAmountError::InputTooLarge); } - let negative = s.chars().next().unwrap() == '-'; - if negative { + let is_negative = s.chars().next().unwrap() == '-'; + if is_negative { if s.len() == 1 { return Err(ParseAmountError::InvalidFormat); } @@ -160,7 +165,7 @@ fn parse_signed_to_satoshi( // there are no decimals and the last digits are zeroes as // many as the difference in precision. let last_n = precision_diff.abs() as usize; - if s.contains(".") || s.chars().rev().take(last_n).any(|d| d != '0') { + if is_too_precise(s, last_n) { return Err(ParseAmountError::TooPrecise); } s = &s[0..s.len() - last_n]; @@ -208,7 +213,7 @@ fn parse_signed_to_satoshi( }; } - Ok((negative, value)) + Ok((is_negative, value)) } /// Format the given satoshi amount in the given denomination. @@ -1208,6 +1213,15 @@ mod tests { assert_eq!(sp("-200000000000 BTC"), Err(E::TooBig)); assert_eq!(p("18446744073709551616 sat"), Err(E::TooBig)); + assert_eq!(sp("0 msat"), Err(E::TooPrecise)); + assert_eq!(sp("-0 msat"), Err(E::TooPrecise)); + assert_eq!(sp("000 msat"), Err(E::TooPrecise)); + assert_eq!(sp("-000 msat"), Err(E::TooPrecise)); + assert_eq!(p("0 msat"), Err(E::TooPrecise)); + assert_eq!(p("-0 msat"), Err(E::TooPrecise)); + assert_eq!(p("000 msat"), Err(E::TooPrecise)); + assert_eq!(p("-000 msat"), Err(E::TooPrecise)); + assert_eq!(p(".5 bits"), Ok(Amount::from_sat(50))); assert_eq!(sp("-.5 bits"), Ok(SignedAmount::from_sat(-50))); assert_eq!(p("0.00253583 BTC"), Ok(Amount::from_sat(253583)));