From e8aca40eb25e33013cb8ac2ca0c8e20400f20ea9 Mon Sep 17 00:00:00 2001 From: NingLin-P Date: Fri, 15 Nov 2024 05:30:42 +0800 Subject: [PATCH] Support more types in TypeWithDefault (#6411) # Description When using `TypeWithDefault` as the default nonce provider to overcome the [replay attack](https://wiki.polkadot.network/docs/transaction-attacks#replay-attack) issue, it fails to compile due to `TypeWithDefault: TryFrom` is not satisfied (which is required by trait `BaseArithmetic`). This is because the blanket implementation `TryFrom for T where U: Into` only impl `TryFrom` and `TryFrom` for `u32` since `u32` only impl `Into` for `u16` and `u8` but not `u64`. This PR fixes the issue by adding `TryFrom` and `From` impl (using macro) for `TypeWithDefault` and removing the blanket impl (otherwise the compiler will complain about conflicting impl), such that `TypeWithDefault: AtLeast8/16/32Bit` is satisfied. ## Integration This PR adds support to more types to be used with `TypeWithDefault`, existing code that used `u64` with `TypeWithDefault` should not be affected, an unit test is added to ensure that. ## Review Notes This PR simply makes `TypeWithDefault: AtLeast8/16/32Bit` satisfied --------- Signed-off-by: linning (cherry picked from commit 5bc571b0f2de67bd650a8c852c0afdd438377f3f) --- prdoc/pr_6411.prdoc | 10 ++ .../runtime/src/type_with_default.rs | 123 +++++++++++++----- 2 files changed, 103 insertions(+), 30 deletions(-) create mode 100644 prdoc/pr_6411.prdoc diff --git a/prdoc/pr_6411.prdoc b/prdoc/pr_6411.prdoc new file mode 100644 index 000000000000..3d8c2219e90e --- /dev/null +++ b/prdoc/pr_6411.prdoc @@ -0,0 +1,10 @@ +title: "Support more types in TypeWithDefault" + +doc: + - audience: Runtime Dev + description: | + This PR supports more integer types to be used with `TypeWithDefault` and makes `TypeWithDefault: BaseArithmetic` satisfied + +crates: + - name: sp-runtime + bump: patch diff --git a/substrate/primitives/runtime/src/type_with_default.rs b/substrate/primitives/runtime/src/type_with_default.rs index a75bcc2a9525..58e67e91319c 100644 --- a/substrate/primitives/runtime/src/type_with_default.rs +++ b/substrate/primitives/runtime/src/type_with_default.rs @@ -103,24 +103,6 @@ impl> Default for TypeWithDefault { } } -impl, D: Get> From for TypeWithDefault { - fn from(value: u16) -> Self { - Self::new(value.into()) - } -} - -impl, D: Get> From for TypeWithDefault { - fn from(value: u32) -> Self { - Self::new(value.into()) - } -} - -impl, D: Get> From for TypeWithDefault { - fn from(value: u64) -> Self { - Self::new(value.into()) - } -} - impl> CheckedNeg for TypeWithDefault { fn checked_neg(&self) -> Option { self.0.checked_neg().map(Self::new) @@ -217,24 +199,45 @@ impl> AddAssign for TypeWithDefault { } } -impl, D: Get> From for TypeWithDefault { - fn from(value: u8) -> Self { - Self::new(value.into()) - } -} - impl> Display for TypeWithDefault { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { write!(f, "{}", self.0) } } -impl, D: Get> TryFrom for TypeWithDefault { - type Error = >::Error; - fn try_from(n: u128) -> Result, Self::Error> { - T::try_from(n).map(Self::new) - } -} +macro_rules! impl_from { + ($for_type:ty $(, $from_type:ty)*) => { + $( + impl> From<$from_type> for TypeWithDefault<$for_type, D> { + fn from(value: $from_type) -> Self { + Self::new(value.into()) + } + } + )* + } +} +impl_from!(u128, u128, u64, u32, u16, u8); +impl_from!(u64, u64, u32, u16, u8); +impl_from!(u32, u32, u16, u8); +impl_from!(u16, u16, u8); +impl_from!(u8, u8); + +macro_rules! impl_try_from { + ($for_type:ty $(, $try_from_type:ty)*) => { + $( + impl> TryFrom<$try_from_type> for TypeWithDefault<$for_type, D> { + type Error = <$for_type as TryFrom<$try_from_type>>::Error; + fn try_from(n: $try_from_type) -> Result, Self::Error> { + <$for_type as TryFrom<$try_from_type>>::try_from(n).map(Self::new) + } + } + )* + } +} +impl_try_from!(u8, u16, u32, u64, u128); +impl_try_from!(u16, u32, u64, u128); +impl_try_from!(u32, u64, u128); +impl_try_from!(u64, u128); impl, D: Get> TryFrom for TypeWithDefault { type Error = >::Error; @@ -516,3 +519,63 @@ impl> CompactAs for TypeWithDefault { Ok(Self::new(val)) } } + +#[cfg(test)] +mod tests { + use super::TypeWithDefault; + use sp_arithmetic::traits::{AtLeast16Bit, AtLeast32Bit, AtLeast8Bit}; + use sp_core::Get; + + #[test] + #[allow(dead_code)] + fn test_type_with_default_impl_base_arithmetic() { + trait WrapAtLeast8Bit: AtLeast8Bit {} + trait WrapAtLeast16Bit: AtLeast16Bit {} + trait WrapAtLeast32Bit: AtLeast32Bit {} + + struct Getu8; + impl Get for Getu8 { + fn get() -> u8 { + 0 + } + } + type U8WithDefault = TypeWithDefault; + impl WrapAtLeast8Bit for U8WithDefault {} + + struct Getu16; + impl Get for Getu16 { + fn get() -> u16 { + 0 + } + } + type U16WithDefault = TypeWithDefault; + impl WrapAtLeast16Bit for U16WithDefault {} + + struct Getu32; + impl Get for Getu32 { + fn get() -> u32 { + 0 + } + } + type U32WithDefault = TypeWithDefault; + impl WrapAtLeast32Bit for U32WithDefault {} + + struct Getu64; + impl Get for Getu64 { + fn get() -> u64 { + 0 + } + } + type U64WithDefault = TypeWithDefault; + impl WrapAtLeast32Bit for U64WithDefault {} + + struct Getu128; + impl Get for Getu128 { + fn get() -> u128 { + 0 + } + } + type U128WithDefault = TypeWithDefault; + impl WrapAtLeast32Bit for U128WithDefault {} + } +}