Merge pull request #309 from elichai/2019-08-amount-precision

Check that the amount precision isn't more than the size of the amount
This commit is contained in:
Andrew Poelstra 2019-08-12 17:20:18 +00:00 committed by GitHub
commit cc0f1143dc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 18 additions and 4 deletions

View File

@ -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)));