From 7d0a3debb66be02c196482d65f387c172fa8aee2 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Tue, 28 Jul 2020 10:57:33 -0700 Subject: [PATCH] chain: ensure impl Deserialize for Amount validates data. This uses serde's try_from attribute to run deserialized values through the TryFrom impl. Also adds a test to make sure that validation actually does happen. --- Cargo.lock | 11 +++++++++++ zebra-chain/Cargo.toml | 1 + zebra-chain/src/types/amount.rs | 25 +++++++++++++++++++++++++ 3 files changed, 37 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 768f7fc9..a9a51c6e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -152,6 +152,16 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdcf67bb7ba7797a081cd19009948ab533af7c355d5caf1d08c777582d351e9c" +[[package]] +name = "bincode" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f30d3a39baa26f9651f17b375061f3233dde33424a8b72b0dbe93a68a0bc896d" +dependencies = [ + "byteorder", + "serde", +] + [[package]] name = "bit-set" version = "0.5.2" @@ -2611,6 +2621,7 @@ name = "zebra-chain" version = "3.0.0-alpha.0" dependencies = [ "bech32", + "bincode", "blake2b_simd", "blake2s_simd", "bs58", diff --git a/zebra-chain/Cargo.toml b/zebra-chain/Cargo.toml index 70d97c46..b9ef62ff 100644 --- a/zebra-chain/Cargo.toml +++ b/zebra-chain/Cargo.toml @@ -37,3 +37,4 @@ proptest = "0.10" proptest-derive = "0.2.0" zebra-test = { path = "../zebra-test/" } color-eyre = "0.5" +bincode = "1" diff --git a/zebra-chain/src/types/amount.rs b/zebra-chain/src/types/amount.rs index 31e5f8bb..84565b88 100644 --- a/zebra-chain/src/types/amount.rs +++ b/zebra-chain/src/types/amount.rs @@ -9,6 +9,8 @@ type Result = std::result::Result; /// A runtime validated type for representing amounts of zatoshis #[derive(Debug, Eq, PartialEq, Clone, Copy, Serialize, Deserialize)] +#[serde(try_from = "i64")] +#[serde(bound = "C: AmountConstraint")] pub struct Amount(i64, PhantomData); impl Amount { @@ -384,4 +386,27 @@ mod test { Ok(()) } + + #[test] + fn deserialize_checks_bounds() -> Result<()> { + let big = MAX_MONEY * 2; + let neg = -10; + + let big_bytes = bincode::serialize(&big)?; + let neg_bytes = bincode::serialize(&neg)?; + + bincode::deserialize::>(&big_bytes) + .expect_err("deserialization should reject too large values"); + bincode::deserialize::>(&big_bytes) + .expect_err("deserialization should reject too large values"); + + bincode::deserialize::>(&neg_bytes) + .expect_err("NonNegative deserialization should reject negative values"); + let amount = bincode::deserialize::>(&neg_bytes) + .expect("NegativeAllowed deserialization should allow negative values"); + + assert_eq!(amount.0, neg); + + Ok(()) + } }