diff --git a/Cargo.lock b/Cargo.lock index 5115bf4d42b8..8020668a7077 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,7 +1,5 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 - [[package]] name = "Inflector" version = "0.11.4" @@ -1823,6 +1821,7 @@ dependencies = [ "frame-system", "impl-trait-for-tuples", "log", + "max-encoded-len", "once_cell", "parity-scale-codec", "parity-util-mem", @@ -3724,6 +3723,29 @@ dependencies = [ "rawpointer", ] +[[package]] +name = "max-encoded-len" +version = "3.0.0" +dependencies = [ + "frame-support", + "impl-trait-for-tuples", + "max-encoded-len-derive", + "parity-scale-codec", + "primitive-types", + "rustversion", + "trybuild", +] + +[[package]] +name = "max-encoded-len-derive" +version = "3.0.0" +dependencies = [ + "proc-macro-crate 1.0.0", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "maybe-uninit" version = "2.0.0" @@ -4296,6 +4318,7 @@ dependencies = [ "frame-try-runtime", "hex-literal", "log", + "max-encoded-len", "node-primitives", "pallet-assets", "pallet-authority-discovery", @@ -4629,6 +4652,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", + "max-encoded-len", "pallet-balances", "parity-scale-codec", "sp-core", @@ -4739,6 +4763,7 @@ dependencies = [ "frame-support", "frame-system", "log", + "max-encoded-len", "pallet-transaction-payment", "parity-scale-codec", "sp-core", @@ -5265,6 +5290,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", + "max-encoded-len", "pallet-balances", "pallet-utility", "parity-scale-codec", @@ -5639,9 +5665,9 @@ dependencies = [ [[package]] name = "parity-scale-codec" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "731f4d179ed52b1c7eeb29baf29c604ea9301b889b23ce93660220a5465d5c6f" +checksum = "e0f518afaa5a47d0d6386229b0a6e01e86427291d643aa4cabb4992219f504f8" dependencies = [ "arrayvec 0.7.0", "bitvec", @@ -8570,6 +8596,7 @@ dependencies = [ name = "sp-application-crypto" version = "3.0.0" dependencies = [ + "max-encoded-len", "parity-scale-codec", "serde", "sp-core", @@ -8789,6 +8816,7 @@ dependencies = [ "lazy_static", "libsecp256k1", "log", + "max-encoded-len", "merlin", "num-traits", "parity-scale-codec", @@ -9015,6 +9043,7 @@ dependencies = [ "hash256-std-hasher", "impl-trait-for-tuples", "log", + "max-encoded-len", "parity-scale-codec", "parity-util-mem", "paste 1.0.4", @@ -10476,9 +10505,9 @@ dependencies = [ [[package]] name = "trybuild" -version = "1.0.41" +version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99471a206425fba51842a9186315f32d91c56eadc21ea4c21f847b59cf778f8b" +checksum = "1768998d9a3b179411618e377dbb134c58a88cda284b0aa71c42c40660127d46" dependencies = [ "dissimilar", "glob", diff --git a/Cargo.toml b/Cargo.toml index 9d7017be1d0d..5bd83b70f4c2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -202,6 +202,9 @@ members = [ "utils/frame/rpc/system", "utils/prometheus", "utils/wasm-builder", + # temp deps + "max-encoded-len", + "max-encoded-len/derive", ] # The list of dependencies below (which can be both direct and indirect dependencies) are crates diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index 16189a23289f..335d9a1aa2a9 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -87,6 +87,8 @@ pallet-transaction-payment = { version = "3.0.0", default-features = false, path pallet-transaction-payment-rpc-runtime-api = { version = "3.0.0", default-features = false, path = "../../../frame/transaction-payment/rpc/runtime-api/" } pallet-vesting = { version = "3.0.0", default-features = false, path = "../../../frame/vesting" } +max-encoded-len = { version = "3.0.0", default-features = false, path = "../../../max-encoded-len", features = [ "derive" ] } + [build-dependencies] substrate-wasm-builder = { version = "4.0.0", path = "../../../utils/wasm-builder" } @@ -159,6 +161,7 @@ std = [ "log/std", "frame-try-runtime/std", "sp-npos-elections/std", + "max-encoded-len/std", ] runtime-benchmarks = [ "frame-benchmarking", diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 92f3d43901a9..c51799d11a94 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -33,7 +33,7 @@ use frame_support::{ }, traits::{ Currency, Imbalance, KeyOwnerProofSystem, OnUnbalanced, LockIdentifier, - U128CurrencyToVote, + U128CurrencyToVote, MaxEncodedLen, }, }; use frame_system::{ @@ -114,8 +114,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // and set impl_version to 0. If only runtime // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. - spec_version: 265, - impl_version: 1, + spec_version: 266, + impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 2, }; @@ -253,7 +253,7 @@ parameter_types! { } /// The type used to represent the kinds of proxying allowed. -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, RuntimeDebug)] +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, RuntimeDebug, MaxEncodedLen)] pub enum ProxyType { Any, NonTransfer, diff --git a/frame/assets/Cargo.toml b/frame/assets/Cargo.toml index 7137cf1d789a..7afd08d8c11f 100644 --- a/frame/assets/Cargo.toml +++ b/frame/assets/Cargo.toml @@ -22,6 +22,7 @@ frame-support = { version = "3.0.0", default-features = false, path = "../suppor # `system` module provides us with all sorts of useful stuff and macros depend on it being around. frame-system = { version = "3.0.0", default-features = false, path = "../system" } frame-benchmarking = { version = "3.1.0", default-features = false, path = "../benchmarking", optional = true } +max-encoded-len = { version = "3.0.0", default-features = false, path = "../../max-encoded-len", features = [ "derive" ] } [dev-dependencies] sp-core = { version = "3.0.0", path = "../../primitives/core" } @@ -38,6 +39,7 @@ std = [ "frame-support/std", "frame-system/std", "frame-benchmarking/std", + "max-encoded-len/std", ] runtime-benchmarks = [ "frame-benchmarking", diff --git a/frame/assets/src/lib.rs b/frame/assets/src/lib.rs index e856211289b0..ccbe1920e997 100644 --- a/frame/assets/src/lib.rs +++ b/frame/assets/src/lib.rs @@ -138,14 +138,15 @@ mod functions; mod types; pub use types::*; -use sp_std::{prelude::*, borrow::Borrow}; +use sp_std::{prelude::*, borrow::Borrow, convert::TryInto}; use sp_runtime::{ - RuntimeDebug, TokenError, ArithmeticError, traits::{ + TokenError, ArithmeticError, + traits::{ AtLeast32BitUnsigned, Zero, StaticLookup, Saturating, CheckedSub, CheckedAdd, Bounded, StoredMapError, } }; -use codec::{Encode, Decode, HasCompact}; +use codec::HasCompact; use frame_support::{ensure, dispatch::{DispatchError, DispatchResult}}; use frame_support::traits::{Currency, ReservableCurrency, BalanceStatus::Reserved, StoredMap}; use frame_support::traits::tokens::{WithdrawConsequence, DepositConsequence, fungibles}; @@ -165,6 +166,7 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] + #[pallet::generate_storage_info] pub struct Pallet(_); #[pallet::config] @@ -174,10 +176,10 @@ pub mod pallet { type Event: From> + IsType<::Event>; /// The units in which we record balances. - type Balance: Member + Parameter + AtLeast32BitUnsigned + Default + Copy; + type Balance: Member + Parameter + AtLeast32BitUnsigned + Default + Copy + MaxEncodedLen; /// Identifier for the class of asset. - type AssetId: Member + Parameter + Default + Copy + HasCompact; + type AssetId: Member + Parameter + Default + Copy + HasCompact + MaxEncodedLen; /// The currency mechanism. type Currency: ReservableCurrency; @@ -207,7 +209,7 @@ pub mod pallet { type Freezer: FrozenBalance; /// Additional data to be stored with an account's asset balance. - type Extra: Member + Parameter + Default; + type Extra: Member + Parameter + Default + MaxEncodedLen; /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; @@ -232,6 +234,8 @@ pub mod pallet { T::AccountId, AssetBalance, ValueQuery, + GetDefault, + ConstU32<300_000>, >; #[pallet::storage] @@ -247,6 +251,8 @@ pub mod pallet { ), Approval>, OptionQuery, + GetDefault, + ConstU32<300_000>, >; #[pallet::storage] @@ -255,8 +261,10 @@ pub mod pallet { _, Blake2_128Concat, T::AssetId, - AssetMetadata>, + AssetMetadata, BoundedVec>, ValueQuery, + GetDefault, + ConstU32<300_000>, >; #[pallet::event] @@ -899,8 +907,14 @@ pub mod pallet { ) -> DispatchResult { let origin = ensure_signed(origin)?; - ensure!(name.len() <= T::StringLimit::get() as usize, Error::::BadMetadata); - ensure!(symbol.len() <= T::StringLimit::get() as usize, Error::::BadMetadata); + let bounded_name: BoundedVec = name + .clone() + .try_into() + .map_err(|_| Error::::BadMetadata)?; + let bounded_symbol: BoundedVec = symbol + .clone() + .try_into() + .map_err(|_| Error::::BadMetadata)?; let d = Asset::::get(id).ok_or(Error::::Unknown)?; ensure!(&origin == &d.owner, Error::::NoPermission); @@ -924,8 +938,8 @@ pub mod pallet { *metadata = Some(AssetMetadata { deposit: new_deposit, - name: name.clone(), - symbol: symbol.clone(), + name: bounded_name, + symbol: bounded_symbol, decimals, is_frozen: false, }); @@ -989,16 +1003,23 @@ pub mod pallet { ) -> DispatchResult { T::ForceOrigin::ensure_origin(origin)?; - ensure!(name.len() <= T::StringLimit::get() as usize, Error::::BadMetadata); - ensure!(symbol.len() <= T::StringLimit::get() as usize, Error::::BadMetadata); + let bounded_name: BoundedVec = name + .clone() + .try_into() + .map_err(|_| Error::::BadMetadata)?; + + let bounded_symbol: BoundedVec = symbol + .clone() + .try_into() + .map_err(|_| Error::::BadMetadata)?; ensure!(Asset::::contains_key(id), Error::::Unknown); Metadata::::try_mutate_exists(id, |metadata| { let deposit = metadata.take().map_or(Zero::zero(), |m| m.deposit); *metadata = Some(AssetMetadata { deposit, - name: name.clone(), - symbol: symbol.clone(), + name: bounded_name, + symbol: bounded_symbol, decimals, is_frozen, }); diff --git a/frame/assets/src/types.rs b/frame/assets/src/types.rs index 0cfcb64e137f..afd6b536cf18 100644 --- a/frame/assets/src/types.rs +++ b/frame/assets/src/types.rs @@ -18,11 +18,12 @@ //! Various basic types for use in the assets pallet. use super::*; +use frame_support::pallet_prelude::*; pub(super) type DepositBalanceOf = <>::Currency as Currency<::AccountId>>::Balance; -#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug)] +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, MaxEncodedLen)] pub struct AssetDetails< Balance, AccountId, @@ -66,7 +67,7 @@ impl AssetDetails { /// The amount of funds approved for the balance transfer from the owner to some delegated /// target. @@ -75,7 +76,7 @@ pub struct Approval { pub(super) deposit: DepositBalance, } -#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, Default)] +#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, Default, MaxEncodedLen)] pub struct AssetBalance { /// The balance. pub(super) balance: Balance, @@ -87,16 +88,16 @@ pub struct AssetBalance { pub(super) extra: Extra, } -#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, Default)] -pub struct AssetMetadata { +#[derive(Clone, Encode, Decode, Eq, PartialEq, Default, RuntimeDebug, MaxEncodedLen)] +pub struct AssetMetadata { /// The balance deposited for this metadata. /// /// This pays for the data stored in this struct. pub(super) deposit: DepositBalance, /// The user friendly name of this asset. Limited in length by `StringLimit`. - pub(super) name: Vec, + pub(super) name: BoundedString, /// The ticker symbol for this asset. Limited in length by `StringLimit`. - pub(super) symbol: Vec, + pub(super) symbol: BoundedString, /// The number of decimals this asset uses to represent one unit. pub(super) decimals: u8, /// Whether the asset metadata may be changed by a non Force origin. @@ -104,7 +105,7 @@ pub struct AssetMetadata { } /// Witness data for the destroy transactions. -#[derive(Copy, Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug)] +#[derive(Copy, Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, MaxEncodedLen)] pub struct DestroyWitness { /// The number of accounts holding the asset. #[codec(compact)] diff --git a/frame/balances/Cargo.toml b/frame/balances/Cargo.toml index 116a52151583..c4ab509aa0d4 100644 --- a/frame/balances/Cargo.toml +++ b/frame/balances/Cargo.toml @@ -20,6 +20,7 @@ frame-benchmarking = { version = "3.1.0", default-features = false, path = "../b frame-support = { version = "3.0.0", default-features = false, path = "../support" } frame-system = { version = "3.0.0", default-features = false, path = "../system" } log = { version = "0.4.14", default-features = false } +max-encoded-len = { version = "3.0.0", default-features = false, path = "../../max-encoded-len", features = [ "derive" ] } [dev-dependencies] sp-io = { version = "3.0.0", path = "../../primitives/io" } @@ -36,6 +37,7 @@ std = [ "frame-support/std", "frame-system/std", "log/std", + "max-encoded-len/std", ] runtime-benchmarks = ["frame-benchmarking"] try-runtime = ["frame-support/try-runtime"] diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index c0566f84a1be..04dacc785864 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -159,9 +159,9 @@ use sp_std::prelude::*; use sp_std::{cmp, result, mem, fmt::Debug, ops::BitOr}; use codec::{Codec, Encode, Decode}; use frame_support::{ - ensure, + ensure, WeakBoundedVec, traits::{ - Currency, OnUnbalanced, TryDrop, StoredMap, + Currency, OnUnbalanced, TryDrop, StoredMap, MaxEncodedLen, WithdrawReasons, LockIdentifier, LockableCurrency, ExistenceRequirement, Imbalance, SignedImbalance, ReservableCurrency, Get, ExistenceRequirement::KeepAlive, ExistenceRequirement::AllowDeath, @@ -193,7 +193,7 @@ pub mod pallet { pub trait Config: frame_system::Config { /// The balance of an account. type Balance: Parameter + Member + AtLeast32BitUnsigned + Codec + Default + Copy + - MaybeSerializeDeserialize + Debug; + MaybeSerializeDeserialize + Debug + MaxEncodedLen; /// Handler for the unbalanced reduction when removing a dust account. type DustRemoval: OnUnbalanced>; @@ -218,6 +218,7 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] + #[pallet::generate_storage_info] pub struct Pallet(PhantomData<(T, I)>); #[pallet::call] @@ -424,7 +425,9 @@ pub mod pallet { Blake2_128Concat, T::AccountId, AccountData, - ValueQuery + ValueQuery, + GetDefault, + ConstU32<300_000>, >; /// Any liquidity locks on some account balances. @@ -435,8 +438,10 @@ pub mod pallet { _, Blake2_128Concat, T::AccountId, - Vec>, - ValueQuery + WeakBoundedVec, T::MaxLocks>, + ValueQuery, + GetDefault, + ConstU32<300_000>, >; /// Storage version of the pallet. @@ -513,7 +518,7 @@ impl, I: 'static> GenesisConfig { } /// Simplified reasons for withdrawing balance. -#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug)] +#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, MaxEncodedLen)] pub enum Reasons { /// Paying system transaction fees. Fee = 0, @@ -545,7 +550,7 @@ impl BitOr for Reasons { /// A single lock on a balance. There can be many of these on an account and they "overlap", so the /// same balance is frozen by multiple locks. -#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)] +#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, MaxEncodedLen)] pub struct BalanceLock { /// An identifier for this lock. Only one lock may be in existence for each identifier. pub id: LockIdentifier, @@ -556,7 +561,7 @@ pub struct BalanceLock { } /// All balance information for an account. -#[derive(Encode, Decode, Clone, PartialEq, Eq, Default, RuntimeDebug)] +#[derive(Encode, Decode, Clone, PartialEq, Eq, Default, RuntimeDebug, MaxEncodedLen)] pub struct AccountData { /// Non-reserved part of the balance. There may still be restrictions on this, but it is the /// total pool what may in principle be transferred, reserved and used for tipping. @@ -602,7 +607,7 @@ impl AccountData { // A value placed in storage that represents the current version of the Balances storage. // This value is used by the `on_runtime_upgrade` logic to determine whether we run // storage migration logic. This should match directly with the semantic versions of the Rust crate. -#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug)] +#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, MaxEncodedLen)] enum Releases { V1_0_0, V2_0_0, @@ -822,6 +827,11 @@ impl, I: 'static> Pallet { /// Update the account entry for `who`, given the locks. fn update_locks(who: &T::AccountId, locks: &[BalanceLock]) { + let bounded_locks = WeakBoundedVec::<_, T::MaxLocks>::force_from( + locks.to_vec(), + Some("Balances Update Locks"), + ); + if locks.len() as u32 > T::MaxLocks::get() { log::warn!( target: "runtime::balances", @@ -853,7 +863,7 @@ impl, I: 'static> Pallet { system::Pallet::::dec_consumers(who); } } else { - Locks::::insert(who, locks); + Locks::::insert(who, bounded_locks); if !existed { if system::Pallet::::inc_consumers(who).is_err() { // No providers for the locks. This is impossible under normal circumstances diff --git a/frame/proxy/Cargo.toml b/frame/proxy/Cargo.toml index d8f7afe433cb..deec8aab7268 100644 --- a/frame/proxy/Cargo.toml +++ b/frame/proxy/Cargo.toml @@ -20,6 +20,7 @@ sp-core = { version = "3.0.0", default-features = false, path = "../../primitive sp-io = { version = "3.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "3.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "3.0.0", default-features = false, path = "../../primitives/std" } +max-encoded-len = { version = "3.0.0", default-features = false, path = "../../max-encoded-len", features = [ "derive" ] } frame-benchmarking = { version = "3.1.0", default-features = false, path = "../benchmarking", optional = true } @@ -36,7 +37,8 @@ std = [ "frame-support/std", "frame-system/std", "sp-std/std", - "sp-io/std" + "sp-io/std", + "max-encoded-len/std", ] runtime-benchmarks = [ "frame-benchmarking", diff --git a/frame/proxy/src/lib.rs b/frame/proxy/src/lib.rs index 0f541bd4d45e..f308dbd28955 100644 --- a/frame/proxy/src/lib.rs +++ b/frame/proxy/src/lib.rs @@ -33,7 +33,7 @@ mod tests; mod benchmarking; pub mod weights; -use sp_std::prelude::*; +use sp_std::{prelude::*, convert::TryInto}; use codec::{Encode, Decode}; use sp_io::hashing::blake2_256; use sp_runtime::{ @@ -43,8 +43,11 @@ use sp_runtime::{ use frame_support::{ RuntimeDebug, ensure, dispatch::{DispatchResultWithPostInfo, PostDispatchInfo}, - traits::{Get, ReservableCurrency, Currency, InstanceFilter, OriginTrait, IsType, IsSubType}, - weights::{Weight, GetDispatchInfo} + traits::{ + Get, ReservableCurrency, Currency, InstanceFilter, OriginTrait, + IsType, IsSubType, MaxEncodedLen, + }, + weights::GetDispatchInfo, }; use frame_system::{self as system}; use frame_support::dispatch::DispatchError; @@ -58,7 +61,7 @@ type BalanceOf = <::Currency as Currency< { /// The account which may act on behalf of another. delegate: AccountId, @@ -70,7 +73,7 @@ pub struct ProxyDefinition { } /// Details surrounding a specific instance of an announcement to make a call. -#[derive(Encode, Decode, Clone, Copy, Eq, PartialEq, RuntimeDebug)] +#[derive(Encode, Decode, Clone, Copy, Eq, PartialEq, RuntimeDebug, MaxEncodedLen)] pub struct Announcement { /// The account which made the announcement. real: AccountId, @@ -88,6 +91,7 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] + #[pallet::generate_storage_info] pub struct Pallet(_); /// Configuration trait. @@ -109,7 +113,7 @@ pub mod pallet { /// /// IMPORTANT: `Default` must be provided and MUST BE the the *most permissive* value. type ProxyType: Parameter + Member + Ord + PartialOrd + InstanceFilter<::Call> - + Default; + + Default + MaxEncodedLen; /// The base amount of currency needed to reserve for creating a proxy. /// @@ -128,7 +132,7 @@ pub mod pallet { /// The maximum amount of proxies allowed for a single account. #[pallet::constant] - type MaxProxies: Get; + type MaxProxies: Get; /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; @@ -293,14 +297,20 @@ pub mod pallet { let anonymous = Self::anonymous_account(&who, &proxy_type, index, None); ensure!(!Proxies::::contains_key(&anonymous), Error::::Duplicate); - let deposit = T::ProxyDepositBase::get() + T::ProxyDepositFactor::get(); - T::Currency::reserve(&who, deposit)?; + let proxy_def = ProxyDefinition { delegate: who.clone(), proxy_type: proxy_type.clone(), delay, }; - Proxies::::insert(&anonymous, (vec![proxy_def], deposit)); + let bounded_proxies: BoundedVec<_, T::MaxProxies> = vec![proxy_def] + .try_into() + .map_err(|_| Error::::TooMany)?; + + let deposit = T::ProxyDepositBase::get() + T::ProxyDepositFactor::get(); + T::Currency::reserve(&who, deposit)?; + + Proxies::::insert(&anonymous, (bounded_proxies, deposit)); Self::deposit_event(Event::AnonymousCreated(anonymous, who, proxy_type, index)); Ok(().into()) @@ -386,8 +396,7 @@ pub mod pallet { }; Announcements::::try_mutate(&who, |(ref mut pending, ref mut deposit)| { - ensure!(pending.len() < T::MaxPending::get() as usize, Error::::TooMany); - pending.push(announcement); + pending.try_push(announcement).map_err(|_| Error::::TooMany)?; Self::rejig_deposit( &who, *deposit, @@ -555,7 +564,13 @@ pub mod pallet { _, Twox64Concat, T::AccountId, - (Vec>, BalanceOf), + ( + BoundedVec< + ProxyDefinition, + T::MaxProxies, + >, + BalanceOf + ), ValueQuery >; @@ -566,7 +581,13 @@ pub mod pallet { _, Twox64Concat, T::AccountId, - (Vec, T::BlockNumber>>, BalanceOf), + ( + BoundedVec< + Announcement, T::BlockNumber>, + T::MaxPending, + >, + BalanceOf, + ), ValueQuery >; @@ -616,10 +637,9 @@ impl Pallet { ) -> DispatchResultWithPostInfo { ensure!(delegator != &delegatee, Error::::NoSelfProxy); Proxies::::try_mutate(delegator, |(ref mut proxies, ref mut deposit)| { - ensure!(proxies.len() < T::MaxProxies::get() as usize, Error::::TooMany); let proxy_def = ProxyDefinition { delegate: delegatee, proxy_type, delay }; let i = proxies.binary_search(&proxy_def).err().ok_or(Error::::Duplicate)?; - proxies.insert(i, proxy_def); + proxies.try_insert(i, proxy_def).map_err(|_| Error::::TooMany)?; let new_deposit = Self::deposit(proxies.len() as u32); if new_deposit > *deposit { T::Currency::reserve(delegator, new_deposit - *deposit)?; @@ -749,32 +769,3 @@ impl Pallet { Self::deposit_event(Event::ProxyExecuted(e.map(|_| ()).map_err(|e| e.error))); } } - -/// Migration utilities for upgrading the Proxy pallet between its different versions. -pub mod migration { - use super::*; - - /// Migration code for - /// - /// Details: This migration was introduced between Substrate 2.0-RC6 and Substrate 2.0 releases. - /// Before this migration, the `Proxies` storage item used a tuple of `AccountId` and - /// `ProxyType` to represent the proxy definition. After #6770, we switched to use a struct - /// `ProxyDefinition` which additionally included a `BlockNumber` delay value. This function, - /// simply takes any existing proxies using the old tuple format, and migrates it to the new - /// struct by setting the delay to zero. - pub fn migrate_to_time_delayed_proxies() -> Weight { - Proxies::::translate::<(Vec<(T::AccountId, T::ProxyType)>, BalanceOf), _>( - |_, (targets, deposit)| Some(( - targets.into_iter() - .map(|(a, t)| ProxyDefinition { - delegate: a, - proxy_type: t, - delay: Zero::zero(), - }) - .collect::>(), - deposit, - )) - ); - T::BlockWeights::get().max_block - } -} diff --git a/frame/proxy/src/tests.rs b/frame/proxy/src/tests.rs index 0b34edb43e73..fd632b91bb35 100644 --- a/frame/proxy/src/tests.rs +++ b/frame/proxy/src/tests.rs @@ -100,7 +100,10 @@ parameter_types! { pub const AnnouncementDepositBase: u64 = 1; pub const AnnouncementDepositFactor: u64 = 1; } -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, RuntimeDebug)] +#[derive( + Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, RuntimeDebug, + max_encoded_len::MaxEncodedLen, +)] pub enum ProxyType { Any, JustTransfer, @@ -180,15 +183,17 @@ fn announcement_works() { assert_eq!(Balances::reserved_balance(3), 0); assert_ok!(Proxy::announce(Origin::signed(3), 1, [1; 32].into())); - assert_eq!(Announcements::::get(3), (vec![Announcement { + let announcements = Announcements::::get(3); + assert_eq!(announcements.0, vec![Announcement { real: 1, call_hash: [1; 32].into(), height: 1, - }], 2)); - assert_eq!(Balances::reserved_balance(3), 2); + }]); + assert_eq!(Balances::reserved_balance(3), announcements.1); assert_ok!(Proxy::announce(Origin::signed(3), 2, [2; 32].into())); - assert_eq!(Announcements::::get(3), (vec![ + let announcements = Announcements::::get(3); + assert_eq!(announcements.0, vec![ Announcement { real: 1, call_hash: [1; 32].into(), @@ -199,8 +204,8 @@ fn announcement_works() { call_hash: [2; 32].into(), height: 1, }, - ], 3)); - assert_eq!(Balances::reserved_balance(3), 3); + ]); + assert_eq!(Balances::reserved_balance(3), announcements.1); assert_noop!(Proxy::announce(Origin::signed(3), 2, [3; 32].into()), Error::::TooMany); }); @@ -216,12 +221,13 @@ fn remove_announcement_works() { let e = Error::::NotFound; assert_noop!(Proxy::remove_announcement(Origin::signed(3), 1, [0; 32].into()), e); assert_ok!(Proxy::remove_announcement(Origin::signed(3), 1, [1; 32].into())); - assert_eq!(Announcements::::get(3), (vec![Announcement { + let announcements = Announcements::::get(3); + assert_eq!(announcements.0, vec![Announcement { real: 2, call_hash: [2; 32].into(), height: 1, - }], 2)); - assert_eq!(Balances::reserved_balance(3), 2); + }]); + assert_eq!(Balances::reserved_balance(3), announcements.1); }); } @@ -237,12 +243,13 @@ fn reject_announcement_works() { let e = Error::::NotFound; assert_noop!(Proxy::reject_announcement(Origin::signed(4), 3, [1; 32].into()), e); assert_ok!(Proxy::reject_announcement(Origin::signed(1), 3, [1; 32].into())); - assert_eq!(Announcements::::get(3), (vec![Announcement { + let announcements = Announcements::::get(3); + assert_eq!(announcements.0, vec![Announcement { real: 2, call_hash: [2; 32].into(), height: 1, - }], 2)); - assert_eq!(Balances::reserved_balance(3), 2); + }]); + assert_eq!(Balances::reserved_balance(3), announcements.1); }); } @@ -284,12 +291,13 @@ fn proxy_announced_removes_announcement_and_returns_deposit() { system::Pallet::::set_block_number(2); assert_ok!(Proxy::proxy_announced(Origin::signed(0), 3, 1, None, call.clone())); - assert_eq!(Announcements::::get(3), (vec![Announcement { + let announcements = Announcements::::get(3); + assert_eq!(announcements.0, vec![Announcement { real: 2, call_hash, height: 1, - }], 2)); - assert_eq!(Balances::reserved_balance(3), 2); + }]); + assert_eq!(Balances::reserved_balance(3), announcements.1); }); } diff --git a/frame/sudo/src/lib.rs b/frame/sudo/src/lib.rs index 839c819c8d95..51cc1df05070 100644 --- a/frame/sudo/src/lib.rs +++ b/frame/sudo/src/lib.rs @@ -125,6 +125,7 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] + #[pallet::generate_storage_info] pub struct Pallet(PhantomData); #[pallet::call] diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index 173e3da27984..0c9aacaf307b 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -16,6 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] serde = { version = "1.0.101", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "2.1.0", default-features = false, features = ["derive"] } frame-metadata = { version = "13.0.0", default-features = false, path = "../metadata" } +max-encoded-len = { version = "3.0.0", default-features = false, path = "../../max-encoded-len", features = [ "derive" ] } sp-std = { version = "3.0.0", default-features = false, path = "../../primitives/std" } sp-io = { version = "3.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "3.0.0", default-features = false, path = "../../primitives/runtime" } @@ -55,6 +56,7 @@ std = [ "sp-state-machine", "frame-support-procedural/std", "log/std", + "max-encoded-len/std", ] runtime-benchmarks = [] try-runtime = [] diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index 13b3f317e144..23cb557e6dd7 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -28,7 +28,6 @@ mod debug_no_bound; mod clone_no_bound; mod partial_eq_no_bound; mod default_no_bound; -mod max_encoded_len; mod key_prefix; pub(crate) use storage::INHERENT_INSTANCE_NAME; @@ -447,12 +446,6 @@ pub fn crate_to_pallet_version(input: TokenStream) -> TokenStream { /// and up to `NUMBER_OF_INSTANCE`. pub(crate) const NUMBER_OF_INSTANCE: u8 = 16; -/// Derive `MaxEncodedLen`. -#[proc_macro_derive(MaxEncodedLen)] -pub fn derive_max_encoded_len(input: TokenStream) -> TokenStream { - max_encoded_len::derive_max_encoded_len(input) -} - /// This macro is meant to be used by frame-support only. /// It implements the trait `HasKeyPrefix` and `HasReversibleKeyPrefix` for tuple of `Key`. #[proc_macro] diff --git a/frame/support/procedural/src/storage/mod.rs b/frame/support/procedural/src/storage/mod.rs index 3a1915e43144..570ef447a43c 100644 --- a/frame/support/procedural/src/storage/mod.rs +++ b/frame/support/procedural/src/storage/mod.rs @@ -117,7 +117,7 @@ impl From for DeclStorageDefExt { fn from(mut def: DeclStorageDef) -> Self { let hidden_crate_name = def.hidden_crate.as_ref().map(|i| i.to_string()) .unwrap_or_else(|| "decl_storage".to_string()); - + let hidden_crate = generate_crate_access(&hidden_crate_name, "frame-support"); let hidden_imports = generate_hidden_includes(&hidden_crate_name, "frame-support"); diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 911373bfad45..f7a9375839a1 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -76,7 +76,7 @@ pub use self::hash::{ pub use self::storage::{ StorageValue, StorageMap, StorageDoubleMap, StorageNMap, StoragePrefixedMap, IterableStorageMap, IterableStorageDoubleMap, IterableStorageNMap, migration, - bounded_vec::{self, BoundedVec}, + bounded_vec::BoundedVec, weak_bounded_vec::WeakBoundedVec, }; pub use self::dispatch::{Parameter, Callable}; pub use sp_runtime::{self, ConsensusEngineId, print, traits::Printable}; @@ -1241,7 +1241,7 @@ pub mod pallet_prelude { RuntimeDebug, storage, traits::{ Get, Hooks, IsType, GetPalletVersion, EnsureOrigin, PalletInfoAccess, StorageInfoTrait, - ConstU32, GetDefault, + ConstU32, GetDefault, MaxEncodedLen, }, dispatch::{DispatchResultWithPostInfo, Parameter, DispatchError, DispatchResult}, weights::{DispatchClass, Pays, Weight}, @@ -2341,3 +2341,7 @@ pub mod pallet_prelude { /// * use the newest nightly possible. /// pub use frame_support_procedural::pallet; + +/// The `max_encoded_len` module contains the `MaxEncodedLen` trait and derive macro, which is +/// useful for computing upper bounds on storage size. +pub use max_encoded_len; diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index 295995b1bfeb..52def92ef9b4 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -81,33 +81,5 @@ pub use dispatch::{EnsureOrigin, OriginTrait, UnfilteredDispatchable}; mod voting; pub use voting::{CurrencyToVote, SaturatingCurrencyToVote, U128CurrencyToVote}; -mod max_encoded_len; -// This looks like an overlapping import/export, but it isn't: -// macros and traits live in distinct namespaces. +// for backwards-compatibility with existing imports pub use max_encoded_len::MaxEncodedLen; -/// Derive [`MaxEncodedLen`][max_encoded_len::MaxEncodedLen]. -/// -/// # Examples -/// -/// ``` -/// # use codec::Encode; -/// # use frame_support::traits::MaxEncodedLen; -/// #[derive(Encode, MaxEncodedLen)] -/// struct TupleStruct(u8, u32); -/// -/// assert_eq!(TupleStruct::max_encoded_len(), u8::max_encoded_len() + u32::max_encoded_len()); -/// ``` -/// -/// ``` -/// # use codec::Encode; -/// # use frame_support::traits::MaxEncodedLen; -/// #[derive(Encode, MaxEncodedLen)] -/// enum GenericEnum { -/// A, -/// B(T), -/// } -/// -/// assert_eq!(GenericEnum::::max_encoded_len(), u8::max_encoded_len() + u8::max_encoded_len()); -/// assert_eq!(GenericEnum::::max_encoded_len(), u8::max_encoded_len() + u128::max_encoded_len()); -/// ``` -pub use frame_support_procedural::MaxEncodedLen; diff --git a/frame/support/src/traits/tokens/currency.rs b/frame/support/src/traits/tokens/currency.rs index 567ca44aa78c..a18e0b6593bc 100644 --- a/frame/support/src/traits/tokens/currency.rs +++ b/frame/support/src/traits/tokens/currency.rs @@ -22,7 +22,7 @@ use sp_runtime::traits::MaybeSerializeDeserialize; use crate::dispatch::{DispatchResult, DispatchError}; use super::misc::{Balance, WithdrawReasons, ExistenceRequirement}; use super::imbalance::{Imbalance, SignedImbalance}; - +use frame_support::traits::MaxEncodedLen; mod reservable; pub use reservable::ReservableCurrency; @@ -32,7 +32,7 @@ pub use lockable::{LockableCurrency, VestingSchedule, LockIdentifier}; /// Abstraction over a fungible assets system. pub trait Currency { /// The balance of an account. - type Balance: Balance + MaybeSerializeDeserialize + Debug; + type Balance: Balance + MaybeSerializeDeserialize + Debug + MaxEncodedLen; /// The opaque token type for an imbalance. This is returned by unbalanced operations /// and must be dealt with. It may be dropped but cannot be cloned. diff --git a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr index e3e94f1fc3eb..1d0e96be9edb 100644 --- a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr +++ b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr @@ -4,7 +4,7 @@ error[E0277]: the trait bound `::Bar: WrapperTypeDecode` is 20 | fn foo(origin: OriginFor, bar: T::Bar) -> DispatchResultWithPostInfo { | ^ the trait `WrapperTypeDecode` is not implemented for `::Bar` | - ::: /usr/local/cargo/registry/src/github.zerozr99.workers.dev-1ecc6299db9ec823/parity-scale-codec-2.1.0/src/codec.rs:277:18 + ::: /usr/local/cargo/registry/src/github.zerozr99.workers.dev-1ecc6299db9ec823/parity-scale-codec-2.1.1/src/codec.rs:277:18 | 277 | fn decode(input: &mut I) -> Result; | ----- required by this bound in `pallet::_::_parity_scale_codec::Decode::decode` @@ -17,7 +17,7 @@ error[E0277]: the trait bound `::Bar: WrapperTypeEncode` is 20 | fn foo(origin: OriginFor, bar: T::Bar) -> DispatchResultWithPostInfo { | ^ the trait `WrapperTypeEncode` is not implemented for `::Bar` | - ::: /usr/local/cargo/registry/src/github.zerozr99.workers.dev-1ecc6299db9ec823/parity-scale-codec-2.1.0/src/codec.rs:216:21 + ::: /usr/local/cargo/registry/src/github.zerozr99.workers.dev-1ecc6299db9ec823/parity-scale-codec-2.1.1/src/codec.rs:216:21 | 216 | fn encode_to(&self, dest: &mut T) { | ------ required by this bound in `encode_to` diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 8595b94c08de..6938df7e86c2 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -88,7 +88,7 @@ use frame_support::{ Parameter, storage, traits::{ SortedMembers, Get, PalletInfo, OnNewAccount, OnKilledAccount, HandleLifetime, - StoredMap, EnsureOrigin, OriginTrait, Filter, + StoredMap, EnsureOrigin, OriginTrait, Filter, MaxEncodedLen, }, weights::{ Weight, RuntimeDbWeight, DispatchInfo, DispatchClass, @@ -194,19 +194,20 @@ pub mod pallet { type BlockNumber: Parameter + Member + MaybeSerializeDeserialize + Debug + MaybeDisplay + AtLeast32BitUnsigned + Default + Bounded + Copy + sp_std::hash::Hash + - sp_std::str::FromStr + MaybeMallocSizeOf; + sp_std::str::FromStr + MaybeMallocSizeOf + MaxEncodedLen; /// The output of the `Hashing` function. type Hash: Parameter + Member + MaybeSerializeDeserialize + Debug + MaybeDisplay + SimpleBitOps + Ord - + Default + Copy + CheckEqual + sp_std::hash::Hash + AsRef<[u8]> + AsMut<[u8]> + MaybeMallocSizeOf; + + Default + Copy + CheckEqual + sp_std::hash::Hash + AsRef<[u8]> + AsMut<[u8]> + + MaybeMallocSizeOf + MaxEncodedLen; /// The hashing system (algorithm) being used in the runtime (e.g. Blake2). type Hashing: Hash; /// The user account identifier type for the runtime. type AccountId: Parameter + Member + MaybeSerializeDeserialize + Debug + MaybeDisplay + Ord - + Default; + + Default + MaxEncodedLen; /// Converting trait to take a source type and convert to `AccountId`. /// diff --git a/frame/timestamp/src/lib.rs b/frame/timestamp/src/lib.rs index dde635c6a8a3..3315fadb1c1c 100644 --- a/frame/timestamp/src/lib.rs +++ b/frame/timestamp/src/lib.rs @@ -116,7 +116,7 @@ pub mod pallet { pub trait Config: frame_system::Config { /// Type used for expressing timestamp. type Moment: Parameter + Default + AtLeast32Bit - + Scale + Copy; + + Scale + Copy + MaxEncodedLen; /// Something which can be notified when the timestamp is set. Set this to `()` if not needed. type OnTimestampSet: OnTimestampSet; @@ -134,6 +134,7 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] + #[pallet::generate_storage_info] pub struct Pallet(PhantomData); /// Current time for the current block. diff --git a/frame/utility/src/tests.rs b/frame/utility/src/tests.rs index 1828418bd7fb..6d9db2f0c612 100644 --- a/frame/utility/src/tests.rs +++ b/frame/utility/src/tests.rs @@ -41,14 +41,14 @@ pub mod example { decl_module! { pub struct Module for enum Call where origin: ::Origin { - #[weight = *weight] - fn noop(_origin, weight: Weight) { } + #[weight = *_weight] + fn noop(_origin, _weight: Weight) { } - #[weight = *start_weight] + #[weight = *_start_weight] fn foobar( origin, err: bool, - start_weight: Weight, + _start_weight: Weight, end_weight: Option, ) -> DispatchResultWithPostInfo { let _ = ensure_signed(origin)?; diff --git a/max-encoded-len/Cargo.toml b/max-encoded-len/Cargo.toml new file mode 100644 index 000000000000..994a3c6a5e13 --- /dev/null +++ b/max-encoded-len/Cargo.toml @@ -0,0 +1,36 @@ +[package] +name = "max-encoded-len" +version = "3.0.0" +authors = ["Parity Technologies "] +edition = "2018" +license = "Apache-2.0" +homepage = "https://substrate.dev" +repository = "https://github.com/paritytech/substrate/" +description = "Trait MaxEncodedLen bounds the max encoded length of an item." + + +[dependencies] +codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } +impl-trait-for-tuples = "0.2.1" +max-encoded-len-derive = { package = "max-encoded-len-derive", version = "3.0.0", path = "derive", default-features = false, optional = true } +primitive-types = { version = "0.9.0", default-features = false, features = ["codec"] } + +[dev-dependencies] +codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = [ "derive" ] } +frame-support = { path = "../frame/support" } +rustversion = "1.0.4" +trybuild = "1.0.42" + +[features] +default = [ + "derive", + "std", +] +derive = [ + "max-encoded-len-derive", +] +std = [ + "codec/std", + "max-encoded-len-derive/std", + "primitive-types/std", +] diff --git a/max-encoded-len/derive/Cargo.toml b/max-encoded-len/derive/Cargo.toml new file mode 100644 index 000000000000..42c13dc50edd --- /dev/null +++ b/max-encoded-len/derive/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "max-encoded-len-derive" +version = "3.0.0" +authors = ["Parity Technologies "] +edition = "2018" +license = "Apache-2.0" +homepage = "https://substrate.dev" +repository = "https://github.com/paritytech/substrate/" +description = "Derive support for MaxEncodedLen" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[lib] +proc-macro = true + +[dependencies] +proc-macro2 = "1.0.6" +proc-macro-crate = "1.0.0" +quote = "1.0.3" +syn = { version = "1.0.58", features = ["full"] } + +[features] +default = ["std"] +std = [] diff --git a/frame/support/procedural/src/max_encoded_len.rs b/max-encoded-len/derive/src/lib.rs similarity index 56% rename from frame/support/procedural/src/max_encoded_len.rs rename to max-encoded-len/derive/src/lib.rs index 72efa446b3f4..34bf42f30cb3 100644 --- a/frame/support/procedural/src/max_encoded_len.rs +++ b/max-encoded-len/derive/src/lib.rs @@ -15,21 +15,39 @@ // See the License for the specific language governing permissions and // limitations under the License. -use frame_support_procedural_tools::generate_crate_access_2018; use quote::{quote, quote_spanned}; use syn::{ - Data, DeriveInput, Fields, GenericParam, Generics, TraitBound, Type, TypeParamBound, - parse_quote, spanned::Spanned, + Data, DeriveInput, Error, Fields, GenericParam, Generics, Meta, TraitBound, Type, + TypeParamBound, parse_quote, spanned::Spanned, }; +use proc_macro_crate::{crate_name, FoundCrate}; +use proc_macro2::{Ident, Span}; -/// impl for `#[derive(MaxEncodedLen)]` +/// Generate the crate access for the crate using 2018 syntax. +fn generate_crate_access_2018(def_crate: &str) -> Result { + match crate_name(def_crate) { + Ok(FoundCrate::Itself) => { + let name = def_crate.to_string().replace("-", "_"); + Ok(syn::Ident::new(&name, Span::call_site())) + }, + Ok(FoundCrate::Name(name)) => { + Ok(Ident::new(&name, Span::call_site())) + }, + Err(e) => { + Err(Error::new(Span::call_site(), e)) + } + } +} + +/// Derive `MaxEncodedLen`. +#[proc_macro_derive(MaxEncodedLen, attributes(max_encoded_len_crate))] pub fn derive_max_encoded_len(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let input: DeriveInput = match syn::parse(input) { Ok(input) => input, Err(e) => return e.to_compile_error().into(), }; - let mel_trait = match max_encoded_len_trait() { + let mel_trait = match max_encoded_len_trait(&input) { Ok(mel_trait) => mel_trait, Err(e) => return e.to_compile_error().into(), }; @@ -52,9 +70,63 @@ pub fn derive_max_encoded_len(input: proc_macro::TokenStream) -> proc_macro::Tok .into() } -fn max_encoded_len_trait() -> syn::Result { - let frame_support = generate_crate_access_2018("frame-support")?; - Ok(parse_quote!(#frame_support::traits::MaxEncodedLen)) +fn max_encoded_len_trait(input: &DeriveInput) -> syn::Result { + let mel = { + const EXPECT_LIST: &str = "expect: #[max_encoded_len_crate(path::to::crate)]"; + const EXPECT_PATH: &str = "expect: path::to::crate"; + + macro_rules! return_err { + ($wrong_style:expr, $err:expr) => { + return Err(Error::new($wrong_style.span(), $err)) + }; + } + + let mut mel_crates = Vec::with_capacity(2); + mel_crates.extend(input + .attrs + .iter() + .filter(|attr| attr.path == parse_quote!(max_encoded_len_crate)) + .take(2) + .map(|attr| { + let meta_list = match attr.parse_meta()? { + Meta::List(meta_list) => meta_list, + Meta::Path(wrong_style) => return_err!(wrong_style, EXPECT_LIST), + Meta::NameValue(wrong_style) => return_err!(wrong_style, EXPECT_LIST), + }; + if meta_list.nested.len() != 1 { + return_err!(meta_list, "expected exactly 1 item"); + } + let first_nested = + meta_list.nested.into_iter().next().expect("length checked above"); + let meta = match first_nested { + syn::NestedMeta::Lit(l) => { + return_err!(l, "expected a path item, not a literal") + } + syn::NestedMeta::Meta(meta) => meta, + }; + let path = match meta { + Meta::Path(path) => path, + Meta::List(ref wrong_style) => return_err!(wrong_style, EXPECT_PATH), + Meta::NameValue(ref wrong_style) => return_err!(wrong_style, EXPECT_PATH), + }; + Ok(path) + }) + .collect::, _>>()?); + + // we have to return `Result` here in order to satisfy the trait + // bounds for `.or_else` for `generate_crate_access_2018`, even though `Option` + // would be more natural in this circumstance. + match mel_crates.len() { + 0 => Err(Error::new( + input.span(), + "this error is spurious and swallowed by the or_else below", + )), + 1 => Ok(mel_crates.into_iter().next().expect("length is checked")), + _ => return_err!(mel_crates[1], "duplicate max_encoded_len_crate definition"), + } + } + .or_else(|_| generate_crate_access_2018("max-encoded-len").map(|ident| ident.into()))?; + Ok(parse_quote!(#mel::MaxEncodedLen)) } // Add a bound `T: MaxEncodedLen` to every type parameter T. @@ -126,8 +198,7 @@ fn data_length_expr(data: &Data) -> proc_macro2::TokenStream { Data::Union(ref data) => { // https://github.com/paritytech/parity-scale-codec/ // blob/f0341dabb01aa9ff0548558abb6dcc5c31c669a1/derive/src/encode.rs#L290-L293 - syn::Error::new(data.union_token.span(), "Union types are not supported") - .to_compile_error() + Error::new(data.union_token.span(), "Union types are not supported").to_compile_error() } } } diff --git a/frame/support/src/traits/max_encoded_len.rs b/max-encoded-len/src/lib.rs similarity index 65% rename from frame/support/src/traits/max_encoded_len.rs rename to max-encoded-len/src/lib.rs index 2cf9007d4d62..e216d3b17415 100644 --- a/frame/support/src/traits/max_encoded_len.rs +++ b/max-encoded-len/src/lib.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,9 +15,38 @@ // See the License for the specific language governing permissions and // limitations under the License. +//! `trait MaxEncodedLen` bounds the max encoded length of items. + +#![cfg_attr(not(feature = "std"), no_std)] + use codec::{Compact, Encode}; use impl_trait_for_tuples::impl_for_tuples; -use sp_std::{mem, marker::PhantomData}; +use core::{mem, marker::PhantomData}; +use primitive_types::{H160, H256, H512}; + +/// Derive macro for `MaxEncodedLen`. +/// +/// ``` +/// # use max_encoded_len::MaxEncodedLen; +/// # use codec::Encode; +/// #[derive(Encode, MaxEncodedLen)] +/// struct Example; +/// ``` +/// +/// Sometimes the `MaxEncodedLen` trait and macro are accessed without explicitly importing its +/// crate, notably via the `frame_support::max_encoded_len` re-binding. In these circumstances, +/// the derive macro needs some help to understand where its crate should be: +/// +/// ``` +/// # use codec::Encode; +/// use frame_support::max_encoded_len::MaxEncodedLen; +/// +/// #[derive(Encode, MaxEncodedLen)] +/// #[max_encoded_len_crate(frame_support::max_encoded_len)] +/// struct Example; +/// ``` +#[cfg(feature = "derive")] +pub use max_encoded_len_derive::MaxEncodedLen; /// Items implementing `MaxEncodedLen` have a statically known maximum encoded size. /// @@ -42,7 +71,7 @@ macro_rules! impl_primitives { }; } -impl_primitives!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, bool); +impl_primitives!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, bool, H160, H256, H512); macro_rules! impl_compact { ($( $t:ty => $e:expr; )*) => { @@ -57,15 +86,15 @@ macro_rules! impl_compact { } impl_compact!( - // https://github.com/paritytech/parity-scale-codec/blob/f0341dabb01aa9ff0548558abb6dcc5c31c669a1/src/compact.rs#L261 + // github.com/paritytech/parity-scale-codec/blob/f0341dabb01aa9ff0548558abb6dcc5c31c669a1/src/compact.rs#L261 u8 => 2; - // https://github.com/paritytech/parity-scale-codec/blob/f0341dabb01aa9ff0548558abb6dcc5c31c669a1/src/compact.rs#L291 + // github.com/paritytech/parity-scale-codec/blob/f0341dabb01aa9ff0548558abb6dcc5c31c669a1/src/compact.rs#L291 u16 => 4; - // https://github.com/paritytech/parity-scale-codec/blob/f0341dabb01aa9ff0548558abb6dcc5c31c669a1/src/compact.rs#L326 + // github.com/paritytech/parity-scale-codec/blob/f0341dabb01aa9ff0548558abb6dcc5c31c669a1/src/compact.rs#L326 u32 => 5; - // https://github.com/paritytech/parity-scale-codec/blob/f0341dabb01aa9ff0548558abb6dcc5c31c669a1/src/compact.rs#L369 + // github.com/paritytech/parity-scale-codec/blob/f0341dabb01aa9ff0548558abb6dcc5c31c669a1/src/compact.rs#L369 u64 => 9; - // https://github.com/paritytech/parity-scale-codec/blob/f0341dabb01aa9ff0548558abb6dcc5c31c669a1/src/compact.rs#L413 + // github.com/paritytech/parity-scale-codec/blob/f0341dabb01aa9ff0548558abb6dcc5c31c669a1/src/compact.rs#L413 u128 => 17; ); diff --git a/frame/support/test/tests/max_encoded_len.rs b/max-encoded-len/tests/max_encoded_len.rs similarity index 98% rename from frame/support/test/tests/max_encoded_len.rs rename to max-encoded-len/tests/max_encoded_len.rs index e9e74929108d..665ac8fa98a4 100644 --- a/frame/support/test/tests/max_encoded_len.rs +++ b/max-encoded-len/tests/max_encoded_len.rs @@ -17,7 +17,9 @@ //! Tests for MaxEncodedLen derive macro -use frame_support::traits::MaxEncodedLen; +#![cfg(feature = "derive")] + +use max_encoded_len::MaxEncodedLen; use codec::{Compact, Encode}; // These structs won't even compile if the macro isn't working right. diff --git a/frame/support/test/tests/max_encoded_len_ui.rs b/max-encoded-len/tests/max_encoded_len_ui.rs similarity index 97% rename from frame/support/test/tests/max_encoded_len_ui.rs rename to max-encoded-len/tests/max_encoded_len_ui.rs index c5c0489da924..79d6d49234ff 100644 --- a/frame/support/test/tests/max_encoded_len_ui.rs +++ b/max-encoded-len/tests/max_encoded_len_ui.rs @@ -15,6 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +#[cfg(feature = "derive")] #[rustversion::attr(not(stable), ignore)] #[test] fn derive_no_bound_ui() { diff --git a/max-encoded-len/tests/max_encoded_len_ui/list_list_item.rs b/max-encoded-len/tests/max_encoded_len_ui/list_list_item.rs new file mode 100644 index 000000000000..0cb12991fab4 --- /dev/null +++ b/max-encoded-len/tests/max_encoded_len_ui/list_list_item.rs @@ -0,0 +1,10 @@ +use codec::Encode; +use frame_support::max_encoded_len::MaxEncodedLen; + +#[derive(Encode, MaxEncodedLen)] +#[max_encoded_len_crate(foo())] +struct Example; + +fn main() { + let _ = Example::max_encoded_len(); +} diff --git a/max-encoded-len/tests/max_encoded_len_ui/list_list_item.stderr b/max-encoded-len/tests/max_encoded_len_ui/list_list_item.stderr new file mode 100644 index 000000000000..4ecd40440a46 --- /dev/null +++ b/max-encoded-len/tests/max_encoded_len_ui/list_list_item.stderr @@ -0,0 +1,18 @@ +error: expect: path::to::crate + --> $DIR/list_list_item.rs:5:25 + | +5 | #[max_encoded_len_crate(foo())] + | ^^^ + +error[E0599]: no function or associated item named `max_encoded_len` found for struct `Example` in the current scope + --> $DIR/list_list_item.rs:9:19 + | +6 | struct Example; + | --------------- function or associated item `max_encoded_len` not found for this +... +9 | let _ = Example::max_encoded_len(); + | ^^^^^^^^^^^^^^^ function or associated item not found in `Example` + | + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following trait defines an item `max_encoded_len`, perhaps you need to implement it: + candidate #1: `MaxEncodedLen` diff --git a/max-encoded-len/tests/max_encoded_len_ui/literal_list_item.rs b/max-encoded-len/tests/max_encoded_len_ui/literal_list_item.rs new file mode 100644 index 000000000000..f3f7a72d813b --- /dev/null +++ b/max-encoded-len/tests/max_encoded_len_ui/literal_list_item.rs @@ -0,0 +1,10 @@ +use codec::Encode; +use frame_support::max_encoded_len::MaxEncodedLen; + +#[derive(Encode, MaxEncodedLen)] +#[max_encoded_len_crate("frame_support::max_encoded_len")] +struct Example; + +fn main() { + let _ = Example::max_encoded_len(); +} diff --git a/max-encoded-len/tests/max_encoded_len_ui/literal_list_item.stderr b/max-encoded-len/tests/max_encoded_len_ui/literal_list_item.stderr new file mode 100644 index 000000000000..118259991299 --- /dev/null +++ b/max-encoded-len/tests/max_encoded_len_ui/literal_list_item.stderr @@ -0,0 +1,18 @@ +error: expected a path item, not a literal + --> $DIR/literal_list_item.rs:5:25 + | +5 | #[max_encoded_len_crate("frame_support::max_encoded_len")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0599]: no function or associated item named `max_encoded_len` found for struct `Example` in the current scope + --> $DIR/literal_list_item.rs:9:19 + | +6 | struct Example; + | --------------- function or associated item `max_encoded_len` not found for this +... +9 | let _ = Example::max_encoded_len(); + | ^^^^^^^^^^^^^^^ function or associated item not found in `Example` + | + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following trait defines an item `max_encoded_len`, perhaps you need to implement it: + candidate #1: `MaxEncodedLen` diff --git a/max-encoded-len/tests/max_encoded_len_ui/name_value_attr.rs b/max-encoded-len/tests/max_encoded_len_ui/name_value_attr.rs new file mode 100644 index 000000000000..382310d3a7dd --- /dev/null +++ b/max-encoded-len/tests/max_encoded_len_ui/name_value_attr.rs @@ -0,0 +1,10 @@ +use codec::Encode; +use frame_support::max_encoded_len::MaxEncodedLen; + +#[derive(Encode, MaxEncodedLen)] +#[max_encoded_len_crate = "frame_support::max_encoded_len"] +struct Example; + +fn main() { + let _ = Example::max_encoded_len(); +} diff --git a/max-encoded-len/tests/max_encoded_len_ui/name_value_attr.stderr b/max-encoded-len/tests/max_encoded_len_ui/name_value_attr.stderr new file mode 100644 index 000000000000..4949631049ba --- /dev/null +++ b/max-encoded-len/tests/max_encoded_len_ui/name_value_attr.stderr @@ -0,0 +1,18 @@ +error: expect: #[max_encoded_len_crate(path::to::crate)] + --> $DIR/name_value_attr.rs:5:3 + | +5 | #[max_encoded_len_crate = "frame_support::max_encoded_len"] + | ^^^^^^^^^^^^^^^^^^^^^ + +error[E0599]: no function or associated item named `max_encoded_len` found for struct `Example` in the current scope + --> $DIR/name_value_attr.rs:9:19 + | +6 | struct Example; + | --------------- function or associated item `max_encoded_len` not found for this +... +9 | let _ = Example::max_encoded_len(); + | ^^^^^^^^^^^^^^^ function or associated item not found in `Example` + | + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following trait defines an item `max_encoded_len`, perhaps you need to implement it: + candidate #1: `MaxEncodedLen` diff --git a/max-encoded-len/tests/max_encoded_len_ui/name_value_list_item.rs b/max-encoded-len/tests/max_encoded_len_ui/name_value_list_item.rs new file mode 100644 index 000000000000..44f92e8d5d99 --- /dev/null +++ b/max-encoded-len/tests/max_encoded_len_ui/name_value_list_item.rs @@ -0,0 +1,10 @@ +use codec::Encode; +use frame_support::max_encoded_len::MaxEncodedLen; + +#[derive(Encode, MaxEncodedLen)] +#[max_encoded_len_crate(path = "frame_support::max_encoded_len")] +struct Example; + +fn main() { + let _ = Example::max_encoded_len(); +} diff --git a/max-encoded-len/tests/max_encoded_len_ui/name_value_list_item.stderr b/max-encoded-len/tests/max_encoded_len_ui/name_value_list_item.stderr new file mode 100644 index 000000000000..2faa1108c49d --- /dev/null +++ b/max-encoded-len/tests/max_encoded_len_ui/name_value_list_item.stderr @@ -0,0 +1,18 @@ +error: expect: path::to::crate + --> $DIR/name_value_list_item.rs:5:25 + | +5 | #[max_encoded_len_crate(path = "frame_support::max_encoded_len")] + | ^^^^ + +error[E0599]: no function or associated item named `max_encoded_len` found for struct `Example` in the current scope + --> $DIR/name_value_list_item.rs:9:19 + | +6 | struct Example; + | --------------- function or associated item `max_encoded_len` not found for this +... +9 | let _ = Example::max_encoded_len(); + | ^^^^^^^^^^^^^^^ function or associated item not found in `Example` + | + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following trait defines an item `max_encoded_len`, perhaps you need to implement it: + candidate #1: `MaxEncodedLen` diff --git a/max-encoded-len/tests/max_encoded_len_ui/no_path_list_items.rs b/max-encoded-len/tests/max_encoded_len_ui/no_path_list_items.rs new file mode 100644 index 000000000000..069c8af5a77e --- /dev/null +++ b/max-encoded-len/tests/max_encoded_len_ui/no_path_list_items.rs @@ -0,0 +1,10 @@ +use codec::Encode; +use frame_support::max_encoded_len::MaxEncodedLen; + +#[derive(Encode, MaxEncodedLen)] +#[max_encoded_len_crate] +struct Example; + +fn main() { + let _ = Example::max_encoded_len(); +} diff --git a/max-encoded-len/tests/max_encoded_len_ui/no_path_list_items.stderr b/max-encoded-len/tests/max_encoded_len_ui/no_path_list_items.stderr new file mode 100644 index 000000000000..4d36039d33b3 --- /dev/null +++ b/max-encoded-len/tests/max_encoded_len_ui/no_path_list_items.stderr @@ -0,0 +1,18 @@ +error: expect: #[max_encoded_len_crate(path::to::crate)] + --> $DIR/no_path_list_items.rs:5:3 + | +5 | #[max_encoded_len_crate] + | ^^^^^^^^^^^^^^^^^^^^^ + +error[E0599]: no function or associated item named `max_encoded_len` found for struct `Example` in the current scope + --> $DIR/no_path_list_items.rs:9:19 + | +6 | struct Example; + | --------------- function or associated item `max_encoded_len` not found for this +... +9 | let _ = Example::max_encoded_len(); + | ^^^^^^^^^^^^^^^ function or associated item not found in `Example` + | + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following trait defines an item `max_encoded_len`, perhaps you need to implement it: + candidate #1: `MaxEncodedLen` diff --git a/frame/support/test/tests/max_encoded_len_ui/not_encode.rs b/max-encoded-len/tests/max_encoded_len_ui/not_encode.rs similarity index 58% rename from frame/support/test/tests/max_encoded_len_ui/not_encode.rs rename to max-encoded-len/tests/max_encoded_len_ui/not_encode.rs index ed6fe94471e5..5e8eb6035547 100644 --- a/frame/support/test/tests/max_encoded_len_ui/not_encode.rs +++ b/max-encoded-len/tests/max_encoded_len_ui/not_encode.rs @@ -1,4 +1,4 @@ -use frame_support::traits::MaxEncodedLen; +use max_encoded_len::MaxEncodedLen; #[derive(MaxEncodedLen)] struct NotEncode; diff --git a/frame/support/test/tests/max_encoded_len_ui/not_encode.stderr b/max-encoded-len/tests/max_encoded_len_ui/not_encode.stderr similarity index 54% rename from frame/support/test/tests/max_encoded_len_ui/not_encode.stderr rename to max-encoded-len/tests/max_encoded_len_ui/not_encode.stderr index f4dbeac04084..1e0ead0854a0 100644 --- a/frame/support/test/tests/max_encoded_len_ui/not_encode.stderr +++ b/max-encoded-len/tests/max_encoded_len_ui/not_encode.stderr @@ -1,13 +1,13 @@ -error[E0277]: the trait bound `NotEncode: WrapperTypeEncode` is not satisfied +error[E0277]: the trait bound `NotEncode: parity_scale_codec::codec::WrapperTypeEncode` is not satisfied --> $DIR/not_encode.rs:3:10 | 3 | #[derive(MaxEncodedLen)] - | ^^^^^^^^^^^^^ the trait `WrapperTypeEncode` is not implemented for `NotEncode` + | ^^^^^^^^^^^^^ the trait `parity_scale_codec::codec::WrapperTypeEncode` is not implemented for `NotEncode` | - ::: $WORKSPACE/frame/support/src/traits/max_encoded_len.rs + ::: $WORKSPACE/max-encoded-len/src/lib.rs | | pub trait MaxEncodedLen: Encode { | ------ required by this bound in `MaxEncodedLen` | - = note: required because of the requirements on the impl of `frame_support::dispatch::Encode` for `NotEncode` + = note: required because of the requirements on the impl of `parity_scale_codec::codec::Encode` for `NotEncode` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/frame/support/test/tests/max_encoded_len_ui/not_mel.rs b/max-encoded-len/tests/max_encoded_len_ui/not_mel.rs similarity index 80% rename from frame/support/test/tests/max_encoded_len_ui/not_mel.rs rename to max-encoded-len/tests/max_encoded_len_ui/not_mel.rs index 6116f30e5272..cbaf820ff58e 100644 --- a/frame/support/test/tests/max_encoded_len_ui/not_mel.rs +++ b/max-encoded-len/tests/max_encoded_len_ui/not_mel.rs @@ -1,5 +1,5 @@ use codec::Encode; -use frame_support::traits::MaxEncodedLen; +use max_encoded_len::MaxEncodedLen; #[derive(Encode)] struct NotMel; diff --git a/frame/support/test/tests/max_encoded_len_ui/not_mel.stderr b/max-encoded-len/tests/max_encoded_len_ui/not_mel.stderr similarity index 100% rename from frame/support/test/tests/max_encoded_len_ui/not_mel.stderr rename to max-encoded-len/tests/max_encoded_len_ui/not_mel.stderr diff --git a/max-encoded-len/tests/max_encoded_len_ui/path_attr.rs b/max-encoded-len/tests/max_encoded_len_ui/path_attr.rs new file mode 100644 index 000000000000..069c8af5a77e --- /dev/null +++ b/max-encoded-len/tests/max_encoded_len_ui/path_attr.rs @@ -0,0 +1,10 @@ +use codec::Encode; +use frame_support::max_encoded_len::MaxEncodedLen; + +#[derive(Encode, MaxEncodedLen)] +#[max_encoded_len_crate] +struct Example; + +fn main() { + let _ = Example::max_encoded_len(); +} diff --git a/max-encoded-len/tests/max_encoded_len_ui/path_attr.stderr b/max-encoded-len/tests/max_encoded_len_ui/path_attr.stderr new file mode 100644 index 000000000000..84745efc5e6f --- /dev/null +++ b/max-encoded-len/tests/max_encoded_len_ui/path_attr.stderr @@ -0,0 +1,18 @@ +error: expect: #[max_encoded_len_crate(path::to::crate)] + --> $DIR/path_attr.rs:5:3 + | +5 | #[max_encoded_len_crate] + | ^^^^^^^^^^^^^^^^^^^^^ + +error[E0599]: no function or associated item named `max_encoded_len` found for struct `Example` in the current scope + --> $DIR/path_attr.rs:9:19 + | +6 | struct Example; + | --------------- function or associated item `max_encoded_len` not found for this +... +9 | let _ = Example::max_encoded_len(); + | ^^^^^^^^^^^^^^^ function or associated item not found in `Example` + | + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following trait defines an item `max_encoded_len`, perhaps you need to implement it: + candidate #1: `MaxEncodedLen` diff --git a/max-encoded-len/tests/max_encoded_len_ui/two_path_list_items.rs b/max-encoded-len/tests/max_encoded_len_ui/two_path_list_items.rs new file mode 100644 index 000000000000..2b29648cbaa2 --- /dev/null +++ b/max-encoded-len/tests/max_encoded_len_ui/two_path_list_items.rs @@ -0,0 +1,10 @@ +use codec::Encode; +use frame_support::max_encoded_len::MaxEncodedLen; + +#[derive(Encode, MaxEncodedLen)] +#[max_encoded_len_crate(max_encoded_len, frame_support::max_encoded_len)] +struct Example; + +fn main() { + let _ = Example::max_encoded_len(); +} diff --git a/max-encoded-len/tests/max_encoded_len_ui/two_path_list_items.stderr b/max-encoded-len/tests/max_encoded_len_ui/two_path_list_items.stderr new file mode 100644 index 000000000000..9252a4065f25 --- /dev/null +++ b/max-encoded-len/tests/max_encoded_len_ui/two_path_list_items.stderr @@ -0,0 +1,18 @@ +error: expected exactly 1 item + --> $DIR/two_path_list_items.rs:5:3 + | +5 | #[max_encoded_len_crate(max_encoded_len, frame_support::max_encoded_len)] + | ^^^^^^^^^^^^^^^^^^^^^ + +error[E0599]: no function or associated item named `max_encoded_len` found for struct `Example` in the current scope + --> $DIR/two_path_list_items.rs:9:19 + | +6 | struct Example; + | --------------- function or associated item `max_encoded_len` not found for this +... +9 | let _ = Example::max_encoded_len(); + | ^^^^^^^^^^^^^^^ function or associated item not found in `Example` + | + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following trait defines an item `max_encoded_len`, perhaps you need to implement it: + candidate #1: `MaxEncodedLen` diff --git a/frame/support/test/tests/max_encoded_len_ui/union.rs b/max-encoded-len/tests/max_encoded_len_ui/union.rs similarity index 70% rename from frame/support/test/tests/max_encoded_len_ui/union.rs rename to max-encoded-len/tests/max_encoded_len_ui/union.rs index c685b6939e9b..932c484b9e67 100644 --- a/frame/support/test/tests/max_encoded_len_ui/union.rs +++ b/max-encoded-len/tests/max_encoded_len_ui/union.rs @@ -1,5 +1,5 @@ use codec::Encode; -use frame_support::traits::MaxEncodedLen; +use max_encoded_len::MaxEncodedLen; #[derive(Encode, MaxEncodedLen)] union Union { diff --git a/frame/support/test/tests/max_encoded_len_ui/union.stderr b/max-encoded-len/tests/max_encoded_len_ui/union.stderr similarity index 100% rename from frame/support/test/tests/max_encoded_len_ui/union.stderr rename to max-encoded-len/tests/max_encoded_len_ui/union.stderr diff --git a/frame/support/test/tests/max_encoded_len_ui/unsupported_variant.rs b/max-encoded-len/tests/max_encoded_len_ui/unsupported_variant.rs similarity index 77% rename from frame/support/test/tests/max_encoded_len_ui/unsupported_variant.rs rename to max-encoded-len/tests/max_encoded_len_ui/unsupported_variant.rs index 675f62c168a6..2fa94867471b 100644 --- a/frame/support/test/tests/max_encoded_len_ui/unsupported_variant.rs +++ b/max-encoded-len/tests/max_encoded_len_ui/unsupported_variant.rs @@ -1,5 +1,5 @@ use codec::Encode; -use frame_support::traits::MaxEncodedLen; +use max_encoded_len::MaxEncodedLen; #[derive(Encode)] struct NotMel; diff --git a/frame/support/test/tests/max_encoded_len_ui/unsupported_variant.stderr b/max-encoded-len/tests/max_encoded_len_ui/unsupported_variant.stderr similarity index 100% rename from frame/support/test/tests/max_encoded_len_ui/unsupported_variant.stderr rename to max-encoded-len/tests/max_encoded_len_ui/unsupported_variant.stderr diff --git a/primitives/application-crypto/Cargo.toml b/primitives/application-crypto/Cargo.toml index fff289e9a1d8..7f3e48ae4825 100644 --- a/primitives/application-crypto/Cargo.toml +++ b/primitives/application-crypto/Cargo.toml @@ -20,10 +20,19 @@ codec = { package = "parity-scale-codec", version = "2.0.0", default-features = serde = { version = "1.0.101", optional = true, features = ["derive"] } sp-std = { version = "3.0.0", default-features = false, path = "../std" } sp-io = { version = "3.0.0", default-features = false, path = "../io" } +max-encoded-len = { version = "3.0.0", default-features = false, path = "../../max-encoded-len", features = [ "derive" ] } [features] default = [ "std" ] -std = [ "full_crypto", "sp-core/std", "codec/std", "serde", "sp-std/std", "sp-io/std" ] +std = [ + "full_crypto", + "sp-core/std", + "codec/std", + "serde", + "sp-std/std", + "sp-io/std", + "max-encoded-len/std", +] # This feature enables all crypto primitives for `no_std` builds like microcontrollers # or Intel SGX. diff --git a/primitives/application-crypto/src/lib.rs b/primitives/application-crypto/src/lib.rs index d085d961a102..58e5c5b7a311 100644 --- a/primitives/application-crypto/src/lib.rs +++ b/primitives/application-crypto/src/lib.rs @@ -39,6 +39,8 @@ pub use sp_std::{ ops::Deref, vec::Vec, }; +#[doc(hidden)] +pub use max_encoded_len; pub mod ed25519; pub mod sr25519; @@ -194,12 +196,13 @@ macro_rules! app_crypto_public_full_crypto { $crate::wrap!{ /// A generic `AppPublic` wrapper type over $public crypto; this has no specific App. #[derive( - Clone, Default, Eq, PartialEq, Ord, PartialOrd, + Clone, Default, Eq, Hash, PartialEq, PartialOrd, Ord, $crate::codec::Encode, $crate::codec::Decode, $crate::RuntimeDebug, + $crate::max_encoded_len::MaxEncodedLen, )] - #[derive(Hash)] + #[max_encoded_len_crate($crate::max_encoded_len)] pub struct Public($public); } diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index 3d9cf1287e05..79973bc78257 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -40,6 +40,7 @@ parity-util-mem = { version = "0.9.0", default-features = false, features = ["pr futures = { version = "0.3.1", optional = true } dyn-clonable = { version = "0.9.0", optional = true } thiserror = { version = "1.0.21", optional = true } +max-encoded-len = { version = "3.0.0", default-features = false, path = "../../max-encoded-len", features = [ "derive" ] } # full crypto ed25519-dalek = { version = "1.0.1", default-features = false, features = ["u64_backend", "alloc"], optional = true } @@ -114,6 +115,7 @@ std = [ "futures/thread-pool", "libsecp256k1/std", "dyn-clonable", + "max-encoded-len/std", ] # This feature enables all crypto primitives for `no_std` builds like microcontrollers diff --git a/primitives/core/src/crypto.rs b/primitives/core/src/crypto.rs index 4d075dc6ff4f..08e6211e3233 100644 --- a/primitives/core/src/crypto.rs +++ b/primitives/core/src/crypto.rs @@ -20,6 +20,7 @@ // end::description[] use crate::{sr25519, ed25519}; +use max_encoded_len::MaxEncodedLen; use sp_std::hash::Hash; use sp_std::vec::Vec; use sp_std::str; @@ -689,7 +690,7 @@ pub trait Public: } /// An opaque 32-byte cryptographic identifier. -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Default, Encode, Decode)] +#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Default, Encode, Decode, MaxEncodedLen)] #[cfg_attr(feature = "std", derive(Hash))] pub struct AccountId32([u8; 32]); diff --git a/primitives/core/src/ecdsa.rs b/primitives/core/src/ecdsa.rs index 60fa7c3e8193..1fb80f24eaf3 100644 --- a/primitives/core/src/ecdsa.rs +++ b/primitives/core/src/ecdsa.rs @@ -52,7 +52,7 @@ pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"ecds"); type Seed = [u8; 32]; /// The ECDSA compressed public key. -#[derive(Clone, Encode, Decode, PassByInner)] +#[derive(Clone, Encode, Decode, PassByInner, max_encoded_len::MaxEncodedLen)] pub struct Public(pub [u8; 33]); impl PartialOrd for Public { diff --git a/primitives/core/src/ed25519.rs b/primitives/core/src/ed25519.rs index 4b160e55b86a..392dc2eec6c6 100644 --- a/primitives/core/src/ed25519.rs +++ b/primitives/core/src/ed25519.rs @@ -54,7 +54,10 @@ type Seed = [u8; 32]; /// A public key. #[cfg_attr(feature = "full_crypto", derive(Hash))] -#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Encode, Decode, Default, PassByInner)] +#[derive( + PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Encode, Decode, Default, PassByInner, + max_encoded_len::MaxEncodedLen, +)] pub struct Public(pub [u8; 32]); /// A key pair. diff --git a/primitives/core/src/sr25519.rs b/primitives/core/src/sr25519.rs index f8e17f7b802a..269f19cba007 100644 --- a/primitives/core/src/sr25519.rs +++ b/primitives/core/src/sr25519.rs @@ -60,7 +60,10 @@ pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"sr25"); /// An Schnorrkel/Ristretto x25519 ("sr25519") public key. #[cfg_attr(feature = "full_crypto", derive(Hash))] -#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Encode, Decode, Default, PassByInner)] +#[derive( + PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Encode, Decode, Default, PassByInner, + max_encoded_len::MaxEncodedLen, +)] pub struct Public(pub [u8; 32]); /// An Schnorrkel/Ristretto x25519 ("sr25519") key pair. diff --git a/primitives/runtime/Cargo.toml b/primitives/runtime/Cargo.toml index 7d33e7fa62d2..aec2bc416ee3 100644 --- a/primitives/runtime/Cargo.toml +++ b/primitives/runtime/Cargo.toml @@ -29,6 +29,7 @@ impl-trait-for-tuples = "0.2.1" parity-util-mem = { version = "0.9.0", default-features = false, features = ["primitive-types"] } hash256-std-hasher = { version = "0.15.2", default-features = false } either = { version = "1.5", default-features = false } +max-encoded-len = { version = "3.0.0", default-features = false, path = "../../max-encoded-len", features = [ "derive" ] } [dev-dependencies] serde_json = "1.0.41" @@ -55,4 +56,5 @@ std = [ "parity-util-mem/std", "hash256-std-hasher/std", "either/use_std", + "max-encoded-len/std", ] diff --git a/primitives/runtime/src/traits.rs b/primitives/runtime/src/traits.rs index 22f6cb044a00..2379fce9949e 100644 --- a/primitives/runtime/src/traits.rs +++ b/primitives/runtime/src/traits.rs @@ -40,6 +40,7 @@ pub use sp_arithmetic::traits::{ use sp_application_crypto::AppKey; use impl_trait_for_tuples::impl_for_tuples; use crate::DispatchResult; +use max_encoded_len::MaxEncodedLen; /// A lazy value. pub trait Lazy { @@ -386,7 +387,7 @@ impl::Output> { /// The hash type produced. type Output: Member + MaybeSerializeDeserialize + Debug + sp_std::hash::Hash - + AsRef<[u8]> + AsMut<[u8]> + Copy + Default + Encode + Decode; + + AsRef<[u8]> + AsMut<[u8]> + Copy + Default + Encode + Decode + MaxEncodedLen; /// Produce the hash of some byte-slice. fn hash(s: &[u8]) -> Self::Output {