zcash_protocol: Use `BalanceError` instead of `()` for monetary range violations.
This commit is contained in:
parent
51d4464472
commit
5675a76f0d
|
@ -47,40 +47,44 @@ impl ZatBalance {
|
||||||
/// Creates an ZatBalance from an i64.
|
/// Creates an ZatBalance from an i64.
|
||||||
///
|
///
|
||||||
/// Returns an error if the amount is outside the range `{-MAX_BALANCE..MAX_BALANCE}`.
|
/// Returns an error if the amount is outside the range `{-MAX_BALANCE..MAX_BALANCE}`.
|
||||||
pub fn from_i64(amount: i64) -> Result<Self, ()> {
|
pub fn from_i64(amount: i64) -> Result<Self, BalanceError> {
|
||||||
if (-MAX_BALANCE..=MAX_BALANCE).contains(&amount) {
|
if (-MAX_BALANCE..=MAX_BALANCE).contains(&amount) {
|
||||||
Ok(ZatBalance(amount))
|
Ok(ZatBalance(amount))
|
||||||
|
} else if amount < -MAX_BALANCE {
|
||||||
|
Err(BalanceError::Underflow)
|
||||||
} else {
|
} else {
|
||||||
Err(())
|
Err(BalanceError::Overflow)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a non-negative ZatBalance from an i64.
|
/// Creates a non-negative ZatBalance from an i64.
|
||||||
///
|
///
|
||||||
/// Returns an error if the amount is outside the range `{0..MAX_BALANCE}`.
|
/// Returns an error if the amount is outside the range `{0..MAX_BALANCE}`.
|
||||||
pub fn from_nonnegative_i64(amount: i64) -> Result<Self, ()> {
|
pub fn from_nonnegative_i64(amount: i64) -> Result<Self, BalanceError> {
|
||||||
if (0..=MAX_BALANCE).contains(&amount) {
|
if (0..=MAX_BALANCE).contains(&amount) {
|
||||||
Ok(ZatBalance(amount))
|
Ok(ZatBalance(amount))
|
||||||
|
} else if amount < 0 {
|
||||||
|
Err(BalanceError::Underflow)
|
||||||
} else {
|
} else {
|
||||||
Err(())
|
Err(BalanceError::Overflow)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an ZatBalance from a u64.
|
/// Creates an ZatBalance from a u64.
|
||||||
///
|
///
|
||||||
/// Returns an error if the amount is outside the range `{0..MAX_MONEY}`.
|
/// Returns an error if the amount is outside the range `{0..MAX_MONEY}`.
|
||||||
pub fn from_u64(amount: u64) -> Result<Self, ()> {
|
pub fn from_u64(amount: u64) -> Result<Self, BalanceError> {
|
||||||
if amount <= MAX_MONEY {
|
if amount <= MAX_MONEY {
|
||||||
Ok(ZatBalance(amount as i64))
|
Ok(ZatBalance(amount as i64))
|
||||||
} else {
|
} else {
|
||||||
Err(())
|
Err(BalanceError::Overflow)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reads an ZatBalance from a signed 64-bit little-endian integer.
|
/// Reads an ZatBalance from a signed 64-bit little-endian integer.
|
||||||
///
|
///
|
||||||
/// Returns an error if the amount is outside the range `{-MAX_BALANCE..MAX_BALANCE}`.
|
/// Returns an error if the amount is outside the range `{-MAX_BALANCE..MAX_BALANCE}`.
|
||||||
pub fn from_i64_le_bytes(bytes: [u8; 8]) -> Result<Self, ()> {
|
pub fn from_i64_le_bytes(bytes: [u8; 8]) -> Result<Self, BalanceError> {
|
||||||
let amount = i64::from_le_bytes(bytes);
|
let amount = i64::from_le_bytes(bytes);
|
||||||
ZatBalance::from_i64(amount)
|
ZatBalance::from_i64(amount)
|
||||||
}
|
}
|
||||||
|
@ -88,7 +92,7 @@ impl ZatBalance {
|
||||||
/// Reads a non-negative ZatBalance from a signed 64-bit little-endian integer.
|
/// Reads a non-negative ZatBalance from a signed 64-bit little-endian integer.
|
||||||
///
|
///
|
||||||
/// Returns an error if the amount is outside the range `{0..MAX_BALANCE}`.
|
/// Returns an error if the amount is outside the range `{0..MAX_BALANCE}`.
|
||||||
pub fn from_nonnegative_i64_le_bytes(bytes: [u8; 8]) -> Result<Self, ()> {
|
pub fn from_nonnegative_i64_le_bytes(bytes: [u8; 8]) -> Result<Self, BalanceError> {
|
||||||
let amount = i64::from_le_bytes(bytes);
|
let amount = i64::from_le_bytes(bytes);
|
||||||
ZatBalance::from_nonnegative_i64(amount)
|
ZatBalance::from_nonnegative_i64(amount)
|
||||||
}
|
}
|
||||||
|
@ -96,7 +100,7 @@ impl ZatBalance {
|
||||||
/// Reads an ZatBalance from an unsigned 64-bit little-endian integer.
|
/// Reads an ZatBalance from an unsigned 64-bit little-endian integer.
|
||||||
///
|
///
|
||||||
/// Returns an error if the amount is outside the range `{0..MAX_BALANCE}`.
|
/// Returns an error if the amount is outside the range `{0..MAX_BALANCE}`.
|
||||||
pub fn from_u64_le_bytes(bytes: [u8; 8]) -> Result<Self, ()> {
|
pub fn from_u64_le_bytes(bytes: [u8; 8]) -> Result<Self, BalanceError> {
|
||||||
let amount = u64::from_le_bytes(bytes);
|
let amount = u64::from_le_bytes(bytes);
|
||||||
ZatBalance::from_u64(amount)
|
ZatBalance::from_u64(amount)
|
||||||
}
|
}
|
||||||
|
@ -128,9 +132,9 @@ impl ZatBalance {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<i64> for ZatBalance {
|
impl TryFrom<i64> for ZatBalance {
|
||||||
type Error = ();
|
type Error = BalanceError;
|
||||||
|
|
||||||
fn try_from(value: i64) -> Result<Self, ()> {
|
fn try_from(value: i64) -> Result<Self, BalanceError> {
|
||||||
ZatBalance::from_i64(value)
|
ZatBalance::from_i64(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -148,10 +152,10 @@ impl From<&ZatBalance> for i64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<ZatBalance> for u64 {
|
impl TryFrom<ZatBalance> for u64 {
|
||||||
type Error = ();
|
type Error = BalanceError;
|
||||||
|
|
||||||
fn try_from(value: ZatBalance) -> Result<Self, Self::Error> {
|
fn try_from(value: ZatBalance) -> Result<Self, Self::Error> {
|
||||||
value.0.try_into().map_err(|_| ())
|
value.0.try_into().map_err(|_| BalanceError::Overflow)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,11 +241,11 @@ impl Zatoshis {
|
||||||
/// Creates a Zatoshis from a u64.
|
/// Creates a Zatoshis from a u64.
|
||||||
///
|
///
|
||||||
/// Returns an error if the amount is outside the range `{0..MAX_MONEY}`.
|
/// Returns an error if the amount is outside the range `{0..MAX_MONEY}`.
|
||||||
pub fn from_u64(amount: u64) -> Result<Self, ()> {
|
pub fn from_u64(amount: u64) -> Result<Self, BalanceError> {
|
||||||
if (0..=MAX_MONEY).contains(&amount) {
|
if (0..=MAX_MONEY).contains(&amount) {
|
||||||
Ok(Zatoshis(amount))
|
Ok(Zatoshis(amount))
|
||||||
} else {
|
} else {
|
||||||
Err(())
|
Err(BalanceError::Overflow)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,14 +260,18 @@ impl Zatoshis {
|
||||||
/// Creates a Zatoshis from an i64.
|
/// Creates a Zatoshis from an i64.
|
||||||
///
|
///
|
||||||
/// Returns an error if the amount is outside the range `{0..MAX_MONEY}`.
|
/// Returns an error if the amount is outside the range `{0..MAX_MONEY}`.
|
||||||
pub fn from_nonnegative_i64(amount: i64) -> Result<Self, ()> {
|
pub fn from_nonnegative_i64(amount: i64) -> Result<Self, BalanceError> {
|
||||||
Self::from_u64(u64::try_from(amount).map_err(|_| ())?)
|
if amount >= 0 {
|
||||||
|
Self::from_u64(u64::try_from(amount).unwrap())
|
||||||
|
} else {
|
||||||
|
Err(BalanceError::Underflow)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reads an Zatoshis from an unsigned 64-bit little-endian integer.
|
/// Reads an Zatoshis from an unsigned 64-bit little-endian integer.
|
||||||
///
|
///
|
||||||
/// Returns an error if the amount is outside the range `{0..MAX_MONEY}`.
|
/// Returns an error if the amount is outside the range `{0..MAX_MONEY}`.
|
||||||
pub fn from_u64_le_bytes(bytes: [u8; 8]) -> Result<Self, ()> {
|
pub fn from_u64_le_bytes(bytes: [u8; 8]) -> Result<Self, BalanceError> {
|
||||||
let amount = u64::from_le_bytes(bytes);
|
let amount = u64::from_le_bytes(bytes);
|
||||||
Self::from_u64(amount)
|
Self::from_u64(amount)
|
||||||
}
|
}
|
||||||
|
@ -272,7 +280,7 @@ impl Zatoshis {
|
||||||
/// complement 64-bit little-endian value.
|
/// complement 64-bit little-endian value.
|
||||||
///
|
///
|
||||||
/// Returns an error if the amount is outside the range `{0..MAX_MONEY}`.
|
/// Returns an error if the amount is outside the range `{0..MAX_MONEY}`.
|
||||||
pub fn from_nonnegative_i64_le_bytes(bytes: [u8; 8]) -> Result<Self, ()> {
|
pub fn from_nonnegative_i64_le_bytes(bytes: [u8; 8]) -> Result<Self, BalanceError> {
|
||||||
let amount = i64::from_le_bytes(bytes);
|
let amount = i64::from_le_bytes(bytes);
|
||||||
Self::from_nonnegative_i64(amount)
|
Self::from_nonnegative_i64(amount)
|
||||||
}
|
}
|
||||||
|
@ -313,7 +321,7 @@ impl From<Zatoshis> for u64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<u64> for Zatoshis {
|
impl TryFrom<u64> for Zatoshis {
|
||||||
type Error = ();
|
type Error = BalanceError;
|
||||||
|
|
||||||
fn try_from(value: u64) -> Result<Self, Self::Error> {
|
fn try_from(value: u64) -> Result<Self, Self::Error> {
|
||||||
Zatoshis::from_u64(value)
|
Zatoshis::from_u64(value)
|
||||||
|
@ -321,7 +329,7 @@ impl TryFrom<u64> for Zatoshis {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<ZatBalance> for Zatoshis {
|
impl TryFrom<ZatBalance> for Zatoshis {
|
||||||
type Error = ();
|
type Error = BalanceError;
|
||||||
|
|
||||||
fn try_from(value: ZatBalance) -> Result<Self, Self::Error> {
|
fn try_from(value: ZatBalance) -> Result<Self, Self::Error> {
|
||||||
Zatoshis::from_nonnegative_i64(value.0)
|
Zatoshis::from_nonnegative_i64(value.0)
|
||||||
|
|
|
@ -19,7 +19,7 @@ use zcash_primitives::{
|
||||||
memo::{self, MemoBytes},
|
memo::{self, MemoBytes},
|
||||||
transaction::components::amount::NonNegativeAmount,
|
transaction::components::amount::NonNegativeAmount,
|
||||||
};
|
};
|
||||||
use zcash_protocol::consensus;
|
use zcash_protocol::{consensus, value::BalanceError};
|
||||||
|
|
||||||
use crate::address::Address;
|
use crate::address::Address;
|
||||||
|
|
||||||
|
@ -206,11 +206,13 @@ impl TransactionRequest {
|
||||||
///
|
///
|
||||||
/// Returns `Err` in the case of overflow, or if the value is
|
/// Returns `Err` in the case of overflow, or if the value is
|
||||||
/// outside the range `0..=MAX_MONEY` zatoshis.
|
/// outside the range `0..=MAX_MONEY` zatoshis.
|
||||||
pub fn total(&self) -> Result<NonNegativeAmount, ()> {
|
pub fn total(&self) -> Result<NonNegativeAmount, BalanceError> {
|
||||||
self.payments
|
self.payments
|
||||||
.values()
|
.values()
|
||||||
.map(|p| p.amount)
|
.map(|p| p.amount)
|
||||||
.fold(Ok(NonNegativeAmount::ZERO), |acc, a| (acc? + a).ok_or(()))
|
.fold(Ok(NonNegativeAmount::ZERO), |acc, a| {
|
||||||
|
(acc? + a).ok_or(BalanceError::Overflow)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A utility for use in tests to help check round-trip serialization properties.
|
/// A utility for use in tests to help check round-trip serialization properties.
|
||||||
|
@ -469,6 +471,7 @@ mod parse {
|
||||||
consensus, transaction::components::amount::NonNegativeAmount,
|
consensus, transaction::components::amount::NonNegativeAmount,
|
||||||
transaction::components::amount::COIN,
|
transaction::components::amount::COIN,
|
||||||
};
|
};
|
||||||
|
use zcash_protocol::value::BalanceError;
|
||||||
|
|
||||||
use crate::address::Address;
|
use crate::address::Address;
|
||||||
|
|
||||||
|
@ -666,7 +669,7 @@ mod parse {
|
||||||
coins
|
coins
|
||||||
.checked_mul(COIN)
|
.checked_mul(COIN)
|
||||||
.and_then(|coin_zats| coin_zats.checked_add(zats))
|
.and_then(|coin_zats| coin_zats.checked_add(zats))
|
||||||
.ok_or(())
|
.ok_or(BalanceError::Overflow)
|
||||||
.and_then(NonNegativeAmount::from_u64)
|
.and_then(NonNegativeAmount::from_u64)
|
||||||
.map_err(|_| format!("Not a valid zat amount: {}.{}", coins, zats))
|
.map_err(|_| format!("Not a valid zat amount: {}.{}", coins, zats))
|
||||||
},
|
},
|
||||||
|
|
|
@ -1238,8 +1238,7 @@ mod tests {
|
||||||
|
|
||||||
#[cfg(feature = "unstable")]
|
#[cfg(feature = "unstable")]
|
||||||
use {
|
use {
|
||||||
crate::testing::AddressType,
|
crate::testing::AddressType, zcash_client_backend::keys::sapling,
|
||||||
zcash_client_backend::keys::sapling,
|
|
||||||
zcash_primitives::transaction::components::amount::NonNegativeAmount,
|
zcash_primitives::transaction::components::amount::NonNegativeAmount,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,9 @@ and this library adheres to Rust's notion of
|
||||||
- `zcash_primitives::consensus` re-exports `zcash_protocol::consensus`.
|
- `zcash_primitives::consensus` re-exports `zcash_protocol::consensus`.
|
||||||
- `zcash_primitives::constants` re-exports `zcash_protocol::constants`.
|
- `zcash_primitives::constants` re-exports `zcash_protocol::constants`.
|
||||||
- `zcash_primitives::transaction::components::amount` re-exports
|
- `zcash_primitives::transaction::components::amount` re-exports
|
||||||
`zcash_protocol::value`.
|
`zcash_protocol::value`. Many of the conversions to and from the
|
||||||
|
`Amount` and `NonNegativeAmount` value types now return
|
||||||
|
`Result<_, BalanceError>` instead of `Result<_, ()>`.
|
||||||
- `zcash_primitives::memo` re-exports `zcash_protocol::memo`.
|
- `zcash_primitives::memo` re-exports `zcash_protocol::memo`.
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
|
|
Loading…
Reference in New Issue