From 21c92dfd2985b2b8957c4c82d55501cf6515278a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 31 Mar 2020 20:54:57 +0200 Subject: [PATCH] Check that `PerThing` valid on decode (#5475) --- .../primitives/arithmetic/src/per_things.rs | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/substrate/primitives/arithmetic/src/per_things.rs b/substrate/primitives/arithmetic/src/per_things.rs index cbbeeae0cc..11f897fcc0 100644 --- a/substrate/primitives/arithmetic/src/per_things.rs +++ b/substrate/primitives/arithmetic/src/per_things.rs @@ -18,7 +18,7 @@ use serde::{Serialize, Deserialize}; use sp_std::{ops, fmt, prelude::*, convert::TryInto}; -use codec::{Encode, Decode, CompactAs}; +use codec::{Encode, CompactAs}; use crate::traits::{ SaturatedConversion, UniqueSaturatedInto, Saturating, BaseArithmetic, Bounded, Zero, }; @@ -311,7 +311,7 @@ macro_rules! implement_per_thing { /// #[doc = $title] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] - #[derive(Encode, Decode, Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, + #[derive(Encode, Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, CompactAs)] pub struct $name($type); @@ -534,6 +534,18 @@ macro_rules! implement_per_thing { } } + impl codec::Decode for $name { + fn decode(input: &mut I) -> Result { + let inner = <$type as codec::Decode>::decode(input)?; + + if inner <= ::ACCURACY { + Ok(Self(inner)) + } else { + Err("Value is greater than allowed maximum!".into()) + } + } + } + impl crate::traits::Bounded for $name { fn min_value() -> Self { ::zero() @@ -629,6 +641,21 @@ macro_rules! implement_per_thing { } } + #[test] + fn fail_on_invalid_encoded_value() { + let value = <$upper_type>::from($max) * 2; + let casted = value as $type; + let encoded = casted.encode(); + + // For types where `$max == $type::maximum()` we can not + if <$upper_type>::from(casted) == value { + assert_eq!( + $name::decode(&mut &encoded[..]), + Err("Value is greater than allowed maximum!".into()), + ); + } + } + #[test] fn per_thing_api_works() { // some really basic stuff