From dda12d499db3da8a4acd3bc84472a77a7d2a3f2a Mon Sep 17 00:00:00 2001 From: Ankan Date: Fri, 29 Mar 2024 10:13:36 +0100 Subject: [PATCH 001/257] add ability to super bond to staking --- substrate/frame/staking/src/ledger.rs | 32 ++++-- substrate/frame/staking/src/pallet/impls.rs | 119 +++++++++++++++++++- substrate/frame/staking/src/pallet/mod.rs | 44 +++----- substrate/frame/staking/src/slashing.rs | 22 ++-- substrate/primitives/staking/src/lib.rs | 95 +++++++++++++++- 5 files changed, 259 insertions(+), 53 deletions(-) diff --git a/substrate/frame/staking/src/ledger.rs b/substrate/frame/staking/src/ledger.rs index 9461daefed65..641d7c81ae41 100644 --- a/substrate/frame/staking/src/ledger.rs +++ b/substrate/frame/staking/src/ledger.rs @@ -33,13 +33,14 @@ use frame_support::{ defensive, ensure, - traits::{Defensive, LockableCurrency, WithdrawReasons}, + traits::{Defensive, LockableCurrency}, }; use sp_staking::StakingAccount; use sp_std::prelude::*; use crate::{ - BalanceOf, Bonded, Config, Error, Ledger, Payee, RewardDestination, StakingLedger, STAKING_ID, + BalanceOf, Bonded, Config, Error, Ledger, Pallet, Payee, RewardDestination, StakingLedger, + STAKING_ID, }; #[cfg(any(feature = "runtime-benchmarks", test))] @@ -187,7 +188,7 @@ impl StakingLedger { return Err(Error::::NotStash) } - T::Currency::set_lock(STAKING_ID, &self.stash, self.total, WithdrawReasons::all()); + Pallet::::update_lock(&self.stash, self.total).map_err(|_| Error::::BadState)?; Ledger::::insert( &self.controller().ok_or_else(|| { defensive!("update called on a ledger that is not bonded."); @@ -204,22 +205,29 @@ impl StakingLedger { /// It sets the reward preferences for the bonded stash. pub(crate) fn bond(self, payee: RewardDestination) -> Result<(), Error> { if >::contains_key(&self.stash) { - Err(Error::::AlreadyBonded) - } else { - >::insert(&self.stash, payee); - >::insert(&self.stash, &self.stash); - self.update() + return Err(Error::::AlreadyBonded) + } + if Pallet::::restrict_reward_destination(&self.stash, payee.clone()) { + return Err(Error::::RewardDestinationRestricted); } + + >::insert(&self.stash, payee); + >::insert(&self.stash, &self.stash); + self.update() } /// Sets the ledger Payee. pub(crate) fn set_payee(self, payee: RewardDestination) -> Result<(), Error> { if !>::contains_key(&self.stash) { - Err(Error::::NotStash) - } else { - >::insert(&self.stash, payee); - Ok(()) + return Err(Error::::NotStash) + } + + if Pallet::::restrict_reward_destination(&self.stash, payee.clone()) { + return Err(Error::::RewardDestinationRestricted); } + + >::insert(&self.stash, payee); + Ok(()) } /// Sets the ledger controller to its stash. diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 2f43e4847e45..a7428d9ad905 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -28,14 +28,16 @@ use frame_support::{ pallet_prelude::*, traits::{ Currency, Defensive, DefensiveSaturating, EstimateNextNewSession, Get, Imbalance, - InspectLockableCurrency, Len, OnUnbalanced, TryCollect, UnixTime, + InspectLockableCurrency, Len, LockableCurrency, OnUnbalanced, TryCollect, UnixTime, }, weights::Weight, }; use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin}; use pallet_session::historical; use sp_runtime::{ - traits::{Bounded, Convert, One, SaturatedConversion, Saturating, StaticLookup, Zero}, + traits::{ + Bounded, CheckedSub, Convert, One, SaturatedConversion, Saturating, StaticLookup, Zero, + }, Perbill, Percent, }; use sp_staking::{ @@ -149,6 +151,37 @@ impl Pallet { Self::slashable_balance_of_vote_weight(who, issuance) } + pub(super) fn do_bond_extra(stash: &T::AccountId, additional: BalanceOf) -> DispatchResult { + let mut ledger = Self::ledger(StakingAccount::Stash(stash.clone()))?; + + let extra = if Self::is_virtual_nominator(stash) { + additional + } else { + // additional amount or actual balance of stash whichever is lower. + additional.min( + T::Currency::free_balance(stash) + .checked_sub(&ledger.total) + .ok_or(sp_runtime::ArithmeticError::Overflow)?, + ) + }; + + ledger.total += extra; + ledger.active += extra; + // Last check: the new active amount of ledger must be more than ED. + ensure!(ledger.active >= T::Currency::minimum_balance(), Error::::InsufficientBond); + + // NOTE: ledger must be updated prior to calling `Self::weight_of`. + ledger.update()?; + // update this staker in the sorted list, if they exist in it. + if T::VoterList::contains(stash) { + let _ = T::VoterList::on_update(&stash, Self::weight_of(stash)).defensive(); + } + + Self::deposit_event(Event::::Bonded { stash: stash.clone(), amount: extra }); + + Ok(()) + } + pub(super) fn do_withdraw_unbonded( controller: &T::AccountId, num_slashing_spans: u32, @@ -1132,6 +1165,45 @@ impl Pallet { ) -> Exposure> { EraInfo::::get_full_exposure(era, account) } + + /// Whether the passed reward destination is restricted for the given account. + /// + /// Virtual nominators are not allowed to compound their rewards as this pallet does not manage + /// locks for them. For external pallets that manage the virtual bond, it is their + /// responsibility to distribute the reward and re-bond them. + /// + /// Conservatively, we expect them to always set the reward destination to a non stash account. + pub(crate) fn restrict_reward_destination( + who: &T::AccountId, + reward_destination: RewardDestination, + ) -> bool { + Self::is_virtual_nominator(who) && + match reward_destination { + RewardDestination::Account(payee) => payee == *who, + _ => true, + } + } + + pub(crate) fn is_virtual_nominator(who: &T::AccountId) -> bool { + VirtualNominators::::contains_key(who) + } + + pub(crate) fn update_lock( + who: &T::AccountId, + amount: BalanceOf, + ) -> sp_runtime::DispatchResult { + // Skip locking virtual nominators. They are handled by external pallets. + if !Self::is_virtual_nominator(who) { + T::Currency::set_lock( + crate::STAKING_ID, + who, + amount, + frame_support::traits::WithdrawReasons::all(), + ); + } + + Ok(()) + } } impl Pallet { @@ -1748,6 +1820,15 @@ impl StakingInterface for Pallet { .map(|_| ()) } + fn update_payee(stash: &Self::AccountId, reward_acc: &Self::AccountId) -> DispatchResult { + // since controller is deprecated and this function is never used for old ledgers with + // distinct controllers, we can safely assume that stash is the controller. + Self::set_payee( + RawOrigin::Signed(stash.clone()).into(), + RewardDestination::Account(reward_acc.clone()), + ) + } + fn chill(who: &Self::AccountId) -> DispatchResult { // defensive-only: any account bonded via this interface has the stash set as the // controller, but we have to be sure. Same comment anywhere else that we read this. @@ -1832,6 +1913,10 @@ impl StakingInterface for Pallet { } } + fn slash_reward_fraction() -> Perbill { + SlashRewardFraction::::get() + } + sp_staking::runtime_benchmarks_enabled! { fn nominations(who: &Self::AccountId) -> Option> { Nominators::::get(who).map(|n| n.targets.into_inner()) @@ -1860,6 +1945,36 @@ impl StakingInterface for Pallet { } } +impl sp_staking::StakingUnsafe for Pallet { + fn force_release(who: &Self::AccountId) { + T::Currency::remove_lock(crate::STAKING_ID, who) + } + + fn virtual_bond( + who: &Self::AccountId, + value: Self::Balance, + payee: &Self::AccountId, + ) -> DispatchResult { + if StakingLedger::::is_bonded(StakingAccount::Stash(who.clone())) { + return Err(Error::::AlreadyBonded.into()) + } + + frame_system::Pallet::::inc_consumers(&who).map_err(|_| Error::::BadState)?; + + // mark who as a virtual nominator + VirtualNominators::::insert(who, ()); + + Self::deposit_event(Event::::Bonded { stash: who.clone(), amount: value }); + let ledger = StakingLedger::::new(who.clone(), value); + + // You're auto-bonded forever, here. We might improve this by only bonding when + // you actually validate/nominate and remove once you unbond __everything__. + ledger.bond(RewardDestination::Account(payee.clone()))?; + + Ok(()) + } +} + #[cfg(any(test, feature = "try-runtime"))] impl Pallet { pub(crate) fn do_try_state(_: BlockNumberFor) -> Result<(), TryRuntimeError> { diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 2e5b3aa7b873..bd5372a3e6f2 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -32,7 +32,7 @@ use frame_support::{ }; use frame_system::{ensure_root, ensure_signed, pallet_prelude::*}; use sp_runtime::{ - traits::{CheckedSub, SaturatedConversion, StaticLookup, Zero}, + traits::{SaturatedConversion, StaticLookup, Zero}, ArithmeticError, Perbill, Percent, }; @@ -379,6 +379,16 @@ pub mod pallet { pub type Nominators = CountedStorageMap<_, Twox64Concat, T::AccountId, Nominations>; + /// Nominators whose funds are managed by other pallets. + /// + /// This pallet does not apply any locks on them, therefore they are only virtually bonded. They + /// are expected to be keyless accounts and hence should not be allowed to mutate their ledger + /// directly via this pallet. Instead, these accounts are managed by other pallets and accessed + /// via low level apis. We keep track of them to do minimal integrity checks. + // TODO(ank4n): Can we keep this entry in `Ledger`? Worth a migration? + #[pallet::storage] + pub type VirtualNominators = CountedStorageMap<_, Twox64Concat, T::AccountId, ()>; + /// The maximum nominator count before we stop allowing new validators to join. /// /// When this value is not set, no limits are enforced. @@ -858,6 +868,10 @@ pub mod pallet { ControllerDeprecated, /// Cannot reset a ledger. CannotRestoreLedger, + /// Provided reward destination is not allowed. + RewardDestinationRestricted, + /// Not enough funds available to withdraw + NotEnoughFunds, } #[pallet::hooks] @@ -985,29 +999,7 @@ pub mod pallet { #[pallet::compact] max_additional: BalanceOf, ) -> DispatchResult { let stash = ensure_signed(origin)?; - let mut ledger = Self::ledger(StakingAccount::Stash(stash.clone()))?; - - let stash_balance = T::Currency::free_balance(&stash); - if let Some(extra) = stash_balance.checked_sub(&ledger.total) { - let extra = extra.min(max_additional); - ledger.total += extra; - ledger.active += extra; - // Last check: the new active amount of ledger must be more than ED. - ensure!( - ledger.active >= T::Currency::minimum_balance(), - Error::::InsufficientBond - ); - - // NOTE: ledger must be updated prior to calling `Self::weight_of`. - ledger.update()?; - // update this staker in the sorted list, if they exist in it. - if T::VoterList::contains(&stash) { - let _ = T::VoterList::on_update(&stash, Self::weight_of(&stash)).defensive(); - } - - Self::deposit_event(Event::::Bonded { stash, amount: extra }); - } - Ok(()) + Self::do_bond_extra(&stash, max_additional) } /// Schedule a portion of the stash to be unlocked ready for transfer out after the bond @@ -1315,9 +1307,7 @@ pub mod pallet { Error::::ControllerDeprecated ); - let _ = ledger - .set_payee(payee) - .defensive_proof("ledger was retrieved from storage, thus its bonded; qed.")?; + ledger.set_payee(payee)?; Ok(()) } diff --git a/substrate/frame/staking/src/slashing.rs b/substrate/frame/staking/src/slashing.rs index 709fd1441ec3..19424f57dcdb 100644 --- a/substrate/frame/staking/src/slashing.rs +++ b/substrate/frame/staking/src/slashing.rs @@ -609,8 +609,13 @@ pub fn do_slash( }; let value = ledger.slash(value, T::Currency::minimum_balance(), slash_era); + if value.is_zero() { + // nothing to do + return + } - if !value.is_zero() { + // Skip slashing for virtual nominators. The pallets managing them should handle the slashing. + if !Pallet::::is_virtual_nominator(stash) { let (imbalance, missing) = T::Currency::slash(stash, value); slashed_imbalance.subsume(imbalance); @@ -618,17 +623,14 @@ pub fn do_slash( // deduct overslash from the reward payout *reward_payout = reward_payout.saturating_sub(missing); } + } - let _ = ledger - .update() - .defensive_proof("ledger fetched from storage so it exists in storage; qed."); + let _ = ledger + .update() + .defensive_proof("ledger fetched from storage so it exists in storage; qed."); - // trigger the event - >::deposit_event(super::Event::::Slashed { - staker: stash.clone(), - amount: value, - }); - } + // trigger the event + >::deposit_event(super::Event::::Slashed { staker: stash.clone(), amount: value }); } /// Apply a previously-unapplied slash. diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index 11b7ef41b9a7..3f2c8c9fb493 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -29,7 +29,7 @@ use core::ops::Sub; use scale_info::TypeInfo; use sp_runtime::{ traits::{AtLeast32BitUnsigned, Zero}, - DispatchError, DispatchResult, RuntimeDebug, Saturating, + DispatchError, DispatchResult, Perbill, RuntimeDebug, Saturating, }; pub mod offence; @@ -254,6 +254,9 @@ pub trait StakingInterface { /// schedules have reached their unlocking era should allow more calls to this function. fn unbond(stash: &Self::AccountId, value: Self::Balance) -> DispatchResult; + /// Update the reward destination for the ledger associated with the stash. + fn update_payee(stash: &Self::AccountId, reward_acc: &Self::AccountId) -> DispatchResult; + /// Unlock any funds schedule to unlock before or at the current era. /// /// Returns whether the stash was killed because of this withdraw or not. @@ -274,7 +277,7 @@ pub trait StakingInterface { /// Checks whether an account `staker` has been exposed in an era. fn is_exposed_in_era(who: &Self::AccountId, era: &EraIndex) -> bool; - /// Return the status of the given staker, `None` if not staked at all. + /// Return the status of the given staker, `Err` if not staked at all. fn status(who: &Self::AccountId) -> Result, DispatchError>; /// Checks whether or not this is a validator account. @@ -290,6 +293,9 @@ pub trait StakingInterface { } } + /// Returns the fraction of the slash to be rewarded to reporter. + fn slash_reward_fraction() -> Perbill; + #[cfg(feature = "runtime-benchmarks")] fn max_exposure_page_size() -> Page; @@ -304,6 +310,27 @@ pub trait StakingInterface { fn set_current_era(era: EraIndex); } +/// Set of low level apis to manipulate staking ledger. +/// +/// These apis bypass some or all safety checks and should only be used if you know what you are +/// doing. +pub trait StakingUnsafe: StakingInterface { + /// Release all funds bonded for stake without unbonding the ledger. + /// + /// Unsafe, only used for migration of `nominator` to `virtual_nominator`. + fn force_release(who: &Self::AccountId); + + /// Book-keep a new bond for `who` without applying any locks (hence virtual). + /// + /// It is important that who is a keyless account and therefore cannot interact with staking + /// pallet directly. Caller is responsible for ensuring the passed amount is locked and valid. + fn virtual_bond( + keyless_who: &Self::AccountId, + value: Self::Balance, + payee: &Self::AccountId, + ) -> DispatchResult; +} + /// The amount of exposure for an era that an individual nominator has (susceptible to slashing). #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] pub struct IndividualExposure { @@ -422,4 +449,68 @@ pub struct PagedExposureMetadata { pub page_count: Page, } +/// Extension of [`StakingInterface`] with delegation functionality. +/// +/// Introduces two new actors: +/// - `Delegator`: An account that delegates funds to a `Delegatee`. +/// - `Delegatee`: An account that receives delegated funds from `Delegators`. It can then use these +/// funds to participate in the staking system. It can never use its own funds. +/// +/// The `Delegatee` is responsible for managing rewards and slashing for all the `Delegators` that +/// have delegated funds to it. +pub trait DelegatedStakeInterface: StakingInterface { + /// Effective balance of the `delegatee` account. + /// + /// This takes into account any pending slashes to `Delegatee`. + fn delegatee_balance(delegatee: &Self::AccountId) -> Self::Balance; + + /// Returns the total amount of funds delegated by a `delegator`. + fn delegator_balance(delegator: &Self::AccountId) -> Self::Balance; + + /// Delegate funds to `delegatee`. + /// + /// Only used for the initial delegation. Use [`Self::delegate_extra`] to add more delegation. + fn delegate( + delegator: &Self::AccountId, + delegatee: &Self::AccountId, + reward_account: &Self::AccountId, + amount: Self::Balance, + ) -> DispatchResult; + + /// Add more delegation to the `delegatee`. + /// + /// If this is the first delegation, use [`Self::delegate`] instead. + fn delegate_extra( + delegator: &Self::AccountId, + delegatee: &Self::AccountId, + amount: Self::Balance, + ) -> DispatchResult; + + /// Withdraw or revoke delegation to `delegatee`. + /// + /// If there are `delegatee` funds upto `amount` available to withdraw, then those funds would + /// be released to the `delegator` + fn withdraw_delegation( + delegator: &Self::AccountId, + delegatee: &Self::AccountId, + amount: Self::Balance, + ) -> DispatchResult; + + /// Returns true if there are pending slashes posted to the `delegatee` account. + /// + /// Slashes to `delegatee` account are not immediate and are applied lazily. Since `delegatee` + /// has an unbounded number of delegators, immediate slashing is not possible. + fn has_pending_slash(delegatee: &Self::AccountId) -> bool; + + /// Apply a pending slash to a `delegatee` by slashing `value` from `delegator`. + /// + /// If a reporter is provided, the reporter will receive a fraction of the slash as reward. + fn delegator_slash( + delegatee: &Self::AccountId, + delegator: &Self::AccountId, + value: Self::Balance, + maybe_reporter: Option, + ) -> sp_runtime::DispatchResult; +} + sp_core::generate_feature_enabled_macro!(runtime_benchmarks_enabled, feature = "runtime-benchmarks", $); From 802784c44f2d3f691f708ba7ba3910f5445bf5e0 Mon Sep 17 00:00:00 2001 From: Ankan Date: Fri, 29 Mar 2024 10:25:28 +0100 Subject: [PATCH 002/257] some comments --- substrate/frame/staking/src/pallet/impls.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index a7428d9ad905..bd890e86468c 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -154,6 +154,8 @@ impl Pallet { pub(super) fn do_bond_extra(stash: &T::AccountId, additional: BalanceOf) -> DispatchResult { let mut ledger = Self::ledger(StakingAccount::Stash(stash.clone()))?; + // for virtual nominators, we don't need to check the balance. Since they are only accessed + // via low level apis, we can assume that the caller has done the due diligence. let extra = if Self::is_virtual_nominator(stash) { additional } else { @@ -1184,10 +1186,15 @@ impl Pallet { } } + /// Whether `who` is a virtual nominator whose funds are managed by another pallet. pub(crate) fn is_virtual_nominator(who: &T::AccountId) -> bool { VirtualNominators::::contains_key(who) } + + /// Update the lock for a staker. + /// + /// For virtual nominators, it is no-op. pub(crate) fn update_lock( who: &T::AccountId, amount: BalanceOf, From d2b680e4b6d337fa39fca748e5a95c44dba5dc8d Mon Sep 17 00:00:00 2001 From: Ankan Date: Fri, 29 Mar 2024 10:35:25 +0100 Subject: [PATCH 003/257] fix tests --- substrate/frame/nomination-pools/src/mock.rs | 8 ++++++++ substrate/frame/staking/src/pallet/impls.rs | 1 - 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/substrate/frame/nomination-pools/src/mock.rs b/substrate/frame/nomination-pools/src/mock.rs index 686759604c23..2e30bbeed59e 100644 --- a/substrate/frame/nomination-pools/src/mock.rs +++ b/substrate/frame/nomination-pools/src/mock.rs @@ -128,6 +128,10 @@ impl sp_staking::StakingInterface for StakingMock { Ok(()) } + fn update_payee(_stash: &Self::AccountId, _reward_acc: &Self::AccountId) -> DispatchResult { + unimplemented!("method currently not used in testing") + } + fn chill(_: &Self::AccountId) -> sp_runtime::DispatchResult { Ok(()) } @@ -220,6 +224,10 @@ impl sp_staking::StakingInterface for StakingMock { fn max_exposure_page_size() -> sp_staking::Page { unimplemented!("method currently not used in testing") } + + fn slash_reward_fraction() -> Perbill { + unimplemented!("method currently not used in testing") + } } #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index bd890e86468c..aed8eba61383 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -1191,7 +1191,6 @@ impl Pallet { VirtualNominators::::contains_key(who) } - /// Update the lock for a staker. /// /// For virtual nominators, it is no-op. From 646c7f4edff8bbd9aee1e4af8cbf865cf1772744 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 31 Mar 2024 21:19:48 +0200 Subject: [PATCH 004/257] tests --- substrate/frame/staking/src/ledger.rs | 11 +-- substrate/frame/staking/src/pallet/impls.rs | 11 ++- substrate/frame/staking/src/pallet/mod.rs | 4 +- substrate/frame/staking/src/tests.rs | 74 +++++++++++++++++++++ substrate/primitives/staking/src/lib.rs | 64 ------------------ 5 files changed, 91 insertions(+), 73 deletions(-) diff --git a/substrate/frame/staking/src/ledger.rs b/substrate/frame/staking/src/ledger.rs index 641d7c81ae41..2c9fb65925a0 100644 --- a/substrate/frame/staking/src/ledger.rs +++ b/substrate/frame/staking/src/ledger.rs @@ -38,10 +38,7 @@ use frame_support::{ use sp_staking::StakingAccount; use sp_std::prelude::*; -use crate::{ - BalanceOf, Bonded, Config, Error, Ledger, Pallet, Payee, RewardDestination, StakingLedger, - STAKING_ID, -}; +use crate::{BalanceOf, Bonded, Config, Error, Ledger, Pallet, Payee, RewardDestination, StakingLedger, STAKING_ID, VirtualStakers}; #[cfg(any(feature = "runtime-benchmarks", test))] use sp_runtime::traits::Zero; @@ -188,7 +185,9 @@ impl StakingLedger { return Err(Error::::NotStash) } + // update lock on stash based on ledger. Pallet::::update_lock(&self.stash, self.total).map_err(|_| Error::::BadState)?; + Ledger::::insert( &self.controller().ok_or_else(|| { defensive!("update called on a ledger that is not bonded."); @@ -207,6 +206,8 @@ impl StakingLedger { if >::contains_key(&self.stash) { return Err(Error::::AlreadyBonded) } + + // check if the payee is ok. if Pallet::::restrict_reward_destination(&self.stash, payee.clone()) { return Err(Error::::RewardDestinationRestricted); } @@ -222,6 +223,7 @@ impl StakingLedger { return Err(Error::::NotStash) } + // check if the payee is ok. if Pallet::::restrict_reward_destination(&self.stash, payee.clone()) { return Err(Error::::RewardDestinationRestricted); } @@ -265,6 +267,7 @@ impl StakingLedger { >::remove(&stash); >::remove(&stash); + >::remove(&stash); Ok(()) })? diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index aed8eba61383..0a72222e5c5e 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -1188,7 +1188,7 @@ impl Pallet { /// Whether `who` is a virtual nominator whose funds are managed by another pallet. pub(crate) fn is_virtual_nominator(who: &T::AccountId) -> bool { - VirtualNominators::::contains_key(who) + VirtualStakers::::contains_key(who) } /// Update the lock for a staker. @@ -1965,10 +1965,14 @@ impl sp_staking::StakingUnsafe for Pallet { return Err(Error::::AlreadyBonded.into()) } + // check if payee not same as who. + ensure!(who != payee, Error::::RewardDestinationRestricted); + + // mark this pallet as consumer of `who`. frame_system::Pallet::::inc_consumers(&who).map_err(|_| Error::::BadState)?; - // mark who as a virtual nominator - VirtualNominators::::insert(who, ()); + // mark who as a virtual nominator. + VirtualStakers::::insert(who, ()); Self::deposit_event(Event::::Bonded { stash: who.clone(), amount: value }); let ledger = StakingLedger::::new(who.clone(), value); @@ -2105,6 +2109,7 @@ impl Pallet { /// * Staking ledger and bond are not corrupted. fn check_ledgers() -> Result<(), TryRuntimeError> { Bonded::::iter() + .filter(|(stash, _)| !VirtualStakers::::contains_key(stash)) .map(|(stash, ctrl)| { // ensure locks consistency. ensure!( diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index bd5372a3e6f2..8f18102175c0 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -379,7 +379,7 @@ pub mod pallet { pub type Nominators = CountedStorageMap<_, Twox64Concat, T::AccountId, Nominations>; - /// Nominators whose funds are managed by other pallets. + /// Stakers whose funds are managed by other pallets. /// /// This pallet does not apply any locks on them, therefore they are only virtually bonded. They /// are expected to be keyless accounts and hence should not be allowed to mutate their ledger @@ -387,7 +387,7 @@ pub mod pallet { /// via low level apis. We keep track of them to do minimal integrity checks. // TODO(ank4n): Can we keep this entry in `Ledger`? Worth a migration? #[pallet::storage] - pub type VirtualNominators = CountedStorageMap<_, Twox64Concat, T::AccountId, ()>; + pub type VirtualStakers = CountedStorageMap<_, Twox64Concat, T::AccountId, ()>; /// The maximum nominator count before we stop allowing new validators to join. /// diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index a5c9abe2f176..f79586072f1d 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -6849,6 +6849,80 @@ mod staking_interface { } } +mod staking_unsafe { + use frame_support::traits::InspectLockableCurrency; + use sp_staking::{StakingUnsafe, StakingInterface, Stake}; + + use super::*; + + #[test] + fn virtual_bond_does_not_lock() { + ExtBuilder::default().build_and_execute(|| { + mock::start_active_era(1); + assert_eq!(Balances::free_balance(10), 1); + // 10 can bond more than its balance amount since we do not require lock for virtual + // bonding. + assert_ok!(::virtual_bond(&10, 100, &15)); + // nothing is locked on 10. + assert_eq!(Balances::balance_locked(STAKING_ID, &10), 0); + // adding more balance does not lock anything as well. + assert_ok!(::bond_extra(&10, 1000)); + // but ledger is updated correctly. + assert_eq!(::stake(&10), Ok(Stake { total: 1100, active: 1100 })); + + // lets try unbonding some amount. + assert_ok!(::unbond(&10, 200)); + assert_eq!( + Staking::ledger(10.into()).unwrap(), + StakingLedgerInspect { + stash: 10, + total: 1100, + active: 1100 - 200, + unlocking: bounded_vec![UnlockChunk { value: 200, era: 1 + 3 }], + legacy_claimed_rewards: bounded_vec![], + }); + + assert_eq!(::stake(&10), Ok(Stake { total: 1100, active: 900 })); + // still no locks. + assert_eq!(Balances::balance_locked(STAKING_ID, &10), 0); + + mock::start_active_era(2); + // cannot withdraw without waiting for unbonding period. + assert_ok!(::withdraw_unbonded(10, 0)); + assert_eq!(::stake(&10), Ok(Stake { total: 1100, active: 900 })); + + // in era 4, 10 can withdraw unlocking amount. + mock::start_active_era(4); + assert_ok!(::withdraw_unbonded(10, 0)); + assert_eq!(::stake(&10), Ok(Stake { total: 900, active: 900 })); + + // unbond all. + assert_ok!(::unbond(&10, 900)); + assert_eq!(::stake(&10), Ok(Stake { total: 900, active: 0 })); + mock::start_active_era(7); + assert_ok!(::withdraw_unbonded(10, 0)); + + // ensure withdrawing all amount cleans up storage. + assert_eq!(Staking::ledger(10.into()), Err(Error::::NotStash)); + assert_eq!(VirtualStakers::::contains_key(10), false); + }) + } + + #[test] + fn virtual_nominator_cannot_pay_reward_to_self_account() { + ExtBuilder::default().build_and_execute(|| { + // cannot set payee to self + assert_noop!(::virtual_bond(&10, 100, &10), Error::::RewardDestinationRestricted); + + // to another account works + assert_ok!(::virtual_bond(&10, 100, &11)); + + // cannot set via set_payee as well. + assert_noop!(::update_payee(&10, &10), Error::::RewardDestinationRestricted); + }); + } +} + mod ledger { use super::*; diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index 3f2c8c9fb493..0e1812e10ab2 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -449,68 +449,4 @@ pub struct PagedExposureMetadata { pub page_count: Page, } -/// Extension of [`StakingInterface`] with delegation functionality. -/// -/// Introduces two new actors: -/// - `Delegator`: An account that delegates funds to a `Delegatee`. -/// - `Delegatee`: An account that receives delegated funds from `Delegators`. It can then use these -/// funds to participate in the staking system. It can never use its own funds. -/// -/// The `Delegatee` is responsible for managing rewards and slashing for all the `Delegators` that -/// have delegated funds to it. -pub trait DelegatedStakeInterface: StakingInterface { - /// Effective balance of the `delegatee` account. - /// - /// This takes into account any pending slashes to `Delegatee`. - fn delegatee_balance(delegatee: &Self::AccountId) -> Self::Balance; - - /// Returns the total amount of funds delegated by a `delegator`. - fn delegator_balance(delegator: &Self::AccountId) -> Self::Balance; - - /// Delegate funds to `delegatee`. - /// - /// Only used for the initial delegation. Use [`Self::delegate_extra`] to add more delegation. - fn delegate( - delegator: &Self::AccountId, - delegatee: &Self::AccountId, - reward_account: &Self::AccountId, - amount: Self::Balance, - ) -> DispatchResult; - - /// Add more delegation to the `delegatee`. - /// - /// If this is the first delegation, use [`Self::delegate`] instead. - fn delegate_extra( - delegator: &Self::AccountId, - delegatee: &Self::AccountId, - amount: Self::Balance, - ) -> DispatchResult; - - /// Withdraw or revoke delegation to `delegatee`. - /// - /// If there are `delegatee` funds upto `amount` available to withdraw, then those funds would - /// be released to the `delegator` - fn withdraw_delegation( - delegator: &Self::AccountId, - delegatee: &Self::AccountId, - amount: Self::Balance, - ) -> DispatchResult; - - /// Returns true if there are pending slashes posted to the `delegatee` account. - /// - /// Slashes to `delegatee` account are not immediate and are applied lazily. Since `delegatee` - /// has an unbounded number of delegators, immediate slashing is not possible. - fn has_pending_slash(delegatee: &Self::AccountId) -> bool; - - /// Apply a pending slash to a `delegatee` by slashing `value` from `delegator`. - /// - /// If a reporter is provided, the reporter will receive a fraction of the slash as reward. - fn delegator_slash( - delegatee: &Self::AccountId, - delegator: &Self::AccountId, - value: Self::Balance, - maybe_reporter: Option, - ) -> sp_runtime::DispatchResult; -} - sp_core::generate_feature_enabled_macro!(runtime_benchmarks_enabled, feature = "runtime-benchmarks", $); From bc92a19056a1a9496c54b0be5ced3711b9394434 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 31 Mar 2024 21:24:25 +0200 Subject: [PATCH 005/257] fix naming --- substrate/frame/staking/src/pallet/impls.rs | 20 ++++++++++---------- substrate/frame/staking/src/slashing.rs | 4 ++-- substrate/frame/staking/src/tests.rs | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 0a72222e5c5e..5fda07fecf4a 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -154,9 +154,9 @@ impl Pallet { pub(super) fn do_bond_extra(stash: &T::AccountId, additional: BalanceOf) -> DispatchResult { let mut ledger = Self::ledger(StakingAccount::Stash(stash.clone()))?; - // for virtual nominators, we don't need to check the balance. Since they are only accessed + // for virtual stakers, we don't need to check the balance. Since they are only accessed // via low level apis, we can assume that the caller has done the due diligence. - let extra = if Self::is_virtual_nominator(stash) { + let extra = if Self::is_virtual_staker(stash) { additional } else { // additional amount or actual balance of stash whichever is lower. @@ -1170,7 +1170,7 @@ impl Pallet { /// Whether the passed reward destination is restricted for the given account. /// - /// Virtual nominators are not allowed to compound their rewards as this pallet does not manage + /// virtual stakers are not allowed to compound their rewards as this pallet does not manage /// locks for them. For external pallets that manage the virtual bond, it is their /// responsibility to distribute the reward and re-bond them. /// @@ -1179,27 +1179,27 @@ impl Pallet { who: &T::AccountId, reward_destination: RewardDestination, ) -> bool { - Self::is_virtual_nominator(who) && + Self::is_virtual_staker(who) && match reward_destination { RewardDestination::Account(payee) => payee == *who, _ => true, } } - /// Whether `who` is a virtual nominator whose funds are managed by another pallet. - pub(crate) fn is_virtual_nominator(who: &T::AccountId) -> bool { + /// Whether `who` is a virtual staker whose funds are managed by another pallet. + pub(crate) fn is_virtual_staker(who: &T::AccountId) -> bool { VirtualStakers::::contains_key(who) } /// Update the lock for a staker. /// - /// For virtual nominators, it is no-op. + /// For virtual stakers, it is no-op. pub(crate) fn update_lock( who: &T::AccountId, amount: BalanceOf, ) -> sp_runtime::DispatchResult { - // Skip locking virtual nominators. They are handled by external pallets. - if !Self::is_virtual_nominator(who) { + // Skip locking virtual stakers. They are handled by external pallets. + if !Self::is_virtual_staker(who) { T::Currency::set_lock( crate::STAKING_ID, who, @@ -1971,7 +1971,7 @@ impl sp_staking::StakingUnsafe for Pallet { // mark this pallet as consumer of `who`. frame_system::Pallet::::inc_consumers(&who).map_err(|_| Error::::BadState)?; - // mark who as a virtual nominator. + // mark who as a virtual staker. VirtualStakers::::insert(who, ()); Self::deposit_event(Event::::Bonded { stash: who.clone(), amount: value }); diff --git a/substrate/frame/staking/src/slashing.rs b/substrate/frame/staking/src/slashing.rs index 19424f57dcdb..2011e9eb8301 100644 --- a/substrate/frame/staking/src/slashing.rs +++ b/substrate/frame/staking/src/slashing.rs @@ -614,8 +614,8 @@ pub fn do_slash( return } - // Skip slashing for virtual nominators. The pallets managing them should handle the slashing. - if !Pallet::::is_virtual_nominator(stash) { + // Skip slashing for virtual stakers. The pallets managing them should handle the slashing. + if !Pallet::::is_virtual_staker(stash) { let (imbalance, missing) = T::Currency::slash(stash, value); slashed_imbalance.subsume(imbalance); diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index f79586072f1d..7d614366d522 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -6909,7 +6909,7 @@ mod staking_unsafe { } #[test] - fn virtual_nominator_cannot_pay_reward_to_self_account() { + fn virtual_staker_cannot_pay_reward_to_self_account() { ExtBuilder::default().build_and_execute(|| { // cannot set payee to self assert_noop!(::virtual_bond(&10, 100, &10), Error::::RewardDestinationRestricted); From 2528da740db8b615d3c428cf5c03068a059dc473 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 31 Mar 2024 21:24:51 +0200 Subject: [PATCH 006/257] fmt --- substrate/frame/staking/src/ledger.rs | 5 ++- substrate/frame/staking/src/tests.rs | 54 +++++++++++++++++++-------- 2 files changed, 42 insertions(+), 17 deletions(-) diff --git a/substrate/frame/staking/src/ledger.rs b/substrate/frame/staking/src/ledger.rs index 2c9fb65925a0..4d3bfe980482 100644 --- a/substrate/frame/staking/src/ledger.rs +++ b/substrate/frame/staking/src/ledger.rs @@ -38,7 +38,10 @@ use frame_support::{ use sp_staking::StakingAccount; use sp_std::prelude::*; -use crate::{BalanceOf, Bonded, Config, Error, Ledger, Pallet, Payee, RewardDestination, StakingLedger, STAKING_ID, VirtualStakers}; +use crate::{ + BalanceOf, Bonded, Config, Error, Ledger, Pallet, Payee, RewardDestination, StakingLedger, + VirtualStakers, STAKING_ID, +}; #[cfg(any(feature = "runtime-benchmarks", test))] use sp_runtime::traits::Zero; diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 7d614366d522..bde67760cb0e 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -6851,7 +6851,7 @@ mod staking_interface { mod staking_unsafe { use frame_support::traits::InspectLockableCurrency; - use sp_staking::{StakingUnsafe, StakingInterface, Stake}; + use sp_staking::{Stake, StakingInterface, StakingUnsafe}; use super::*; @@ -6868,37 +6868,53 @@ mod staking_unsafe { // adding more balance does not lock anything as well. assert_ok!(::bond_extra(&10, 1000)); // but ledger is updated correctly. - assert_eq!(::stake(&10), Ok(Stake { total: 1100, active: 1100 })); + assert_eq!( + ::stake(&10), + Ok(Stake { total: 1100, active: 1100 }) + ); // lets try unbonding some amount. assert_ok!(::unbond(&10, 200)); assert_eq!( - Staking::ledger(10.into()).unwrap(), - StakingLedgerInspect { - stash: 10, - total: 1100, - active: 1100 - 200, - unlocking: bounded_vec![UnlockChunk { value: 200, era: 1 + 3 }], - legacy_claimed_rewards: bounded_vec![], - }); + Staking::ledger(10.into()).unwrap(), + StakingLedgerInspect { + stash: 10, + total: 1100, + active: 1100 - 200, + unlocking: bounded_vec![UnlockChunk { value: 200, era: 1 + 3 }], + legacy_claimed_rewards: bounded_vec![], + } + ); - assert_eq!(::stake(&10), Ok(Stake { total: 1100, active: 900 })); + assert_eq!( + ::stake(&10), + Ok(Stake { total: 1100, active: 900 }) + ); // still no locks. assert_eq!(Balances::balance_locked(STAKING_ID, &10), 0); mock::start_active_era(2); // cannot withdraw without waiting for unbonding period. assert_ok!(::withdraw_unbonded(10, 0)); - assert_eq!(::stake(&10), Ok(Stake { total: 1100, active: 900 })); + assert_eq!( + ::stake(&10), + Ok(Stake { total: 1100, active: 900 }) + ); // in era 4, 10 can withdraw unlocking amount. mock::start_active_era(4); assert_ok!(::withdraw_unbonded(10, 0)); - assert_eq!(::stake(&10), Ok(Stake { total: 900, active: 900 })); + assert_eq!( + ::stake(&10), + Ok(Stake { total: 900, active: 900 }) + ); // unbond all. assert_ok!(::unbond(&10, 900)); - assert_eq!(::stake(&10), Ok(Stake { total: 900, active: 0 })); + assert_eq!( + ::stake(&10), + Ok(Stake { total: 900, active: 0 }) + ); mock::start_active_era(7); assert_ok!(::withdraw_unbonded(10, 0)); @@ -6912,13 +6928,19 @@ mod staking_unsafe { fn virtual_staker_cannot_pay_reward_to_self_account() { ExtBuilder::default().build_and_execute(|| { // cannot set payee to self - assert_noop!(::virtual_bond(&10, 100, &10), Error::::RewardDestinationRestricted); + assert_noop!( + ::virtual_bond(&10, 100, &10), + Error::::RewardDestinationRestricted + ); // to another account works assert_ok!(::virtual_bond(&10, 100, &11)); // cannot set via set_payee as well. - assert_noop!(::update_payee(&10, &10), Error::::RewardDestinationRestricted); + assert_noop!( + ::update_payee(&10, &10), + Error::::RewardDestinationRestricted + ); }); } } From 0cbec7debe4217eacc9b378d100070056be61208 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sat, 30 Mar 2024 01:38:53 +0100 Subject: [PATCH 007/257] delegated staking without pool tests --- Cargo.lock | 23 + Cargo.toml | 1 + substrate/frame/delegated-staking/Cargo.toml | 70 ++ .../delegated-staking/src/benchmarking.rs | 20 + .../frame/delegated-staking/src/impls.rs | 288 ++++++ substrate/frame/delegated-staking/src/lib.rs | 827 ++++++++++++++++++ substrate/frame/delegated-staking/src/mock.rs | 329 +++++++ .../frame/delegated-staking/src/tests.rs | 541 ++++++++++++ .../frame/delegated-staking/src/types.rs | 314 +++++++ 9 files changed, 2413 insertions(+) create mode 100644 substrate/frame/delegated-staking/Cargo.toml create mode 100644 substrate/frame/delegated-staking/src/benchmarking.rs create mode 100644 substrate/frame/delegated-staking/src/impls.rs create mode 100644 substrate/frame/delegated-staking/src/lib.rs create mode 100644 substrate/frame/delegated-staking/src/mock.rs create mode 100644 substrate/frame/delegated-staking/src/tests.rs create mode 100644 substrate/frame/delegated-staking/src/types.rs diff --git a/Cargo.lock b/Cargo.lock index 81eb682a27d7..8555a55d037f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9698,6 +9698,29 @@ dependencies = [ "sp-std 14.0.0", ] +[[package]] +name = "pallet-delegated-staking" +version = "4.0.0-dev" +dependencies = [ + "frame-election-provider-support", + "frame-support", + "frame-system", + "pallet-balances", + "pallet-nomination-pools", + "pallet-staking", + "pallet-staking-reward-curve", + "pallet-timestamp", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-staking", + "sp-std 14.0.0", + "sp-tracing 16.0.0", + "substrate-test-utils", +] + [[package]] name = "pallet-democracy" version = "28.0.0" diff --git a/Cargo.toml b/Cargo.toml index e6162830375f..2966e45fbec0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -385,6 +385,7 @@ members = [ "substrate/frame/staking/reward-curve", "substrate/frame/staking/reward-fn", "substrate/frame/staking/runtime-api", + "substrate/frame/delegated-staking", "substrate/frame/state-trie-migration", "substrate/frame/statement", "substrate/frame/sudo", diff --git a/substrate/frame/delegated-staking/Cargo.toml b/substrate/frame/delegated-staking/Cargo.toml new file mode 100644 index 000000000000..b4b9768256c6 --- /dev/null +++ b/substrate/frame/delegated-staking/Cargo.toml @@ -0,0 +1,70 @@ +[package] +name = "pallet-delegated-staking" +version = "4.0.0-dev" +authors.workspace = true +edition.workspace = true +license = "Apache-2.0" +homepage = "https://substrate.io" +repository.workspace = true +description = "FRAME delegated staking pallet" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } +frame-support = { path = "../support", default-features = false} +frame-system = { path = "../system", default-features = false} +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +sp-std = { path = "../../primitives/std", default-features = false} +sp-runtime = { path = "../../primitives/runtime", default-features = false} +sp-staking = { path = "../../primitives/staking", default-features = false } + +[dev-dependencies] +sp-core = { path = "../../primitives/core" } +sp-io = { path = "../../primitives/io" } +substrate-test-utils = { path = "../../test-utils" } +sp-tracing = { path = "../../primitives/tracing" } +pallet-staking = { path = "../staking" } +pallet-nomination-pools = { path = "../nomination-pools" } +pallet-balances = { path = "../balances" } +pallet-timestamp = { path = "../timestamp" } +pallet-staking-reward-curve = { path = "../staking/reward-curve" } +frame-election-provider-support = { path = "../election-provider-support", default-features = false} + +[features] +default = [ "std" ] +std = [ + "codec/std", + "frame-support/std", + "frame-system/std", + "scale-info/std", + "sp-core/std", + "sp-io/std", + "sp-std/std", + "sp-runtime/std", + "sp-staking/std", + "pallet-balances/std", + "pallet-staking/std", + "pallet-timestamp/std", + "frame-election-provider-support/std", +] +runtime-benchmarks = [ + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", + "sp-staking/runtime-benchmarks", + "pallet-balances/runtime-benchmarks", + "pallet-staking/runtime-benchmarks", + "pallet-timestamp/runtime-benchmarks", + "frame-election-provider-support/runtime-benchmarks", +] +try-runtime = [ + "frame-support/try-runtime", + "frame-system/try-runtime", + "sp-runtime/try-runtime", + "pallet-balances/try-runtime", + "pallet-staking/try-runtime", + "pallet-timestamp/try-runtime", + "frame-election-provider-support/try-runtime", +] diff --git a/substrate/frame/delegated-staking/src/benchmarking.rs b/substrate/frame/delegated-staking/src/benchmarking.rs new file mode 100644 index 000000000000..808d19a5ce9a --- /dev/null +++ b/substrate/frame/delegated-staking/src/benchmarking.rs @@ -0,0 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Benchmarking for pallet-delegated-staking. + +#![cfg(feature = "runtime-benchmarks")] diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs new file mode 100644 index 000000000000..2ba000b253d6 --- /dev/null +++ b/substrate/frame/delegated-staking/src/impls.rs @@ -0,0 +1,288 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Implementations of public traits, namely [StakingInterface], [DelegatedStakeInterface] and +//! [OnStakingUpdate]. + +use super::*; +use sp_staking::{DelegatedStakeInterface, OnStakingUpdate}; + +/// StakingInterface implementation with delegation support. +/// +/// Only supports Nominators via Delegated Bonds. It is possible for a nominator to migrate and +/// become a `delegatee`. +impl StakingInterface for Pallet { + type Balance = BalanceOf; + type AccountId = T::AccountId; + type CurrencyToVote = ::CurrencyToVote; + + fn minimum_nominator_bond() -> Self::Balance { + T::CoreStaking::minimum_nominator_bond() + } + + fn minimum_validator_bond() -> Self::Balance { + T::CoreStaking::minimum_validator_bond() + } + + fn stash_by_ctrl(_controller: &Self::AccountId) -> Result { + // ctrl are deprecated, just return err. + Err(Error::::NotSupported.into()) + } + + fn bonding_duration() -> EraIndex { + T::CoreStaking::bonding_duration() + } + + fn current_era() -> EraIndex { + T::CoreStaking::current_era() + } + + fn stake(who: &Self::AccountId) -> Result, DispatchError> { + ensure!(Self::is_delegatee(who), Error::::NotSupported); + return T::CoreStaking::stake(who); + } + + fn total_stake(who: &Self::AccountId) -> Result { + if Self::is_delegatee(who) { + return T::CoreStaking::total_stake(who); + } + + if Self::is_delegator(who) { + let delegation = Delegation::::get(who).defensive_ok_or(Error::::BadState)?; + return Ok(delegation.amount); + } + + Err(Error::::NotSupported.into()) + } + + fn active_stake(who: &Self::AccountId) -> Result { + T::CoreStaking::active_stake(who) + } + + fn is_unbonding(who: &Self::AccountId) -> Result { + T::CoreStaking::is_unbonding(who) + } + + fn fully_unbond(who: &Self::AccountId) -> DispatchResult { + ensure!(Self::is_delegatee(who), Error::::NotSupported); + return T::CoreStaking::fully_unbond(who); + } + + fn bond( + who: &Self::AccountId, + value: Self::Balance, + payee: &Self::AccountId, + ) -> DispatchResult { + // ensure who is not already staked + ensure!(T::CoreStaking::status(who).is_err(), Error::::AlreadyStaking); + let delegatee = Delegatee::::from(who)?; + + ensure!(delegatee.available_to_bond() >= value, Error::::NotEnoughFunds); + ensure!(delegatee.ledger.payee == *payee, Error::::InvalidRewardDestination); + + T::CoreStaking::virtual_bond(who, value, payee) + } + + fn nominate(who: &Self::AccountId, validators: Vec) -> DispatchResult { + ensure!(Self::is_delegatee(who), Error::::NotDelegatee); + return T::CoreStaking::nominate(who, validators); + } + + fn chill(who: &Self::AccountId) -> DispatchResult { + ensure!(Self::is_delegatee(who), Error::::NotDelegatee); + return T::CoreStaking::chill(who); + } + + fn bond_extra(who: &Self::AccountId, extra: Self::Balance) -> DispatchResult { + let ledger = >::get(who).ok_or(Error::::NotDelegatee)?; + ensure!(ledger.stakeable_balance() >= extra, Error::::NotEnoughFunds); + + T::CoreStaking::bond_extra(who, extra) + } + + fn unbond(stash: &Self::AccountId, value: Self::Balance) -> DispatchResult { + let delegatee = Delegatee::::from(stash)?; + ensure!(delegatee.bonded_stake() >= value, Error::::NotEnoughFunds); + + T::CoreStaking::unbond(stash, value) + } + + fn update_payee(stash: &Self::AccountId, reward_acc: &Self::AccountId) -> DispatchResult { + T::CoreStaking::update_payee(stash, reward_acc) + } + + /// Withdraw unbonding funds until current era. + /// + /// Funds are moved to unclaimed_withdrawals register of the `DelegateeLedger`. + fn withdraw_unbonded( + delegatee_acc: Self::AccountId, + num_slashing_spans: u32, + ) -> Result { + Pallet::::withdraw_unbonded(&delegatee_acc, num_slashing_spans) + .map(|delegatee| delegatee.ledger.total_delegated.is_zero()) + } + + fn desired_validator_count() -> u32 { + T::CoreStaking::desired_validator_count() + } + + fn election_ongoing() -> bool { + T::CoreStaking::election_ongoing() + } + + fn force_unstake(_who: Self::AccountId) -> DispatchResult { + Err(Error::::NotSupported.into()) + } + + fn is_exposed_in_era(who: &Self::AccountId, era: &EraIndex) -> bool { + T::CoreStaking::is_exposed_in_era(who, era) + } + + fn status(who: &Self::AccountId) -> Result, DispatchError> { + ensure!(Self::is_delegatee(who), Error::::NotDelegatee); + T::CoreStaking::status(who) + } + + fn is_validator(who: &Self::AccountId) -> bool { + T::CoreStaking::is_validator(who) + } + + fn nominations(who: &Self::AccountId) -> Option> { + T::CoreStaking::nominations(who) + } + + fn slash_reward_fraction() -> Perbill { + T::CoreStaking::slash_reward_fraction() + } + + #[cfg(feature = "runtime-benchmarks")] + fn max_exposure_page_size() -> sp_staking::Page { + T::CoreStaking::max_exposure_page_size() + } + + #[cfg(feature = "runtime-benchmarks")] + fn add_era_stakers( + current_era: &EraIndex, + stash: &Self::AccountId, + exposures: Vec<(Self::AccountId, Self::Balance)>, + ) { + T::CoreStaking::add_era_stakers(current_era, stash, exposures) + } + + #[cfg(feature = "runtime-benchmarks")] + fn set_current_era(era: EraIndex) { + T::CoreStaking::set_current_era(era) + } +} + +impl DelegatedStakeInterface for Pallet { + /// Effective balance of the delegatee account. + fn delegatee_balance(who: &Self::AccountId) -> Self::Balance { + Delegatee::::from(who) + .map(|delegatee| delegatee.ledger.effective_balance()) + .unwrap_or_default() + } + + fn delegator_balance(delegator: &Self::AccountId) -> Self::Balance { + Delegation::::get(delegator).map(|d| d.amount).unwrap_or_default() + } + + /// Delegate funds to `Delegatee`. + fn delegate( + who: &Self::AccountId, + delegatee: &Self::AccountId, + reward_account: &Self::AccountId, + amount: Self::Balance, + ) -> DispatchResult { + Pallet::::register_as_delegatee( + RawOrigin::Signed(delegatee.clone()).into(), + reward_account.clone(), + )?; + + // Delegate the funds from who to the delegatee account. + Pallet::::delegate_funds( + RawOrigin::Signed(who.clone()).into(), + delegatee.clone(), + amount, + ) + } + + /// Add more delegation to the delegatee account. + fn delegate_extra( + who: &Self::AccountId, + delegatee: &Self::AccountId, + amount: Self::Balance, + ) -> DispatchResult { + Pallet::::delegate_funds( + RawOrigin::Signed(who.clone()).into(), + delegatee.clone(), + amount, + ) + } + + /// Withdraw delegation of `delegator` to `delegatee`. + /// + /// If there are funds in `delegatee` account that can be withdrawn, then those funds would be + /// unlocked/released in the delegator's account. + fn withdraw_delegation( + delegator: &Self::AccountId, + delegatee: &Self::AccountId, + amount: Self::Balance, + ) -> DispatchResult { + // fixme(ank4n): Can this not require slashing spans? + Pallet::::release( + RawOrigin::Signed(delegatee.clone()).into(), + delegator.clone(), + amount, + 0, + ) + } + + /// Returns true if the `delegatee` have any slash pending to be applied. + fn has_pending_slash(delegatee: &Self::AccountId) -> bool { + Delegatee::::from(delegatee) + .map(|d| !d.ledger.pending_slash.is_zero()) + .unwrap_or(false) + } + + fn delegator_slash( + delegatee: &Self::AccountId, + delegator: &Self::AccountId, + value: Self::Balance, + maybe_reporter: Option, + ) -> sp_runtime::DispatchResult { + Pallet::::do_slash(delegatee.clone(), delegator.clone(), value, maybe_reporter) + } +} + +impl OnStakingUpdate> for Pallet { + fn on_slash( + who: &T::AccountId, + _slashed_active: BalanceOf, + _slashed_unlocking: &sp_std::collections::btree_map::BTreeMap>, + slashed_total: BalanceOf, + ) { + >::mutate(who, |maybe_register| match maybe_register { + // if delegatee, register the slashed amount as pending slash. + Some(register) => register.pending_slash.saturating_accrue(slashed_total), + None => { + // nothing to do + }, + }); + } +} diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs new file mode 100644 index 000000000000..3b49ff477f27 --- /dev/null +++ b/substrate/frame/delegated-staking/src/lib.rs @@ -0,0 +1,827 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! # Delegated Staking Pallet +//! +//! An abstraction over staking pallet to support delegation of funds to a `delegatee` account which +//! can use all the delegated funds to it in the staking pallet as if its own fund. +//! +//! NOTE: The pallet exposes some dispatchable calls already, but they might not be fully usable +//! from outside the runtime. In the current version, the pallet is meant to be used by other +//! pallets in the same runtime. Eventually though, expect those calls to be functionally complete +//! and usable by off-chain programs as well as xcm based multi locations. +//! +//! Declaring dispatchable still has the benefit of being transactable for unit tests as well as +//! aligned with general direction of moving towards a permissionless pallet. For example, we could +//! clearly signal who is the expected signer of any interaction with this pallet and take into +//! account any security considerations associated with those interactions. +//! +//! ## Goals +//! +//! Direct nomination on the Staking pallet does not scale well. Nominations pools were created to +//! address this by pooling delegator funds into one account and then staking it. This though had +//! a very critical limitation that the funds were moved from delegator account to pool account +//! and hence the delegator lost control over their funds for using it for other purposes such as +//! governance. This pallet aims to solve this by extending the staking pallet to support a new +//! primitive function: delegation of funds to an account for the intent of staking. +//! +//! #### Reward and Slashing +//! This pallet does not enforce any specific strategy for how rewards or slashes are applied. It +//! is upto the `delegatee` account to decide how to apply the rewards and slashes. +//! +//! This importantly allows clients of this pallet to build their own strategies for reward/slashes. +//! For example, a `delegatee` account can choose to first slash the reward pot before slashing the +//! delegators. Or part of the reward can go to a insurance fund that can be used to cover any +//! potential future slashes. The goal is to eventually allow foreign MultiLocations +//! (smart contracts or pallets on another chain) to build their own pooled staking solutions +//! similar to `NominationPools`. +//! +//! ## Key Terminologies +//! - **Delegatee**: An account who accepts delegations from other accounts. +//! - **Delegator**: An account who delegates their funds to a `delegatee`. +//! - **DelegateeLedger**: A data structure that stores important information about the `delegatee` +//! such as their total delegated stake. +//! - **Delegation**: A data structure that stores the amount of funds delegated to a `delegatee` by +//! a `delegator`. +//! +//! ## Interface +//! +//! #### Dispatchable Calls +//! The pallet exposes the following [`Call`]s: +//! - `register_as_delegatee`: Register an account to be a `delegatee`. Once an account is +//! registered as a `delegatee`, for staking operations, only its delegated funds are used. This +//! means it cannot use its own free balance to stake. +//! - `migrate_to_delegate`: This allows a `Nominator` account to become a `delegatee` account. +//! Explained in more detail in the `Migration` section. +//! - `release`: Release funds to `delegator` from `unclaimed_withdrawals` register of the +//! `delegatee`. +//! - `migrate_delegation`: Migrate delegated funds from one account to another. This is useful for +//! example, delegators to a pool account which has migrated to be `delegatee` to migrate their +//! funds from pool account back to their own account and delegated to pool as a `delegator`. Once +//! the funds are migrated, the `delegator` can use the funds for other purposes which allows +//! usage of held funds in an account, such as governance. +//! - `delegate_funds`: Delegate funds to a `delegatee` account and update the bond to staking. +//! - `apply_slash`: If there is a pending slash in `delegatee` ledger, the passed delegator's +//! balance is slashed by the amount and the slash is removed from the delegatee ledger. +//! +//! #### [Staking Interface](StakingInterface) +//! This pallet reimplements the staking interface as a wrapper implementation over +//! [Config::CoreStaking] to provide delegation based staking. NominationPool can use this pallet as +//! its Staking provider to support delegation based staking from pool accounts. +//! +//! ## Lazy Slashing +//! One of the reasons why direct nominators on staking pallet cannot scale well is because all +//! nominators are slashed at the same time. This is expensive and needs to be bounded operation. +//! +//! This pallet implements a lazy slashing mechanism. Any slashes to a `delegatee` are posted in its +//! `DelegateeLedger` as a pending slash. Since the actual amount is held in the multiple +//! `delegator` accounts, this pallet has no way to know how to apply slash. It is `delegatee`'s +//! responsibility to apply slashes for each delegator, one at a time. Staking pallet ensures the +//! pending slash never exceeds staked amount and would freeze further withdraws until pending +//! slashes are applied. +//! +//! The user of this pallet can apply slash using +//! [StakingInterface::delegator_slash](sp_staking::StakingInterface::delegator_slash). +//! +//! ## Migration from Nominator to Delegatee +//! More details [here](https://hackmd.io/@ak0n/np-delegated-staking-migration). +//! +//! ## Nomination Pool vs Delegation Staking +//! This pallet is not a replacement for Nomination Pool but adds a new primitive over staking +//! pallet that can be used by Nomination Pool to support delegation based staking. It can be +//! thought of as something in middle of Nomination Pool and Staking Pallet. Technically, these +//! changes could be made in one of those pallets as well but that would have meant significant +//! refactoring and high chances of introducing a regression. With this approach, we can keep the +//! existing pallets with minimal changes and introduce a new pallet that can be optionally used by +//! Nomination Pool. This is completely configurable and a runtime can choose whether to use +//! this pallet or not. +//! +//! With that said, following is the main difference between +//! #### Nomination Pool without delegation support +//! 1) transfer fund from delegator to pool account, and +//! 2) stake from pool account as a direct nominator. +//! +//! #### Nomination Pool with delegation support +//! 1) delegate fund from delegator to pool account, and +//! 2) stake from pool account as a `Delegatee` account on the staking pallet. +//! +//! The difference being, in the second approach, the delegated funds will be locked in-place in +//! user's account enabling them to participate in use cases that allows use of `held` funds such +//! as participation in governance voting. +//! +//! Nomination pool still does all the heavy lifting around pool administration, reward +//! distribution, lazy slashing and as such, is not meant to be replaced with this pallet. +//! +//! ## Limitations +//! - Rewards can not be auto-compounded. +//! - Slashes are lazy and hence there could be a period of time when an account can use funds for +//! operations such as voting in governance even though they should be slashed. + +#![cfg_attr(not(feature = "std"), no_std)] +#![deny(rustdoc::broken_intra_doc_links)] + +#[cfg(test)] +mod mock; +#[cfg(test)] +mod tests; + +pub use pallet::*; + +mod types; + +use types::*; + +mod impls; + +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; + +use frame_support::{ + pallet_prelude::*, + traits::{ + fungible::{ + hold::{ + Balanced as FunHoldBalanced, Inspect as FunHoldInspect, Mutate as FunHoldMutate, + }, + Balanced, Inspect as FunInspect, Mutate as FunMutate, + }, + tokens::{fungible::Credit, Fortitude, Precision, Preservation}, + Defensive, DefensiveOption, Imbalance, OnUnbalanced, + }, + weights::Weight, +}; + +use sp_runtime::{ + traits::{AccountIdConversion, CheckedAdd, CheckedSub, Zero}, + ArithmeticError, DispatchResult, Perbill, RuntimeDebug, Saturating, +}; +use sp_staking::{EraIndex, Stake, StakerStatus, StakingInterface, StakingUnsafe}; +use sp_std::{convert::TryInto, prelude::*}; + +pub type BalanceOf = + <::Currency as FunInspect<::AccountId>>::Balance; + +use frame_system::{ensure_signed, pallet_prelude::*, RawOrigin}; + +#[frame_support::pallet] +pub mod pallet { + use super::*; + + #[pallet::pallet] + pub struct Pallet(PhantomData); + + #[pallet::config] + pub trait Config: frame_system::Config { + /// The overarching event type. + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + /// Injected identifier for the pallet. + #[pallet::constant] + type PalletId: Get; + + /// Currency type. + type Currency: FunHoldMutate + + FunMutate + + FunHoldBalanced; + + /// Handler for the unbalanced reduction when slashing a delegator. + type OnSlash: OnUnbalanced>; + + /// Overarching hold reason. + type RuntimeHoldReason: From; + + /// Core staking implementation. + type CoreStaking: StakingUnsafe, AccountId = Self::AccountId>; + } + + #[pallet::error] + pub enum Error { + /// The account cannot perform this operation. + NotAllowed, + /// An existing staker cannot perform this action. + AlreadyStaking, + /// Reward Destination cannot be `delegatee` account. + InvalidRewardDestination, + /// Delegation conditions are not met. + /// + /// Possible issues are + /// 1) Cannot delegate to self, + /// 2) Cannot delegate to multiple delegates, + InvalidDelegation, + /// The account does not have enough funds to perform the operation. + NotEnoughFunds, + /// Not an existing delegatee account. + NotDelegatee, + /// Not a Delegator account. + NotDelegator, + /// Some corruption in internal state. + BadState, + /// Unapplied pending slash restricts operation on `delegatee`. + UnappliedSlash, + /// Failed to withdraw amount from Core Staking. + WithdrawFailed, + /// Operation not supported by this pallet. + NotSupported, + } + + /// A reason for placing a hold on funds. + #[pallet::composite_enum] + pub enum HoldReason { + /// Funds held for stake delegation to another account. + #[codec(index = 0)] + Delegating, + } + + #[pallet::event] + #[pallet::generate_deposit(pub (super) fn deposit_event)] + pub enum Event { + /// Funds delegated by a delegator. + Delegated { delegatee: T::AccountId, delegator: T::AccountId, amount: BalanceOf }, + /// Funds released to a delegator. + Released { delegatee: T::AccountId, delegator: T::AccountId, amount: BalanceOf }, + /// Funds slashed from a delegator. + Slashed { delegatee: T::AccountId, delegator: T::AccountId, amount: BalanceOf }, + } + + /// Map of Delegators to their `Delegation`. + /// + /// Implementation note: We are not using a double map with `delegator` and `delegatee` account + /// as keys since we want to restrict delegators to delegate only to one account at a time. + #[pallet::storage] + pub(crate) type Delegators = + CountedStorageMap<_, Twox64Concat, T::AccountId, Delegation, OptionQuery>; + + /// Map of `Delegatee` to their `DelegateeLedger`. + #[pallet::storage] + pub(crate) type Delegatees = + CountedStorageMap<_, Twox64Concat, T::AccountId, DelegateeLedger, OptionQuery>; + + #[pallet::call] + impl Pallet { + /// Register an account to be a `Delegatee`. + /// + /// `Delegatee` accounts accepts delegations from other `delegator`s and stake funds on + /// their behalf. + #[pallet::call_index(0)] + #[pallet::weight(Weight::default())] + pub fn register_as_delegatee( + origin: OriginFor, + reward_account: T::AccountId, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + + // Existing `delegatee` cannot register again. + ensure!(!Self::is_delegatee(&who), Error::::NotAllowed); + + // A delegator cannot become a `delegatee`. + ensure!(!Self::is_delegator(&who), Error::::NotAllowed); + + // They cannot be already a direct staker in the staking pallet. + ensure!(Self::not_direct_staker(&who), Error::::AlreadyStaking); + + // Reward account cannot be same as `delegatee` account. + ensure!(reward_account != who, Error::::InvalidRewardDestination); + + Self::do_register_delegatee(&who, &reward_account); + Ok(()) + } + + /// Migrate from a `Nominator` account to `Delegatee` account. + /// + /// The origin needs to + /// - be a `Nominator` with `CoreStaking`, + /// - not already a `Delegatee`, + /// - have enough funds to transfer existential deposit to a delegator account created for + /// the migration. + /// + /// This operation will create a new delegator account for the origin called + /// `proxy_delegator` and transfer the staked amount to it. The `proxy_delegator` delegates + /// the funds to the origin making origin a `Delegatee` account. The actual `delegator` + /// accounts of the origin can later migrate their funds using [Call::migrate_delegation] to + /// claim back their share of delegated funds from `proxy_delegator` to self. + #[pallet::call_index(1)] + #[pallet::weight(Weight::default())] + pub fn migrate_to_delegatee( + origin: OriginFor, + reward_account: T::AccountId, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + // ensure who is not already a delegatee. + ensure!(!Self::is_delegatee(&who), Error::::NotAllowed); + + // and they should already be a nominator in `CoreStaking`. + ensure!(Self::is_direct_nominator(&who), Error::::NotAllowed); + + // Reward account cannot be same as `delegatee` account. + ensure!(reward_account != who, Error::::InvalidRewardDestination); + + Self::do_migrate_to_delegatee(&who, &reward_account) + } + + /// Release delegated amount to delegator. + /// + /// This can be called by existing `delegatee` accounts. + /// + /// Tries to withdraw unbonded fund from `CoreStaking` if needed and release amount to + /// `delegator`. + #[pallet::call_index(2)] + #[pallet::weight(Weight::default())] + pub fn release( + origin: OriginFor, + delegator: T::AccountId, + amount: BalanceOf, + num_slashing_spans: u32, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + Self::do_release(&who, &delegator, amount, num_slashing_spans) + } + + /// Migrate delegated fund. + /// + /// This can be called by migrating `delegatee` accounts. + /// + /// This moves delegator funds from `pxoxy_delegator` account to `delegator` account. + #[pallet::call_index(3)] + #[pallet::weight(Weight::default())] + pub fn migrate_delegation( + origin: OriginFor, + delegator: T::AccountId, + amount: BalanceOf, + ) -> DispatchResult { + let delegatee = ensure_signed(origin)?; + + // Ensure they have minimum delegation. + ensure!(amount >= T::Currency::minimum_balance(), Error::::NotEnoughFunds); + + // Ensure delegator is sane. + ensure!(!Self::is_delegatee(&delegator), Error::::NotAllowed); + ensure!(!Self::is_delegator(&delegator), Error::::NotAllowed); + ensure!(Self::not_direct_staker(&delegator), Error::::AlreadyStaking); + + // ensure delegatee is sane. + ensure!(Self::is_delegatee(&delegatee), Error::::NotDelegatee); + + // and has enough delegated balance to migrate. + let proxy_delegator = Self::sub_account(AccountType::ProxyDelegator, delegatee); + let balance_remaining = Self::held_balance_of(&proxy_delegator); + ensure!(balance_remaining >= amount, Error::::NotEnoughFunds); + + Self::do_migrate_delegation(&proxy_delegator, &delegator, amount) + } + + /// Delegate funds to a `Delegatee` account and bonds it to [Config::CoreStaking]. + /// + /// If delegation already exists, it increases the delegation by `amount`. + #[pallet::call_index(4)] + #[pallet::weight(Weight::default())] + pub fn delegate_funds( + origin: OriginFor, + delegatee: T::AccountId, + amount: BalanceOf, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + + // ensure amount is over minimum to delegate + ensure!(amount > T::Currency::minimum_balance(), Error::::NotEnoughFunds); + + // ensure delegator is sane. + ensure!(Delegation::::can_delegate(&who, &delegatee), Error::::InvalidDelegation); + ensure!(Self::not_direct_staker(&who), Error::::AlreadyStaking); + + // ensure delegatee is sane. + ensure!(Self::is_delegatee(&delegatee), Error::::NotDelegatee); + + let delegator_balance = + T::Currency::reducible_balance(&who, Preservation::Preserve, Fortitude::Polite); + ensure!(delegator_balance >= amount, Error::::NotEnoughFunds); + + // add to delegation + Self::do_delegate(&who, &delegatee, amount)?; + // bond the amount to `CoreStaking`. + Self::do_bond(&delegatee, amount) + } + + /// Apply slash to a delegator account. + /// + /// `Delegatee` accounts with pending slash in their ledger can call this to apply slash to + /// one of its `delegator` account. Each slash to a delegator account needs to be posted + /// separately until all pending slash is cleared. + #[pallet::call_index(5)] + #[pallet::weight(Weight::default())] + pub fn apply_slash( + origin: OriginFor, + delegator: T::AccountId, + amount: BalanceOf, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + Self::do_slash(who, delegator, amount, None) + } + } + + #[pallet::hooks] + impl Hooks> for Pallet { + #[cfg(feature = "try-runtime")] + fn try_state(_n: BlockNumberFor) -> Result<(), TryRuntimeError> { + Self::do_try_state() + } + + fn integrity_test() {} + } +} + +impl Pallet { + /// Derive a (keyless) pot account from the given delegatee account and account type. + pub(crate) fn sub_account( + account_type: AccountType, + delegatee_account: T::AccountId, + ) -> T::AccountId { + T::PalletId::get().into_sub_account_truncating((account_type, delegatee_account.clone())) + } + + /// Balance of a delegator that is delegated. + pub(crate) fn held_balance_of(who: &T::AccountId) -> BalanceOf { + T::Currency::balance_on_hold(&HoldReason::Delegating.into(), who) + } + + /// Returns true if who is registered as a `Delegatee`. + fn is_delegatee(who: &T::AccountId) -> bool { + >::contains_key(who) + } + + /// Returns true if who is delegating to a `Delegatee` account. + fn is_delegator(who: &T::AccountId) -> bool { + >::contains_key(who) + } + + /// Returns true if who is not already staking on [`Config::CoreStaking`]. + fn not_direct_staker(who: &T::AccountId) -> bool { + T::CoreStaking::status(&who).is_err() + } + + /// Returns true if who is a [`StakerStatus::Nominator`] on [`Config::CoreStaking`]. + fn is_direct_nominator(who: &T::AccountId) -> bool { + T::CoreStaking::status(who) + .map(|status| matches!(status, StakerStatus::Nominator(_))) + .unwrap_or(false) + } + + fn do_register_delegatee(who: &T::AccountId, reward_account: &T::AccountId) { + DelegateeLedger::::new(reward_account).save(who); + + // Delegatee is a virtual account. Make this account exist. + // TODO: Someday if we expose these calls in a runtime, we should take a deposit for + // being a delegator. + frame_system::Pallet::::inc_providers(who); + } + + fn do_migrate_to_delegatee( + who: &T::AccountId, + reward_account: &T::AccountId, + ) -> DispatchResult { + // We create a proxy delegator that will keep all the delegation funds until funds are + // transferred to actual delegator. + let proxy_delegator = Self::sub_account(AccountType::ProxyDelegator, who.clone()); + + // Transfer minimum balance to proxy delegator. + T::Currency::transfer( + who, + &proxy_delegator, + T::Currency::minimum_balance(), + Preservation::Protect, + ) + .map_err(|_| Error::::NotEnoughFunds)?; + + // Get current stake + let stake = T::CoreStaking::stake(who)?; + + // release funds from core staking. + T::CoreStaking::force_release(who); + + // transferring just released staked amount. This should never fail but if it does, it + // indicates bad state and we abort. + T::Currency::transfer(who, &proxy_delegator, stake.total, Preservation::Protect) + .map_err(|_| Error::::BadState)?; + + Self::do_register_delegatee(who, reward_account); + T::CoreStaking::update_payee(who, reward_account)?; + + Self::do_delegate(&proxy_delegator, who, stake.total) + } + + fn do_bond(delegatee_acc: &T::AccountId, amount: BalanceOf) -> DispatchResult { + let delegatee = Delegatee::::from(delegatee_acc)?; + + let available_to_bond = delegatee.available_to_bond(); + defensive_assert!(amount == available_to_bond, "not expected value to bond"); + + if delegatee.is_bonded() { + T::CoreStaking::bond_extra(&delegatee.key, amount) + } else { + T::CoreStaking::virtual_bond(&delegatee.key, amount, &delegatee.reward_account()) + } + } + + fn do_delegate( + delegator: &T::AccountId, + delegatee: &T::AccountId, + amount: BalanceOf, + ) -> DispatchResult { + let mut ledger = DelegateeLedger::::get(delegatee).ok_or(Error::::NotDelegatee)?; + + let new_delegation_amount = + if let Some(existing_delegation) = Delegation::::get(delegator) { + ensure!(&existing_delegation.delegatee == delegatee, Error::::InvalidDelegation); + existing_delegation + .amount + .checked_add(&amount) + .ok_or(ArithmeticError::Overflow)? + } else { + amount + }; + + Delegation::::from(delegatee, new_delegation_amount).save_or_kill(delegator); + ledger.total_delegated = + ledger.total_delegated.checked_add(&amount).ok_or(ArithmeticError::Overflow)?; + ledger.save(delegatee); + + T::Currency::hold(&HoldReason::Delegating.into(), delegator, amount)?; + + Self::deposit_event(Event::::Delegated { + delegatee: delegatee.clone(), + delegator: delegator.clone(), + amount, + }); + + Ok(()) + } + + fn do_release( + who: &T::AccountId, + delegator: &T::AccountId, + amount: BalanceOf, + num_slashing_spans: u32, + ) -> DispatchResult { + let mut delegatee = Delegatee::::from(who)?; + let mut delegation = Delegation::::get(delegator).ok_or(Error::::NotDelegator)?; + + // make sure delegation to be released is sound. + ensure!(&delegation.delegatee == who, Error::::NotDelegatee); + ensure!(delegation.amount >= amount, Error::::NotEnoughFunds); + + // if we do not already have enough funds to be claimed, try withdraw some more. + if delegatee.ledger.unclaimed_withdrawals < amount { + // get the updated delegatee + delegatee = Self::withdraw_unbonded(who, num_slashing_spans)?; + } + + // if we still do not have enough funds to release, abort. + ensure!(delegatee.ledger.unclaimed_withdrawals >= amount, Error::::NotEnoughFunds); + + // claim withdraw from delegatee. + delegatee.remove_unclaimed_withdraw(amount)?.save_or_kill()?; + + // book keep delegation + delegation.amount = delegation + .amount + .checked_sub(&amount) + .defensive_ok_or(ArithmeticError::Overflow)?; + + // remove delegator if nothing delegated anymore + delegation.save_or_kill(delegator); + + let released = T::Currency::release( + &HoldReason::Delegating.into(), + &delegator, + amount, + Precision::BestEffort, + )?; + + defensive_assert!(released == amount, "hold should have been released fully"); + + Self::deposit_event(Event::::Released { + delegatee: who.clone(), + delegator: delegator.clone(), + amount, + }); + + Ok(()) + } + + fn withdraw_unbonded( + delegatee_acc: &T::AccountId, + num_slashing_spans: u32, + ) -> Result, DispatchError> { + let delegatee = Delegatee::::from(delegatee_acc)?; + let pre_total = T::CoreStaking::stake(delegatee_acc).defensive()?.total; + + let stash_killed: bool = + T::CoreStaking::withdraw_unbonded(delegatee_acc.clone(), num_slashing_spans) + .map_err(|_| Error::::WithdrawFailed)?; + + let maybe_post_total = T::CoreStaking::stake(delegatee_acc); + // One of them should be true + defensive_assert!( + !(stash_killed && maybe_post_total.is_ok()), + "something horrible happened while withdrawing" + ); + + let post_total = maybe_post_total.map_or(Zero::zero(), |s| s.total); + + let new_withdrawn = + pre_total.checked_sub(&post_total).defensive_ok_or(Error::::BadState)?; + + let delegatee = delegatee.add_unclaimed_withdraw(new_withdrawn)?; + + delegatee.clone().save(); + + Ok(delegatee) + } + + /// Migrates delegation of `amount` from `source` account to `destination` account. + fn do_migrate_delegation( + source_delegator: &T::AccountId, + destination_delegator: &T::AccountId, + amount: BalanceOf, + ) -> DispatchResult { + let source_delegation = + Delegators::::get(&source_delegator).defensive_ok_or(Error::::BadState)?; + + // some checks that must have already been checked before. + ensure!(source_delegation.amount >= amount, Error::::NotEnoughFunds); + debug_assert!( + !Self::is_delegator(destination_delegator) && + !Self::is_delegatee(destination_delegator) + ); + + // update delegations + Delegation::::from(&source_delegation.delegatee, amount) + .save_or_kill(destination_delegator); + + source_delegation + .decrease_delegation(amount) + .defensive_ok_or(Error::::BadState)? + .save_or_kill(source_delegator); + + // release funds from source + let released = T::Currency::release( + &HoldReason::Delegating.into(), + &source_delegator, + amount, + Precision::BestEffort, + )?; + + defensive_assert!(released == amount, "hold should have been released fully"); + + // transfer the released amount to `destination_delegator`. + // Note: The source should have been funded ED in the beginning so it should not be dusted. + T::Currency::transfer( + &source_delegator, + destination_delegator, + amount, + Preservation::Preserve, + ) + .map_err(|_| Error::::BadState)?; + + // hold the funds again in the new delegator account. + T::Currency::hold(&HoldReason::Delegating.into(), &destination_delegator, amount)?; + + Ok(()) + } + + pub fn do_slash( + delegatee_acc: T::AccountId, + delegator: T::AccountId, + amount: BalanceOf, + maybe_reporter: Option, + ) -> DispatchResult { + let delegatee = Delegatee::::from(&delegatee_acc)?; + let delegation = >::get(&delegator).ok_or(Error::::NotDelegator)?; + + ensure!(delegation.delegatee == delegatee_acc, Error::::NotDelegatee); + ensure!(delegation.amount >= amount, Error::::NotEnoughFunds); + + let (mut credit, missing) = + T::Currency::slash(&HoldReason::Delegating.into(), &delegator, amount); + + defensive_assert!(missing.is_zero(), "slash should have been fully applied"); + + let actual_slash = credit.peek(); + + // remove the applied slashed amount from delegatee. + delegatee.remove_slash(actual_slash).save(); + + delegation + .decrease_delegation(actual_slash) + .ok_or(ArithmeticError::Overflow)? + .save_or_kill(&delegator); + + if let Some(reporter) = maybe_reporter { + let reward_payout: BalanceOf = + T::CoreStaking::slash_reward_fraction() * actual_slash; + let (reporter_reward, rest) = credit.split(reward_payout); + credit = rest; + + // fixme(ank4n): handle error + let _ = T::Currency::resolve(&reporter, reporter_reward); + } + + T::OnSlash::on_unbalanced(credit); + + Self::deposit_event(Event::::Slashed { delegatee: delegatee_acc, delegator, amount }); + + Ok(()) + } + + /// Total balance that is available for stake. Includes already staked amount. + #[cfg(test)] + pub(crate) fn stakeable_balance(who: &T::AccountId) -> BalanceOf { + Delegatee::::from(who) + .map(|delegatee| delegatee.ledger.stakeable_balance()) + .unwrap_or_default() + } +} + +#[cfg(any(test, feature = "try-runtime"))] +use sp_std::collections::btree_map::BTreeMap; + +#[cfg(any(test, feature = "try-runtime"))] +impl Pallet { + pub(crate) fn do_try_state() -> Result<(), sp_runtime::TryRuntimeError> { + // build map to avoid reading storage multiple times. + let delegation_map = Delegators::::iter().collect::>(); + let ledger_map = Delegatees::::iter().collect::>(); + + Self::check_delegates(ledger_map.clone())?; + Self::check_delegators(delegation_map, ledger_map)?; + + Ok(()) + } + + fn check_delegates( + ledgers: BTreeMap>, + ) -> Result<(), sp_runtime::TryRuntimeError> { + for (delegatee, ledger) in ledgers { + ensure!( + matches!( + T::CoreStaking::status(&delegatee).expect("delegatee should be bonded"), + StakerStatus::Nominator(_) | StakerStatus::Idle + ), + "delegatee should be bonded and not validator" + ); + + ensure!( + ledger.stakeable_balance() >= + T::CoreStaking::total_stake(&delegatee) + .expect("delegatee should exist as a nominator"), + "Cannot stake more than balance" + ); + } + + Ok(()) + } + + fn check_delegators( + delegations: BTreeMap>, + ledger: BTreeMap>, + ) -> Result<(), sp_runtime::TryRuntimeError> { + let mut delegation_aggregation = BTreeMap::>::new(); + for (delegator, delegation) in delegations.iter() { + ensure!( + T::CoreStaking::status(delegator).is_err(), + "delegator should not be directly staked" + ); + ensure!(!Self::is_delegatee(delegator), "delegator cannot be delegatee"); + + delegation_aggregation + .entry(delegation.delegatee.clone()) + .and_modify(|e| *e += delegation.amount) + .or_insert(delegation.amount); + } + + for (delegatee, total_delegated) in delegation_aggregation { + ensure!(!Self::is_delegator(&delegatee), "delegatee cannot be delegator"); + + let ledger = ledger.get(&delegatee).expect("ledger should exist"); + ensure!( + ledger.total_delegated == total_delegated, + "ledger total delegated should match delegations" + ); + } + + Ok(()) + } +} diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs new file mode 100644 index 000000000000..47c65dc8f471 --- /dev/null +++ b/substrate/frame/delegated-staking/src/mock.rs @@ -0,0 +1,329 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::{self as delegated_staking, types::Delegatee, HoldReason}; +use frame_support::{ + assert_ok, derive_impl, + pallet_prelude::*, + parameter_types, + traits::{fungible::InspectHold, ConstU64, Currency}, + PalletId, +}; + +use sp_runtime::{traits::IdentityLookup, BuildStorage, Perbill}; + +use frame_election_provider_support::{ + bounds::{ElectionBounds, ElectionBoundsBuilder}, + onchain, SequentialPhragmen, +}; +use frame_support::dispatch::RawOrigin; +use pallet_staking::CurrentEra; +use sp_core::U256; +use sp_runtime::traits::Convert; +use sp_staking::{Stake, StakingInterface}; + +pub type T = Runtime; +type Block = frame_system::mocking::MockBlock; +pub type AccountId = u128; + +pub const GENESIS_VALIDATOR: AccountId = 1; +pub const GENESIS_NOMINATOR_ONE: AccountId = 101; +pub const GENESIS_NOMINATOR_TWO: AccountId = 102; + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +impl frame_system::Config for Runtime { + type Block = Block; + type AccountData = pallet_balances::AccountData; + type AccountId = AccountId; + type Lookup = IdentityLookup; +} + +impl pallet_timestamp::Config for Runtime { + type Moment = u64; + type OnTimestampSet = (); + type MinimumPeriod = ConstU64<5>; + type WeightInfo = (); +} + +pub type Balance = u128; + +parameter_types! { + pub static ExistentialDeposit: Balance = 1; +} +impl pallet_balances::Config for Runtime { + type MaxLocks = ConstU32<128>; + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; + type Balance = Balance; + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); + type FreezeIdentifier = RuntimeFreezeReason; + type MaxFreezes = ConstU32<1>; + type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; +} + +pallet_staking_reward_curve::build! { + const I_NPOS: sp_runtime::curve::PiecewiseLinear<'static> = curve!( + min_inflation: 0_025_000, + max_inflation: 0_100_000, + ideal_stake: 0_500_000, + falloff: 0_050_000, + max_piece_count: 40, + test_precision: 0_005_000, + ); +} + +parameter_types! { + pub const RewardCurve: &'static sp_runtime::curve::PiecewiseLinear<'static> = &I_NPOS; + pub static BondingDuration: u32 = 3; + pub static ElectionsBoundsOnChain: ElectionBounds = ElectionBoundsBuilder::default().build(); +} +pub struct OnChainSeqPhragmen; +impl onchain::Config for OnChainSeqPhragmen { + type System = Runtime; + type Solver = SequentialPhragmen; + type DataProvider = Staking; + type WeightInfo = (); + type MaxWinners = ConstU32<100>; + type Bounds = ElectionsBoundsOnChain; +} + +impl pallet_staking::Config for Runtime { + type Currency = Balances; + type CurrencyBalance = Balance; + type UnixTime = pallet_timestamp::Pallet; + type CurrencyToVote = (); + type RewardRemainder = (); + type RuntimeEvent = RuntimeEvent; + type Slash = (); + type Reward = (); + type SessionsPerEra = (); + type SlashDeferDuration = (); + type AdminOrigin = frame_system::EnsureRoot; + type BondingDuration = BondingDuration; + type SessionInterface = (); + type EraPayout = pallet_staking::ConvertCurve; + type NextNewSession = (); + type HistoryDepth = ConstU32<84>; + type MaxExposurePageSize = ConstU32<64>; + type OffendingValidatorsThreshold = (); + type ElectionProvider = onchain::OnChainExecution; + type GenesisElectionProvider = Self::ElectionProvider; + type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; + type TargetList = pallet_staking::UseValidatorsMap; + type NominationsQuota = pallet_staking::FixedNominationsQuota<16>; + type MaxUnlockingChunks = ConstU32<32>; + type MaxControllersInDeprecationBatch = ConstU32<100>; + type EventListeners = DelegatedStaking; + type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; + type WeightInfo = (); +} + +parameter_types! { + pub const DelegatedStakingPalletId: PalletId = PalletId(*b"py/dlstk"); +} +impl delegated_staking::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type PalletId = DelegatedStakingPalletId; + type Currency = Balances; + type OnSlash = (); + type RuntimeHoldReason = RuntimeHoldReason; + type CoreStaking = Staking; +} + +pub struct BalanceToU256; +impl Convert for BalanceToU256 { + fn convert(n: Balance) -> U256 { + n.into() + } +} +pub struct U256ToBalance; +impl Convert for U256ToBalance { + fn convert(n: U256) -> Balance { + n.try_into().unwrap() + } +} + +parameter_types! { + pub static MaxUnbonding: u32 = 8; +} + +frame_support::construct_runtime!( + pub enum Runtime { + System: frame_system, + Timestamp: pallet_timestamp, + Balances: pallet_balances, + Staking: pallet_staking, + DelegatedStaking: delegated_staking, + } +); + +pub struct ExtBuilder {} + +impl Default for ExtBuilder { + fn default() -> Self { + Self {} + } +} + +impl ExtBuilder { + fn build(self) -> sp_io::TestExternalities { + sp_tracing::try_init_simple(); + let mut storage = + frame_system::GenesisConfig::::default().build_storage().unwrap(); + + let _ = pallet_balances::GenesisConfig:: { + balances: vec![ + (GENESIS_VALIDATOR, 10000), + (GENESIS_NOMINATOR_ONE, 1000), + (GENESIS_NOMINATOR_TWO, 2000), + ], + } + .assimilate_storage(&mut storage); + + let stakers = vec![ + ( + GENESIS_VALIDATOR, + GENESIS_VALIDATOR, + 1000, + sp_staking::StakerStatus::::Validator, + ), + ( + GENESIS_NOMINATOR_ONE, + GENESIS_NOMINATOR_ONE, + 100, + sp_staking::StakerStatus::::Nominator(vec![1]), + ), + ( + GENESIS_NOMINATOR_TWO, + GENESIS_NOMINATOR_TWO, + 200, + sp_staking::StakerStatus::::Nominator(vec![1]), + ), + ]; + + let _ = pallet_staking::GenesisConfig:: { + stakers: stakers.clone(), + // ideal validator count + validator_count: 2, + minimum_validator_count: 1, + invulnerables: vec![], + slash_reward_fraction: Perbill::from_percent(10), + min_nominator_bond: ExistentialDeposit::get(), + min_validator_bond: ExistentialDeposit::get(), + ..Default::default() + } + .assimilate_storage(&mut storage); + + let mut ext = sp_io::TestExternalities::from(storage); + + ext.execute_with(|| { + // for events to be deposited. + frame_system::Pallet::::set_block_number(1); + }); + + ext + } + pub fn build_and_execute(self, test: impl FnOnce() -> ()) { + sp_tracing::try_init_simple(); + let mut ext = self.build(); + ext.execute_with(test); + ext.execute_with(|| { + DelegatedStaking::do_try_state().unwrap(); + }); + } +} + +/// fund and return who. +pub(crate) fn fund(who: &AccountId, amount: Balance) { + let _ = Balances::deposit_creating(who, amount); +} + +/// Sets up delegation for passed delegators, returns total delegated amount. +/// +/// `delegate_amount` is incremented by the amount `increment` starting with `base_delegate_amount` +/// from lower index to higher index of delegators. +pub(crate) fn setup_delegation_stake( + delegatee: AccountId, + reward_acc: AccountId, + delegators: Vec, + base_delegate_amount: Balance, + increment: Balance, +) -> Balance { + fund(&delegatee, 100); + assert_ok!(DelegatedStaking::register_as_delegatee( + RawOrigin::Signed(delegatee).into(), + reward_acc + )); + let mut delegated_amount: Balance = 0; + for (index, delegator) in delegators.iter().enumerate() { + let amount_to_delegate = base_delegate_amount + increment * index as Balance; + delegated_amount += amount_to_delegate; + + fund(delegator, amount_to_delegate + ExistentialDeposit::get()); + assert_ok!(DelegatedStaking::delegate_funds( + RawOrigin::Signed(delegator.clone()).into(), + delegatee, + amount_to_delegate + )); + } + + // sanity checks + assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), delegated_amount); + assert_eq!(Delegatee::::from(&delegatee).unwrap().available_to_bond(), 0); + + delegated_amount +} + +pub(crate) fn start_era(era: sp_staking::EraIndex) { + CurrentEra::::set(Some(era)); +} + +pub(crate) fn eq_stake(who: AccountId, total: Balance, active: Balance) -> bool { + Staking::stake(&who).unwrap() == Stake { total, active } && + get_delegatee(&who).ledger.stakeable_balance() == total +} + +pub(crate) fn get_delegatee(delegatee: &AccountId) -> Delegatee { + Delegatee::::from(delegatee).expect("delegate should exist") +} + + +pub(crate) fn held_balance(who: &AccountId) -> Balance { + Balances::balance_on_hold(&HoldReason::Delegating.into(), &who) +} + +parameter_types! { + static ObservedEventsDelegatedStaking: usize = 0; +} + +pub(crate) fn events_since_last_call() -> Vec> { + let events = System::events() + .into_iter() + .map(|r| r.event) + .filter_map( + |e| if let RuntimeEvent::DelegatedStaking(inner) = e { Some(inner) } else { None }, + ) + .collect::>(); + let already_seen = ObservedEventsDelegatedStaking::get(); + ObservedEventsDelegatedStaking::set(events.len()); + events.into_iter().skip(already_seen).collect() +} diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs new file mode 100644 index 000000000000..790e96fbe692 --- /dev/null +++ b/substrate/frame/delegated-staking/src/tests.rs @@ -0,0 +1,541 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Tests for pallet-delegated-staking. + +use super::*; +use crate::mock::*; +use frame_support::{assert_noop, assert_ok, traits::fungible::InspectHold}; +use pallet_staking::Error as StakingError; + +#[test] +fn create_a_delegatee_with_first_delegator() { + ExtBuilder::default().build_and_execute(|| { + let delegatee: AccountId = 200; + let reward_account: AccountId = 201; + let delegator: AccountId = 202; + + // set intention to accept delegation. + fund(&delegatee, 1000); + assert_ok!(DelegatedStaking::register_as_delegatee( + RawOrigin::Signed(delegatee).into(), + reward_account + )); + + // delegate to this account + fund(&delegator, 1000); + assert_ok!(DelegatedStaking::delegate_funds( + RawOrigin::Signed(delegator).into(), + delegatee, + 100 + )); + + // verify + assert!(DelegatedStaking::is_delegatee(&delegatee)); + assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), 100); + assert_eq!(Balances::balance_on_hold(&HoldReason::Delegating.into(), &delegator), 100); + }); +} + +#[test] +fn cannot_become_delegatee() { + ExtBuilder::default().build_and_execute(|| { + // cannot set reward account same as delegatee account + assert_noop!( + DelegatedStaking::register_as_delegatee(RawOrigin::Signed(100).into(), 100), + Error::::InvalidRewardDestination + ); + + // an existing validator cannot become delegatee + assert_noop!( + DelegatedStaking::register_as_delegatee( + RawOrigin::Signed(mock::GENESIS_VALIDATOR).into(), + 100 + ), + Error::::AlreadyStaking + ); + + // an existing nominator cannot become delegatee + assert_noop!( + DelegatedStaking::register_as_delegatee( + RawOrigin::Signed(mock::GENESIS_NOMINATOR_ONE).into(), + 100 + ), + Error::::AlreadyStaking + ); + assert_noop!( + DelegatedStaking::register_as_delegatee( + RawOrigin::Signed(mock::GENESIS_NOMINATOR_TWO).into(), + 100 + ), + Error::::AlreadyStaking + ); + }); +} + +#[test] +fn create_multiple_delegators() { + ExtBuilder::default().build_and_execute(|| { + let delegatee: AccountId = 200; + let reward_account: AccountId = 201; + + // stakeable balance is 0 for non delegatee + fund(&delegatee, 1000); + assert!(!DelegatedStaking::is_delegatee(&delegatee)); + assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), 0); + + // set intention to accept delegation. + assert_ok!(DelegatedStaking::register_as_delegatee( + RawOrigin::Signed(delegatee).into(), + reward_account + )); + + // create 100 delegators + for i in 202..302 { + fund(&i, 100 + ExistentialDeposit::get()); + assert_ok!(DelegatedStaking::delegate_funds( + RawOrigin::Signed(i).into(), + delegatee, + 100 + )); + // Balance of 100 held on delegator account for delegating to the delegatee. + assert_eq!(Balances::balance_on_hold(&HoldReason::Delegating.into(), &i), 100); + } + + // verify + assert!(DelegatedStaking::is_delegatee(&delegatee)); + assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), 100 * 100); + }); +} + +#[test] +fn delegatee_restrictions() { + // Similar to creating a nomination pool + ExtBuilder::default().build_and_execute(|| { + let delegatee_one = 200; + let delegator_one = 210; + fund(&delegatee_one, 100); + assert_ok!(DelegatedStaking::register_as_delegatee( + RawOrigin::Signed(delegatee_one).into(), + delegatee_one + 1 + )); + fund(&delegator_one, 200); + assert_ok!(DelegatedStaking::delegate_funds( + RawOrigin::Signed(delegator_one).into(), + delegatee_one, + 100 + )); + + let delegatee_two = 300; + let delegator_two = 310; + fund(&delegatee_two, 100); + assert_ok!(DelegatedStaking::register_as_delegatee( + RawOrigin::Signed(delegatee_two).into(), + delegatee_two + 1 + )); + fund(&delegator_two, 200); + assert_ok!(DelegatedStaking::delegate_funds( + RawOrigin::Signed(delegator_two).into(), + delegatee_two, + 100 + )); + + // delegatee one tries to delegate to delegatee 2 + assert_noop!( + DelegatedStaking::delegate_funds( + RawOrigin::Signed(delegatee_one).into(), + delegatee_two, + 10 + ), + Error::::InvalidDelegation + ); + + // delegatee one tries to delegate to a delegator + assert_noop!( + DelegatedStaking::delegate_funds( + RawOrigin::Signed(delegatee_one).into(), + delegator_one, + 10 + ), + Error::::InvalidDelegation + ); + assert_noop!( + DelegatedStaking::delegate_funds( + RawOrigin::Signed(delegatee_one).into(), + delegator_two, + 10 + ), + Error::::InvalidDelegation + ); + + // delegator one tries to delegate to delegatee 2 as well (it already delegates to delegatee + // 1) + assert_noop!( + DelegatedStaking::delegate_funds( + RawOrigin::Signed(delegator_one).into(), + delegatee_two, + 10 + ), + Error::::InvalidDelegation + ); + }); +} + +#[test] +fn apply_pending_slash() { + ExtBuilder::default().build_and_execute(|| { + ( + // fixme(ank4n): add tests for apply_pending_slash + ) + }); +} + +/// Integration tests with pallet-staking. +mod staking_integration { + use super::*; + use pallet_staking::RewardDestination; + use sp_staking::Stake; + + #[test] + fn bond() { + ExtBuilder::default().build_and_execute(|| { + let delegatee: AccountId = 99; + let reward_acc: AccountId = 100; + assert_eq!(Staking::status(&delegatee), Err(StakingError::::NotStash.into())); + + // set intention to become a delegatee + fund(&delegatee, 100); + assert_ok!(DelegatedStaking::register_as_delegatee( + RawOrigin::Signed(delegatee).into(), + reward_acc + )); + assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), 0); + + let mut delegated_balance: Balance = 0; + + // set some delegations + for delegator in 200..250 { + fund(&delegator, 200); + assert_ok!(DelegatedStaking::delegate_funds( + RawOrigin::Signed(delegator).into(), + delegatee, + 100 + )); + delegated_balance += 100; + assert_eq!( + Balances::balance_on_hold(&HoldReason::Delegating.into(), &delegator), + 100 + ); + + let delegatee_obj = get_delegatee(&delegatee); + assert_eq!(delegatee_obj.ledger.stakeable_balance(), delegated_balance); + assert_eq!(delegatee_obj.available_to_bond(), 0); + assert_eq!(delegatee_obj.bonded_stake(), delegated_balance); + } + + assert_eq!( + Staking::stake(&delegatee).unwrap(), + Stake { total: 50 * 100, active: 50 * 100 } + ) + }); + } + + #[test] + fn withdraw_test() { + ExtBuilder::default().build_and_execute(|| { + // initial era + start_era(1); + let delegatee: AccountId = 200; + let reward_acc: AccountId = 201; + let delegators: Vec = (301..=350).collect(); + let total_staked = + setup_delegation_stake(delegatee, reward_acc, delegators.clone(), 10, 10); + + // lets go to a new era + start_era(2); + + assert!(eq_stake(delegatee, total_staked, total_staked)); + // Withdrawing without unbonding would fail. + assert_noop!( + DelegatedStaking::release(RawOrigin::Signed(delegatee).into(), 301, 50, 0), + Error::::NotEnoughFunds + ); + // assert_noop!(DelegatedStaking::release(RawOrigin::Signed(delegatee).into(), 200, 50, + // 0), Error::::NotAllowed); active and total stake remains same + assert!(eq_stake(delegatee, total_staked, total_staked)); + + // 305 wants to unbond 50 in era 2, withdrawable in era 5. + assert_ok!(DelegatedStaking::unbond(&delegatee, 50)); + // 310 wants to unbond 100 in era 3, withdrawable in era 6. + start_era(3); + assert_ok!(DelegatedStaking::unbond(&delegatee, 100)); + // 320 wants to unbond 200 in era 4, withdrawable in era 7. + start_era(4); + assert_ok!(DelegatedStaking::unbond(&delegatee, 200)); + + // active stake is now reduced.. + let expected_active = total_staked - (50 + 100 + 200); + assert!(eq_stake(delegatee, total_staked, expected_active)); + + // nothing to withdraw at era 4 + assert_noop!( + DelegatedStaking::release(RawOrigin::Signed(delegatee).into(), 305, 50, 0), + Error::::NotEnoughFunds + ); + + assert!(eq_stake(delegatee, total_staked, expected_active)); + assert_eq!(get_delegatee(&delegatee).available_to_bond(), 0); + // full amount is still delegated + assert_eq!(get_delegatee(&delegatee).ledger.effective_balance(), total_staked); + + start_era(5); + // at era 5, 50 tokens are withdrawable, cannot withdraw more. + assert_noop!( + DelegatedStaking::release(RawOrigin::Signed(delegatee).into(), 305, 51, 0), + Error::::NotEnoughFunds + ); + // less is possible + assert_ok!(DelegatedStaking::release(RawOrigin::Signed(delegatee).into(), 305, 30, 0)); + assert_ok!(DelegatedStaking::release(RawOrigin::Signed(delegatee).into(), 305, 20, 0)); + + // Lets go to future era where everything is unbonded. Withdrawable amount: 100 + 200 + start_era(7); + // 305 has no more amount delegated so it cannot withdraw. + assert_noop!( + DelegatedStaking::release(RawOrigin::Signed(delegatee).into(), 305, 5, 0), + Error::::NotDelegator + ); + // 309 is an active delegator but has total delegation of 90, so it cannot withdraw more + // than that. + assert_noop!( + DelegatedStaking::release(RawOrigin::Signed(delegatee).into(), 309, 91, 0), + Error::::NotEnoughFunds + ); + // 310 cannot withdraw more than delegated funds. + assert_noop!( + DelegatedStaking::release(RawOrigin::Signed(delegatee).into(), 310, 101, 0), + Error::::NotEnoughFunds + ); + // but can withdraw all its delegation amount. + assert_ok!(DelegatedStaking::release(RawOrigin::Signed(delegatee).into(), 310, 100, 0)); + // 320 can withdraw all its delegation amount. + assert_ok!(DelegatedStaking::release(RawOrigin::Signed(delegatee).into(), 320, 200, 0)); + + // cannot withdraw anything more.. + assert_noop!( + DelegatedStaking::release(RawOrigin::Signed(delegatee).into(), 301, 1, 0), + Error::::NotEnoughFunds + ); + assert_noop!( + DelegatedStaking::release(RawOrigin::Signed(delegatee).into(), 350, 1, 0), + Error::::NotEnoughFunds + ); + }); + } + + #[test] + fn withdraw_happens_with_unbonded_balance_first() { + ExtBuilder::default().build_and_execute(|| { + let delegatee = 200; + setup_delegation_stake(delegatee, 201, (300..350).collect(), 100, 0); + + // verify withdraw not possible yet + assert_noop!( + DelegatedStaking::release(RawOrigin::Signed(delegatee).into(), 300, 100, 0), + Error::::NotEnoughFunds + ); + + // add new delegation that is not staked + + // FIXME(ank4n): add scenario where staked funds are withdrawn from ledger but not + // withdrawn and test its claimed from there first. + + // fund(&300, 1000); + // assert_ok!(DelegatedStaking::delegate_funds(RawOrigin::Signed(300.into()), delegate, + // 100)); + // + // // verify unbonded balance + // assert_eq!(get_delegatee(&delegatee).available_to_bond(), 100); + // + // // withdraw works now without unbonding + // assert_ok!(DelegatedStaking::release(RawOrigin::Signed(delegatee).into(), 300, 100, + // 0)); assert_eq!(get_delegatee(&delegatee).available_to_bond(), 0); + }); + } + + #[test] + fn reward_destination_restrictions() { + ExtBuilder::default().build_and_execute(|| { + // give some funds to 200 + fund(&200, 1000); + let balance_200 = Balances::free_balance(200); + + // `delegatee` account cannot be reward destination + assert_noop!( + DelegatedStaking::register_as_delegatee(RawOrigin::Signed(200).into(), 200), + Error::::InvalidRewardDestination + ); + + // different reward account works + assert_ok!(DelegatedStaking::register_as_delegatee(RawOrigin::Signed(200).into(), 201)); + // add some delegations to it + fund(&300, 1000); + assert_ok!(DelegatedStaking::delegate_funds(RawOrigin::Signed(300).into(), 200, 100)); + + // if delegate calls Staking pallet directly with a different reward destination, it + // fails. + assert_noop!( + Staking::set_payee(RuntimeOrigin::signed(200), RewardDestination::Stash), + StakingError::::RewardDestinationRestricted + ); + + // passing correct reward destination works + assert_ok!(Staking::set_payee( + RuntimeOrigin::signed(200), + RewardDestination::Account(201) + )); + + // amount is staked correctly + assert!(eq_stake(200, 100, 100)); + assert_eq!(get_delegatee(&200).available_to_bond(), 0); + assert_eq!(get_delegatee(&200).ledger.effective_balance(), 100); + + // free balance of delegate is untouched + assert_eq!(Balances::free_balance(200), balance_200); + }); + } + + #[test] + fn delegatee_restrictions() { + ExtBuilder::default().build_and_execute(|| { + setup_delegation_stake(200, 201, (202..203).collect(), 100, 0); + + // Registering again is noop + assert_noop!( + DelegatedStaking::register_as_delegatee(RawOrigin::Signed(200).into(), 201), + Error::::NotAllowed + ); + // a delegator cannot become delegate + assert_noop!( + DelegatedStaking::register_as_delegatee(RawOrigin::Signed(202).into(), 203), + Error::::NotAllowed + ); + // existing staker cannot become a delegate + assert_noop!( + DelegatedStaking::register_as_delegatee( + RawOrigin::Signed(GENESIS_NOMINATOR_ONE).into(), + 201 + ), + Error::::AlreadyStaking + ); + assert_noop!( + DelegatedStaking::register_as_delegatee( + RawOrigin::Signed(GENESIS_VALIDATOR).into(), + 201 + ), + Error::::AlreadyStaking + ); + }); + } + + #[test] + fn slash_works() { + ExtBuilder::default().build_and_execute(|| { + setup_delegation_stake(200, 201, (210..250).collect(), 100, 0); + start_era(1); + // fixme(ank4n): add tests for slashing + }); + } + + #[test] + fn migration_works() { + ExtBuilder::default().build_and_execute(|| { + // add a nominator + fund(&200, 5000); + let staked_amount = 4000; + assert_ok!(Staking::bond( + RuntimeOrigin::signed(200), + staked_amount, + RewardDestination::Account(201) + )); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(200), vec![GENESIS_VALIDATOR],)); + let init_stake = Staking::stake(&200).unwrap(); + + // scenario: 200 is a pool account, and the stake comes from its 4 delegators (300..304) + // in equal parts. lets try to migrate this nominator into delegate based stake. + + // all balance currently is in 200 + assert_eq!(Balances::free_balance(200), 5000); + + // to migrate, nominator needs to set an account as a proxy delegator where staked funds + // will be moved and delegated back to this old nominator account. This should be funded + // with at least ED. + let proxy_delegator = DelegatedStaking::sub_account(AccountType::ProxyDelegator, 200); + + assert_ok!(DelegatedStaking::migrate_to_delegatee(RawOrigin::Signed(200).into(), 201)); + + // verify all went well + let mut expected_proxy_delegated_amount = staked_amount; + assert_eq!( + Balances::balance_on_hold(&HoldReason::Delegating.into(), &proxy_delegator), + expected_proxy_delegated_amount + ); + // ED + stake amount is transferred from delegate to proxy delegator account. + assert_eq!( + Balances::free_balance(200), + 5000 - staked_amount - ExistentialDeposit::get() + ); + assert_eq!(DelegatedStaking::stake(&200).unwrap(), init_stake); + assert_eq!(get_delegatee(&200).ledger.effective_balance(), 4000); + assert_eq!(get_delegatee(&200).available_to_bond(), 0); + + // now lets migrate the delegators + let delegator_share = staked_amount / 4; + for delegator in 300..304 { + assert_eq!(Balances::free_balance(delegator), 0); + // fund them with ED + fund(&delegator, ExistentialDeposit::get()); + // migrate 1/4th amount into each delegator + assert_ok!(DelegatedStaking::migrate_delegation( + RawOrigin::Signed(200).into(), + delegator, + delegator_share + )); + assert_eq!( + Balances::balance_on_hold(&HoldReason::Delegating.into(), &delegator), + delegator_share + ); + expected_proxy_delegated_amount -= delegator_share; + assert_eq!( + Balances::balance_on_hold(&HoldReason::Delegating.into(), &proxy_delegator), + expected_proxy_delegated_amount + ); + + // delegate stake is unchanged. + assert_eq!(DelegatedStaking::stake(&200).unwrap(), init_stake); + assert_eq!(get_delegatee(&200).ledger.effective_balance(), 4000); + assert_eq!(get_delegatee(&200).available_to_bond(), 0); + } + + // cannot use migrate delegator anymore + assert_noop!( + DelegatedStaking::migrate_delegation(RawOrigin::Signed(200).into(), 305, 1), + Error::::NotEnoughFunds + ); + }); + } +} \ No newline at end of file diff --git a/substrate/frame/delegated-staking/src/types.rs b/substrate/frame/delegated-staking/src/types.rs new file mode 100644 index 000000000000..0dcdcc0659a4 --- /dev/null +++ b/substrate/frame/delegated-staking/src/types.rs @@ -0,0 +1,314 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Basic types used in delegated staking. + +use super::*; +use frame_support::traits::DefensiveSaturating; + +/// The type of pot account being created. +#[derive(Encode, Decode)] +pub(crate) enum AccountType { + /// A proxy delegator account created for a nominator who migrated to a `delegatee` account. + /// + /// Funds for unmigrated `delegator` accounts of the `delegatee` are kept here. + ProxyDelegator, +} + +/// Information about delegation of a `delegator`. +#[derive(Default, Encode, Clone, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] +#[scale_info(skip_type_params(T))] +pub struct Delegation { + /// The target of delegation. + pub delegatee: T::AccountId, + /// The amount delegated. + pub amount: BalanceOf, +} + +impl Delegation { + /// Get delegation of a `delegator`. + pub(crate) fn get(delegator: &T::AccountId) -> Option { + >::get(delegator) + } + + /// Create and return a new delegation instance. + pub(crate) fn from(delegatee: &T::AccountId, amount: BalanceOf) -> Self { + Delegation { delegatee: delegatee.clone(), amount } + } + + /// Ensure the delegator is either a new delegator or they are adding more delegation to the + /// existing delegatee. + /// + /// Delegators are prevented from delegating to multiple delegatees at the same time. + pub(crate) fn can_delegate(delegator: &T::AccountId, delegatee: &T::AccountId) -> bool { + Delegation::::get(delegator) + .map(|delegation| delegation.delegatee == delegatee.clone()) + .unwrap_or( + // all good if its a new delegator except it should not be an existing delegatee. + !>::contains_key(delegator), + ) + } + + /// Checked decrease of delegation amount. Consumes self and returns a new copy. + pub(crate) fn decrease_delegation(self, amount: BalanceOf) -> Option { + let updated_delegation = self.amount.checked_sub(&amount)?; + Some(Delegation::from(&self.delegatee, updated_delegation)) + } + + /// Checked increase of delegation amount. Consumes self and returns a new copy. + #[allow(unused)] + pub(crate) fn increase_delegation(self, amount: BalanceOf) -> Option { + let updated_delegation = self.amount.checked_add(&amount)?; + Some(Delegation::from(&self.delegatee, updated_delegation)) + } + + /// Save self to storage. If the delegation amount is zero, remove the delegation. + pub(crate) fn save_or_kill(self, key: &T::AccountId) { + // Clean up if no delegation left. + if self.amount == Zero::zero() { + >::remove(key); + return + } + + >::insert(key, self) + } +} + +/// Ledger of all delegations to a `Delegatee`. +/// +/// This keeps track of the active balance of the `delegatee` that is made up from the funds that +/// are currently delegated to this `delegatee`. It also tracks the pending slashes yet to be +/// applied among other things. +#[derive(Default, Clone, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] +#[scale_info(skip_type_params(T))] +pub struct DelegateeLedger { + /// Where the reward should be paid out. + pub payee: T::AccountId, + /// Sum of all delegated funds to this `delegatee`. + #[codec(compact)] + pub total_delegated: BalanceOf, + /// Funds that are withdrawn from core staking but not released to delegator/s. It is a subset + /// of `total_delegated` and can never be greater than it. + /// + /// We need this register to ensure that the `delegatee` does not bond funds from delegated + /// funds that are withdrawn and should be claimed by delegators. + // FIXME(ank4n): Check/test about rebond: where delegator rebond what is unlocking. + #[codec(compact)] + pub unclaimed_withdrawals: BalanceOf, + /// Slashes that are not yet applied. This affects the effective balance of the `delegatee`. + #[codec(compact)] + pub pending_slash: BalanceOf, +} + +impl DelegateeLedger { + /// Create a new instance of `DelegateeLedger`. + pub(crate) fn new(reward_destination: &T::AccountId) -> Self { + DelegateeLedger { + payee: reward_destination.clone(), + total_delegated: Zero::zero(), + unclaimed_withdrawals: Zero::zero(), + pending_slash: Zero::zero(), + } + } + + /// Get `DelegateeLedger` from storage. + pub(crate) fn get(key: &T::AccountId) -> Option { + >::get(key) + } + + /// Save self to storage with the given key. + pub(crate) fn save(self, key: &T::AccountId) { + >::insert(key, self) + } + + /// Effective total balance of the `delegatee`. + /// + /// This takes into account any slashes reported to `Delegatee` but unapplied. + pub(crate) fn effective_balance(&self) -> BalanceOf { + defensive_assert!( + self.total_delegated >= self.pending_slash, + "slash cannot be higher than actual balance of delegator" + ); + + // pending slash needs to be burned and cannot be used for stake. + self.total_delegated.saturating_sub(self.pending_slash) + } + + /// Delegatee balance that can be staked/bonded in [`T::CoreStaking`]. + pub(crate) fn stakeable_balance(&self) -> BalanceOf { + self.effective_balance().saturating_sub(self.unclaimed_withdrawals) + } +} + +/// Wrapper around `DelegateeLedger` to provide additional functionality. +#[derive(Clone)] +pub struct Delegatee { + /// storage key + pub key: T::AccountId, + /// storage value + pub ledger: DelegateeLedger, +} + +impl Delegatee { + /// Get `Delegatee` from storage if it exists or return an error. + pub(crate) fn from(delegatee: &T::AccountId) -> Result, DispatchError> { + let ledger = DelegateeLedger::::get(delegatee).ok_or(Error::::NotDelegatee)?; + Ok(Delegatee { key: delegatee.clone(), ledger }) + } + + /// Remove funds that are withdrawn from [Config::CoreStaking] but not claimed by a delegator. + /// + /// Checked decrease of delegation amount from `total_delegated` and `unclaimed_withdrawals` + /// registers. Consumes self and returns a new instance of self if success. + pub(crate) fn remove_unclaimed_withdraw( + self, + amount: BalanceOf, + ) -> Result { + let new_total_delegated = self + .ledger + .total_delegated + .checked_sub(&amount) + .defensive_ok_or(ArithmeticError::Overflow)?; + let new_unclaimed_withdrawals = self + .ledger + .unclaimed_withdrawals + .checked_sub(&amount) + .defensive_ok_or(ArithmeticError::Overflow)?; + + Ok(Delegatee { + ledger: DelegateeLedger { + total_delegated: new_total_delegated, + unclaimed_withdrawals: new_unclaimed_withdrawals, + ..self.ledger + }, + ..self + }) + } + + /// Add funds that are withdrawn from [Config::CoreStaking] to be claimed by delegators later. + pub(crate) fn add_unclaimed_withdraw( + self, + amount: BalanceOf, + ) -> Result { + let new_unclaimed_withdrawals = self + .ledger + .unclaimed_withdrawals + .checked_add(&amount) + .defensive_ok_or(ArithmeticError::Overflow)?; + + Ok(Delegatee { + ledger: DelegateeLedger { + unclaimed_withdrawals: new_unclaimed_withdrawals, + ..self.ledger + }, + ..self + }) + } + + /// Amount that is delegated but not bonded yet. + /// + /// This importantly does not include `unclaimed_withdrawals` as those should not be bonded + /// again unless explicitly requested. + pub(crate) fn available_to_bond(&self) -> BalanceOf { + let bonded_stake = self.bonded_stake(); + let stakeable = self.ledger.stakeable_balance(); + + defensive_assert!( + stakeable >= bonded_stake, + "cannot be bonded with more than delegatee balance" + ); + + stakeable.saturating_sub(bonded_stake) + } + + /// Remove slashes from the `DelegateeLedger`. + pub(crate) fn remove_slash(self, amount: BalanceOf) -> Self { + let pending_slash = self.ledger.pending_slash.defensive_saturating_sub(amount); + let total_delegated = self.ledger.total_delegated.defensive_saturating_sub(amount); + + Delegatee { + ledger: DelegateeLedger { pending_slash, total_delegated, ..self.ledger }, + ..self + } + } + + /// Get the total stake of delegatee bonded in [`Config::CoreStaking`]. + pub(crate) fn bonded_stake(&self) -> BalanceOf { + T::CoreStaking::total_stake(&self.key).unwrap_or(Zero::zero()) + } + + /// Returns true if the delegatee is bonded in [`Config::CoreStaking`]. + pub(crate) fn is_bonded(&self) -> bool { + T::CoreStaking::stake(&self.key).is_ok() + } + + /// Returns the reward account registered by the delegatee. + pub(crate) fn reward_account(&self) -> &T::AccountId { + &self.ledger.payee + } + + /// Save self to storage. + pub(crate) fn save(self) { + let key = self.key; + self.ledger.save(&key) + } + + /// Save self and remove if no delegation left. + /// + /// Returns error if the delegate is in an unexpected state. + pub(crate) fn save_or_kill(self) -> Result<(), DispatchError> { + let key = self.key; + // see if delegate can be killed + if self.ledger.total_delegated == Zero::zero() { + ensure!( + self.ledger.unclaimed_withdrawals == Zero::zero() && + self.ledger.pending_slash == Zero::zero(), + Error::::BadState + ); + >::remove(key); + } else { + self.ledger.save(&key) + } + + Ok(()) + } + + /// Reloads self from storage. + #[cfg(test)] + pub(crate) fn refresh(&self) -> Result, DispatchError> { + Self::from(&self.key) + } + + /// Balance of `Delegatee` that is not bonded. + /// + /// This is similar to [Self::available_to_bond] except it also includes `unclaimed_withdrawals` + /// of `Delegatee`. + #[cfg(test)] + pub(crate) fn total_unbonded(&self) -> BalanceOf { + let bonded_stake = self.bonded_stake(); + + let net_balance = self.ledger.effective_balance(); + + defensive_assert!( + net_balance >= bonded_stake, + "cannot be bonded with more than the delegatee balance" + ); + + net_balance.saturating_sub(bonded_stake) + } +} From e6152ed5eb7ac7ade5922adf63de60273c730a7b Mon Sep 17 00:00:00 2001 From: Ankan Date: Sat, 30 Mar 2024 02:08:12 +0100 Subject: [PATCH 008/257] fix clippy errors --- .../frame/delegated-staking/src/impls.rs | 8 ++++---- substrate/frame/delegated-staking/src/lib.rs | 20 +++++++++---------- substrate/frame/delegated-staking/src/mock.rs | 16 ++++++--------- .../frame/delegated-staking/src/tests.rs | 6 ++---- .../frame/delegated-staking/src/types.rs | 2 ++ 5 files changed, 24 insertions(+), 28 deletions(-) diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs index 2ba000b253d6..b188db4aa5f9 100644 --- a/substrate/frame/delegated-staking/src/impls.rs +++ b/substrate/frame/delegated-staking/src/impls.rs @@ -54,7 +54,7 @@ impl StakingInterface for Pallet { fn stake(who: &Self::AccountId) -> Result, DispatchError> { ensure!(Self::is_delegatee(who), Error::::NotSupported); - return T::CoreStaking::stake(who); + T::CoreStaking::stake(who) } fn total_stake(who: &Self::AccountId) -> Result { @@ -80,7 +80,7 @@ impl StakingInterface for Pallet { fn fully_unbond(who: &Self::AccountId) -> DispatchResult { ensure!(Self::is_delegatee(who), Error::::NotSupported); - return T::CoreStaking::fully_unbond(who); + T::CoreStaking::fully_unbond(who) } fn bond( @@ -100,12 +100,12 @@ impl StakingInterface for Pallet { fn nominate(who: &Self::AccountId, validators: Vec) -> DispatchResult { ensure!(Self::is_delegatee(who), Error::::NotDelegatee); - return T::CoreStaking::nominate(who, validators); + T::CoreStaking::nominate(who, validators) } fn chill(who: &Self::AccountId) -> DispatchResult { ensure!(Self::is_delegatee(who), Error::::NotDelegatee); - return T::CoreStaking::chill(who); + T::CoreStaking::chill(who) } fn bond_extra(who: &Self::AccountId, extra: Self::Balance) -> DispatchResult { diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs index 3b49ff477f27..d2097bb49cb3 100644 --- a/substrate/frame/delegated-staking/src/lib.rs +++ b/substrate/frame/delegated-staking/src/lib.rs @@ -54,9 +54,9 @@ //! - **Delegatee**: An account who accepts delegations from other accounts. //! - **Delegator**: An account who delegates their funds to a `delegatee`. //! - **DelegateeLedger**: A data structure that stores important information about the `delegatee` -//! such as their total delegated stake. +//! such as their total delegated stake. //! - **Delegation**: A data structure that stores the amount of funds delegated to a `delegatee` by -//! a `delegator`. +//! a `delegator`. //! //! ## Interface //! @@ -129,7 +129,7 @@ //! ## Limitations //! - Rewards can not be auto-compounded. //! - Slashes are lazy and hence there could be a period of time when an account can use funds for -//! operations such as voting in governance even though they should be slashed. +//! operations such as voting in governance even though they should be slashed. #![cfg_attr(not(feature = "std"), no_std)] #![deny(rustdoc::broken_intra_doc_links)] @@ -469,7 +469,7 @@ impl Pallet { /// Returns true if who is not already staking on [`Config::CoreStaking`]. fn not_direct_staker(who: &T::AccountId) -> bool { - T::CoreStaking::status(&who).is_err() + T::CoreStaking::status(who).is_err() } /// Returns true if who is a [`StakerStatus::Nominator`] on [`Config::CoreStaking`]. @@ -531,7 +531,7 @@ impl Pallet { if delegatee.is_bonded() { T::CoreStaking::bond_extra(&delegatee.key, amount) } else { - T::CoreStaking::virtual_bond(&delegatee.key, amount, &delegatee.reward_account()) + T::CoreStaking::virtual_bond(&delegatee.key, amount, delegatee.reward_account()) } } @@ -605,7 +605,7 @@ impl Pallet { let released = T::Currency::release( &HoldReason::Delegating.into(), - &delegator, + delegator, amount, Precision::BestEffort, )?; @@ -658,7 +658,7 @@ impl Pallet { amount: BalanceOf, ) -> DispatchResult { let source_delegation = - Delegators::::get(&source_delegator).defensive_ok_or(Error::::BadState)?; + Delegators::::get(source_delegator).defensive_ok_or(Error::::BadState)?; // some checks that must have already been checked before. ensure!(source_delegation.amount >= amount, Error::::NotEnoughFunds); @@ -679,7 +679,7 @@ impl Pallet { // release funds from source let released = T::Currency::release( &HoldReason::Delegating.into(), - &source_delegator, + source_delegator, amount, Precision::BestEffort, )?; @@ -689,7 +689,7 @@ impl Pallet { // transfer the released amount to `destination_delegator`. // Note: The source should have been funded ED in the beginning so it should not be dusted. T::Currency::transfer( - &source_delegator, + source_delegator, destination_delegator, amount, Preservation::Preserve, @@ -697,7 +697,7 @@ impl Pallet { .map_err(|_| Error::::BadState)?; // hold the funds again in the new delegator account. - T::Currency::hold(&HoldReason::Delegating.into(), &destination_delegator, amount)?; + T::Currency::hold(&HoldReason::Delegating.into(), destination_delegator, amount)?; Ok(()) } diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs index 47c65dc8f471..84854d6864d6 100644 --- a/substrate/frame/delegated-staking/src/mock.rs +++ b/substrate/frame/delegated-staking/src/mock.rs @@ -176,14 +176,9 @@ frame_support::construct_runtime!( } ); +#[derive(Default)] pub struct ExtBuilder {} -impl Default for ExtBuilder { - fn default() -> Self { - Self {} - } -} - impl ExtBuilder { fn build(self) -> sp_io::TestExternalities { sp_tracing::try_init_simple(); @@ -242,7 +237,7 @@ impl ExtBuilder { ext } - pub fn build_and_execute(self, test: impl FnOnce() -> ()) { + pub fn build_and_execute(self, test: impl FnOnce()) { sp_tracing::try_init_simple(); let mut ext = self.build(); ext.execute_with(test); @@ -280,7 +275,7 @@ pub(crate) fn setup_delegation_stake( fund(delegator, amount_to_delegate + ExistentialDeposit::get()); assert_ok!(DelegatedStaking::delegate_funds( - RawOrigin::Signed(delegator.clone()).into(), + RawOrigin::Signed(*delegator).into(), delegatee, amount_to_delegate )); @@ -306,15 +301,16 @@ pub(crate) fn get_delegatee(delegatee: &AccountId) -> Delegatee { Delegatee::::from(delegatee).expect("delegate should exist") } - +#[allow(unused)] pub(crate) fn held_balance(who: &AccountId) -> Balance { - Balances::balance_on_hold(&HoldReason::Delegating.into(), &who) + Balances::balance_on_hold(&HoldReason::Delegating.into(), who) } parameter_types! { static ObservedEventsDelegatedStaking: usize = 0; } +#[allow(unused)] pub(crate) fn events_since_last_call() -> Vec> { let events = System::events() .into_iter() diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs index 790e96fbe692..844ab74bfa09 100644 --- a/substrate/frame/delegated-staking/src/tests.rs +++ b/substrate/frame/delegated-staking/src/tests.rs @@ -198,9 +198,7 @@ fn delegatee_restrictions() { #[test] fn apply_pending_slash() { ExtBuilder::default().build_and_execute(|| { - ( - // fixme(ank4n): add tests for apply_pending_slash - ) + // fixme(ank4n): add tests for apply_pending_slash }); } @@ -538,4 +536,4 @@ mod staking_integration { ); }); } -} \ No newline at end of file +} diff --git a/substrate/frame/delegated-staking/src/types.rs b/substrate/frame/delegated-staking/src/types.rs index 0dcdcc0659a4..bd971f39cde6 100644 --- a/substrate/frame/delegated-staking/src/types.rs +++ b/substrate/frame/delegated-staking/src/types.rs @@ -290,6 +290,7 @@ impl Delegatee { /// Reloads self from storage. #[cfg(test)] + #[allow(unused)] pub(crate) fn refresh(&self) -> Result, DispatchError> { Self::from(&self.key) } @@ -299,6 +300,7 @@ impl Delegatee { /// This is similar to [Self::available_to_bond] except it also includes `unclaimed_withdrawals` /// of `Delegatee`. #[cfg(test)] + #[allow(unused)] pub(crate) fn total_unbonded(&self) -> BalanceOf { let bonded_stake = self.bonded_stake(); From a91a417823893042d2e9af8c05ae4d2faf278aaa Mon Sep 17 00:00:00 2001 From: Ankan Date: Sat, 30 Mar 2024 02:12:01 +0100 Subject: [PATCH 009/257] remove pool dependency --- Cargo.lock | 1 - substrate/frame/delegated-staking/Cargo.toml | 1 - 2 files changed, 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8555a55d037f..fd82e1711fdf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9706,7 +9706,6 @@ dependencies = [ "frame-support", "frame-system", "pallet-balances", - "pallet-nomination-pools", "pallet-staking", "pallet-staking-reward-curve", "pallet-timestamp", diff --git a/substrate/frame/delegated-staking/Cargo.toml b/substrate/frame/delegated-staking/Cargo.toml index b4b9768256c6..b43d09692db5 100644 --- a/substrate/frame/delegated-staking/Cargo.toml +++ b/substrate/frame/delegated-staking/Cargo.toml @@ -26,7 +26,6 @@ sp-io = { path = "../../primitives/io" } substrate-test-utils = { path = "../../test-utils" } sp-tracing = { path = "../../primitives/tracing" } pallet-staking = { path = "../staking" } -pallet-nomination-pools = { path = "../nomination-pools" } pallet-balances = { path = "../balances" } pallet-timestamp = { path = "../timestamp" } pallet-staking-reward-curve = { path = "../staking/reward-curve" } From d6069a42c465ff282df8fd9bc1a29e5a10d8aaaa Mon Sep 17 00:00:00 2001 From: Ankan Date: Sat, 30 Mar 2024 02:15:55 +0100 Subject: [PATCH 010/257] fix imports --- substrate/frame/delegated-staking/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs index d2097bb49cb3..84271f0246ed 100644 --- a/substrate/frame/delegated-staking/src/lib.rs +++ b/substrate/frame/delegated-staking/src/lib.rs @@ -435,7 +435,7 @@ pub mod pallet { #[pallet::hooks] impl Hooks> for Pallet { #[cfg(feature = "try-runtime")] - fn try_state(_n: BlockNumberFor) -> Result<(), TryRuntimeError> { + fn try_state(_n: BlockNumberFor) -> Result<(), sp_runtime::TryRuntimeError> { Self::do_try_state() } From 3e379167c41ae6f4d328272b20aebfbdab27aa4e Mon Sep 17 00:00:00 2001 From: Ankan Date: Sat, 30 Mar 2024 02:28:18 +0100 Subject: [PATCH 011/257] taplo fmt toml files --- substrate/frame/delegated-staking/Cargo.toml | 68 ++++++++++---------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/substrate/frame/delegated-staking/Cargo.toml b/substrate/frame/delegated-staking/Cargo.toml index b43d09692db5..cecaefbe779f 100644 --- a/substrate/frame/delegated-staking/Cargo.toml +++ b/substrate/frame/delegated-staking/Cargo.toml @@ -13,11 +13,11 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } -frame-support = { path = "../support", default-features = false} -frame-system = { path = "../system", default-features = false} +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -sp-std = { path = "../../primitives/std", default-features = false} -sp-runtime = { path = "../../primitives/runtime", default-features = false} +sp-std = { path = "../../primitives/std", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } sp-staking = { path = "../../primitives/staking", default-features = false } [dev-dependencies] @@ -29,41 +29,41 @@ pallet-staking = { path = "../staking" } pallet-balances = { path = "../balances" } pallet-timestamp = { path = "../timestamp" } pallet-staking-reward-curve = { path = "../staking/reward-curve" } -frame-election-provider-support = { path = "../election-provider-support", default-features = false} +frame-election-provider-support = { path = "../election-provider-support", default-features = false } [features] -default = [ "std" ] +default = ["std"] std = [ - "codec/std", - "frame-support/std", - "frame-system/std", - "scale-info/std", - "sp-core/std", - "sp-io/std", - "sp-std/std", - "sp-runtime/std", - "sp-staking/std", - "pallet-balances/std", - "pallet-staking/std", - "pallet-timestamp/std", - "frame-election-provider-support/std", + "codec/std", + "frame-election-provider-support/std", + "frame-support/std", + "frame-system/std", + "pallet-balances/std", + "pallet-staking/std", + "pallet-timestamp/std", + "scale-info/std", + "sp-core/std", + "sp-io/std", + "sp-runtime/std", + "sp-staking/std", + "sp-std/std", ] runtime-benchmarks = [ - "frame-support/runtime-benchmarks", - "frame-system/runtime-benchmarks", - "sp-runtime/runtime-benchmarks", - "sp-staking/runtime-benchmarks", - "pallet-balances/runtime-benchmarks", - "pallet-staking/runtime-benchmarks", - "pallet-timestamp/runtime-benchmarks", - "frame-election-provider-support/runtime-benchmarks", + "frame-election-provider-support/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "pallet-balances/runtime-benchmarks", + "pallet-staking/runtime-benchmarks", + "pallet-timestamp/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", + "sp-staking/runtime-benchmarks", ] try-runtime = [ - "frame-support/try-runtime", - "frame-system/try-runtime", - "sp-runtime/try-runtime", - "pallet-balances/try-runtime", - "pallet-staking/try-runtime", - "pallet-timestamp/try-runtime", - "frame-election-provider-support/try-runtime", + "frame-election-provider-support/try-runtime", + "frame-support/try-runtime", + "frame-system/try-runtime", + "pallet-balances/try-runtime", + "pallet-staking/try-runtime", + "pallet-timestamp/try-runtime", + "sp-runtime/try-runtime", ] From 79c4a8607f2179206b3796dcc4ab2978c8a9d124 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sat, 30 Mar 2024 02:30:38 +0100 Subject: [PATCH 012/257] taplo refmt --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 2966e45fbec0..f9f89d313175 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -317,6 +317,7 @@ members = [ "substrate/frame/contracts/uapi", "substrate/frame/conviction-voting", "substrate/frame/core-fellowship", + "substrate/frame/delegated-staking", "substrate/frame/democracy", "substrate/frame/election-provider-multi-phase", "substrate/frame/election-provider-multi-phase/test-staking-e2e", @@ -385,7 +386,6 @@ members = [ "substrate/frame/staking/reward-curve", "substrate/frame/staking/reward-fn", "substrate/frame/staking/runtime-api", - "substrate/frame/delegated-staking", "substrate/frame/state-trie-migration", "substrate/frame/statement", "substrate/frame/sudo", From 35c5e804de7817ee8e3c783aef359c71e3cd6841 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 31 Mar 2024 18:46:28 +0200 Subject: [PATCH 013/257] remove calls --- .../frame/delegated-staking/src/impls.rs | 22 +-- substrate/frame/delegated-staking/src/lib.rs | 166 +++++++++--------- substrate/frame/delegated-staking/src/mock.rs | 4 +- .../frame/delegated-staking/src/tests.rs | 94 +++++----- .../frame/delegated-staking/src/types.rs | 2 +- 5 files changed, 141 insertions(+), 147 deletions(-) diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs index b188db4aa5f9..e09a4b373834 100644 --- a/substrate/frame/delegated-staking/src/impls.rs +++ b/substrate/frame/delegated-staking/src/impls.rs @@ -53,12 +53,12 @@ impl StakingInterface for Pallet { } fn stake(who: &Self::AccountId) -> Result, DispatchError> { - ensure!(Self::is_delegatee(who), Error::::NotSupported); + ensure!(Self::is_agent(who), Error::::NotSupported); T::CoreStaking::stake(who) } fn total_stake(who: &Self::AccountId) -> Result { - if Self::is_delegatee(who) { + if Self::is_agent(who) { return T::CoreStaking::total_stake(who); } @@ -79,7 +79,7 @@ impl StakingInterface for Pallet { } fn fully_unbond(who: &Self::AccountId) -> DispatchResult { - ensure!(Self::is_delegatee(who), Error::::NotSupported); + ensure!(Self::is_agent(who), Error::::NotSupported); T::CoreStaking::fully_unbond(who) } @@ -99,17 +99,17 @@ impl StakingInterface for Pallet { } fn nominate(who: &Self::AccountId, validators: Vec) -> DispatchResult { - ensure!(Self::is_delegatee(who), Error::::NotDelegatee); + ensure!(Self::is_agent(who), Error::::NotAgent); T::CoreStaking::nominate(who, validators) } fn chill(who: &Self::AccountId) -> DispatchResult { - ensure!(Self::is_delegatee(who), Error::::NotDelegatee); + ensure!(Self::is_agent(who), Error::::NotAgent); T::CoreStaking::chill(who) } fn bond_extra(who: &Self::AccountId, extra: Self::Balance) -> DispatchResult { - let ledger = >::get(who).ok_or(Error::::NotDelegatee)?; + let ledger = >::get(who).ok_or(Error::::NotAgent)?; ensure!(ledger.stakeable_balance() >= extra, Error::::NotEnoughFunds); T::CoreStaking::bond_extra(who, extra) @@ -154,7 +154,7 @@ impl StakingInterface for Pallet { } fn status(who: &Self::AccountId) -> Result, DispatchError> { - ensure!(Self::is_delegatee(who), Error::::NotDelegatee); + ensure!(Self::is_agent(who), Error::::NotAgent); T::CoreStaking::status(who) } @@ -209,13 +209,13 @@ impl DelegatedStakeInterface for Pallet { reward_account: &Self::AccountId, amount: Self::Balance, ) -> DispatchResult { - Pallet::::register_as_delegatee( + Pallet::::register_agent( RawOrigin::Signed(delegatee.clone()).into(), reward_account.clone(), )?; // Delegate the funds from who to the delegatee account. - Pallet::::delegate_funds( + Pallet::::delegate_to_agent( RawOrigin::Signed(who.clone()).into(), delegatee.clone(), amount, @@ -228,7 +228,7 @@ impl DelegatedStakeInterface for Pallet { delegatee: &Self::AccountId, amount: Self::Balance, ) -> DispatchResult { - Pallet::::delegate_funds( + Pallet::::delegate_to_agent( RawOrigin::Signed(who.clone()).into(), delegatee.clone(), amount, @@ -245,7 +245,7 @@ impl DelegatedStakeInterface for Pallet { amount: Self::Balance, ) -> DispatchResult { // fixme(ank4n): Can this not require slashing spans? - Pallet::::release( + Pallet::::release_delegation( RawOrigin::Signed(delegatee.clone()).into(), delegator.clone(), amount, diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs index 84271f0246ed..fcf633af85f5 100644 --- a/substrate/frame/delegated-staking/src/lib.rs +++ b/substrate/frame/delegated-staking/src/lib.rs @@ -162,7 +162,6 @@ use frame_support::{ tokens::{fungible::Credit, Fortitude, Precision, Preservation}, Defensive, DefensiveOption, Imbalance, OnUnbalanced, }, - weights::Weight, }; use sp_runtime::{ @@ -225,7 +224,7 @@ pub mod pallet { /// The account does not have enough funds to perform the operation. NotEnoughFunds, /// Not an existing delegatee account. - NotDelegatee, + NotAgent, /// Not a Delegator account. NotDelegator, /// Some corruption in internal state. @@ -270,37 +269,44 @@ pub mod pallet { pub(crate) type Delegatees = CountedStorageMap<_, Twox64Concat, T::AccountId, DelegateeLedger, OptionQuery>; - #[pallet::call] + // This pallet is not currently written with the intention of exposing any calls. But the + // functions defined in the following impl block should act as a good reference for how the + // exposed calls would look like when exposed. impl Pallet { - /// Register an account to be a `Delegatee`. + /// Register an account to become a stake `Agent`. Sometimes also called a `Delegatee`. /// - /// `Delegatee` accounts accepts delegations from other `delegator`s and stake funds on - /// their behalf. - #[pallet::call_index(0)] - #[pallet::weight(Weight::default())] - pub fn register_as_delegatee( + /// Delegators can authorize `Agent`s to stake on their behalf by delegating their funds to + /// them. The `Agent` can then use the delegated funds to stake to [`Config::CoreStaking`]. + /// + /// Implementation note: This function allows any account to become an agent. It is + /// important though that accounts that call [`StakingUnsafe::virtual_bond`] are keyless + /// accounts. This is not a problem for now since this is only used by other pallets in the + /// runtime which use keyless account as agents. If we later want to expose this as a + /// dispatchable call, we should derive a sub-account from the caller and use that as the + /// agent account. + pub fn register_agent( origin: OriginFor, reward_account: T::AccountId, ) -> DispatchResult { let who = ensure_signed(origin)?; - // Existing `delegatee` cannot register again. - ensure!(!Self::is_delegatee(&who), Error::::NotAllowed); + // Existing `agent` cannot register again. + ensure!(!Self::is_agent(&who), Error::::NotAllowed); - // A delegator cannot become a `delegatee`. + // A delegator cannot become an `agent`. ensure!(!Self::is_delegator(&who), Error::::NotAllowed); // They cannot be already a direct staker in the staking pallet. ensure!(Self::not_direct_staker(&who), Error::::AlreadyStaking); - // Reward account cannot be same as `delegatee` account. + // Reward account cannot be same as `agent` account. ensure!(reward_account != who, Error::::InvalidRewardDestination); - Self::do_register_delegatee(&who, &reward_account); + Self::do_register_agent(&who, &reward_account); Ok(()) } - /// Migrate from a `Nominator` account to `Delegatee` account. + /// Migrate from a `Nominator` account to `Agent` account. /// /// The origin needs to /// - be a `Nominator` with `CoreStaking`, @@ -308,39 +314,35 @@ pub mod pallet { /// - have enough funds to transfer existential deposit to a delegator account created for /// the migration. /// - /// This operation will create a new delegator account for the origin called - /// `proxy_delegator` and transfer the staked amount to it. The `proxy_delegator` delegates - /// the funds to the origin making origin a `Delegatee` account. The actual `delegator` - /// accounts of the origin can later migrate their funds using [Call::migrate_delegation] to + /// This function will create a proxy account to the agent called `proxy_delegator` and + /// transfer the directly staked amount by the agent to it. The `proxy_delegator` delegates + /// the funds to the origin making origin an `Agent` account. The real `delegator` + /// accounts of the origin can later migrate their funds using [Self::migrate_delegation] to /// claim back their share of delegated funds from `proxy_delegator` to self. - #[pallet::call_index(1)] - #[pallet::weight(Weight::default())] - pub fn migrate_to_delegatee( + pub fn migrate_to_agent( origin: OriginFor, reward_account: T::AccountId, ) -> DispatchResult { let who = ensure_signed(origin)?; - // ensure who is not already a delegatee. - ensure!(!Self::is_delegatee(&who), Error::::NotAllowed); + // ensure who is not already an agent. + ensure!(!Self::is_agent(&who), Error::::NotAllowed); // and they should already be a nominator in `CoreStaking`. ensure!(Self::is_direct_nominator(&who), Error::::NotAllowed); - // Reward account cannot be same as `delegatee` account. + // Reward account cannot be same as `agent` account. ensure!(reward_account != who, Error::::InvalidRewardDestination); - Self::do_migrate_to_delegatee(&who, &reward_account) + Self::do_migrate_to_agent(&who, &reward_account) } - /// Release delegated amount to delegator. + /// Release previously delegated funds by delegator to origin. /// - /// This can be called by existing `delegatee` accounts. + /// Only agents can call this. /// - /// Tries to withdraw unbonded fund from `CoreStaking` if needed and release amount to + /// Tries to withdraw unbonded funds from `CoreStaking` if needed and release amount to /// `delegator`. - #[pallet::call_index(2)] - #[pallet::weight(Weight::default())] - pub fn release( + pub fn release_delegation( origin: OriginFor, delegator: T::AccountId, amount: BalanceOf, @@ -350,85 +352,81 @@ pub mod pallet { Self::do_release(&who, &delegator, amount, num_slashing_spans) } - /// Migrate delegated fund. + /// Claim delegated funds that are held in `proxy_delegator` to the claiming delegator's + /// account. If successful, the specified funds will be delegated directly from `delegator` + /// account to the agent. /// - /// This can be called by migrating `delegatee` accounts. + /// This can be called by `agent` accounts that were previously a direct `Nominator` with + /// [`Config::CoreStaking`] and has some remaining unclaimed delegations. /// - /// This moves delegator funds from `pxoxy_delegator` account to `delegator` account. - #[pallet::call_index(3)] - #[pallet::weight(Weight::default())] - pub fn migrate_delegation( + /// Internally, it moves some delegations from `pxoxy_delegator` account to `delegator` + /// account and reapplying the holds. + pub fn claim_delegation( origin: OriginFor, delegator: T::AccountId, amount: BalanceOf, ) -> DispatchResult { - let delegatee = ensure_signed(origin)?; + let agent = ensure_signed(origin)?; // Ensure they have minimum delegation. ensure!(amount >= T::Currency::minimum_balance(), Error::::NotEnoughFunds); // Ensure delegator is sane. - ensure!(!Self::is_delegatee(&delegator), Error::::NotAllowed); + ensure!(!Self::is_agent(&delegator), Error::::NotAllowed); ensure!(!Self::is_delegator(&delegator), Error::::NotAllowed); ensure!(Self::not_direct_staker(&delegator), Error::::AlreadyStaking); // ensure delegatee is sane. - ensure!(Self::is_delegatee(&delegatee), Error::::NotDelegatee); + ensure!(Self::is_agent(&agent), Error::::NotAgent); // and has enough delegated balance to migrate. - let proxy_delegator = Self::sub_account(AccountType::ProxyDelegator, delegatee); + let proxy_delegator = Self::sub_account(AccountType::ProxyDelegator, agent); let balance_remaining = Self::held_balance_of(&proxy_delegator); ensure!(balance_remaining >= amount, Error::::NotEnoughFunds); Self::do_migrate_delegation(&proxy_delegator, &delegator, amount) } - /// Delegate funds to a `Delegatee` account and bonds it to [Config::CoreStaking]. + /// Delegate given `amount` of tokens to an `Agent` account. + /// + /// If `origin` is the first time delegator, we add them to state. If they are already + /// delegating, we increase the delegation. /// - /// If delegation already exists, it increases the delegation by `amount`. - #[pallet::call_index(4)] - #[pallet::weight(Weight::default())] - pub fn delegate_funds( + /// Conditions: + /// - Delegators cannot delegate to more than one agent. + /// - The `agent` account should already be registered as such. See [`Self::register_agent`] + pub fn delegate_to_agent( origin: OriginFor, - delegatee: T::AccountId, + agent: T::AccountId, amount: BalanceOf, ) -> DispatchResult { - let who = ensure_signed(origin)?; + let delegator = ensure_signed(origin)?; // ensure amount is over minimum to delegate ensure!(amount > T::Currency::minimum_balance(), Error::::NotEnoughFunds); // ensure delegator is sane. - ensure!(Delegation::::can_delegate(&who, &delegatee), Error::::InvalidDelegation); - ensure!(Self::not_direct_staker(&who), Error::::AlreadyStaking); + ensure!( + Delegation::::can_delegate(&delegator, &agent), + Error::::InvalidDelegation + ); + ensure!(Self::not_direct_staker(&delegator), Error::::AlreadyStaking); - // ensure delegatee is sane. - ensure!(Self::is_delegatee(&delegatee), Error::::NotDelegatee); + // ensure agent is sane. + ensure!(Self::is_agent(&agent), Error::::NotAgent); - let delegator_balance = - T::Currency::reducible_balance(&who, Preservation::Preserve, Fortitude::Polite); + let delegator_balance = T::Currency::reducible_balance( + &delegator, + Preservation::Preserve, + Fortitude::Polite, + ); ensure!(delegator_balance >= amount, Error::::NotEnoughFunds); // add to delegation - Self::do_delegate(&who, &delegatee, amount)?; - // bond the amount to `CoreStaking`. - Self::do_bond(&delegatee, amount) - } + Self::do_delegate(&delegator, &agent, amount)?; - /// Apply slash to a delegator account. - /// - /// `Delegatee` accounts with pending slash in their ledger can call this to apply slash to - /// one of its `delegator` account. Each slash to a delegator account needs to be posted - /// separately until all pending slash is cleared. - #[pallet::call_index(5)] - #[pallet::weight(Weight::default())] - pub fn apply_slash( - origin: OriginFor, - delegator: T::AccountId, - amount: BalanceOf, - ) -> DispatchResult { - let who = ensure_signed(origin)?; - Self::do_slash(who, delegator, amount, None) + // bond the newly delegated amount to `CoreStaking`. + Self::do_bond(&agent, amount) } } @@ -458,7 +456,7 @@ impl Pallet { } /// Returns true if who is registered as a `Delegatee`. - fn is_delegatee(who: &T::AccountId) -> bool { + fn is_agent(who: &T::AccountId) -> bool { >::contains_key(who) } @@ -479,7 +477,7 @@ impl Pallet { .unwrap_or(false) } - fn do_register_delegatee(who: &T::AccountId, reward_account: &T::AccountId) { + fn do_register_agent(who: &T::AccountId, reward_account: &T::AccountId) { DelegateeLedger::::new(reward_account).save(who); // Delegatee is a virtual account. Make this account exist. @@ -488,10 +486,7 @@ impl Pallet { frame_system::Pallet::::inc_providers(who); } - fn do_migrate_to_delegatee( - who: &T::AccountId, - reward_account: &T::AccountId, - ) -> DispatchResult { + fn do_migrate_to_agent(who: &T::AccountId, reward_account: &T::AccountId) -> DispatchResult { // We create a proxy delegator that will keep all the delegation funds until funds are // transferred to actual delegator. let proxy_delegator = Self::sub_account(AccountType::ProxyDelegator, who.clone()); @@ -516,7 +511,7 @@ impl Pallet { T::Currency::transfer(who, &proxy_delegator, stake.total, Preservation::Protect) .map_err(|_| Error::::BadState)?; - Self::do_register_delegatee(who, reward_account); + Self::do_register_agent(who, reward_account); T::CoreStaking::update_payee(who, reward_account)?; Self::do_delegate(&proxy_delegator, who, stake.total) @@ -540,7 +535,7 @@ impl Pallet { delegatee: &T::AccountId, amount: BalanceOf, ) -> DispatchResult { - let mut ledger = DelegateeLedger::::get(delegatee).ok_or(Error::::NotDelegatee)?; + let mut ledger = DelegateeLedger::::get(delegatee).ok_or(Error::::NotAgent)?; let new_delegation_amount = if let Some(existing_delegation) = Delegation::::get(delegator) { @@ -579,7 +574,7 @@ impl Pallet { let mut delegation = Delegation::::get(delegator).ok_or(Error::::NotDelegator)?; // make sure delegation to be released is sound. - ensure!(&delegation.delegatee == who, Error::::NotDelegatee); + ensure!(&delegation.delegatee == who, Error::::NotAgent); ensure!(delegation.amount >= amount, Error::::NotEnoughFunds); // if we do not already have enough funds to be claimed, try withdraw some more. @@ -663,8 +658,7 @@ impl Pallet { // some checks that must have already been checked before. ensure!(source_delegation.amount >= amount, Error::::NotEnoughFunds); debug_assert!( - !Self::is_delegator(destination_delegator) && - !Self::is_delegatee(destination_delegator) + !Self::is_delegator(destination_delegator) && !Self::is_agent(destination_delegator) ); // update delegations @@ -711,7 +705,7 @@ impl Pallet { let delegatee = Delegatee::::from(&delegatee_acc)?; let delegation = >::get(&delegator).ok_or(Error::::NotDelegator)?; - ensure!(delegation.delegatee == delegatee_acc, Error::::NotDelegatee); + ensure!(delegation.delegatee == delegatee_acc, Error::::NotAgent); ensure!(delegation.amount >= amount, Error::::NotEnoughFunds); let (mut credit, missing) = @@ -804,7 +798,7 @@ impl Pallet { T::CoreStaking::status(delegator).is_err(), "delegator should not be directly staked" ); - ensure!(!Self::is_delegatee(delegator), "delegator cannot be delegatee"); + ensure!(!Self::is_agent(delegator), "delegator cannot be delegatee"); delegation_aggregation .entry(delegation.delegatee.clone()) diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs index 84854d6864d6..1a4f079735b7 100644 --- a/substrate/frame/delegated-staking/src/mock.rs +++ b/substrate/frame/delegated-staking/src/mock.rs @@ -264,7 +264,7 @@ pub(crate) fn setup_delegation_stake( increment: Balance, ) -> Balance { fund(&delegatee, 100); - assert_ok!(DelegatedStaking::register_as_delegatee( + assert_ok!(DelegatedStaking::register_agent( RawOrigin::Signed(delegatee).into(), reward_acc )); @@ -274,7 +274,7 @@ pub(crate) fn setup_delegation_stake( delegated_amount += amount_to_delegate; fund(delegator, amount_to_delegate + ExistentialDeposit::get()); - assert_ok!(DelegatedStaking::delegate_funds( + assert_ok!(DelegatedStaking::delegate_to_agent( RawOrigin::Signed(*delegator).into(), delegatee, amount_to_delegate diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs index 844ab74bfa09..9b9dd92bc227 100644 --- a/substrate/frame/delegated-staking/src/tests.rs +++ b/substrate/frame/delegated-staking/src/tests.rs @@ -31,21 +31,21 @@ fn create_a_delegatee_with_first_delegator() { // set intention to accept delegation. fund(&delegatee, 1000); - assert_ok!(DelegatedStaking::register_as_delegatee( + assert_ok!(DelegatedStaking::register_agent( RawOrigin::Signed(delegatee).into(), reward_account )); // delegate to this account fund(&delegator, 1000); - assert_ok!(DelegatedStaking::delegate_funds( + assert_ok!(DelegatedStaking::delegate_to_agent( RawOrigin::Signed(delegator).into(), delegatee, 100 )); // verify - assert!(DelegatedStaking::is_delegatee(&delegatee)); + assert!(DelegatedStaking::is_agent(&delegatee)); assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), 100); assert_eq!(Balances::balance_on_hold(&HoldReason::Delegating.into(), &delegator), 100); }); @@ -56,13 +56,13 @@ fn cannot_become_delegatee() { ExtBuilder::default().build_and_execute(|| { // cannot set reward account same as delegatee account assert_noop!( - DelegatedStaking::register_as_delegatee(RawOrigin::Signed(100).into(), 100), + DelegatedStaking::register_agent(RawOrigin::Signed(100).into(), 100), Error::::InvalidRewardDestination ); // an existing validator cannot become delegatee assert_noop!( - DelegatedStaking::register_as_delegatee( + DelegatedStaking::register_agent( RawOrigin::Signed(mock::GENESIS_VALIDATOR).into(), 100 ), @@ -71,14 +71,14 @@ fn cannot_become_delegatee() { // an existing nominator cannot become delegatee assert_noop!( - DelegatedStaking::register_as_delegatee( + DelegatedStaking::register_agent( RawOrigin::Signed(mock::GENESIS_NOMINATOR_ONE).into(), 100 ), Error::::AlreadyStaking ); assert_noop!( - DelegatedStaking::register_as_delegatee( + DelegatedStaking::register_agent( RawOrigin::Signed(mock::GENESIS_NOMINATOR_TWO).into(), 100 ), @@ -95,11 +95,11 @@ fn create_multiple_delegators() { // stakeable balance is 0 for non delegatee fund(&delegatee, 1000); - assert!(!DelegatedStaking::is_delegatee(&delegatee)); + assert!(!DelegatedStaking::is_agent(&delegatee)); assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), 0); // set intention to accept delegation. - assert_ok!(DelegatedStaking::register_as_delegatee( + assert_ok!(DelegatedStaking::register_agent( RawOrigin::Signed(delegatee).into(), reward_account )); @@ -107,7 +107,7 @@ fn create_multiple_delegators() { // create 100 delegators for i in 202..302 { fund(&i, 100 + ExistentialDeposit::get()); - assert_ok!(DelegatedStaking::delegate_funds( + assert_ok!(DelegatedStaking::delegate_to_agent( RawOrigin::Signed(i).into(), delegatee, 100 @@ -117,7 +117,7 @@ fn create_multiple_delegators() { } // verify - assert!(DelegatedStaking::is_delegatee(&delegatee)); + assert!(DelegatedStaking::is_agent(&delegatee)); assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), 100 * 100); }); } @@ -129,12 +129,12 @@ fn delegatee_restrictions() { let delegatee_one = 200; let delegator_one = 210; fund(&delegatee_one, 100); - assert_ok!(DelegatedStaking::register_as_delegatee( + assert_ok!(DelegatedStaking::register_agent( RawOrigin::Signed(delegatee_one).into(), delegatee_one + 1 )); fund(&delegator_one, 200); - assert_ok!(DelegatedStaking::delegate_funds( + assert_ok!(DelegatedStaking::delegate_to_agent( RawOrigin::Signed(delegator_one).into(), delegatee_one, 100 @@ -143,12 +143,12 @@ fn delegatee_restrictions() { let delegatee_two = 300; let delegator_two = 310; fund(&delegatee_two, 100); - assert_ok!(DelegatedStaking::register_as_delegatee( + assert_ok!(DelegatedStaking::register_agent( RawOrigin::Signed(delegatee_two).into(), delegatee_two + 1 )); fund(&delegator_two, 200); - assert_ok!(DelegatedStaking::delegate_funds( + assert_ok!(DelegatedStaking::delegate_to_agent( RawOrigin::Signed(delegator_two).into(), delegatee_two, 100 @@ -156,7 +156,7 @@ fn delegatee_restrictions() { // delegatee one tries to delegate to delegatee 2 assert_noop!( - DelegatedStaking::delegate_funds( + DelegatedStaking::delegate_to_agent( RawOrigin::Signed(delegatee_one).into(), delegatee_two, 10 @@ -166,7 +166,7 @@ fn delegatee_restrictions() { // delegatee one tries to delegate to a delegator assert_noop!( - DelegatedStaking::delegate_funds( + DelegatedStaking::delegate_to_agent( RawOrigin::Signed(delegatee_one).into(), delegator_one, 10 @@ -174,7 +174,7 @@ fn delegatee_restrictions() { Error::::InvalidDelegation ); assert_noop!( - DelegatedStaking::delegate_funds( + DelegatedStaking::delegate_to_agent( RawOrigin::Signed(delegatee_one).into(), delegator_two, 10 @@ -185,7 +185,7 @@ fn delegatee_restrictions() { // delegator one tries to delegate to delegatee 2 as well (it already delegates to delegatee // 1) assert_noop!( - DelegatedStaking::delegate_funds( + DelegatedStaking::delegate_to_agent( RawOrigin::Signed(delegator_one).into(), delegatee_two, 10 @@ -217,7 +217,7 @@ mod staking_integration { // set intention to become a delegatee fund(&delegatee, 100); - assert_ok!(DelegatedStaking::register_as_delegatee( + assert_ok!(DelegatedStaking::register_agent( RawOrigin::Signed(delegatee).into(), reward_acc )); @@ -228,7 +228,7 @@ mod staking_integration { // set some delegations for delegator in 200..250 { fund(&delegator, 200); - assert_ok!(DelegatedStaking::delegate_funds( + assert_ok!(DelegatedStaking::delegate_to_agent( RawOrigin::Signed(delegator).into(), delegatee, 100 @@ -269,10 +269,10 @@ mod staking_integration { assert!(eq_stake(delegatee, total_staked, total_staked)); // Withdrawing without unbonding would fail. assert_noop!( - DelegatedStaking::release(RawOrigin::Signed(delegatee).into(), 301, 50, 0), + DelegatedStaking::release_delegation(RawOrigin::Signed(delegatee).into(), 301, 50, 0), Error::::NotEnoughFunds ); - // assert_noop!(DelegatedStaking::release(RawOrigin::Signed(delegatee).into(), 200, 50, + // assert_noop!(DelegatedStaking::release_delegation(RawOrigin::Signed(delegatee).into(), 200, 50, // 0), Error::::NotAllowed); active and total stake remains same assert!(eq_stake(delegatee, total_staked, total_staked)); @@ -291,7 +291,7 @@ mod staking_integration { // nothing to withdraw at era 4 assert_noop!( - DelegatedStaking::release(RawOrigin::Signed(delegatee).into(), 305, 50, 0), + DelegatedStaking::release_delegation(RawOrigin::Signed(delegatee).into(), 305, 50, 0), Error::::NotEnoughFunds ); @@ -303,43 +303,43 @@ mod staking_integration { start_era(5); // at era 5, 50 tokens are withdrawable, cannot withdraw more. assert_noop!( - DelegatedStaking::release(RawOrigin::Signed(delegatee).into(), 305, 51, 0), + DelegatedStaking::release_delegation(RawOrigin::Signed(delegatee).into(), 305, 51, 0), Error::::NotEnoughFunds ); // less is possible - assert_ok!(DelegatedStaking::release(RawOrigin::Signed(delegatee).into(), 305, 30, 0)); - assert_ok!(DelegatedStaking::release(RawOrigin::Signed(delegatee).into(), 305, 20, 0)); + assert_ok!(DelegatedStaking::release_delegation(RawOrigin::Signed(delegatee).into(), 305, 30, 0)); + assert_ok!(DelegatedStaking::release_delegation(RawOrigin::Signed(delegatee).into(), 305, 20, 0)); // Lets go to future era where everything is unbonded. Withdrawable amount: 100 + 200 start_era(7); // 305 has no more amount delegated so it cannot withdraw. assert_noop!( - DelegatedStaking::release(RawOrigin::Signed(delegatee).into(), 305, 5, 0), + DelegatedStaking::release_delegation(RawOrigin::Signed(delegatee).into(), 305, 5, 0), Error::::NotDelegator ); // 309 is an active delegator but has total delegation of 90, so it cannot withdraw more // than that. assert_noop!( - DelegatedStaking::release(RawOrigin::Signed(delegatee).into(), 309, 91, 0), + DelegatedStaking::release_delegation(RawOrigin::Signed(delegatee).into(), 309, 91, 0), Error::::NotEnoughFunds ); // 310 cannot withdraw more than delegated funds. assert_noop!( - DelegatedStaking::release(RawOrigin::Signed(delegatee).into(), 310, 101, 0), + DelegatedStaking::release_delegation(RawOrigin::Signed(delegatee).into(), 310, 101, 0), Error::::NotEnoughFunds ); // but can withdraw all its delegation amount. - assert_ok!(DelegatedStaking::release(RawOrigin::Signed(delegatee).into(), 310, 100, 0)); + assert_ok!(DelegatedStaking::release_delegation(RawOrigin::Signed(delegatee).into(), 310, 100, 0)); // 320 can withdraw all its delegation amount. - assert_ok!(DelegatedStaking::release(RawOrigin::Signed(delegatee).into(), 320, 200, 0)); + assert_ok!(DelegatedStaking::release_delegation(RawOrigin::Signed(delegatee).into(), 320, 200, 0)); // cannot withdraw anything more.. assert_noop!( - DelegatedStaking::release(RawOrigin::Signed(delegatee).into(), 301, 1, 0), + DelegatedStaking::release_delegation(RawOrigin::Signed(delegatee).into(), 301, 1, 0), Error::::NotEnoughFunds ); assert_noop!( - DelegatedStaking::release(RawOrigin::Signed(delegatee).into(), 350, 1, 0), + DelegatedStaking::release_delegation(RawOrigin::Signed(delegatee).into(), 350, 1, 0), Error::::NotEnoughFunds ); }); @@ -353,7 +353,7 @@ mod staking_integration { // verify withdraw not possible yet assert_noop!( - DelegatedStaking::release(RawOrigin::Signed(delegatee).into(), 300, 100, 0), + DelegatedStaking::release_delegation(RawOrigin::Signed(delegatee).into(), 300, 100, 0), Error::::NotEnoughFunds ); @@ -363,14 +363,14 @@ mod staking_integration { // withdrawn and test its claimed from there first. // fund(&300, 1000); - // assert_ok!(DelegatedStaking::delegate_funds(RawOrigin::Signed(300.into()), delegate, + // assert_ok!(DelegatedStaking::delegate_to_agent(RawOrigin::Signed(300.into()), delegate, // 100)); // // // verify unbonded balance // assert_eq!(get_delegatee(&delegatee).available_to_bond(), 100); // // // withdraw works now without unbonding - // assert_ok!(DelegatedStaking::release(RawOrigin::Signed(delegatee).into(), 300, 100, + // assert_ok!(DelegatedStaking::release_delegation(RawOrigin::Signed(delegatee).into(), 300, 100, // 0)); assert_eq!(get_delegatee(&delegatee).available_to_bond(), 0); }); } @@ -384,15 +384,15 @@ mod staking_integration { // `delegatee` account cannot be reward destination assert_noop!( - DelegatedStaking::register_as_delegatee(RawOrigin::Signed(200).into(), 200), + DelegatedStaking::register_agent(RawOrigin::Signed(200).into(), 200), Error::::InvalidRewardDestination ); // different reward account works - assert_ok!(DelegatedStaking::register_as_delegatee(RawOrigin::Signed(200).into(), 201)); + assert_ok!(DelegatedStaking::register_agent(RawOrigin::Signed(200).into(), 201)); // add some delegations to it fund(&300, 1000); - assert_ok!(DelegatedStaking::delegate_funds(RawOrigin::Signed(300).into(), 200, 100)); + assert_ok!(DelegatedStaking::delegate_to_agent(RawOrigin::Signed(300).into(), 200, 100)); // if delegate calls Staking pallet directly with a different reward destination, it // fails. @@ -424,24 +424,24 @@ mod staking_integration { // Registering again is noop assert_noop!( - DelegatedStaking::register_as_delegatee(RawOrigin::Signed(200).into(), 201), + DelegatedStaking::register_agent(RawOrigin::Signed(200).into(), 201), Error::::NotAllowed ); // a delegator cannot become delegate assert_noop!( - DelegatedStaking::register_as_delegatee(RawOrigin::Signed(202).into(), 203), + DelegatedStaking::register_agent(RawOrigin::Signed(202).into(), 203), Error::::NotAllowed ); // existing staker cannot become a delegate assert_noop!( - DelegatedStaking::register_as_delegatee( + DelegatedStaking::register_agent( RawOrigin::Signed(GENESIS_NOMINATOR_ONE).into(), 201 ), Error::::AlreadyStaking ); assert_noop!( - DelegatedStaking::register_as_delegatee( + DelegatedStaking::register_agent( RawOrigin::Signed(GENESIS_VALIDATOR).into(), 201 ), @@ -484,7 +484,7 @@ mod staking_integration { // with at least ED. let proxy_delegator = DelegatedStaking::sub_account(AccountType::ProxyDelegator, 200); - assert_ok!(DelegatedStaking::migrate_to_delegatee(RawOrigin::Signed(200).into(), 201)); + assert_ok!(DelegatedStaking::migrate_to_agent(RawOrigin::Signed(200).into(), 201)); // verify all went well let mut expected_proxy_delegated_amount = staked_amount; @@ -508,7 +508,7 @@ mod staking_integration { // fund them with ED fund(&delegator, ExistentialDeposit::get()); // migrate 1/4th amount into each delegator - assert_ok!(DelegatedStaking::migrate_delegation( + assert_ok!(DelegatedStaking::claim_delegation( RawOrigin::Signed(200).into(), delegator, delegator_share @@ -531,7 +531,7 @@ mod staking_integration { // cannot use migrate delegator anymore assert_noop!( - DelegatedStaking::migrate_delegation(RawOrigin::Signed(200).into(), 305, 1), + DelegatedStaking::claim_delegation(RawOrigin::Signed(200).into(), 305, 1), Error::::NotEnoughFunds ); }); diff --git a/substrate/frame/delegated-staking/src/types.rs b/substrate/frame/delegated-staking/src/types.rs index bd971f39cde6..494a616e76f8 100644 --- a/substrate/frame/delegated-staking/src/types.rs +++ b/substrate/frame/delegated-staking/src/types.rs @@ -167,7 +167,7 @@ pub struct Delegatee { impl Delegatee { /// Get `Delegatee` from storage if it exists or return an error. pub(crate) fn from(delegatee: &T::AccountId) -> Result, DispatchError> { - let ledger = DelegateeLedger::::get(delegatee).ok_or(Error::::NotDelegatee)?; + let ledger = DelegateeLedger::::get(delegatee).ok_or(Error::::NotAgent)?; Ok(Delegatee { key: delegatee.clone(), ledger }) } From c5a5d32431d27bd893562726e0f226b9b89cf88d Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 31 Mar 2024 19:24:16 +0200 Subject: [PATCH 014/257] fix docs --- substrate/frame/delegated-staking/src/lib.rs | 119 +++++++++---------- 1 file changed, 55 insertions(+), 64 deletions(-) diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs index fcf633af85f5..615787200d6a 100644 --- a/substrate/frame/delegated-staking/src/lib.rs +++ b/substrate/frame/delegated-staking/src/lib.rs @@ -17,18 +17,23 @@ //! # Delegated Staking Pallet //! -//! An abstraction over staking pallet to support delegation of funds to a `delegatee` account which -//! can use all the delegated funds to it in the staking pallet as if its own fund. +//! This pallet implements [`sp_staking::DelegatedStakeInterface`] that extends [`StakingInterface`] +//! to support delegation of stake. It consumes [`Config::CoreStaking`] to provide primitive staking +//! functions and only implements the delegation features. //! -//! NOTE: The pallet exposes some dispatchable calls already, but they might not be fully usable -//! from outside the runtime. In the current version, the pallet is meant to be used by other -//! pallets in the same runtime. Eventually though, expect those calls to be functionally complete -//! and usable by off-chain programs as well as xcm based multi locations. +//! Currently, it does not expose any dispatchable calls but is written with a vision to expose them +//! in the future such that it can be utilised by any external account, off-chain entity or xcm +//! multi location such as a parachain or a smart contract. //! -//! Declaring dispatchable still has the benefit of being transactable for unit tests as well as -//! aligned with general direction of moving towards a permissionless pallet. For example, we could -//! clearly signal who is the expected signer of any interaction with this pallet and take into -//! account any security considerations associated with those interactions. +//! ## Key Terminologies +//! - **Agent**: An account who accepts delegations from other accounts and act as an agent on their +//! behalf for staking these delegated funds. Also, sometimes referred as `Delegatee`. +//! - **Delegator**: An account who delegates their funds to an `agent` and authorises them to use +//! it for staking. +//! - **DelegateeLedger**: A data structure that holds important information about the `agent` such +//! as total delegations they have received, any slashes posted to them, etc. +//! - **Delegation**: A data structure that stores the amount of funds delegated to an `agent` by a +//! `delegator`. //! //! ## Goals //! @@ -37,78 +42,64 @@ //! a very critical limitation that the funds were moved from delegator account to pool account //! and hence the delegator lost control over their funds for using it for other purposes such as //! governance. This pallet aims to solve this by extending the staking pallet to support a new -//! primitive function: delegation of funds to an account for the intent of staking. +//! primitive function: delegation of funds to an `agent` with the intent of staking. The agent can +//! then stake the delegated funds to [`Config::CoreStaking`] on behalf of the delegators. //! //! #### Reward and Slashing //! This pallet does not enforce any specific strategy for how rewards or slashes are applied. It -//! is upto the `delegatee` account to decide how to apply the rewards and slashes. +//! is upto the `agent` account to decide how to apply the rewards and slashes. //! //! This importantly allows clients of this pallet to build their own strategies for reward/slashes. -//! For example, a `delegatee` account can choose to first slash the reward pot before slashing the -//! delegators. Or part of the reward can go to a insurance fund that can be used to cover any +//! For example, an `agent` account can choose to first slash the reward pot before slashing the +//! delegators. Or part of the reward can go to an insurance fund that can be used to cover any //! potential future slashes. The goal is to eventually allow foreign MultiLocations //! (smart contracts or pallets on another chain) to build their own pooled staking solutions //! similar to `NominationPools`. + +//! ## Core functions //! -//! ## Key Terminologies -//! - **Delegatee**: An account who accepts delegations from other accounts. -//! - **Delegator**: An account who delegates their funds to a `delegatee`. -//! - **DelegateeLedger**: A data structure that stores important information about the `delegatee` -//! such as their total delegated stake. -//! - **Delegation**: A data structure that stores the amount of funds delegated to a `delegatee` by -//! a `delegator`. -//! -//! ## Interface -//! -//! #### Dispatchable Calls -//! The pallet exposes the following [`Call`]s: -//! - `register_as_delegatee`: Register an account to be a `delegatee`. Once an account is -//! registered as a `delegatee`, for staking operations, only its delegated funds are used. This -//! means it cannot use its own free balance to stake. -//! - `migrate_to_delegate`: This allows a `Nominator` account to become a `delegatee` account. +//! - Allow an account to receive delegations. See [`Pallet::register_agent`]. +//! - Delegate funds to an `agent` account. See [`Pallet::delegate_to_agent`]. +//! - Release delegated funds from an `agent` account to the `delegator`. See +//! [`Pallet::release_delegation`]. +//! - Migrate a `Nominator` account to an `agent` account. See [`Pallet::migrate_to_agent`]. //! Explained in more detail in the `Migration` section. -//! - `release`: Release funds to `delegator` from `unclaimed_withdrawals` register of the -//! `delegatee`. -//! - `migrate_delegation`: Migrate delegated funds from one account to another. This is useful for -//! example, delegators to a pool account which has migrated to be `delegatee` to migrate their -//! funds from pool account back to their own account and delegated to pool as a `delegator`. Once -//! the funds are migrated, the `delegator` can use the funds for other purposes which allows -//! usage of held funds in an account, such as governance. -//! - `delegate_funds`: Delegate funds to a `delegatee` account and update the bond to staking. -//! - `apply_slash`: If there is a pending slash in `delegatee` ledger, the passed delegator's -//! balance is slashed by the amount and the slash is removed from the delegatee ledger. +//! - Migrate unclaimed delegated funds from `agent` to delegator. When a nominator migrates to an +//! agent, the funds are held in a proxy account. This function allows the delegator to claim their +//! share of the funds from the proxy account. See [`Pallet::claim_delegation`]. //! //! #### [Staking Interface](StakingInterface) //! This pallet reimplements the staking interface as a wrapper implementation over -//! [Config::CoreStaking] to provide delegation based staking. NominationPool can use this pallet as -//! its Staking provider to support delegation based staking from pool accounts. +//! [Config::CoreStaking] to provide delegation based staking. Concretely, a pallet like +//! `NominationPools` can switch to this pallet as its Staking provider to support delegation based +//! staking from pool accounts, allowing its members to lock funds in their own account. //! //! ## Lazy Slashing //! One of the reasons why direct nominators on staking pallet cannot scale well is because all //! nominators are slashed at the same time. This is expensive and needs to be bounded operation. //! -//! This pallet implements a lazy slashing mechanism. Any slashes to a `delegatee` are posted in its +//! This pallet implements a lazy slashing mechanism. Any slashes to the `agent` are posted in its //! `DelegateeLedger` as a pending slash. Since the actual amount is held in the multiple -//! `delegator` accounts, this pallet has no way to know how to apply slash. It is `delegatee`'s +//! `delegator` accounts, this pallet has no way to know how to apply slash. It is the `agent`'s //! responsibility to apply slashes for each delegator, one at a time. Staking pallet ensures the -//! pending slash never exceeds staked amount and would freeze further withdraws until pending -//! slashes are applied. +//! pending slash never exceeds staked amount and would freeze further withdraws until all pending +//! slashes are cleared. //! //! The user of this pallet can apply slash using -//! [StakingInterface::delegator_slash](sp_staking::StakingInterface::delegator_slash). +//! [DelegatedStakeInterface::delegator_slash](sp_staking::DelegatedStakeInterface::delegator_slash). //! -//! ## Migration from Nominator to Delegatee +//! ## Migration from Nominator to Agent //! More details [here](https://hackmd.io/@ak0n/np-delegated-staking-migration). //! //! ## Nomination Pool vs Delegation Staking //! This pallet is not a replacement for Nomination Pool but adds a new primitive over staking //! pallet that can be used by Nomination Pool to support delegation based staking. It can be -//! thought of as something in middle of Nomination Pool and Staking Pallet. Technically, these +//! thought of as layer in between of Nomination Pool and Staking Pallet. Technically, these //! changes could be made in one of those pallets as well but that would have meant significant //! refactoring and high chances of introducing a regression. With this approach, we can keep the //! existing pallets with minimal changes and introduce a new pallet that can be optionally used by -//! Nomination Pool. This is completely configurable and a runtime can choose whether to use -//! this pallet or not. +//! Nomination Pool. The vision is to build this in a configurable way such that runtime can choose +//! whether to use this pallet or not. //! //! With that said, following is the main difference between //! #### Nomination Pool without delegation support @@ -117,7 +108,7 @@ //! //! #### Nomination Pool with delegation support //! 1) delegate fund from delegator to pool account, and -//! 2) stake from pool account as a `Delegatee` account on the staking pallet. +//! 2) stake from pool account as an `Agent` account on the staking pallet. //! //! The difference being, in the second approach, the delegated funds will be locked in-place in //! user's account enabling them to participate in use cases that allows use of `held` funds such @@ -213,7 +204,7 @@ pub mod pallet { NotAllowed, /// An existing staker cannot perform this action. AlreadyStaking, - /// Reward Destination cannot be `delegatee` account. + /// Reward Destination cannot be same as `Agent` account. InvalidRewardDestination, /// Delegation conditions are not met. /// @@ -223,13 +214,13 @@ pub mod pallet { InvalidDelegation, /// The account does not have enough funds to perform the operation. NotEnoughFunds, - /// Not an existing delegatee account. + /// Not an existing `Agent` account. NotAgent, /// Not a Delegator account. NotDelegator, /// Some corruption in internal state. BadState, - /// Unapplied pending slash restricts operation on `delegatee`. + /// Unapplied pending slash restricts operation on `Agent`. UnappliedSlash, /// Failed to withdraw amount from Core Staking. WithdrawFailed, @@ -249,22 +240,22 @@ pub mod pallet { #[pallet::generate_deposit(pub (super) fn deposit_event)] pub enum Event { /// Funds delegated by a delegator. - Delegated { delegatee: T::AccountId, delegator: T::AccountId, amount: BalanceOf }, + Delegated { agent: T::AccountId, delegator: T::AccountId, amount: BalanceOf }, /// Funds released to a delegator. - Released { delegatee: T::AccountId, delegator: T::AccountId, amount: BalanceOf }, + Released { agent: T::AccountId, delegator: T::AccountId, amount: BalanceOf }, /// Funds slashed from a delegator. - Slashed { delegatee: T::AccountId, delegator: T::AccountId, amount: BalanceOf }, + Slashed { agent: T::AccountId, delegator: T::AccountId, amount: BalanceOf }, } /// Map of Delegators to their `Delegation`. /// - /// Implementation note: We are not using a double map with `delegator` and `delegatee` account + /// Implementation note: We are not using a double map with `delegator` and `agent` account /// as keys since we want to restrict delegators to delegate only to one account at a time. #[pallet::storage] pub(crate) type Delegators = CountedStorageMap<_, Twox64Concat, T::AccountId, Delegation, OptionQuery>; - /// Map of `Delegatee` to their `DelegateeLedger`. + /// Map of `Agent` to their `Ledger`. #[pallet::storage] pub(crate) type Delegatees = CountedStorageMap<_, Twox64Concat, T::AccountId, DelegateeLedger, OptionQuery>; @@ -317,7 +308,7 @@ pub mod pallet { /// This function will create a proxy account to the agent called `proxy_delegator` and /// transfer the directly staked amount by the agent to it. The `proxy_delegator` delegates /// the funds to the origin making origin an `Agent` account. The real `delegator` - /// accounts of the origin can later migrate their funds using [Self::migrate_delegation] to + /// accounts of the origin can later migrate their funds using [Self::claim_delegation] to /// claim back their share of delegated funds from `proxy_delegator` to self. pub fn migrate_to_agent( origin: OriginFor, @@ -556,7 +547,7 @@ impl Pallet { T::Currency::hold(&HoldReason::Delegating.into(), delegator, amount)?; Self::deposit_event(Event::::Delegated { - delegatee: delegatee.clone(), + agent: delegatee.clone(), delegator: delegator.clone(), amount, }); @@ -608,7 +599,7 @@ impl Pallet { defensive_assert!(released == amount, "hold should have been released fully"); Self::deposit_event(Event::::Released { - delegatee: who.clone(), + agent: who.clone(), delegator: delegator.clone(), amount, }); @@ -735,7 +726,7 @@ impl Pallet { T::OnSlash::on_unbalanced(credit); - Self::deposit_event(Event::::Slashed { delegatee: delegatee_acc, delegator, amount }); + Self::deposit_event(Event::::Slashed { agent: delegatee_acc, delegator, amount }); Ok(()) } From f82b349de2ed919c20831936001905f47398b0fd Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 31 Mar 2024 19:27:28 +0200 Subject: [PATCH 015/257] rename storage Delegatees to Agents --- substrate/frame/delegated-staking/src/impls.rs | 4 ++-- substrate/frame/delegated-staking/src/lib.rs | 6 +++--- substrate/frame/delegated-staking/src/types.rs | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs index e09a4b373834..7be0866f8ded 100644 --- a/substrate/frame/delegated-staking/src/impls.rs +++ b/substrate/frame/delegated-staking/src/impls.rs @@ -109,7 +109,7 @@ impl StakingInterface for Pallet { } fn bond_extra(who: &Self::AccountId, extra: Self::Balance) -> DispatchResult { - let ledger = >::get(who).ok_or(Error::::NotAgent)?; + let ledger = >::get(who).ok_or(Error::::NotAgent)?; ensure!(ledger.stakeable_balance() >= extra, Error::::NotEnoughFunds); T::CoreStaking::bond_extra(who, extra) @@ -277,7 +277,7 @@ impl OnStakingUpdate> for Pallet { _slashed_unlocking: &sp_std::collections::btree_map::BTreeMap>, slashed_total: BalanceOf, ) { - >::mutate(who, |maybe_register| match maybe_register { + >::mutate(who, |maybe_register| match maybe_register { // if delegatee, register the slashed amount as pending slash. Some(register) => register.pending_slash.saturating_accrue(slashed_total), None => { diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs index 615787200d6a..e831c0f95400 100644 --- a/substrate/frame/delegated-staking/src/lib.rs +++ b/substrate/frame/delegated-staking/src/lib.rs @@ -257,7 +257,7 @@ pub mod pallet { /// Map of `Agent` to their `Ledger`. #[pallet::storage] - pub(crate) type Delegatees = + pub(crate) type Agents = CountedStorageMap<_, Twox64Concat, T::AccountId, DelegateeLedger, OptionQuery>; // This pallet is not currently written with the intention of exposing any calls. But the @@ -448,7 +448,7 @@ impl Pallet { /// Returns true if who is registered as a `Delegatee`. fn is_agent(who: &T::AccountId) -> bool { - >::contains_key(who) + >::contains_key(who) } /// Returns true if who is delegating to a `Delegatee` account. @@ -748,7 +748,7 @@ impl Pallet { pub(crate) fn do_try_state() -> Result<(), sp_runtime::TryRuntimeError> { // build map to avoid reading storage multiple times. let delegation_map = Delegators::::iter().collect::>(); - let ledger_map = Delegatees::::iter().collect::>(); + let ledger_map = Agents::::iter().collect::>(); Self::check_delegates(ledger_map.clone())?; Self::check_delegators(delegation_map, ledger_map)?; diff --git a/substrate/frame/delegated-staking/src/types.rs b/substrate/frame/delegated-staking/src/types.rs index 494a616e76f8..c15ed9f71385 100644 --- a/substrate/frame/delegated-staking/src/types.rs +++ b/substrate/frame/delegated-staking/src/types.rs @@ -60,7 +60,7 @@ impl Delegation { .map(|delegation| delegation.delegatee == delegatee.clone()) .unwrap_or( // all good if its a new delegator except it should not be an existing delegatee. - !>::contains_key(delegator), + !>::contains_key(delegator), ) } @@ -128,12 +128,12 @@ impl DelegateeLedger { /// Get `DelegateeLedger` from storage. pub(crate) fn get(key: &T::AccountId) -> Option { - >::get(key) + >::get(key) } /// Save self to storage with the given key. pub(crate) fn save(self, key: &T::AccountId) { - >::insert(key, self) + >::insert(key, self) } /// Effective total balance of the `delegatee`. @@ -280,7 +280,7 @@ impl Delegatee { self.ledger.pending_slash == Zero::zero(), Error::::BadState ); - >::remove(key); + >::remove(key); } else { self.ledger.save(&key) } From b5500310206c37304744d5e0b76bb09096e61ee6 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 31 Mar 2024 19:34:23 +0200 Subject: [PATCH 016/257] rename all delegatee to agent --- .../frame/delegated-staking/src/impls.rs | 75 +++--- substrate/frame/delegated-staking/src/lib.rs | 139 ++++++----- substrate/frame/delegated-staking/src/mock.rs | 23 +- .../frame/delegated-staking/src/tests.rs | 222 ++++++++++-------- .../frame/delegated-staking/src/types.rs | 102 ++++---- substrate/primitives/staking/src/lib.rs | 64 +++++ 6 files changed, 340 insertions(+), 285 deletions(-) diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs index 7be0866f8ded..72884718dfde 100644 --- a/substrate/frame/delegated-staking/src/impls.rs +++ b/substrate/frame/delegated-staking/src/impls.rs @@ -22,10 +22,7 @@ use super::*; use sp_staking::{DelegatedStakeInterface, OnStakingUpdate}; -/// StakingInterface implementation with delegation support. -/// -/// Only supports Nominators via Delegated Bonds. It is possible for a nominator to migrate and -/// become a `delegatee`. +/// Wrapper `StakingInterface` implementation for `Agents`. impl StakingInterface for Pallet { type Balance = BalanceOf; type AccountId = T::AccountId; @@ -90,10 +87,10 @@ impl StakingInterface for Pallet { ) -> DispatchResult { // ensure who is not already staked ensure!(T::CoreStaking::status(who).is_err(), Error::::AlreadyStaking); - let delegatee = Delegatee::::from(who)?; + let agent = Agent::::from(who)?; - ensure!(delegatee.available_to_bond() >= value, Error::::NotEnoughFunds); - ensure!(delegatee.ledger.payee == *payee, Error::::InvalidRewardDestination); + ensure!(agent.available_to_bond() >= value, Error::::NotEnoughFunds); + ensure!(agent.ledger.payee == *payee, Error::::InvalidRewardDestination); T::CoreStaking::virtual_bond(who, value, payee) } @@ -116,8 +113,8 @@ impl StakingInterface for Pallet { } fn unbond(stash: &Self::AccountId, value: Self::Balance) -> DispatchResult { - let delegatee = Delegatee::::from(stash)?; - ensure!(delegatee.bonded_stake() >= value, Error::::NotEnoughFunds); + let agent = Agent::::from(stash)?; + ensure!(agent.bonded_stake() >= value, Error::::NotEnoughFunds); T::CoreStaking::unbond(stash, value) } @@ -128,13 +125,13 @@ impl StakingInterface for Pallet { /// Withdraw unbonding funds until current era. /// - /// Funds are moved to unclaimed_withdrawals register of the `DelegateeLedger`. + /// Funds are moved to unclaimed_withdrawals register of the `AgentLedger`. fn withdraw_unbonded( - delegatee_acc: Self::AccountId, + agent_acc: Self::AccountId, num_slashing_spans: u32, ) -> Result { - Pallet::::withdraw_unbonded(&delegatee_acc, num_slashing_spans) - .map(|delegatee| delegatee.ledger.total_delegated.is_zero()) + Pallet::::withdraw_unbonded(&agent_acc, num_slashing_spans) + .map(|agent| agent.ledger.total_delegated.is_zero()) } fn desired_validator_count() -> u32 { @@ -191,10 +188,10 @@ impl StakingInterface for Pallet { } impl DelegatedStakeInterface for Pallet { - /// Effective balance of the delegatee account. - fn delegatee_balance(who: &Self::AccountId) -> Self::Balance { - Delegatee::::from(who) - .map(|delegatee| delegatee.ledger.effective_balance()) + /// Effective balance of the `Agent` account. + fn agent_balance(who: &Self::AccountId) -> Self::Balance { + Agent::::from(who) + .map(|agent| agent.ledger.effective_balance()) .unwrap_or_default() } @@ -202,71 +199,63 @@ impl DelegatedStakeInterface for Pallet { Delegation::::get(delegator).map(|d| d.amount).unwrap_or_default() } - /// Delegate funds to `Delegatee`. + /// Delegate funds to an `Agent`. fn delegate( who: &Self::AccountId, - delegatee: &Self::AccountId, + agent: &Self::AccountId, reward_account: &Self::AccountId, amount: Self::Balance, ) -> DispatchResult { Pallet::::register_agent( - RawOrigin::Signed(delegatee.clone()).into(), + RawOrigin::Signed(agent.clone()).into(), reward_account.clone(), )?; - // Delegate the funds from who to the delegatee account. - Pallet::::delegate_to_agent( - RawOrigin::Signed(who.clone()).into(), - delegatee.clone(), - amount, - ) + // Delegate the funds from who to the `Agent` account. + Pallet::::delegate_to_agent(RawOrigin::Signed(who.clone()).into(), agent.clone(), amount) } - /// Add more delegation to the delegatee account. + /// Add more delegation to the `Agent` account. fn delegate_extra( who: &Self::AccountId, - delegatee: &Self::AccountId, + agent: &Self::AccountId, amount: Self::Balance, ) -> DispatchResult { - Pallet::::delegate_to_agent( - RawOrigin::Signed(who.clone()).into(), - delegatee.clone(), - amount, - ) + Pallet::::delegate_to_agent(RawOrigin::Signed(who.clone()).into(), agent.clone(), amount) } - /// Withdraw delegation of `delegator` to `delegatee`. + /// Withdraw delegation of `delegator` to `Agent`. /// - /// If there are funds in `delegatee` account that can be withdrawn, then those funds would be + /// If there are funds in `Agent` account that can be withdrawn, then those funds would be /// unlocked/released in the delegator's account. fn withdraw_delegation( delegator: &Self::AccountId, - delegatee: &Self::AccountId, + agent: &Self::AccountId, amount: Self::Balance, ) -> DispatchResult { // fixme(ank4n): Can this not require slashing spans? Pallet::::release_delegation( - RawOrigin::Signed(delegatee.clone()).into(), + RawOrigin::Signed(agent.clone()).into(), delegator.clone(), amount, 0, ) } - /// Returns true if the `delegatee` have any slash pending to be applied. - fn has_pending_slash(delegatee: &Self::AccountId) -> bool { - Delegatee::::from(delegatee) + /// Returns true if the `Agent` have any slash pending to be applied. + fn has_pending_slash(agent: &Self::AccountId) -> bool { + Agent::::from(agent) .map(|d| !d.ledger.pending_slash.is_zero()) .unwrap_or(false) } fn delegator_slash( - delegatee: &Self::AccountId, + agent: &Self::AccountId, delegator: &Self::AccountId, value: Self::Balance, maybe_reporter: Option, ) -> sp_runtime::DispatchResult { - Pallet::::do_slash(delegatee.clone(), delegator.clone(), value, maybe_reporter) + Pallet::::do_slash(agent.clone(), delegator.clone(), value, maybe_reporter) } } @@ -278,7 +267,7 @@ impl OnStakingUpdate> for Pallet { slashed_total: BalanceOf, ) { >::mutate(who, |maybe_register| match maybe_register { - // if delegatee, register the slashed amount as pending slash. + // if existing agent, register the slashed amount as pending slash. Some(register) => register.pending_slash.saturating_accrue(slashed_total), None => { // nothing to do diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs index e831c0f95400..2de5ae44b85b 100644 --- a/substrate/frame/delegated-staking/src/lib.rs +++ b/substrate/frame/delegated-staking/src/lib.rs @@ -30,8 +30,8 @@ //! behalf for staking these delegated funds. Also, sometimes referred as `Delegatee`. //! - **Delegator**: An account who delegates their funds to an `agent` and authorises them to use //! it for staking. -//! - **DelegateeLedger**: A data structure that holds important information about the `agent` such -//! as total delegations they have received, any slashes posted to them, etc. +//! - **AgentLedger**: A data structure that holds important information about the `agent` such as +//! total delegations they have received, any slashes posted to them, etc. //! - **Delegation**: A data structure that stores the amount of funds delegated to an `agent` by a //! `delegator`. //! @@ -79,7 +79,7 @@ //! nominators are slashed at the same time. This is expensive and needs to be bounded operation. //! //! This pallet implements a lazy slashing mechanism. Any slashes to the `agent` are posted in its -//! `DelegateeLedger` as a pending slash. Since the actual amount is held in the multiple +//! `AgentLedger` as a pending slash. Since the actual amount is held in the multiple //! `delegator` accounts, this pallet has no way to know how to apply slash. It is the `agent`'s //! responsibility to apply slashes for each delegator, one at a time. Staking pallet ensures the //! pending slash never exceeds staked amount and would freeze further withdraws until all pending @@ -258,11 +258,11 @@ pub mod pallet { /// Map of `Agent` to their `Ledger`. #[pallet::storage] pub(crate) type Agents = - CountedStorageMap<_, Twox64Concat, T::AccountId, DelegateeLedger, OptionQuery>; + CountedStorageMap<_, Twox64Concat, T::AccountId, AgentLedger, OptionQuery>; - // This pallet is not currently written with the intention of exposing any calls. But the - // functions defined in the following impl block should act as a good reference for how the - // exposed calls would look like when exposed. + /// This pallet is not currently written with the intention of exposing any calls. But the + /// functions defined in the following impl block should act as a good reference for how the + /// exposed calls would look like when exposed. impl Pallet { /// Register an account to become a stake `Agent`. Sometimes also called a `Delegatee`. /// @@ -301,7 +301,7 @@ pub mod pallet { /// /// The origin needs to /// - be a `Nominator` with `CoreStaking`, - /// - not already a `Delegatee`, + /// - not already an `Agent`, /// - have enough funds to transfer existential deposit to a delegator account created for /// the migration. /// @@ -367,7 +367,7 @@ pub mod pallet { ensure!(!Self::is_delegator(&delegator), Error::::NotAllowed); ensure!(Self::not_direct_staker(&delegator), Error::::AlreadyStaking); - // ensure delegatee is sane. + // ensure agent is sane. ensure!(Self::is_agent(&agent), Error::::NotAgent); // and has enough delegated balance to migrate. @@ -433,12 +433,9 @@ pub mod pallet { } impl Pallet { - /// Derive a (keyless) pot account from the given delegatee account and account type. - pub(crate) fn sub_account( - account_type: AccountType, - delegatee_account: T::AccountId, - ) -> T::AccountId { - T::PalletId::get().into_sub_account_truncating((account_type, delegatee_account.clone())) + /// Derive a (keyless) pot account from the given agent account and account type. + pub(crate) fn sub_account(account_type: AccountType, agent: T::AccountId) -> T::AccountId { + T::PalletId::get().into_sub_account_truncating((account_type, agent.clone())) } /// Balance of a delegator that is delegated. @@ -446,12 +443,12 @@ impl Pallet { T::Currency::balance_on_hold(&HoldReason::Delegating.into(), who) } - /// Returns true if who is registered as a `Delegatee`. + /// Returns true if who is registered as an `Agent`. fn is_agent(who: &T::AccountId) -> bool { >::contains_key(who) } - /// Returns true if who is delegating to a `Delegatee` account. + /// Returns true if who is delegating to an `Agent` account. fn is_delegator(who: &T::AccountId) -> bool { >::contains_key(who) } @@ -469,10 +466,11 @@ impl Pallet { } fn do_register_agent(who: &T::AccountId, reward_account: &T::AccountId) { - DelegateeLedger::::new(reward_account).save(who); + AgentLedger::::new(reward_account).save(who); - // Delegatee is a virtual account. Make this account exist. - // TODO: Someday if we expose these calls in a runtime, we should take a deposit for + // Agent does not hold balance of its own but this pallet will provide for this to exist. + // This is expected to be a keyless account and not created by any user directly so safe. + // TODO: Someday if we allow anyone to be an agent, we should take a deposit for // being a delegator. frame_system::Pallet::::inc_providers(who); } @@ -508,29 +506,29 @@ impl Pallet { Self::do_delegate(&proxy_delegator, who, stake.total) } - fn do_bond(delegatee_acc: &T::AccountId, amount: BalanceOf) -> DispatchResult { - let delegatee = Delegatee::::from(delegatee_acc)?; + fn do_bond(agent_acc: &T::AccountId, amount: BalanceOf) -> DispatchResult { + let agent = Agent::::from(agent_acc)?; - let available_to_bond = delegatee.available_to_bond(); + let available_to_bond = agent.available_to_bond(); defensive_assert!(amount == available_to_bond, "not expected value to bond"); - if delegatee.is_bonded() { - T::CoreStaking::bond_extra(&delegatee.key, amount) + if agent.is_bonded() { + T::CoreStaking::bond_extra(&agent.key, amount) } else { - T::CoreStaking::virtual_bond(&delegatee.key, amount, delegatee.reward_account()) + T::CoreStaking::virtual_bond(&agent.key, amount, agent.reward_account()) } } fn do_delegate( delegator: &T::AccountId, - delegatee: &T::AccountId, + agent: &T::AccountId, amount: BalanceOf, ) -> DispatchResult { - let mut ledger = DelegateeLedger::::get(delegatee).ok_or(Error::::NotAgent)?; + let mut ledger = AgentLedger::::get(agent).ok_or(Error::::NotAgent)?; let new_delegation_amount = if let Some(existing_delegation) = Delegation::::get(delegator) { - ensure!(&existing_delegation.delegatee == delegatee, Error::::InvalidDelegation); + ensure!(&existing_delegation.agent == agent, Error::::InvalidDelegation); existing_delegation .amount .checked_add(&amount) @@ -539,15 +537,15 @@ impl Pallet { amount }; - Delegation::::from(delegatee, new_delegation_amount).save_or_kill(delegator); + Delegation::::from(agent, new_delegation_amount).save_or_kill(delegator); ledger.total_delegated = ledger.total_delegated.checked_add(&amount).ok_or(ArithmeticError::Overflow)?; - ledger.save(delegatee); + ledger.save(agent); T::Currency::hold(&HoldReason::Delegating.into(), delegator, amount)?; Self::deposit_event(Event::::Delegated { - agent: delegatee.clone(), + agent: agent.clone(), delegator: delegator.clone(), amount, }); @@ -561,24 +559,24 @@ impl Pallet { amount: BalanceOf, num_slashing_spans: u32, ) -> DispatchResult { - let mut delegatee = Delegatee::::from(who)?; + let mut agent = Agent::::from(who)?; let mut delegation = Delegation::::get(delegator).ok_or(Error::::NotDelegator)?; // make sure delegation to be released is sound. - ensure!(&delegation.delegatee == who, Error::::NotAgent); + ensure!(&delegation.agent == who, Error::::NotAgent); ensure!(delegation.amount >= amount, Error::::NotEnoughFunds); // if we do not already have enough funds to be claimed, try withdraw some more. - if delegatee.ledger.unclaimed_withdrawals < amount { - // get the updated delegatee - delegatee = Self::withdraw_unbonded(who, num_slashing_spans)?; + if agent.ledger.unclaimed_withdrawals < amount { + // get the updated agent. + agent = Self::withdraw_unbonded(who, num_slashing_spans)?; } // if we still do not have enough funds to release, abort. - ensure!(delegatee.ledger.unclaimed_withdrawals >= amount, Error::::NotEnoughFunds); + ensure!(agent.ledger.unclaimed_withdrawals >= amount, Error::::NotEnoughFunds); - // claim withdraw from delegatee. - delegatee.remove_unclaimed_withdraw(amount)?.save_or_kill()?; + // claim withdraw from agent. + agent.remove_unclaimed_withdraw(amount)?.save_or_kill()?; // book keep delegation delegation.amount = delegation @@ -608,17 +606,17 @@ impl Pallet { } fn withdraw_unbonded( - delegatee_acc: &T::AccountId, + agent_acc: &T::AccountId, num_slashing_spans: u32, - ) -> Result, DispatchError> { - let delegatee = Delegatee::::from(delegatee_acc)?; - let pre_total = T::CoreStaking::stake(delegatee_acc).defensive()?.total; + ) -> Result, DispatchError> { + let agent = Agent::::from(agent_acc)?; + let pre_total = T::CoreStaking::stake(agent_acc).defensive()?.total; let stash_killed: bool = - T::CoreStaking::withdraw_unbonded(delegatee_acc.clone(), num_slashing_spans) + T::CoreStaking::withdraw_unbonded(agent_acc.clone(), num_slashing_spans) .map_err(|_| Error::::WithdrawFailed)?; - let maybe_post_total = T::CoreStaking::stake(delegatee_acc); + let maybe_post_total = T::CoreStaking::stake(agent_acc); // One of them should be true defensive_assert!( !(stash_killed && maybe_post_total.is_ok()), @@ -630,11 +628,11 @@ impl Pallet { let new_withdrawn = pre_total.checked_sub(&post_total).defensive_ok_or(Error::::BadState)?; - let delegatee = delegatee.add_unclaimed_withdraw(new_withdrawn)?; + let agent = agent.add_unclaimed_withdraw(new_withdrawn)?; - delegatee.clone().save(); + agent.clone().save(); - Ok(delegatee) + Ok(agent) } /// Migrates delegation of `amount` from `source` account to `destination` account. @@ -653,8 +651,7 @@ impl Pallet { ); // update delegations - Delegation::::from(&source_delegation.delegatee, amount) - .save_or_kill(destination_delegator); + Delegation::::from(&source_delegation.agent, amount).save_or_kill(destination_delegator); source_delegation .decrease_delegation(amount) @@ -688,15 +685,15 @@ impl Pallet { } pub fn do_slash( - delegatee_acc: T::AccountId, + agent_acc: T::AccountId, delegator: T::AccountId, amount: BalanceOf, maybe_reporter: Option, ) -> DispatchResult { - let delegatee = Delegatee::::from(&delegatee_acc)?; + let agent = Agent::::from(&agent_acc)?; let delegation = >::get(&delegator).ok_or(Error::::NotDelegator)?; - ensure!(delegation.delegatee == delegatee_acc, Error::::NotAgent); + ensure!(delegation.agent == agent_acc, Error::::NotAgent); ensure!(delegation.amount >= amount, Error::::NotEnoughFunds); let (mut credit, missing) = @@ -706,8 +703,8 @@ impl Pallet { let actual_slash = credit.peek(); - // remove the applied slashed amount from delegatee. - delegatee.remove_slash(actual_slash).save(); + // remove the applied slashed amount from agent. + agent.remove_slash(actual_slash).save(); delegation .decrease_delegation(actual_slash) @@ -726,7 +723,7 @@ impl Pallet { T::OnSlash::on_unbalanced(credit); - Self::deposit_event(Event::::Slashed { agent: delegatee_acc, delegator, amount }); + Self::deposit_event(Event::::Slashed { agent: agent_acc, delegator, amount }); Ok(()) } @@ -734,8 +731,8 @@ impl Pallet { /// Total balance that is available for stake. Includes already staked amount. #[cfg(test)] pub(crate) fn stakeable_balance(who: &T::AccountId) -> BalanceOf { - Delegatee::::from(who) - .map(|delegatee| delegatee.ledger.stakeable_balance()) + Agent::::from(who) + .map(|agent| agent.ledger.stakeable_balance()) .unwrap_or_default() } } @@ -757,21 +754,21 @@ impl Pallet { } fn check_delegates( - ledgers: BTreeMap>, + ledgers: BTreeMap>, ) -> Result<(), sp_runtime::TryRuntimeError> { - for (delegatee, ledger) in ledgers { + for (agent, ledger) in ledgers { ensure!( matches!( - T::CoreStaking::status(&delegatee).expect("delegatee should be bonded"), + T::CoreStaking::status(&agent).expect("agent should be bonded"), StakerStatus::Nominator(_) | StakerStatus::Idle ), - "delegatee should be bonded and not validator" + "agent should be bonded and not validator" ); ensure!( ledger.stakeable_balance() >= - T::CoreStaking::total_stake(&delegatee) - .expect("delegatee should exist as a nominator"), + T::CoreStaking::total_stake(&agent) + .expect("agent should exist as a nominator"), "Cannot stake more than balance" ); } @@ -781,7 +778,7 @@ impl Pallet { fn check_delegators( delegations: BTreeMap>, - ledger: BTreeMap>, + ledger: BTreeMap>, ) -> Result<(), sp_runtime::TryRuntimeError> { let mut delegation_aggregation = BTreeMap::>::new(); for (delegator, delegation) in delegations.iter() { @@ -789,18 +786,18 @@ impl Pallet { T::CoreStaking::status(delegator).is_err(), "delegator should not be directly staked" ); - ensure!(!Self::is_agent(delegator), "delegator cannot be delegatee"); + ensure!(!Self::is_agent(delegator), "delegator cannot be an agent"); delegation_aggregation - .entry(delegation.delegatee.clone()) + .entry(delegation.agent.clone()) .and_modify(|e| *e += delegation.amount) .or_insert(delegation.amount); } - for (delegatee, total_delegated) in delegation_aggregation { - ensure!(!Self::is_delegator(&delegatee), "delegatee cannot be delegator"); + for (agent, total_delegated) in delegation_aggregation { + ensure!(!Self::is_delegator(&agent), "agent cannot be delegator"); - let ledger = ledger.get(&delegatee).expect("ledger should exist"); + let ledger = ledger.get(&agent).expect("ledger should exist"); ensure!( ledger.total_delegated == total_delegated, "ledger total delegated should match delegations" diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs index 1a4f079735b7..f98e0c5843bb 100644 --- a/substrate/frame/delegated-staking/src/mock.rs +++ b/substrate/frame/delegated-staking/src/mock.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::{self as delegated_staking, types::Delegatee, HoldReason}; +use crate::{self as delegated_staking, types::Agent, HoldReason}; use frame_support::{ assert_ok, derive_impl, pallet_prelude::*, @@ -257,17 +257,14 @@ pub(crate) fn fund(who: &AccountId, amount: Balance) { /// `delegate_amount` is incremented by the amount `increment` starting with `base_delegate_amount` /// from lower index to higher index of delegators. pub(crate) fn setup_delegation_stake( - delegatee: AccountId, + agent: AccountId, reward_acc: AccountId, delegators: Vec, base_delegate_amount: Balance, increment: Balance, ) -> Balance { - fund(&delegatee, 100); - assert_ok!(DelegatedStaking::register_agent( - RawOrigin::Signed(delegatee).into(), - reward_acc - )); + fund(&agent, 100); + assert_ok!(DelegatedStaking::register_agent(RawOrigin::Signed(agent).into(), reward_acc)); let mut delegated_amount: Balance = 0; for (index, delegator) in delegators.iter().enumerate() { let amount_to_delegate = base_delegate_amount + increment * index as Balance; @@ -276,14 +273,14 @@ pub(crate) fn setup_delegation_stake( fund(delegator, amount_to_delegate + ExistentialDeposit::get()); assert_ok!(DelegatedStaking::delegate_to_agent( RawOrigin::Signed(*delegator).into(), - delegatee, + agent, amount_to_delegate )); } // sanity checks - assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), delegated_amount); - assert_eq!(Delegatee::::from(&delegatee).unwrap().available_to_bond(), 0); + assert_eq!(DelegatedStaking::stakeable_balance(&agent), delegated_amount); + assert_eq!(Agent::::from(&agent).unwrap().available_to_bond(), 0); delegated_amount } @@ -294,11 +291,11 @@ pub(crate) fn start_era(era: sp_staking::EraIndex) { pub(crate) fn eq_stake(who: AccountId, total: Balance, active: Balance) -> bool { Staking::stake(&who).unwrap() == Stake { total, active } && - get_delegatee(&who).ledger.stakeable_balance() == total + get_agent(&who).ledger.stakeable_balance() == total } -pub(crate) fn get_delegatee(delegatee: &AccountId) -> Delegatee { - Delegatee::::from(delegatee).expect("delegate should exist") +pub(crate) fn get_agent(agent: &AccountId) -> Agent { + Agent::::from(agent).expect("delegate should exist") } #[allow(unused)] diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs index 9b9dd92bc227..715436153081 100644 --- a/substrate/frame/delegated-staking/src/tests.rs +++ b/substrate/frame/delegated-staking/src/tests.rs @@ -23,16 +23,16 @@ use frame_support::{assert_noop, assert_ok, traits::fungible::InspectHold}; use pallet_staking::Error as StakingError; #[test] -fn create_a_delegatee_with_first_delegator() { +fn create_a_agent_with_first_delegator() { ExtBuilder::default().build_and_execute(|| { - let delegatee: AccountId = 200; + let agent: AccountId = 200; let reward_account: AccountId = 201; let delegator: AccountId = 202; // set intention to accept delegation. - fund(&delegatee, 1000); + fund(&agent, 1000); assert_ok!(DelegatedStaking::register_agent( - RawOrigin::Signed(delegatee).into(), + RawOrigin::Signed(agent).into(), reward_account )); @@ -40,27 +40,27 @@ fn create_a_delegatee_with_first_delegator() { fund(&delegator, 1000); assert_ok!(DelegatedStaking::delegate_to_agent( RawOrigin::Signed(delegator).into(), - delegatee, + agent, 100 )); // verify - assert!(DelegatedStaking::is_agent(&delegatee)); - assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), 100); + assert!(DelegatedStaking::is_agent(&agent)); + assert_eq!(DelegatedStaking::stakeable_balance(&agent), 100); assert_eq!(Balances::balance_on_hold(&HoldReason::Delegating.into(), &delegator), 100); }); } #[test] -fn cannot_become_delegatee() { +fn cannot_become_agent() { ExtBuilder::default().build_and_execute(|| { - // cannot set reward account same as delegatee account + // cannot set reward account same as agent account assert_noop!( DelegatedStaking::register_agent(RawOrigin::Signed(100).into(), 100), Error::::InvalidRewardDestination ); - // an existing validator cannot become delegatee + // an existing validator cannot become agent assert_noop!( DelegatedStaking::register_agent( RawOrigin::Signed(mock::GENESIS_VALIDATOR).into(), @@ -69,7 +69,7 @@ fn cannot_become_delegatee() { Error::::AlreadyStaking ); - // an existing nominator cannot become delegatee + // an existing nominator cannot become agent assert_noop!( DelegatedStaking::register_agent( RawOrigin::Signed(mock::GENESIS_NOMINATOR_ONE).into(), @@ -90,17 +90,17 @@ fn cannot_become_delegatee() { #[test] fn create_multiple_delegators() { ExtBuilder::default().build_and_execute(|| { - let delegatee: AccountId = 200; + let agent: AccountId = 200; let reward_account: AccountId = 201; - // stakeable balance is 0 for non delegatee - fund(&delegatee, 1000); - assert!(!DelegatedStaking::is_agent(&delegatee)); - assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), 0); + // stakeable balance is 0 for non agent + fund(&agent, 1000); + assert!(!DelegatedStaking::is_agent(&agent)); + assert_eq!(DelegatedStaking::stakeable_balance(&agent), 0); // set intention to accept delegation. assert_ok!(DelegatedStaking::register_agent( - RawOrigin::Signed(delegatee).into(), + RawOrigin::Signed(agent).into(), reward_account )); @@ -109,65 +109,61 @@ fn create_multiple_delegators() { fund(&i, 100 + ExistentialDeposit::get()); assert_ok!(DelegatedStaking::delegate_to_agent( RawOrigin::Signed(i).into(), - delegatee, + agent, 100 )); - // Balance of 100 held on delegator account for delegating to the delegatee. + // Balance of 100 held on delegator account for delegating to the agent. assert_eq!(Balances::balance_on_hold(&HoldReason::Delegating.into(), &i), 100); } // verify - assert!(DelegatedStaking::is_agent(&delegatee)); - assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), 100 * 100); + assert!(DelegatedStaking::is_agent(&agent)); + assert_eq!(DelegatedStaking::stakeable_balance(&agent), 100 * 100); }); } #[test] -fn delegatee_restrictions() { +fn agent_restrictions() { // Similar to creating a nomination pool ExtBuilder::default().build_and_execute(|| { - let delegatee_one = 200; + let agent_one = 200; let delegator_one = 210; - fund(&delegatee_one, 100); + fund(&agent_one, 100); assert_ok!(DelegatedStaking::register_agent( - RawOrigin::Signed(delegatee_one).into(), - delegatee_one + 1 + RawOrigin::Signed(agent_one).into(), + agent_one + 1 )); fund(&delegator_one, 200); assert_ok!(DelegatedStaking::delegate_to_agent( RawOrigin::Signed(delegator_one).into(), - delegatee_one, + agent_one, 100 )); - let delegatee_two = 300; + let agent_two = 300; let delegator_two = 310; - fund(&delegatee_two, 100); + fund(&agent_two, 100); assert_ok!(DelegatedStaking::register_agent( - RawOrigin::Signed(delegatee_two).into(), - delegatee_two + 1 + RawOrigin::Signed(agent_two).into(), + agent_two + 1 )); fund(&delegator_two, 200); assert_ok!(DelegatedStaking::delegate_to_agent( RawOrigin::Signed(delegator_two).into(), - delegatee_two, + agent_two, 100 )); - // delegatee one tries to delegate to delegatee 2 + // agent one tries to delegate to agent 2 assert_noop!( - DelegatedStaking::delegate_to_agent( - RawOrigin::Signed(delegatee_one).into(), - delegatee_two, - 10 - ), + DelegatedStaking::delegate_to_agent(RawOrigin::Signed(agent_one).into(), agent_two, 10), Error::::InvalidDelegation ); - // delegatee one tries to delegate to a delegator + // agent one tries to delegate to a delegator assert_noop!( DelegatedStaking::delegate_to_agent( - RawOrigin::Signed(delegatee_one).into(), + RawOrigin::Signed(agent_one).into(), delegator_one, 10 ), @@ -175,19 +171,19 @@ fn delegatee_restrictions() { ); assert_noop!( DelegatedStaking::delegate_to_agent( - RawOrigin::Signed(delegatee_one).into(), + RawOrigin::Signed(agent_one).into(), delegator_two, 10 ), Error::::InvalidDelegation ); - // delegator one tries to delegate to delegatee 2 as well (it already delegates to delegatee + // delegator one tries to delegate to agent 2 as well (it already delegates to agent // 1) assert_noop!( DelegatedStaking::delegate_to_agent( RawOrigin::Signed(delegator_one).into(), - delegatee_two, + agent_two, 10 ), Error::::InvalidDelegation @@ -211,17 +207,17 @@ mod staking_integration { #[test] fn bond() { ExtBuilder::default().build_and_execute(|| { - let delegatee: AccountId = 99; + let agent: AccountId = 99; let reward_acc: AccountId = 100; - assert_eq!(Staking::status(&delegatee), Err(StakingError::::NotStash.into())); + assert_eq!(Staking::status(&agent), Err(StakingError::::NotStash.into())); - // set intention to become a delegatee - fund(&delegatee, 100); + // set intention to become an agent + fund(&agent, 100); assert_ok!(DelegatedStaking::register_agent( - RawOrigin::Signed(delegatee).into(), + RawOrigin::Signed(agent).into(), reward_acc )); - assert_eq!(DelegatedStaking::stakeable_balance(&delegatee), 0); + assert_eq!(DelegatedStaking::stakeable_balance(&agent), 0); let mut delegated_balance: Balance = 0; @@ -230,7 +226,7 @@ mod staking_integration { fund(&delegator, 200); assert_ok!(DelegatedStaking::delegate_to_agent( RawOrigin::Signed(delegator).into(), - delegatee, + agent, 100 )); delegated_balance += 100; @@ -239,16 +235,13 @@ mod staking_integration { 100 ); - let delegatee_obj = get_delegatee(&delegatee); - assert_eq!(delegatee_obj.ledger.stakeable_balance(), delegated_balance); - assert_eq!(delegatee_obj.available_to_bond(), 0); - assert_eq!(delegatee_obj.bonded_stake(), delegated_balance); + let agent_obj = get_agent(&agent); + assert_eq!(agent_obj.ledger.stakeable_balance(), delegated_balance); + assert_eq!(agent_obj.available_to_bond(), 0); + assert_eq!(agent_obj.bonded_stake(), delegated_balance); } - assert_eq!( - Staking::stake(&delegatee).unwrap(), - Stake { total: 50 * 100, active: 50 * 100 } - ) + assert_eq!(Staking::stake(&agent).unwrap(), Stake { total: 50 * 100, active: 50 * 100 }) }); } @@ -257,89 +250,109 @@ mod staking_integration { ExtBuilder::default().build_and_execute(|| { // initial era start_era(1); - let delegatee: AccountId = 200; + let agent: AccountId = 200; let reward_acc: AccountId = 201; let delegators: Vec = (301..=350).collect(); let total_staked = - setup_delegation_stake(delegatee, reward_acc, delegators.clone(), 10, 10); + setup_delegation_stake(agent, reward_acc, delegators.clone(), 10, 10); // lets go to a new era start_era(2); - assert!(eq_stake(delegatee, total_staked, total_staked)); + assert!(eq_stake(agent, total_staked, total_staked)); // Withdrawing without unbonding would fail. assert_noop!( - DelegatedStaking::release_delegation(RawOrigin::Signed(delegatee).into(), 301, 50, 0), + DelegatedStaking::release_delegation(RawOrigin::Signed(agent).into(), 301, 50, 0), Error::::NotEnoughFunds ); - // assert_noop!(DelegatedStaking::release_delegation(RawOrigin::Signed(delegatee).into(), 200, 50, - // 0), Error::::NotAllowed); active and total stake remains same - assert!(eq_stake(delegatee, total_staked, total_staked)); + // assert_noop!(DelegatedStaking::release_delegation(RawOrigin::Signed(agent).into(), + // 200, 50, 0), Error::::NotAllowed); active and total stake remains same + assert!(eq_stake(agent, total_staked, total_staked)); // 305 wants to unbond 50 in era 2, withdrawable in era 5. - assert_ok!(DelegatedStaking::unbond(&delegatee, 50)); + assert_ok!(DelegatedStaking::unbond(&agent, 50)); // 310 wants to unbond 100 in era 3, withdrawable in era 6. start_era(3); - assert_ok!(DelegatedStaking::unbond(&delegatee, 100)); + assert_ok!(DelegatedStaking::unbond(&agent, 100)); // 320 wants to unbond 200 in era 4, withdrawable in era 7. start_era(4); - assert_ok!(DelegatedStaking::unbond(&delegatee, 200)); + assert_ok!(DelegatedStaking::unbond(&agent, 200)); // active stake is now reduced.. let expected_active = total_staked - (50 + 100 + 200); - assert!(eq_stake(delegatee, total_staked, expected_active)); + assert!(eq_stake(agent, total_staked, expected_active)); // nothing to withdraw at era 4 assert_noop!( - DelegatedStaking::release_delegation(RawOrigin::Signed(delegatee).into(), 305, 50, 0), + DelegatedStaking::release_delegation(RawOrigin::Signed(agent).into(), 305, 50, 0), Error::::NotEnoughFunds ); - assert!(eq_stake(delegatee, total_staked, expected_active)); - assert_eq!(get_delegatee(&delegatee).available_to_bond(), 0); + assert!(eq_stake(agent, total_staked, expected_active)); + assert_eq!(get_agent(&agent).available_to_bond(), 0); // full amount is still delegated - assert_eq!(get_delegatee(&delegatee).ledger.effective_balance(), total_staked); + assert_eq!(get_agent(&agent).ledger.effective_balance(), total_staked); start_era(5); // at era 5, 50 tokens are withdrawable, cannot withdraw more. assert_noop!( - DelegatedStaking::release_delegation(RawOrigin::Signed(delegatee).into(), 305, 51, 0), + DelegatedStaking::release_delegation(RawOrigin::Signed(agent).into(), 305, 51, 0), Error::::NotEnoughFunds ); // less is possible - assert_ok!(DelegatedStaking::release_delegation(RawOrigin::Signed(delegatee).into(), 305, 30, 0)); - assert_ok!(DelegatedStaking::release_delegation(RawOrigin::Signed(delegatee).into(), 305, 20, 0)); + assert_ok!(DelegatedStaking::release_delegation( + RawOrigin::Signed(agent).into(), + 305, + 30, + 0 + )); + assert_ok!(DelegatedStaking::release_delegation( + RawOrigin::Signed(agent).into(), + 305, + 20, + 0 + )); // Lets go to future era where everything is unbonded. Withdrawable amount: 100 + 200 start_era(7); // 305 has no more amount delegated so it cannot withdraw. assert_noop!( - DelegatedStaking::release_delegation(RawOrigin::Signed(delegatee).into(), 305, 5, 0), + DelegatedStaking::release_delegation(RawOrigin::Signed(agent).into(), 305, 5, 0), Error::::NotDelegator ); // 309 is an active delegator but has total delegation of 90, so it cannot withdraw more // than that. assert_noop!( - DelegatedStaking::release_delegation(RawOrigin::Signed(delegatee).into(), 309, 91, 0), + DelegatedStaking::release_delegation(RawOrigin::Signed(agent).into(), 309, 91, 0), Error::::NotEnoughFunds ); // 310 cannot withdraw more than delegated funds. assert_noop!( - DelegatedStaking::release_delegation(RawOrigin::Signed(delegatee).into(), 310, 101, 0), + DelegatedStaking::release_delegation(RawOrigin::Signed(agent).into(), 310, 101, 0), Error::::NotEnoughFunds ); // but can withdraw all its delegation amount. - assert_ok!(DelegatedStaking::release_delegation(RawOrigin::Signed(delegatee).into(), 310, 100, 0)); + assert_ok!(DelegatedStaking::release_delegation( + RawOrigin::Signed(agent).into(), + 310, + 100, + 0 + )); // 320 can withdraw all its delegation amount. - assert_ok!(DelegatedStaking::release_delegation(RawOrigin::Signed(delegatee).into(), 320, 200, 0)); + assert_ok!(DelegatedStaking::release_delegation( + RawOrigin::Signed(agent).into(), + 320, + 200, + 0 + )); // cannot withdraw anything more.. assert_noop!( - DelegatedStaking::release_delegation(RawOrigin::Signed(delegatee).into(), 301, 1, 0), + DelegatedStaking::release_delegation(RawOrigin::Signed(agent).into(), 301, 1, 0), Error::::NotEnoughFunds ); assert_noop!( - DelegatedStaking::release_delegation(RawOrigin::Signed(delegatee).into(), 350, 1, 0), + DelegatedStaking::release_delegation(RawOrigin::Signed(agent).into(), 350, 1, 0), Error::::NotEnoughFunds ); }); @@ -348,12 +361,12 @@ mod staking_integration { #[test] fn withdraw_happens_with_unbonded_balance_first() { ExtBuilder::default().build_and_execute(|| { - let delegatee = 200; - setup_delegation_stake(delegatee, 201, (300..350).collect(), 100, 0); + let agent = 200; + setup_delegation_stake(agent, 201, (300..350).collect(), 100, 0); // verify withdraw not possible yet assert_noop!( - DelegatedStaking::release_delegation(RawOrigin::Signed(delegatee).into(), 300, 100, 0), + DelegatedStaking::release_delegation(RawOrigin::Signed(agent).into(), 300, 100, 0), Error::::NotEnoughFunds ); @@ -363,15 +376,15 @@ mod staking_integration { // withdrawn and test its claimed from there first. // fund(&300, 1000); - // assert_ok!(DelegatedStaking::delegate_to_agent(RawOrigin::Signed(300.into()), delegate, - // 100)); + // assert_ok!(DelegatedStaking::delegate_to_agent(RawOrigin::Signed(300.into()), + // delegate, 100)); // // // verify unbonded balance - // assert_eq!(get_delegatee(&delegatee).available_to_bond(), 100); + // assert_eq!(get_agent(&agent).available_to_bond(), 100); // // // withdraw works now without unbonding - // assert_ok!(DelegatedStaking::release_delegation(RawOrigin::Signed(delegatee).into(), 300, 100, - // 0)); assert_eq!(get_delegatee(&delegatee).available_to_bond(), 0); + // assert_ok!(DelegatedStaking::release_delegation(RawOrigin::Signed(agent).into(), 300, + // 100, 0)); assert_eq!(get_agent(&agent).available_to_bond(), 0); }); } @@ -382,7 +395,7 @@ mod staking_integration { fund(&200, 1000); let balance_200 = Balances::free_balance(200); - // `delegatee` account cannot be reward destination + // `Agent` account cannot be reward destination assert_noop!( DelegatedStaking::register_agent(RawOrigin::Signed(200).into(), 200), Error::::InvalidRewardDestination @@ -392,7 +405,11 @@ mod staking_integration { assert_ok!(DelegatedStaking::register_agent(RawOrigin::Signed(200).into(), 201)); // add some delegations to it fund(&300, 1000); - assert_ok!(DelegatedStaking::delegate_to_agent(RawOrigin::Signed(300).into(), 200, 100)); + assert_ok!(DelegatedStaking::delegate_to_agent( + RawOrigin::Signed(300).into(), + 200, + 100 + )); // if delegate calls Staking pallet directly with a different reward destination, it // fails. @@ -409,8 +426,8 @@ mod staking_integration { // amount is staked correctly assert!(eq_stake(200, 100, 100)); - assert_eq!(get_delegatee(&200).available_to_bond(), 0); - assert_eq!(get_delegatee(&200).ledger.effective_balance(), 100); + assert_eq!(get_agent(&200).available_to_bond(), 0); + assert_eq!(get_agent(&200).ledger.effective_balance(), 100); // free balance of delegate is untouched assert_eq!(Balances::free_balance(200), balance_200); @@ -418,7 +435,7 @@ mod staking_integration { } #[test] - fn delegatee_restrictions() { + fn agent_restrictions() { ExtBuilder::default().build_and_execute(|| { setup_delegation_stake(200, 201, (202..203).collect(), 100, 0); @@ -441,10 +458,7 @@ mod staking_integration { Error::::AlreadyStaking ); assert_noop!( - DelegatedStaking::register_agent( - RawOrigin::Signed(GENESIS_VALIDATOR).into(), - 201 - ), + DelegatedStaking::register_agent(RawOrigin::Signed(GENESIS_VALIDATOR).into(), 201), Error::::AlreadyStaking ); }); @@ -498,8 +512,8 @@ mod staking_integration { 5000 - staked_amount - ExistentialDeposit::get() ); assert_eq!(DelegatedStaking::stake(&200).unwrap(), init_stake); - assert_eq!(get_delegatee(&200).ledger.effective_balance(), 4000); - assert_eq!(get_delegatee(&200).available_to_bond(), 0); + assert_eq!(get_agent(&200).ledger.effective_balance(), 4000); + assert_eq!(get_agent(&200).available_to_bond(), 0); // now lets migrate the delegators let delegator_share = staked_amount / 4; @@ -525,8 +539,8 @@ mod staking_integration { // delegate stake is unchanged. assert_eq!(DelegatedStaking::stake(&200).unwrap(), init_stake); - assert_eq!(get_delegatee(&200).ledger.effective_balance(), 4000); - assert_eq!(get_delegatee(&200).available_to_bond(), 0); + assert_eq!(get_agent(&200).ledger.effective_balance(), 4000); + assert_eq!(get_agent(&200).available_to_bond(), 0); } // cannot use migrate delegator anymore diff --git a/substrate/frame/delegated-staking/src/types.rs b/substrate/frame/delegated-staking/src/types.rs index c15ed9f71385..70965374305c 100644 --- a/substrate/frame/delegated-staking/src/types.rs +++ b/substrate/frame/delegated-staking/src/types.rs @@ -24,9 +24,9 @@ use frame_support::traits::DefensiveSaturating; /// The type of pot account being created. #[derive(Encode, Decode)] pub(crate) enum AccountType { - /// A proxy delegator account created for a nominator who migrated to a `delegatee` account. + /// A proxy delegator account created for a nominator who migrated to an `Agent` account. /// - /// Funds for unmigrated `delegator` accounts of the `delegatee` are kept here. + /// Funds for unmigrated `delegator` accounts of the `Agent` are kept here. ProxyDelegator, } @@ -35,7 +35,7 @@ pub(crate) enum AccountType { #[scale_info(skip_type_params(T))] pub struct Delegation { /// The target of delegation. - pub delegatee: T::AccountId, + pub agent: T::AccountId, /// The amount delegated. pub amount: BalanceOf, } @@ -47,19 +47,19 @@ impl Delegation { } /// Create and return a new delegation instance. - pub(crate) fn from(delegatee: &T::AccountId, amount: BalanceOf) -> Self { - Delegation { delegatee: delegatee.clone(), amount } + pub(crate) fn from(agent: &T::AccountId, amount: BalanceOf) -> Self { + Delegation { agent: agent.clone(), amount } } /// Ensure the delegator is either a new delegator or they are adding more delegation to the - /// existing delegatee. + /// existing agent. /// - /// Delegators are prevented from delegating to multiple delegatees at the same time. - pub(crate) fn can_delegate(delegator: &T::AccountId, delegatee: &T::AccountId) -> bool { + /// Delegators are prevented from delegating to multiple agents at the same time. + pub(crate) fn can_delegate(delegator: &T::AccountId, agent: &T::AccountId) -> bool { Delegation::::get(delegator) - .map(|delegation| delegation.delegatee == delegatee.clone()) + .map(|delegation| delegation.agent == agent.clone()) .unwrap_or( - // all good if its a new delegator except it should not be an existing delegatee. + // all good if it is a new delegator except it should not be an existing agent. !>::contains_key(delegator), ) } @@ -67,14 +67,14 @@ impl Delegation { /// Checked decrease of delegation amount. Consumes self and returns a new copy. pub(crate) fn decrease_delegation(self, amount: BalanceOf) -> Option { let updated_delegation = self.amount.checked_sub(&amount)?; - Some(Delegation::from(&self.delegatee, updated_delegation)) + Some(Delegation::from(&self.agent, updated_delegation)) } /// Checked increase of delegation amount. Consumes self and returns a new copy. #[allow(unused)] pub(crate) fn increase_delegation(self, amount: BalanceOf) -> Option { let updated_delegation = self.amount.checked_add(&amount)?; - Some(Delegation::from(&self.delegatee, updated_delegation)) + Some(Delegation::from(&self.agent, updated_delegation)) } /// Save self to storage. If the delegation amount is zero, remove the delegation. @@ -89,36 +89,36 @@ impl Delegation { } } -/// Ledger of all delegations to a `Delegatee`. +/// Ledger of all delegations to an `Agent`. /// -/// This keeps track of the active balance of the `delegatee` that is made up from the funds that -/// are currently delegated to this `delegatee`. It also tracks the pending slashes yet to be +/// This keeps track of the active balance of the `Agent` that is made up from the funds that +/// are currently delegated to this `Agent`. It also tracks the pending slashes yet to be /// applied among other things. #[derive(Default, Clone, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] #[scale_info(skip_type_params(T))] -pub struct DelegateeLedger { +pub struct AgentLedger { /// Where the reward should be paid out. pub payee: T::AccountId, - /// Sum of all delegated funds to this `delegatee`. + /// Sum of all delegated funds to this `Agent`. #[codec(compact)] pub total_delegated: BalanceOf, /// Funds that are withdrawn from core staking but not released to delegator/s. It is a subset /// of `total_delegated` and can never be greater than it. /// - /// We need this register to ensure that the `delegatee` does not bond funds from delegated + /// We need this register to ensure that the `Agent` does not bond funds from delegated /// funds that are withdrawn and should be claimed by delegators. // FIXME(ank4n): Check/test about rebond: where delegator rebond what is unlocking. #[codec(compact)] pub unclaimed_withdrawals: BalanceOf, - /// Slashes that are not yet applied. This affects the effective balance of the `delegatee`. + /// Slashes that are not yet applied. This affects the effective balance of the `Agent`. #[codec(compact)] pub pending_slash: BalanceOf, } -impl DelegateeLedger { - /// Create a new instance of `DelegateeLedger`. +impl AgentLedger { + /// Create a new instance of `AgentLedger`. pub(crate) fn new(reward_destination: &T::AccountId) -> Self { - DelegateeLedger { + AgentLedger { payee: reward_destination.clone(), total_delegated: Zero::zero(), unclaimed_withdrawals: Zero::zero(), @@ -126,7 +126,7 @@ impl DelegateeLedger { } } - /// Get `DelegateeLedger` from storage. + /// Get `AgentLedger` from storage. pub(crate) fn get(key: &T::AccountId) -> Option { >::get(key) } @@ -136,9 +136,9 @@ impl DelegateeLedger { >::insert(key, self) } - /// Effective total balance of the `delegatee`. + /// Effective total balance of the `Agent`. /// - /// This takes into account any slashes reported to `Delegatee` but unapplied. + /// This takes into account any slashes reported to `Agent` but unapplied. pub(crate) fn effective_balance(&self) -> BalanceOf { defensive_assert!( self.total_delegated >= self.pending_slash, @@ -149,26 +149,26 @@ impl DelegateeLedger { self.total_delegated.saturating_sub(self.pending_slash) } - /// Delegatee balance that can be staked/bonded in [`T::CoreStaking`]. + /// Agent balance that can be staked/bonded in [`T::CoreStaking`]. pub(crate) fn stakeable_balance(&self) -> BalanceOf { self.effective_balance().saturating_sub(self.unclaimed_withdrawals) } } -/// Wrapper around `DelegateeLedger` to provide additional functionality. +/// Wrapper around `AgentLedger` to provide some helper functions to mutate the ledger. #[derive(Clone)] -pub struct Delegatee { +pub struct Agent { /// storage key pub key: T::AccountId, /// storage value - pub ledger: DelegateeLedger, + pub ledger: AgentLedger, } -impl Delegatee { - /// Get `Delegatee` from storage if it exists or return an error. - pub(crate) fn from(delegatee: &T::AccountId) -> Result, DispatchError> { - let ledger = DelegateeLedger::::get(delegatee).ok_or(Error::::NotAgent)?; - Ok(Delegatee { key: delegatee.clone(), ledger }) +impl Agent { + /// Get `Agent` from storage if it exists or return an error. + pub(crate) fn from(agent: &T::AccountId) -> Result, DispatchError> { + let ledger = AgentLedger::::get(agent).ok_or(Error::::NotAgent)?; + Ok(Agent { key: agent.clone(), ledger }) } /// Remove funds that are withdrawn from [Config::CoreStaking] but not claimed by a delegator. @@ -190,8 +190,8 @@ impl Delegatee { .checked_sub(&amount) .defensive_ok_or(ArithmeticError::Overflow)?; - Ok(Delegatee { - ledger: DelegateeLedger { + Ok(Agent { + ledger: AgentLedger { total_delegated: new_total_delegated, unclaimed_withdrawals: new_unclaimed_withdrawals, ..self.ledger @@ -211,11 +211,8 @@ impl Delegatee { .checked_add(&amount) .defensive_ok_or(ArithmeticError::Overflow)?; - Ok(Delegatee { - ledger: DelegateeLedger { - unclaimed_withdrawals: new_unclaimed_withdrawals, - ..self.ledger - }, + Ok(Agent { + ledger: AgentLedger { unclaimed_withdrawals: new_unclaimed_withdrawals, ..self.ledger }, ..self }) } @@ -230,34 +227,31 @@ impl Delegatee { defensive_assert!( stakeable >= bonded_stake, - "cannot be bonded with more than delegatee balance" + "cannot be bonded with more than total amount delegated to agent" ); stakeable.saturating_sub(bonded_stake) } - /// Remove slashes from the `DelegateeLedger`. + /// Remove slashes from the `AgentLedger`. pub(crate) fn remove_slash(self, amount: BalanceOf) -> Self { let pending_slash = self.ledger.pending_slash.defensive_saturating_sub(amount); let total_delegated = self.ledger.total_delegated.defensive_saturating_sub(amount); - Delegatee { - ledger: DelegateeLedger { pending_slash, total_delegated, ..self.ledger }, - ..self - } + Agent { ledger: AgentLedger { pending_slash, total_delegated, ..self.ledger }, ..self } } - /// Get the total stake of delegatee bonded in [`Config::CoreStaking`]. + /// Get the total stake of agent bonded in [`Config::CoreStaking`]. pub(crate) fn bonded_stake(&self) -> BalanceOf { T::CoreStaking::total_stake(&self.key).unwrap_or(Zero::zero()) } - /// Returns true if the delegatee is bonded in [`Config::CoreStaking`]. + /// Returns true if the agent is bonded in [`Config::CoreStaking`]. pub(crate) fn is_bonded(&self) -> bool { T::CoreStaking::stake(&self.key).is_ok() } - /// Returns the reward account registered by the delegatee. + /// Returns the reward account registered by the agent. pub(crate) fn reward_account(&self) -> &T::AccountId { &self.ledger.payee } @@ -291,14 +285,14 @@ impl Delegatee { /// Reloads self from storage. #[cfg(test)] #[allow(unused)] - pub(crate) fn refresh(&self) -> Result, DispatchError> { + pub(crate) fn refresh(&self) -> Result, DispatchError> { Self::from(&self.key) } - /// Balance of `Delegatee` that is not bonded. + /// Balance of `Agent` that is not bonded. /// /// This is similar to [Self::available_to_bond] except it also includes `unclaimed_withdrawals` - /// of `Delegatee`. + /// of `Agent`. #[cfg(test)] #[allow(unused)] pub(crate) fn total_unbonded(&self) -> BalanceOf { @@ -308,7 +302,7 @@ impl Delegatee { defensive_assert!( net_balance >= bonded_stake, - "cannot be bonded with more than the delegatee balance" + "cannot be bonded with more than the agent balance" ); net_balance.saturating_sub(bonded_stake) diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index 0e1812e10ab2..13cfbe8e326d 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -449,4 +449,68 @@ pub struct PagedExposureMetadata { pub page_count: Page, } +/// Extension of [`StakingInterface`] with delegation functionality. +/// +/// Introduces two new actors: +/// - `Delegator`: An account that delegates funds to a `Agent`. +/// - `Agent`: An account that receives delegated funds from `Delegators`. It can then use these +/// funds to participate in the staking system. It can never use its own funds to stake. +/// +/// The `Agent` is responsible for managing rewards and slashing for all the `Delegators` that +/// have delegated funds to it. +pub trait DelegatedStakeInterface: StakingInterface { + /// Effective balance of the `Agent` account. + /// + /// This takes into account any pending slashes to `Agent`. + fn agent_balance(agent: &Self::AccountId) -> Self::Balance; + + /// Returns the total amount of funds delegated by a `delegator`. + fn delegator_balance(delegator: &Self::AccountId) -> Self::Balance; + + /// Delegate funds to `Agent`. + /// + /// Only used for the initial delegation. Use [`Self::delegate_extra`] to add more delegation. + fn delegate( + delegator: &Self::AccountId, + agent: &Self::AccountId, + reward_account: &Self::AccountId, + amount: Self::Balance, + ) -> DispatchResult; + + /// Add more delegation to the `Agent`. + /// + /// If this is the first delegation, use [`Self::delegate`] instead. + fn delegate_extra( + delegator: &Self::AccountId, + agent: &Self::AccountId, + amount: Self::Balance, + ) -> DispatchResult; + + /// Withdraw or revoke delegation to `Agent`. + /// + /// If there are `Agent` funds upto `amount` available to withdraw, then those funds would + /// be released to the `delegator` + fn withdraw_delegation( + delegator: &Self::AccountId, + agent: &Self::AccountId, + amount: Self::Balance, + ) -> DispatchResult; + + /// Returns true if there are pending slashes posted to the `Agent` account. + /// + /// Slashes to `Agent` account are not immediate and are applied lazily. Since `Agent` + /// has an unbounded number of delegators, immediate slashing is not possible. + fn has_pending_slash(agent: &Self::AccountId) -> bool; + + /// Apply a pending slash to a `Agent` by slashing `value` from `delegator`. + /// + /// If a reporter is provided, the reporter will receive a fraction of the slash as reward. + fn delegator_slash( + agent: &Self::AccountId, + delegator: &Self::AccountId, + value: Self::Balance, + maybe_reporter: Option, + ) -> sp_runtime::DispatchResult; +} + sp_core::generate_feature_enabled_macro!(runtime_benchmarks_enabled, feature = "runtime-benchmarks", $); From 259076be12a3affe7bde3bf474b3a45b2962953b Mon Sep 17 00:00:00 2001 From: Ankan Date: Sat, 30 Mar 2024 03:27:18 +0100 Subject: [PATCH 017/257] refactor pool to support multiple stake strategies --- .../frame/nomination-pools/src/adapter.rs | 301 ++++++++++++++++++ substrate/frame/nomination-pools/src/lib.rs | 163 ++++++---- .../frame/nomination-pools/src/migration.rs | 5 +- substrate/frame/nomination-pools/src/mock.rs | 2 +- .../nomination-pools/test-staking/src/mock.rs | 2 +- 5 files changed, 398 insertions(+), 75 deletions(-) create mode 100644 substrate/frame/nomination-pools/src/adapter.rs diff --git a/substrate/frame/nomination-pools/src/adapter.rs b/substrate/frame/nomination-pools/src/adapter.rs new file mode 100644 index 000000000000..06580393cc17 --- /dev/null +++ b/substrate/frame/nomination-pools/src/adapter.rs @@ -0,0 +1,301 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::*; +use sp_staking::DelegatedStakeInterface; + +/// An adapter trait that can support multiple staking strategies. +/// +/// Depending on which staking strategy we want to use, the staking logic can be slightly +/// different. Refer the two possible strategies currently: [`TransferStake`] and +/// [`DelegateStake`] for more detail. +pub trait StakeStrategy { + type Balance: frame_support::traits::tokens::Balance; + type AccountId: Clone + sp_std::fmt::Debug; + + fn bonding_duration() -> EraIndex; + fn current_era() -> EraIndex; + fn minimum_nominator_bond() -> Self::Balance; + + /// Transferable balance of the pool. + /// + /// This is the amount that can be withdrawn from the pool. + /// + /// Does not include reward account. + fn transferable_balance(id: PoolId) -> Self::Balance; + + /// Total balance of the pool including amount that is actively staked. + fn total_balance(id: PoolId) -> Self::Balance; + fn member_delegation_balance(member_account: &Self::AccountId) -> Self::Balance; + + fn active_stake(pool: PoolId) -> Self::Balance; + fn total_stake(pool: PoolId) -> Self::Balance; + + fn nominate(pool_id: PoolId, validators: Vec) -> DispatchResult; + + fn chill(pool_id: PoolId) -> DispatchResult; + + fn bond( + who: &Self::AccountId, + pool_id: PoolId, + amount: Self::Balance, + bond_type: BondType, + ) -> DispatchResult; + + fn unbond(pool_id: PoolId, amount: Self::Balance) -> DispatchResult; + + fn withdraw_unbonded(pool_id: PoolId, num_slashing_spans: u32) -> Result; + + fn member_withdraw( + who: &Self::AccountId, + pool: PoolId, + amount: Self::Balance, + ) -> DispatchResult; + + fn has_pending_slash(pool: PoolId) -> bool; + + fn member_slash( + who: &Self::AccountId, + pool: PoolId, + amount: Self::Balance, + maybe_reporter: Option, + ) -> DispatchResult; +} + +/// A staking strategy implementation that supports transfer based staking. +/// +/// In order to stake, this adapter transfers the funds from the member/delegator account to the +/// pool account and stakes through the pool account on `Staking`. +pub struct TransferStake(PhantomData<(T, Staking)>); + +impl, AccountId = T::AccountId>> + StakeStrategy for TransferStake +{ + type Balance = BalanceOf; + type AccountId = T::AccountId; + + fn bonding_duration() -> EraIndex { + Staking::bonding_duration() + } + fn current_era() -> EraIndex { + Staking::current_era() + } + fn minimum_nominator_bond() -> Staking::Balance { + Staking::minimum_nominator_bond() + } + + fn transferable_balance(pool: PoolId) -> BalanceOf { + let pool_account = Pallet::::create_bonded_account(pool); + T::Currency::balance(&pool_account).saturating_sub(Self::active_stake(pool)) + } + + fn total_balance(pool: PoolId) -> BalanceOf { + let pool_account = Pallet::::create_bonded_account(pool); + T::Currency::total_balance(&pool_account) + } + + fn member_delegation_balance(_member_account: &T::AccountId) -> Staking::Balance { + defensive!("delegation not supported"); + Zero::zero() + } + + fn active_stake(pool: PoolId) -> BalanceOf { + let pool_account = Pallet::::create_bonded_account(pool); + Staking::active_stake(&pool_account).unwrap_or_default() + } + + fn total_stake(pool: PoolId) -> Staking::Balance { + let pool_account = Pallet::::create_bonded_account(pool); + Staking::total_stake(&pool_account).unwrap_or_default() + } + + fn nominate(pool_id: PoolId, validators: Vec) -> DispatchResult { + let pool_account = Pallet::::create_bonded_account(pool_id); + Staking::nominate(&pool_account, validators) + } + + fn chill(pool_id: PoolId) -> DispatchResult { + let pool_account = Pallet::::create_bonded_account(pool_id); + Staking::chill(&pool_account) + } + + fn bond( + who: &T::AccountId, + pool: PoolId, + amount: BalanceOf, + bond_type: BondType, + ) -> DispatchResult { + let pool_account = Pallet::::create_bonded_account(pool); + let reward_account = Pallet::::create_reward_account(pool); + + match bond_type { + BondType::Create => { + // first bond + T::Currency::transfer(who, &pool_account, amount, Preservation::Expendable)?; + Staking::bond(&pool_account, amount, &reward_account) + }, + BondType::Later => { + // additional bond + T::Currency::transfer(who, &pool_account, amount, Preservation::Preserve)?; + Staking::bond_extra(&pool_account, amount) + }, + } + } + + fn unbond(pool_id: PoolId, amount: Staking::Balance) -> DispatchResult { + let pool_account = Pallet::::create_bonded_account(pool_id); + Staking::unbond(&pool_account, amount) + } + + fn withdraw_unbonded(pool_id: PoolId, num_slashing_spans: u32) -> Result { + let pool_account = Pallet::::create_bonded_account(pool_id); + Staking::withdraw_unbonded(pool_account, num_slashing_spans) + } + + fn member_withdraw(who: &T::AccountId, pool: PoolId, amount: BalanceOf) -> DispatchResult { + let pool_account = Pallet::::create_bonded_account(pool); + T::Currency::transfer(&pool_account, &who, amount, Preservation::Expendable)?; + + Ok(()) + } + + fn has_pending_slash(_pool: PoolId) -> bool { + // for transfer stake strategy, slashing is greedy + false + } + + fn member_slash( + _who: &T::AccountId, + _pool: PoolId, + _amount: Staking::Balance, + _maybe_reporter: Option, + ) -> DispatchResult { + Err(Error::::Defensive(DefensiveError::DelegationUnsupported).into()) + } +} + +/// A staking strategy implementation that supports delegation based staking. +/// +/// In this approach, first the funds are delegated from delegator to the pool account and later +/// staked with `Staking`. The advantage of this approach is that the funds are held in the +/// user account itself and not in the pool account. +pub struct DelegateStake(PhantomData<(T, Staking)>); + +impl< + T: Config, + Staking: DelegatedStakeInterface, AccountId = T::AccountId>, + > StakeStrategy for DelegateStake +{ + type Balance = BalanceOf; + type AccountId = T::AccountId; + + fn bonding_duration() -> EraIndex { + Staking::bonding_duration() + } + fn current_era() -> EraIndex { + Staking::current_era() + } + fn minimum_nominator_bond() -> Staking::Balance { + Staking::minimum_nominator_bond() + } + + fn transferable_balance(pool: PoolId) -> BalanceOf { + let pool_account = Pallet::::create_bonded_account(pool); + Staking::delegatee_balance(&pool_account).saturating_sub(Self::active_stake(pool)) + } + + fn total_balance(pool: PoolId) -> BalanceOf { + let pool_account = Pallet::::create_bonded_account(pool); + Staking::delegatee_balance(&pool_account) + } + + fn member_delegation_balance(member_account: &T::AccountId) -> Staking::Balance { + Staking::delegator_balance(member_account) + } + + fn active_stake(pool: PoolId) -> BalanceOf { + let pool_account = Pallet::::create_bonded_account(pool); + Staking::active_stake(&pool_account).unwrap_or_default() + } + + fn total_stake(pool: PoolId) -> Staking::Balance { + let pool_account = Pallet::::create_bonded_account(pool); + Staking::total_stake(&pool_account).unwrap_or_default() + } + + fn nominate(pool_id: PoolId, validators: Vec) -> DispatchResult { + let pool_account = Pallet::::create_bonded_account(pool_id); + Staking::nominate(&pool_account, validators) + } + + fn chill(pool_id: PoolId) -> DispatchResult { + let pool_account = Pallet::::create_bonded_account(pool_id); + Staking::chill(&pool_account) + } + + fn bond( + who: &T::AccountId, + pool: PoolId, + amount: BalanceOf, + bond_type: BondType, + ) -> DispatchResult { + let pool_account = Pallet::::create_bonded_account(pool); + + match bond_type { + BondType::Create => { + // first delegation + let reward_account = Pallet::::create_reward_account(pool); + Staking::delegate(who, &pool_account, &reward_account, amount) + }, + BondType::Later => { + // additional delegation + Staking::delegate_extra(who, &pool_account, amount) + }, + } + } + + fn unbond(pool_id: PoolId, amount: Staking::Balance) -> DispatchResult { + let pool_account = Pallet::::create_bonded_account(pool_id); + Staking::unbond(&pool_account, amount) + } + + fn withdraw_unbonded(pool_id: PoolId, num_slashing_spans: u32) -> Result { + let pool_account = Pallet::::create_bonded_account(pool_id); + Staking::withdraw_unbonded(pool_account, num_slashing_spans) + } + + fn member_withdraw(who: &T::AccountId, pool: PoolId, amount: BalanceOf) -> DispatchResult { + let pool_account = Pallet::::create_bonded_account(pool); + Staking::withdraw_delegation(&who, &pool_account, amount) + } + + fn has_pending_slash(pool: PoolId) -> bool { + // for transfer stake strategy, slashing is greedy + let pool_account = Pallet::::create_bonded_account(pool); + Staking::has_pending_slash(&pool_account) + } + + fn member_slash( + who: &T::AccountId, + pool: PoolId, + amount: Staking::Balance, + maybe_reporter: Option, + ) -> DispatchResult { + let pool_account = Pallet::::create_bonded_account(pool); + Staking::delegator_slash(&pool_account, who, amount, maybe_reporter) + } +} diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs index f29a49a2b1b3..9ef052409d17 100644 --- a/substrate/frame/nomination-pools/src/lib.rs +++ b/substrate/frame/nomination-pools/src/lib.rs @@ -351,6 +351,7 @@ #![cfg_attr(not(feature = "std"), no_std)] +use adapter::StakeStrategy; use codec::Codec; use frame_support::{ defensive, defensive_assert, ensure, @@ -397,6 +398,7 @@ pub mod mock; #[cfg(test)] mod tests; +pub mod adapter; pub mod migration; pub mod weights; @@ -425,7 +427,7 @@ pub enum ConfigOp { } /// The type of bonding that can happen to a pool. -enum BondType { +pub enum BondType { /// Someone is bonding into the pool upon creation. Create, /// Someone is adding more funds later to this pool. @@ -545,9 +547,14 @@ impl PoolMember { /// Total balance of the member, both active and unbonding. /// Doesn't mutate state. - #[cfg(any(feature = "try-runtime", feature = "fuzzing", test, debug_assertions))] fn total_balance(&self) -> BalanceOf { - let pool = BondedPool::::get(self.pool_id).unwrap(); + let maybe_pool = BondedPool::::get(self.pool_id); + if maybe_pool.is_none() { + defensive!("pool should exist; qed"); + return Zero::zero(); + } + let pool = maybe_pool.expect("checked pool is not none; qed"); + let active_balance = pool.points_to_balance(self.active_points()); let sub_pools = match SubPoolsStorage::::get(self.pool_id) { @@ -991,8 +998,7 @@ impl BondedPool { /// /// This is often used for bonding and issuing new funds into the pool. fn balance_to_point(&self, new_funds: BalanceOf) -> BalanceOf { - let bonded_balance = - T::Staking::active_stake(&self.bonded_account()).unwrap_or(Zero::zero()); + let bonded_balance = T::StakeAdapter::active_stake(self.id); Pallet::::balance_to_point(bonded_balance, self.points, new_funds) } @@ -1000,8 +1006,7 @@ impl BondedPool { /// /// This is often used for unbonding. fn points_to_balance(&self, points: BalanceOf) -> BalanceOf { - let bonded_balance = - T::Staking::active_stake(&self.bonded_account()).unwrap_or(Zero::zero()); + let bonded_balance = T::StakeAdapter::active_stake(self.id); Pallet::::point_to_balance(bonded_balance, self.points, points) } @@ -1048,18 +1053,6 @@ impl BondedPool { self } - /// The pools balance that is transferable provided it is expendable by staking pallet. - fn transferable_balance(&self) -> BalanceOf { - let account = self.bonded_account(); - // Note on why we can't use `Currency::reducible_balance`: Since pooled account has a - // provider (staking pallet), the account can not be set expendable by - // `pallet-nomination-pool`. This means reducible balance always returns balance preserving - // ED in the account. What we want though is transferable balance given the account can be - // dusted. - T::Currency::balance(&account) - .saturating_sub(T::Staking::active_stake(&account).unwrap_or_default()) - } - fn is_root(&self, who: &T::AccountId) -> bool { self.roles.root.as_ref().map_or(false, |root| root == who) } @@ -1123,8 +1116,7 @@ impl BondedPool { fn ok_to_be_open(&self) -> Result<(), DispatchError> { ensure!(!self.is_destroying(), Error::::CanNotChangeState); - let bonded_balance = - T::Staking::active_stake(&self.bonded_account()).unwrap_or(Zero::zero()); + let bonded_balance = T::StakeAdapter::active_stake(self.id); ensure!(!bonded_balance.is_zero(), Error::::OverflowRisk); let points_to_balance_ratio_floor = self @@ -1253,28 +1245,11 @@ impl BondedPool { amount: BalanceOf, ty: BondType, ) -> Result, DispatchError> { - // Cache the value - let bonded_account = self.bonded_account(); - T::Currency::transfer( - who, - &bonded_account, - amount, - match ty { - BondType::Create => Preservation::Expendable, - BondType::Later => Preservation::Preserve, - }, - )?; // We must calculate the points issued *before* we bond who's funds, else points:balance // ratio will be wrong. let points_issued = self.issue(amount); - match ty { - BondType::Create => T::Staking::bond(&bonded_account, amount, &self.reward_account())?, - // The pool should always be created in such a way its in a state to bond extra, but if - // the active balance is slashed below the minimum bonded or the account cannot be - // found, we exit early. - BondType::Later => T::Staking::bond_extra(&bonded_account, amount)?, - } + T::StakeAdapter::bond(who, self.id, amount, ty)?; TotalValueLocked::::mutate(|tvl| { tvl.saturating_accrue(amount); }); @@ -1282,6 +1257,13 @@ impl BondedPool { Ok(points_issued) } + /// Returns whether the pool nominator has some slashes not applied to the members. + /// + /// Can only happen when slashes are lazy, such as in `delegate and stake` strategy. + fn has_pending_slash(&self) -> bool { + T::StakeAdapter::has_pending_slash(self.id) + } + // Set the state of `self`, and deposit an event if the state changed. State should never be set // directly in in order to ensure a state change event is always correctly deposited. fn set_state(&mut self, state: PoolState) { @@ -1565,7 +1547,7 @@ impl Get for TotalUnbondingPools { // NOTE: this may be dangerous in the scenario bonding_duration gets decreased because // we would no longer be able to decode `BoundedBTreeMap::, // TotalUnbondingPools>`, which uses `TotalUnbondingPools` as the bound - T::Staking::bonding_duration() + T::PostUnbondingPoolsWindow::get() + T::StakeAdapter::bonding_duration() + T::PostUnbondingPoolsWindow::get() } } @@ -1642,7 +1624,7 @@ pub mod pallet { type U256ToBalance: Convert>; /// The interface for nominating. - type Staking: StakingInterface, AccountId = Self::AccountId>; + type StakeAdapter: StakeStrategy>; /// The amount of eras a `SubPools::with_era` pool can exist before it gets merged into the /// `SubPools::no_era` pool. In other words, this is the amount of eras a member will be @@ -1943,6 +1925,8 @@ pub mod pallet { BondExtraRestricted, /// No imbalance in the ED deposit for the pool. NothingToAdjust, + /// No slash pending that can be applied to the member. + NothingToSlash, } #[derive(Encode, Decode, PartialEq, TypeInfo, PalletError, RuntimeDebug)] @@ -1958,6 +1942,8 @@ pub mod pallet { /// The bonded account should only be killed by the staking system when the depositor is /// withdrawing BondedStashKilledPrematurely, + /// The delegation feature is unsupported. + DelegationUnsupported, } impl From for Error { @@ -2134,12 +2120,12 @@ pub mod pallet { &mut reward_pool, )?; - let current_era = T::Staking::current_era(); - let unbond_era = T::Staking::bonding_duration().saturating_add(current_era); + let current_era = T::StakeAdapter::current_era(); + let unbond_era = T::StakeAdapter::bonding_duration().saturating_add(current_era); // Unbond in the actual underlying nominator. let unbonding_balance = bonded_pool.dissolve(unbonding_points); - T::Staking::unbond(&bonded_pool.bonded_account(), unbonding_balance)?; + T::StakeAdapter::unbond(bonded_pool.id, unbonding_balance)?; // Note that we lazily create the unbonding pools here if they don't already exist let mut sub_pools = SubPoolsStorage::::get(member.pool_id) @@ -2202,7 +2188,7 @@ pub mod pallet { // For now we only allow a pool to withdraw unbonded if its not destroying. If the pool // is destroying then `withdraw_unbonded` can be used. ensure!(pool.state != PoolState::Destroying, Error::::NotDestroying); - T::Staking::withdraw_unbonded(pool.bonded_account(), num_slashing_spans)?; + T::StakeAdapter::withdraw_unbonded(pool_id, num_slashing_spans)?; Ok(()) } @@ -2239,13 +2225,18 @@ pub mod pallet { let member_account = T::Lookup::lookup(member_account)?; let mut member = PoolMembers::::get(&member_account).ok_or(Error::::PoolMemberNotFound)?; - let current_era = T::Staking::current_era(); + let current_era = T::StakeAdapter::current_era(); let bonded_pool = BondedPool::::get(member.pool_id) .defensive_ok_or::>(DefensiveError::PoolNotFound.into())?; let mut sub_pools = SubPoolsStorage::::get(member.pool_id).ok_or(Error::::SubPoolsNotFound)?; + if bonded_pool.has_pending_slash() { + // apply slash if any before withdraw. + let _ = Self::do_apply_slash(&member_account, None); + } + bonded_pool.ok_to_withdraw_unbonded_with(&caller, &member_account)?; // NOTE: must do this after we have done the `ok_to_withdraw_unbonded_other_with` check. @@ -2255,7 +2246,7 @@ pub mod pallet { // Before calculating the `balance_to_unbond`, we call withdraw unbonded to ensure the // `transferrable_balance` is correct. let stash_killed = - T::Staking::withdraw_unbonded(bonded_pool.bonded_account(), num_slashing_spans)?; + T::StakeAdapter::withdraw_unbonded(bonded_pool.id, num_slashing_spans)?; // defensive-only: the depositor puts enough funds into the stash so that it will only // be destroyed when they are leaving. @@ -2288,15 +2279,10 @@ pub mod pallet { // don't exist. This check is also defensive in cases where the unbond pool does not // update its balance (e.g. a bug in the slashing hook.) We gracefully proceed in // order to ensure members can leave the pool and it can be destroyed. - .min(bonded_pool.transferable_balance()); + .min(T::StakeAdapter::transferable_balance(bonded_pool.id)); - T::Currency::transfer( - &bonded_pool.bonded_account(), - &member_account, - balance_to_unbond, - Preservation::Expendable, - ) - .defensive()?; + T::StakeAdapter::member_withdraw(&member_account, bonded_pool.id, balance_to_unbond) + .defensive()?; Self::deposit_event(Event::::Withdrawn { member: member_account.clone(), @@ -2426,7 +2412,7 @@ pub mod pallet { Error::::MinimumBondNotMet ); - T::Staking::nominate(&bonded_pool.bonded_account(), validators) + T::StakeAdapter::nominate(bonded_pool.id, validators) } /// Set a new state for the pool. @@ -2614,12 +2600,12 @@ pub mod pallet { .active_points(); if bonded_pool.points_to_balance(depositor_points) >= - T::Staking::minimum_nominator_bond() + T::StakeAdapter::minimum_nominator_bond() { ensure!(bonded_pool.can_nominate(&who), Error::::NotNominator); } - T::Staking::chill(&bonded_pool.bonded_account()) + T::StakeAdapter::chill(bonded_pool.id) } /// `origin` bonds funds from `extra` for some pool member `member` into their respective @@ -2819,6 +2805,19 @@ pub mod pallet { Ok(()) } + + /// Apply a pending slash on a member. + #[pallet::call_index(23)] + // FIXME(ank4n): fix weight info. + #[pallet::weight(T::WeightInfo::set_commission_claim_permission())] + pub fn apply_slash( + origin: OriginFor, + member_account: AccountIdLookupOf, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + let member_account = T::Lookup::lookup(member_account)?; + Self::do_apply_slash(&member_account, Some(who)) + } } #[pallet::hooks] @@ -2834,7 +2833,7 @@ pub mod pallet { "Minimum points to balance ratio must be greater than 0" ); assert!( - T::Staking::bonding_duration() < TotalUnbondingPools::::get(), + T::StakeAdapter::bonding_duration() < TotalUnbondingPools::::get(), "There must be more unbonding pools then the bonding duration / so a slash can be applied to relevant unbonding pools. (We assume / the bonding duration > slash deffer duration.", @@ -2852,7 +2851,7 @@ impl Pallet { /// It is essentially `max { MinNominatorBond, MinCreateBond, MinJoinBond }`, where the former /// is coming from the staking pallet and the latter two are configured in this pallet. pub fn depositor_min_bond() -> BalanceOf { - T::Staking::minimum_nominator_bond() + T::StakeAdapter::minimum_nominator_bond() .max(MinCreateBond::::get()) .max(MinJoinBond::::get()) .max(T::Currency::minimum_balance()) @@ -2888,7 +2887,7 @@ impl Pallet { "bonded account of dissolving pool should have no consumers" ); defensive_assert!( - T::Staking::total_stake(&bonded_account).unwrap_or_default() == Zero::zero(), + T::StakeAdapter::total_stake(bonded_pool.id) == Zero::zero(), "dissolving pool should not have any stake in the staking pallet" ); @@ -2911,11 +2910,12 @@ impl Pallet { "could not transfer all amount to depositor while dissolving pool" ); defensive_assert!( - T::Currency::total_balance(&bonded_pool.bonded_account()) == Zero::zero(), + T::StakeAdapter::total_balance(bonded_pool.id) == Zero::zero(), "dissolving pool should not have any balance" ); // NOTE: Defensively force set balance to zero. T::Currency::set_balance(&reward_account, Zero::zero()); + // fixme(ank4n): Can't really do this with delegated staking? T::Currency::set_balance(&bonded_pool.bonded_account(), Zero::zero()); Self::deposit_event(Event::::Destroyed { pool_id: bonded_pool.id }); @@ -3298,6 +3298,34 @@ impl Pallet { Ok(()) } + /// Slash member against the pending slash for the pool. + fn do_apply_slash( + member_account: &T::AccountId, + reporter: Option, + ) -> DispatchResult { + // calculate points to be slashed. + let member = + PoolMembers::::get(&member_account).ok_or(Error::::PoolMemberNotFound)?; + ensure!(T::StakeAdapter::has_pending_slash(member.pool_id), Error::::NothingToSlash); + + let unslashed_balance = T::StakeAdapter::member_delegation_balance(&member_account); + let slashed_balance = member.total_balance(); + defensive_assert!( + unslashed_balance >= slashed_balance, + "unslashed balance should always be greater or equal to the slashed" + ); + + // if nothing to slash, return error. + ensure!(unslashed_balance > slashed_balance, Error::::NothingToSlash); + + T::StakeAdapter::member_slash( + &member_account, + member.pool_id, + unslashed_balance.defensive_saturating_sub(slashed_balance), + reporter, + ) + } + /// Apply freeze on reward account to restrict it from going below ED. pub(crate) fn freeze_pool_deposit(reward_acc: &T::AccountId) -> DispatchResult { T::Currency::set_freeze( @@ -3461,8 +3489,7 @@ impl Pallet { pool is being destroyed and the depositor is the last member", ); - expected_tvl += - T::Staking::total_stake(&bonded_pool.bonded_account()).unwrap_or_default(); + expected_tvl += T::StakeAdapter::total_stake(bonded_pool.id); Ok(()) })?; @@ -3487,12 +3514,11 @@ impl Pallet { } for (pool_id, _pool) in BondedPools::::iter() { - let pool_account = Pallet::::create_bonded_account(pool_id); let subs = SubPoolsStorage::::get(pool_id).unwrap_or_default(); let sum_unbonding_balance = subs.sum_unbonding_balance(); - let bonded_balance = T::Staking::active_stake(&pool_account).unwrap_or_default(); - let total_balance = T::Currency::total_balance(&pool_account); + let bonded_balance = T::StakeAdapter::active_stake(pool_id); + let total_balance = T::StakeAdapter::total_balance(pool_id); assert!( total_balance >= bonded_balance + sum_unbonding_balance, @@ -3595,8 +3621,7 @@ impl Pallet { /// If the pool ID does not exist, returns 0 ratio balance to points. Used by runtime API. pub fn api_balance_to_points(pool_id: PoolId, new_funds: BalanceOf) -> BalanceOf { if let Some(pool) = BondedPool::::get(pool_id) { - let bonded_balance = - T::Staking::active_stake(&pool.bonded_account()).unwrap_or(Zero::zero()); + let bonded_balance = T::StakeAdapter::active_stake(pool.id); Pallet::::balance_to_point(bonded_balance, pool.points, new_funds) } else { Zero::zero() diff --git a/substrate/frame/nomination-pools/src/migration.rs b/substrate/frame/nomination-pools/src/migration.rs index ca9c0874a83c..ba62ff96011b 100644 --- a/substrate/frame/nomination-pools/src/migration.rs +++ b/substrate/frame/nomination-pools/src/migration.rs @@ -1023,10 +1023,7 @@ mod helpers { pub(crate) fn calculate_tvl_by_total_stake() -> BalanceOf { BondedPools::::iter() - .map(|(id, inner)| { - T::Staking::total_stake(&BondedPool { id, inner: inner.clone() }.bonded_account()) - .unwrap_or_default() - }) + .map(|(id, _inner)| T::StakeAdapter::total_stake(id)) .reduce(|acc, total_balance| acc + total_balance) .unwrap_or_default() } diff --git a/substrate/frame/nomination-pools/src/mock.rs b/substrate/frame/nomination-pools/src/mock.rs index 2e30bbeed59e..346dec66c937 100644 --- a/substrate/frame/nomination-pools/src/mock.rs +++ b/substrate/frame/nomination-pools/src/mock.rs @@ -305,7 +305,7 @@ impl pools::Config for Runtime { type RewardCounter = RewardCounter; type BalanceToU256 = BalanceToU256; type U256ToBalance = U256ToBalance; - type Staking = StakingMock; + type StakeAdapter = adapter::TransferStake; type PostUnbondingPoolsWindow = PostUnbondingPoolsWindow; type PalletId = PoolsPalletId; type MaxMetadataLen = MaxMetadataLen; diff --git a/substrate/frame/nomination-pools/test-staking/src/mock.rs b/substrate/frame/nomination-pools/test-staking/src/mock.rs index 22939ff5e238..567840b5b713 100644 --- a/substrate/frame/nomination-pools/test-staking/src/mock.rs +++ b/substrate/frame/nomination-pools/test-staking/src/mock.rs @@ -180,7 +180,7 @@ impl pallet_nomination_pools::Config for Runtime { type RewardCounter = FixedU128; type BalanceToU256 = BalanceToU256; type U256ToBalance = U256ToBalance; - type Staking = Staking; + type StakeAdapter = pallet_nomination_pools::adapter::TransferStake; type PostUnbondingPoolsWindow = PostUnbondingPoolsWindow; type MaxMetadataLen = ConstU32<256>; type MaxUnbonding = ConstU32<8>; From fcefdb8f6bb5348baec935319c51068f29736f2c Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 31 Mar 2024 07:05:36 +0200 Subject: [PATCH 018/257] np-integration-delegation-compiles --- Cargo.lock | 25 + Cargo.toml | 1 + .../test-delegation-staking/Cargo.toml | 41 + .../test-delegation-staking/src/lib.rs | 823 ++++++++++++++++++ .../test-delegation-staking/src/mock.rs | 284 ++++++ 5 files changed, 1174 insertions(+) create mode 100644 substrate/frame/nomination-pools/test-delegation-staking/Cargo.toml create mode 100644 substrate/frame/nomination-pools/test-delegation-staking/src/lib.rs create mode 100644 substrate/frame/nomination-pools/test-delegation-staking/src/mock.rs diff --git a/Cargo.lock b/Cargo.lock index fd82e1711fdf..35721cf42706 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10404,6 +10404,31 @@ dependencies = [ "sp-std 14.0.0", ] +[[package]] +name = "pallet-nomination-pools-test-delegation-staking" +version = "1.0.0" +dependencies = [ + "frame-election-provider-support", + "frame-support", + "frame-system", + "log", + "pallet-bags-list", + "pallet-balances", + "pallet-delegated-staking", + "pallet-nomination-pools", + "pallet-staking", + "pallet-staking-reward-curve", + "pallet-timestamp", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-staking", + "sp-std 14.0.0", + "sp-tracing 16.0.0", +] + [[package]] name = "pallet-nomination-pools-test-staking" version = "1.0.0" diff --git a/Cargo.toml b/Cargo.toml index f9f89d313175..5c207676dbbb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -360,6 +360,7 @@ members = [ "substrate/frame/nomination-pools/benchmarking", "substrate/frame/nomination-pools/fuzzer", "substrate/frame/nomination-pools/runtime-api", + "substrate/frame/nomination-pools/test-delegation-staking", "substrate/frame/nomination-pools/test-staking", "substrate/frame/offences", "substrate/frame/offences/benchmarking", diff --git a/substrate/frame/nomination-pools/test-delegation-staking/Cargo.toml b/substrate/frame/nomination-pools/test-delegation-staking/Cargo.toml new file mode 100644 index 000000000000..6a2f00c97b36 --- /dev/null +++ b/substrate/frame/nomination-pools/test-delegation-staking/Cargo.toml @@ -0,0 +1,41 @@ +[package] +name = "pallet-nomination-pools-test-delegation-staking" +version = "1.0.0" +authors.workspace = true +edition.workspace = true +license = "Apache-2.0" +homepage = "https://substrate.io" +repository.workspace = true +description = "FRAME nomination pools pallet tests with the staking pallet" +publish = false + +[lints] +workspace = true + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dev-dependencies] +codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } +scale-info = { version = "2.10.0", features = ["derive"] } + +sp-runtime = { path = "../../../primitives/runtime" } +sp-io = { path = "../../../primitives/io" } +sp-std = { path = "../../../primitives/std" } +sp-staking = { path = "../../../primitives/staking" } +sp-core = { path = "../../../primitives/core" } + +frame-system = { path = "../../system" } +frame-support = { path = "../../support" } +frame-election-provider-support = { path = "../../election-provider-support" } + +pallet-timestamp = { path = "../../timestamp" } +pallet-balances = { path = "../../balances" } +pallet-staking = { path = "../../staking" } +pallet-delegated-staking = { path = "../../delegated-staking" } +pallet-bags-list = { path = "../../bags-list" } +pallet-staking-reward-curve = { path = "../../staking/reward-curve" } +pallet-nomination-pools = { path = ".." } + +sp-tracing = { path = "../../../primitives/tracing" } +log = { workspace = true, default-features = true } diff --git a/substrate/frame/nomination-pools/test-delegation-staking/src/lib.rs b/substrate/frame/nomination-pools/test-delegation-staking/src/lib.rs new file mode 100644 index 000000000000..98bff537c908 --- /dev/null +++ b/substrate/frame/nomination-pools/test-delegation-staking/src/lib.rs @@ -0,0 +1,823 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![cfg(test)] + +mod mock; + +use frame_support::{assert_noop, assert_ok, traits::Currency}; +use mock::*; +use pallet_nomination_pools::{ + BondExtra, BondedPools, Error as PoolsError, Event as PoolsEvent, LastPoolId, PoolMember, + PoolMembers, PoolState, +}; +use pallet_staking::{ + CurrentEra, Error as StakingError, Event as StakingEvent, Payee, RewardDestination, +}; +use sp_runtime::{bounded_btree_map, traits::Zero}; + +#[test] +fn pool_lifecycle_e2e() { + new_test_ext().execute_with(|| { + assert_eq!(Balances::minimum_balance(), 5); + assert_eq!(Staking::current_era(), None); + + // create the pool, we know this has id 1. + assert_ok!(Pools::create(RuntimeOrigin::signed(10), 50, 10, 10, 10)); + assert_eq!(LastPoolId::::get(), 1); + + // have the pool nominate. + assert_ok!(Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3])); + + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 50 }] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Created { depositor: 10, pool_id: 1 }, + PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 50, joined: true }, + ] + ); + + // have two members join + assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(21), 10, 1)); + + assert_eq!( + staking_events_since_last_call(), + vec![ + StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, + StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, + ] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: 10, joined: true }, + PoolsEvent::Bonded { member: 21, pool_id: 1, bonded: 10, joined: true }, + ] + ); + + // pool goes into destroying + assert_ok!(Pools::set_state(RuntimeOrigin::signed(10), 1, PoolState::Destroying)); + + // depositor cannot unbond yet. + assert_noop!( + Pools::unbond(RuntimeOrigin::signed(10), 10, 50), + PoolsError::::MinimumBondNotMet, + ); + + // now the members want to unbond. + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 10)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, 10)); + + assert_eq!(PoolMembers::::get(20).unwrap().unbonding_eras.len(), 1); + assert_eq!(PoolMembers::::get(20).unwrap().points, 0); + assert_eq!(PoolMembers::::get(21).unwrap().unbonding_eras.len(), 1); + assert_eq!(PoolMembers::::get(21).unwrap().points, 0); + + assert_eq!( + staking_events_since_last_call(), + vec![ + StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, + StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, + ] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::StateChanged { pool_id: 1, new_state: PoolState::Destroying }, + PoolsEvent::Unbonded { member: 20, pool_id: 1, points: 10, balance: 10, era: 3 }, + PoolsEvent::Unbonded { member: 21, pool_id: 1, points: 10, balance: 10, era: 3 }, + ] + ); + + // depositor cannot still unbond + assert_noop!( + Pools::unbond(RuntimeOrigin::signed(10), 10, 50), + PoolsError::::MinimumBondNotMet, + ); + + for e in 1..BondingDuration::get() { + CurrentEra::::set(Some(e)); + assert_noop!( + Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 0), + PoolsError::::CannotWithdrawAny + ); + } + + // members are now unlocked. + CurrentEra::::set(Some(BondingDuration::get())); + + // depositor cannot still unbond + assert_noop!( + Pools::unbond(RuntimeOrigin::signed(10), 10, 50), + PoolsError::::MinimumBondNotMet, + ); + + // but members can now withdraw. + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(21), 21, 0)); + assert!(PoolMembers::::get(20).is_none()); + assert!(PoolMembers::::get(21).is_none()); + + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 20 },] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Withdrawn { member: 20, pool_id: 1, points: 10, balance: 10 }, + PoolsEvent::MemberRemoved { pool_id: 1, member: 20 }, + PoolsEvent::Withdrawn { member: 21, pool_id: 1, points: 10, balance: 10 }, + PoolsEvent::MemberRemoved { pool_id: 1, member: 21 }, + ] + ); + + // as soon as all members have left, the depositor can try to unbond, but since the + // min-nominator intention is set, they must chill first. + assert_noop!( + Pools::unbond(RuntimeOrigin::signed(10), 10, 50), + pallet_staking::Error::::InsufficientBond + ); + + assert_ok!(Pools::chill(RuntimeOrigin::signed(10), 1)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 50)); + + assert_eq!( + staking_events_since_last_call(), + vec![ + StakingEvent::Chilled { stash: POOL1_BONDED }, + StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 50 }, + ] + ); + assert_eq!( + pool_events_since_last_call(), + vec![PoolsEvent::Unbonded { member: 10, pool_id: 1, points: 50, balance: 50, era: 6 }] + ); + + // waiting another bonding duration: + CurrentEra::::set(Some(BondingDuration::get() * 2)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 1)); + + // pools is fully destroyed now. + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 50 },] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Withdrawn { member: 10, pool_id: 1, points: 50, balance: 50 }, + PoolsEvent::MemberRemoved { pool_id: 1, member: 10 }, + PoolsEvent::Destroyed { pool_id: 1 } + ] + ); + }) +} + +#[test] +fn pool_chill_e2e() { + new_test_ext().execute_with(|| { + assert_eq!(Balances::minimum_balance(), 5); + assert_eq!(Staking::current_era(), None); + + // create the pool, we know this has id 1. + assert_ok!(Pools::create(RuntimeOrigin::signed(10), 50, 10, 10, 10)); + assert_eq!(LastPoolId::::get(), 1); + + // have the pool nominate. + assert_ok!(Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3])); + + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 50 }] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Created { depositor: 10, pool_id: 1 }, + PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 50, joined: true }, + ] + ); + + // have two members join + assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(21), 10, 1)); + + assert_eq!( + staking_events_since_last_call(), + vec![ + StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, + StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, + ] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: 10, joined: true }, + PoolsEvent::Bonded { member: 21, pool_id: 1, bonded: 10, joined: true }, + ] + ); + + // in case depositor does not have more than `MinNominatorBond` staked, we can end up in + // situation where a member unbonding would cause pool balance to drop below + // `MinNominatorBond` and hence not allowed. This can happen if the `MinNominatorBond` is + // increased after the pool is created. + assert_ok!(Staking::set_staking_configs( + RuntimeOrigin::root(), + pallet_staking::ConfigOp::Set(55), // minimum nominator bond + pallet_staking::ConfigOp::Noop, + pallet_staking::ConfigOp::Noop, + pallet_staking::ConfigOp::Noop, + pallet_staking::ConfigOp::Noop, + pallet_staking::ConfigOp::Noop, + pallet_staking::ConfigOp::Noop, + )); + + // members can unbond as long as total stake of the pool is above min nominator bond + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 10),); + assert_eq!(PoolMembers::::get(20).unwrap().unbonding_eras.len(), 1); + assert_eq!(PoolMembers::::get(20).unwrap().points, 0); + + // this member cannot unbond since it will cause `pool stake < MinNominatorBond` + assert_noop!( + Pools::unbond(RuntimeOrigin::signed(21), 21, 10), + StakingError::::InsufficientBond, + ); + + // members can call `chill` permissionlessly now + assert_ok!(Pools::chill(RuntimeOrigin::signed(20), 1)); + + // now another member can unbond. + assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, 10)); + assert_eq!(PoolMembers::::get(21).unwrap().unbonding_eras.len(), 1); + assert_eq!(PoolMembers::::get(21).unwrap().points, 0); + + // nominator can not resume nomination until depositor have enough stake + assert_noop!( + Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3]), + PoolsError::::MinimumBondNotMet, + ); + + // other members joining pool does not affect the depositor's ability to resume nomination + assert_ok!(Pools::join(RuntimeOrigin::signed(22), 10, 1)); + + assert_noop!( + Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3]), + PoolsError::::MinimumBondNotMet, + ); + + // depositor can bond extra stake + assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(10), BondExtra::FreeBalance(10))); + + // `chill` can not be called permissionlessly anymore + assert_noop!( + Pools::chill(RuntimeOrigin::signed(20), 1), + PoolsError::::NotNominator, + ); + + // now nominator can resume nomination + assert_ok!(Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3])); + + // skip to make the unbonding period end. + CurrentEra::::set(Some(BondingDuration::get())); + + // members can now withdraw. + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(21), 21, 0)); + + assert_eq!( + staking_events_since_last_call(), + vec![ + StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, + StakingEvent::Chilled { stash: POOL1_BONDED }, + StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, + StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, // other member bonding + StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, // depositor bond extra + StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 20 }, + ] + ); + }) +} + +#[test] +fn pool_slash_e2e() { + new_test_ext().execute_with(|| { + ExistentialDeposit::set(1); + assert_eq!(Balances::minimum_balance(), 1); + assert_eq!(Staking::current_era(), None); + + // create the pool, we know this has id 1. + assert_ok!(Pools::create(RuntimeOrigin::signed(10), 40, 10, 10, 10)); + assert_eq!(LastPoolId::::get(), 1); + + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 40 }] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Created { depositor: 10, pool_id: 1 }, + PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 40, joined: true }, + ] + ); + + assert_eq!( + Payee::::get(POOL1_BONDED), + Some(RewardDestination::Account(POOL1_REWARD)) + ); + + // have two members join + assert_ok!(Pools::join(RuntimeOrigin::signed(20), 20, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(21), 20, 1)); + + assert_eq!( + staking_events_since_last_call(), + vec![ + StakingEvent::Bonded { stash: POOL1_BONDED, amount: 20 }, + StakingEvent::Bonded { stash: POOL1_BONDED, amount: 20 } + ] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: 20, joined: true }, + PoolsEvent::Bonded { member: 21, pool_id: 1, bonded: 20, joined: true }, + ] + ); + + // now let's progress a bit. + CurrentEra::::set(Some(1)); + + // 20 / 80 of the total funds are unlocked, and safe from any further slash. + assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 10)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 10)); + + assert_eq!( + staking_events_since_last_call(), + vec![ + StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, + StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 } + ] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Unbonded { member: 10, pool_id: 1, balance: 10, points: 10, era: 4 }, + PoolsEvent::Unbonded { member: 20, pool_id: 1, balance: 10, points: 10, era: 4 } + ] + ); + + CurrentEra::::set(Some(2)); + + // note: depositor cannot fully unbond at this point. + // these funds will still get slashed. + assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 10)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 10)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, 10)); + + assert_eq!( + staking_events_since_last_call(), + vec![ + StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, + StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, + StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, + ] + ); + + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Unbonded { member: 10, pool_id: 1, balance: 10, points: 10, era: 5 }, + PoolsEvent::Unbonded { member: 20, pool_id: 1, balance: 10, points: 10, era: 5 }, + PoolsEvent::Unbonded { member: 21, pool_id: 1, balance: 10, points: 10, era: 5 }, + ] + ); + + // At this point, 20 are safe from slash, 30 are unlocking but vulnerable to slash, and and + // another 30 are active and vulnerable to slash. Let's slash half of them. + pallet_staking::slashing::do_slash::( + &POOL1_BONDED, + 30, + &mut Default::default(), + &mut Default::default(), + 2, // slash era 2, affects chunks at era 5 onwards. + ); + + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Slashed { staker: POOL1_BONDED, amount: 30 }] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + // 30 has been slashed to 15 (15 slash) + PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 5, balance: 15 }, + // 30 has been slashed to 15 (15 slash) + PoolsEvent::PoolSlashed { pool_id: 1, balance: 15 } + ] + ); + + CurrentEra::::set(Some(3)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, 10)); + + assert_eq!( + PoolMembers::::get(21).unwrap(), + PoolMember { + pool_id: 1, + points: 0, + last_recorded_reward_counter: Zero::zero(), + // the 10 points unlocked just now correspond to 5 points in the unbond pool. + unbonding_eras: bounded_btree_map!(5 => 10, 6 => 5) + } + ); + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 5 }] + ); + assert_eq!( + pool_events_since_last_call(), + vec![PoolsEvent::Unbonded { member: 21, pool_id: 1, balance: 5, points: 5, era: 6 }] + ); + + // now we start withdrawing. we do it all at once, at era 6 where 20 and 21 are fully free. + CurrentEra::::set(Some(6)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(21), 21, 0)); + + assert_eq!( + pool_events_since_last_call(), + vec![ + // 20 had unbonded 10 safely, and 10 got slashed by half. + PoolsEvent::Withdrawn { member: 20, pool_id: 1, balance: 10 + 5, points: 20 }, + PoolsEvent::MemberRemoved { pool_id: 1, member: 20 }, + // 21 unbonded all of it after the slash + PoolsEvent::Withdrawn { member: 21, pool_id: 1, balance: 5 + 5, points: 15 }, + PoolsEvent::MemberRemoved { pool_id: 1, member: 21 } + ] + ); + assert_eq!( + staking_events_since_last_call(), + // a 10 (un-slashed) + 10/2 (slashed) balance from 10 has also been unlocked + vec![StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 15 + 10 + 15 }] + ); + + // now, finally, we can unbond the depositor further than their current limit. + assert_ok!(Pools::set_state(RuntimeOrigin::signed(10), 1, PoolState::Destroying)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 20)); + + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::StateChanged { pool_id: 1, new_state: PoolState::Destroying }, + PoolsEvent::Unbonded { member: 10, pool_id: 1, points: 10, balance: 10, era: 9 } + ] + ); + + CurrentEra::::set(Some(9)); + assert_eq!( + PoolMembers::::get(10).unwrap(), + PoolMember { + pool_id: 1, + points: 0, + last_recorded_reward_counter: Zero::zero(), + unbonding_eras: bounded_btree_map!(4 => 10, 5 => 10, 9 => 10) + } + ); + // withdraw the depositor, they should lose 12 balance in total due to slash. + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 0)); + + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 10 }] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Withdrawn { member: 10, pool_id: 1, balance: 10 + 15, points: 30 }, + PoolsEvent::MemberRemoved { pool_id: 1, member: 10 }, + PoolsEvent::Destroyed { pool_id: 1 } + ] + ); + }); +} + +#[test] +fn pool_slash_proportional() { + // a typical example where 3 pool members unbond in era 99, 100, and 101, and a slash that + // happened in era 100 should only affect the latter two. + new_test_ext().execute_with(|| { + ExistentialDeposit::set(1); + BondingDuration::set(28); + assert_eq!(Balances::minimum_balance(), 1); + assert_eq!(Staking::current_era(), None); + + // create the pool, we know this has id 1. + assert_ok!(Pools::create(RuntimeOrigin::signed(10), 40, 10, 10, 10)); + assert_eq!(LastPoolId::::get(), 1); + + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 40 }] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Created { depositor: 10, pool_id: 1 }, + PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 40, joined: true }, + ] + ); + + // have two members join + let bond = 20; + assert_ok!(Pools::join(RuntimeOrigin::signed(20), bond, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(21), bond, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(22), bond, 1)); + + assert_eq!( + staking_events_since_last_call(), + vec![ + StakingEvent::Bonded { stash: POOL1_BONDED, amount: bond }, + StakingEvent::Bonded { stash: POOL1_BONDED, amount: bond }, + StakingEvent::Bonded { stash: POOL1_BONDED, amount: bond }, + ] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: bond, joined: true }, + PoolsEvent::Bonded { member: 21, pool_id: 1, bonded: bond, joined: true }, + PoolsEvent::Bonded { member: 22, pool_id: 1, bonded: bond, joined: true }, + ] + ); + + // now let's progress a lot. + CurrentEra::::set(Some(99)); + + // and unbond + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, bond)); + + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond },] + ); + assert_eq!( + pool_events_since_last_call(), + vec![PoolsEvent::Unbonded { + member: 20, + pool_id: 1, + balance: bond, + points: bond, + era: 127 + }] + ); + + CurrentEra::::set(Some(100)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, bond)); + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond },] + ); + assert_eq!( + pool_events_since_last_call(), + vec![PoolsEvent::Unbonded { + member: 21, + pool_id: 1, + balance: bond, + points: bond, + era: 128 + }] + ); + + CurrentEra::::set(Some(101)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(22), 22, bond)); + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond },] + ); + assert_eq!( + pool_events_since_last_call(), + vec![PoolsEvent::Unbonded { + member: 22, + pool_id: 1, + balance: bond, + points: bond, + era: 129 + }] + ); + + // Apply a slash that happened in era 100. This is typically applied with a delay. + // Of the total 100, 50 is slashed. + assert_eq!(BondedPools::::get(1).unwrap().points, 40); + pallet_staking::slashing::do_slash::( + &POOL1_BONDED, + 50, + &mut Default::default(), + &mut Default::default(), + 100, + ); + + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Slashed { staker: POOL1_BONDED, amount: 50 }] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + // This era got slashed 12.5, which rounded up to 13. + PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 128, balance: 7 }, + // This era got slashed 12 instead of 12.5 because an earlier chunk got 0.5 more + // slashed, and 12 is all the remaining slash + PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 129, balance: 8 }, + // Bonded pool got slashed for 25, remaining 15 in it. + PoolsEvent::PoolSlashed { pool_id: 1, balance: 15 } + ] + ); + }); +} + +#[test] +fn pool_slash_non_proportional_only_bonded_pool() { + // A typical example where a pool member unbonds in era 99, and they can get away with a slash + // that happened in era 100, as long as the pool has enough active bond to cover the slash. If + // everything else in the slashing/staking system works, this should always be the case. + // Nonetheless, `ledger.slash` has been written such that it will slash greedily from any chunk + // if it runs out of chunks that it thinks should be affected by the slash. + new_test_ext().execute_with(|| { + ExistentialDeposit::set(1); + BondingDuration::set(28); + assert_eq!(Balances::minimum_balance(), 1); + assert_eq!(Staking::current_era(), None); + + // create the pool, we know this has id 1. + assert_ok!(Pools::create(RuntimeOrigin::signed(10), 40, 10, 10, 10)); + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 40 }] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Created { depositor: 10, pool_id: 1 }, + PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 40, joined: true }, + ] + ); + + // have two members join + let bond = 20; + assert_ok!(Pools::join(RuntimeOrigin::signed(20), bond, 1)); + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: bond }] + ); + assert_eq!( + pool_events_since_last_call(), + vec![PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: bond, joined: true }] + ); + + // progress and unbond. + CurrentEra::::set(Some(99)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, bond)); + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond }] + ); + assert_eq!( + pool_events_since_last_call(), + vec![PoolsEvent::Unbonded { + member: 20, + pool_id: 1, + balance: bond, + points: bond, + era: 127 + }] + ); + + // slash for 30. This will be deducted only from the bonded pool. + CurrentEra::::set(Some(100)); + assert_eq!(BondedPools::::get(1).unwrap().points, 40); + pallet_staking::slashing::do_slash::( + &POOL1_BONDED, + 30, + &mut Default::default(), + &mut Default::default(), + 100, + ); + + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Slashed { staker: POOL1_BONDED, amount: 30 }] + ); + assert_eq!( + pool_events_since_last_call(), + vec![PoolsEvent::PoolSlashed { pool_id: 1, balance: 10 }] + ); + }); +} + +#[test] +fn pool_slash_non_proportional_bonded_pool_and_chunks() { + // An uncommon example where even though some funds are unlocked such that they should not be + // affected by a slash, we still slash out of them. This should not happen at all. If a + // nomination has unbonded, from the next era onwards, their exposure will drop, so if an era + // happens in that era, then their share of that slash should naturally be less, such that only + // their active ledger stake is enough to compensate it. + new_test_ext().execute_with(|| { + ExistentialDeposit::set(1); + BondingDuration::set(28); + assert_eq!(Balances::minimum_balance(), 1); + assert_eq!(Staking::current_era(), None); + + // create the pool, we know this has id 1. + assert_ok!(Pools::create(RuntimeOrigin::signed(10), 40, 10, 10, 10)); + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 40 }] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Created { depositor: 10, pool_id: 1 }, + PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 40, joined: true }, + ] + ); + + // have two members join + let bond = 20; + assert_ok!(Pools::join(RuntimeOrigin::signed(20), bond, 1)); + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: bond }] + ); + assert_eq!( + pool_events_since_last_call(), + vec![PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: bond, joined: true }] + ); + + // progress and unbond. + CurrentEra::::set(Some(99)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, bond)); + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond }] + ); + assert_eq!( + pool_events_since_last_call(), + vec![PoolsEvent::Unbonded { + member: 20, + pool_id: 1, + balance: bond, + points: bond, + era: 127 + }] + ); + + // slash 50. This will be deducted only from the bonded pool and one of the unbonding pools. + CurrentEra::::set(Some(100)); + assert_eq!(BondedPools::::get(1).unwrap().points, 40); + pallet_staking::slashing::do_slash::( + &POOL1_BONDED, + 50, + &mut Default::default(), + &mut Default::default(), + 100, + ); + + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Slashed { staker: POOL1_BONDED, amount: 50 }] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + // out of 20, 10 was taken. + PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 127, balance: 10 }, + // out of 40, all was taken. + PoolsEvent::PoolSlashed { pool_id: 1, balance: 0 } + ] + ); + }); +} diff --git a/substrate/frame/nomination-pools/test-delegation-staking/src/mock.rs b/substrate/frame/nomination-pools/test-delegation-staking/src/mock.rs new file mode 100644 index 000000000000..0b4e59f4faa1 --- /dev/null +++ b/substrate/frame/nomination-pools/test-delegation-staking/src/mock.rs @@ -0,0 +1,284 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use frame_election_provider_support::VoteWeight; +use frame_support::{ + assert_ok, derive_impl, + pallet_prelude::*, + parameter_types, + traits::{ConstU64, ConstU8}, + PalletId, +}; +use sp_runtime::{ + traits::{Convert, IdentityLookup}, + BuildStorage, FixedU128, Perbill, +}; + +type AccountId = u128; +type Nonce = u32; +type BlockNumber = u64; +type Balance = u128; + +pub(crate) type T = Runtime; + +pub(crate) const POOL1_BONDED: AccountId = 20318131474730217858575332831085u128; +pub(crate) const POOL1_REWARD: AccountId = 20397359637244482196168876781421u128; + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] +impl frame_system::Config for Runtime { + type BaseCallFilter = frame_support::traits::Everything; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type RuntimeOrigin = RuntimeOrigin; + type Nonce = Nonce; + type RuntimeCall = RuntimeCall; + type Hash = sp_core::H256; + type Hashing = sp_runtime::traits::BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type Block = Block; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + +impl pallet_timestamp::Config for Runtime { + type Moment = u64; + type OnTimestampSet = (); + type MinimumPeriod = ConstU64<5>; + type WeightInfo = (); +} + +parameter_types! { + pub static ExistentialDeposit: Balance = 5; +} + +impl pallet_balances::Config for Runtime { + type MaxLocks = (); + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; + type Balance = Balance; + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); + type FreezeIdentifier = RuntimeFreezeReason; + type MaxFreezes = ConstU32<1>; + type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = (); +} + +pallet_staking_reward_curve::build! { + const I_NPOS: sp_runtime::curve::PiecewiseLinear<'static> = curve!( + min_inflation: 0_025_000, + max_inflation: 0_100_000, + ideal_stake: 0_500_000, + falloff: 0_050_000, + max_piece_count: 40, + test_precision: 0_005_000, + ); +} + +parameter_types! { + pub const RewardCurve: &'static sp_runtime::curve::PiecewiseLinear<'static> = &I_NPOS; + pub static BondingDuration: u32 = 3; +} + +impl pallet_staking::Config for Runtime { + type Currency = Balances; + type CurrencyBalance = Balance; + type UnixTime = pallet_timestamp::Pallet; + type CurrencyToVote = (); + type RewardRemainder = (); + type RuntimeEvent = RuntimeEvent; + type Slash = (); + type Reward = (); + type SessionsPerEra = (); + type SlashDeferDuration = (); + type AdminOrigin = frame_system::EnsureRoot; + type BondingDuration = BondingDuration; + type SessionInterface = (); + type EraPayout = pallet_staking::ConvertCurve; + type NextNewSession = (); + type MaxExposurePageSize = ConstU32<64>; + type OffendingValidatorsThreshold = (); + type ElectionProvider = + frame_election_provider_support::NoElection<(AccountId, BlockNumber, Staking, ())>; + type GenesisElectionProvider = Self::ElectionProvider; + type VoterList = VoterList; + type TargetList = pallet_staking::UseValidatorsMap; + type NominationsQuota = pallet_staking::FixedNominationsQuota<16>; + type MaxUnlockingChunks = ConstU32<32>; + type MaxControllersInDeprecationBatch = ConstU32<100>; + type HistoryDepth = ConstU32<84>; + type EventListeners = Pools; + type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; + type WeightInfo = (); +} + +parameter_types! { + pub static BagThresholds: &'static [VoteWeight] = &[10, 20, 30, 40, 50, 60, 1_000, 2_000, 10_000]; +} + +type VoterBagsListInstance = pallet_bags_list::Instance1; +impl pallet_bags_list::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); + type BagThresholds = BagThresholds; + type ScoreProvider = Staking; + type Score = VoteWeight; +} + +pub struct BalanceToU256; +impl Convert for BalanceToU256 { + fn convert(n: Balance) -> sp_core::U256 { + n.into() + } +} + +pub struct U256ToBalance; +impl Convert for U256ToBalance { + fn convert(n: sp_core::U256) -> Balance { + n.try_into().unwrap() + } +} + +parameter_types! { + pub const PostUnbondingPoolsWindow: u32 = 10; + pub const PoolsPalletId: PalletId = PalletId(*b"py/nopls"); +} + +impl pallet_nomination_pools::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); + type Currency = Balances; + type RuntimeFreezeReason = RuntimeFreezeReason; + type RewardCounter = FixedU128; + type BalanceToU256 = BalanceToU256; + type U256ToBalance = U256ToBalance; + type StakeAdapter = pallet_nomination_pools::adapter::DelegateStake; + type PostUnbondingPoolsWindow = PostUnbondingPoolsWindow; + type MaxMetadataLen = ConstU32<256>; + type MaxUnbonding = ConstU32<8>; + type MaxPointsToBalance = ConstU8<10>; + type PalletId = PoolsPalletId; +} + +parameter_types! { + pub const DelegatedStakingPalletId: PalletId = PalletId(*b"py/dlstk"); +} +impl pallet_delegated_staking::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type PalletId = DelegatedStakingPalletId; + type Currency = Balances; + type OnSlash = (); + type RuntimeHoldReason = RuntimeHoldReason; + type CoreStaking = Staking; +} +type Block = frame_system::mocking::MockBlock; + +frame_support::construct_runtime!( + pub enum Runtime { + System: frame_system, + Timestamp: pallet_timestamp, + Balances: pallet_balances, + Staking: pallet_staking, + VoterList: pallet_bags_list::, + DelegatedStaking: pallet_delegated_staking, + Pools: pallet_nomination_pools, + } +); + +pub fn new_test_ext() -> sp_io::TestExternalities { + sp_tracing::try_init_simple(); + let mut storage = frame_system::GenesisConfig::::default().build_storage().unwrap(); + let _ = pallet_nomination_pools::GenesisConfig:: { + min_join_bond: 2, + min_create_bond: 2, + max_pools: Some(3), + max_members_per_pool: Some(5), + max_members: Some(3 * 5), + global_max_commission: Some(Perbill::from_percent(90)), + } + .assimilate_storage(&mut storage) + .unwrap(); + + let _ = pallet_balances::GenesisConfig:: { + balances: vec![(10, 100), (20, 100), (21, 100), (22, 100)], + } + .assimilate_storage(&mut storage) + .unwrap(); + + let mut ext = sp_io::TestExternalities::from(storage); + + ext.execute_with(|| { + // for events to be deposited. + frame_system::Pallet::::set_block_number(1); + + // set some limit for nominations. + assert_ok!(Staking::set_staking_configs( + RuntimeOrigin::root(), + pallet_staking::ConfigOp::Set(10), // minimum nominator bond + pallet_staking::ConfigOp::Noop, + pallet_staking::ConfigOp::Noop, + pallet_staking::ConfigOp::Noop, + pallet_staking::ConfigOp::Noop, + pallet_staking::ConfigOp::Noop, + pallet_staking::ConfigOp::Noop, + )); + }); + + ext +} + +parameter_types! { + static ObservedEventsPools: usize = 0; + static ObservedEventsStaking: usize = 0; + static ObservedEventsBalances: usize = 0; +} + +pub(crate) fn pool_events_since_last_call() -> Vec> { + let events = System::events() + .into_iter() + .map(|r| r.event) + .filter_map(|e| if let RuntimeEvent::Pools(inner) = e { Some(inner) } else { None }) + .collect::>(); + let already_seen = ObservedEventsPools::get(); + ObservedEventsPools::set(events.len()); + events.into_iter().skip(already_seen).collect() +} + +pub(crate) fn staking_events_since_last_call() -> Vec> { + let events = System::events() + .into_iter() + .map(|r| r.event) + .filter_map(|e| if let RuntimeEvent::Staking(inner) = e { Some(inner) } else { None }) + .collect::>(); + let already_seen = ObservedEventsStaking::get(); + ObservedEventsStaking::set(events.len()); + events.into_iter().skip(already_seen).collect() +} From fc2ae409593fc47172fbf955cb40cf298350b9d8 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 31 Mar 2024 07:10:31 +0200 Subject: [PATCH 019/257] refactor test crate names --- Cargo.lock | 4 ++-- Cargo.toml | 4 ++-- .../Cargo.toml | 2 +- .../src/lib.rs | 0 .../src/mock.rs | 0 .../{test-staking => test-transfer-stake}/Cargo.toml | 2 +- .../{test-staking => test-transfer-stake}/src/lib.rs | 0 .../{test-staking => test-transfer-stake}/src/mock.rs | 0 8 files changed, 6 insertions(+), 6 deletions(-) rename substrate/frame/nomination-pools/{test-delegation-staking => test-delegate-stake}/Cargo.toml (96%) rename substrate/frame/nomination-pools/{test-delegation-staking => test-delegate-stake}/src/lib.rs (100%) rename substrate/frame/nomination-pools/{test-delegation-staking => test-delegate-stake}/src/mock.rs (100%) rename substrate/frame/nomination-pools/{test-staking => test-transfer-stake}/Cargo.toml (96%) rename substrate/frame/nomination-pools/{test-staking => test-transfer-stake}/src/lib.rs (100%) rename substrate/frame/nomination-pools/{test-staking => test-transfer-stake}/src/mock.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index 35721cf42706..8a35b26679b5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10405,7 +10405,7 @@ dependencies = [ ] [[package]] -name = "pallet-nomination-pools-test-delegation-staking" +name = "pallet-nomination-pools-test-delegate-stake" version = "1.0.0" dependencies = [ "frame-election-provider-support", @@ -10430,7 +10430,7 @@ dependencies = [ ] [[package]] -name = "pallet-nomination-pools-test-staking" +name = "pallet-nomination-pools-test-transfer-stake" version = "1.0.0" dependencies = [ "frame-election-provider-support", diff --git a/Cargo.toml b/Cargo.toml index 5c207676dbbb..b38d17a69707 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -360,8 +360,8 @@ members = [ "substrate/frame/nomination-pools/benchmarking", "substrate/frame/nomination-pools/fuzzer", "substrate/frame/nomination-pools/runtime-api", - "substrate/frame/nomination-pools/test-delegation-staking", - "substrate/frame/nomination-pools/test-staking", + "substrate/frame/nomination-pools/test-delegate-stake", + "substrate/frame/nomination-pools/test-transfer-stake", "substrate/frame/offences", "substrate/frame/offences/benchmarking", "substrate/frame/paged-list", diff --git a/substrate/frame/nomination-pools/test-delegation-staking/Cargo.toml b/substrate/frame/nomination-pools/test-delegate-stake/Cargo.toml similarity index 96% rename from substrate/frame/nomination-pools/test-delegation-staking/Cargo.toml rename to substrate/frame/nomination-pools/test-delegate-stake/Cargo.toml index 6a2f00c97b36..b1431afadbef 100644 --- a/substrate/frame/nomination-pools/test-delegation-staking/Cargo.toml +++ b/substrate/frame/nomination-pools/test-delegate-stake/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "pallet-nomination-pools-test-delegation-staking" +name = "pallet-nomination-pools-test-delegate-stake" version = "1.0.0" authors.workspace = true edition.workspace = true diff --git a/substrate/frame/nomination-pools/test-delegation-staking/src/lib.rs b/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs similarity index 100% rename from substrate/frame/nomination-pools/test-delegation-staking/src/lib.rs rename to substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs diff --git a/substrate/frame/nomination-pools/test-delegation-staking/src/mock.rs b/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs similarity index 100% rename from substrate/frame/nomination-pools/test-delegation-staking/src/mock.rs rename to substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs diff --git a/substrate/frame/nomination-pools/test-staking/Cargo.toml b/substrate/frame/nomination-pools/test-transfer-stake/Cargo.toml similarity index 96% rename from substrate/frame/nomination-pools/test-staking/Cargo.toml rename to substrate/frame/nomination-pools/test-transfer-stake/Cargo.toml index 9c7b12e4c634..52d0cefb0def 100644 --- a/substrate/frame/nomination-pools/test-staking/Cargo.toml +++ b/substrate/frame/nomination-pools/test-transfer-stake/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "pallet-nomination-pools-test-staking" +name = "pallet-nomination-pools-test-transfer-stake" version = "1.0.0" authors.workspace = true edition.workspace = true diff --git a/substrate/frame/nomination-pools/test-staking/src/lib.rs b/substrate/frame/nomination-pools/test-transfer-stake/src/lib.rs similarity index 100% rename from substrate/frame/nomination-pools/test-staking/src/lib.rs rename to substrate/frame/nomination-pools/test-transfer-stake/src/lib.rs diff --git a/substrate/frame/nomination-pools/test-staking/src/mock.rs b/substrate/frame/nomination-pools/test-transfer-stake/src/mock.rs similarity index 100% rename from substrate/frame/nomination-pools/test-staking/src/mock.rs rename to substrate/frame/nomination-pools/test-transfer-stake/src/mock.rs From ca7ec12bdc1d1d680369f1f2d8d4a7de3c00217a Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 31 Mar 2024 15:00:50 +0200 Subject: [PATCH 020/257] add delegated staking to westend --- Cargo.lock | 1 + polkadot/runtime/westend/Cargo.toml | 3 +++ polkadot/runtime/westend/src/lib.rs | 19 ++++++++++++++++++- substrate/bin/node/runtime/src/lib.rs | 2 +- .../test-staking-e2e/src/mock.rs | 2 +- .../nomination-pools/benchmarking/src/mock.rs | 2 +- 6 files changed, 25 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8a35b26679b5..5ba89d974485 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -21945,6 +21945,7 @@ dependencies = [ "pallet-beefy-mmr", "pallet-collective", "pallet-conviction-voting", + "pallet-delegated-staking", "pallet-democracy", "pallet-election-provider-multi-phase", "pallet-election-provider-support-benchmarking", diff --git a/polkadot/runtime/westend/Cargo.toml b/polkadot/runtime/westend/Cargo.toml index 587a6c9a5905..0aeab51dfec4 100644 --- a/polkadot/runtime/westend/Cargo.toml +++ b/polkadot/runtime/westend/Cargo.toml @@ -83,6 +83,7 @@ pallet-society = { path = "../../../substrate/frame/society", default-features = pallet-staking = { path = "../../../substrate/frame/staking", default-features = false } pallet-staking-reward-curve = { package = "pallet-staking-reward-curve", path = "../../../substrate/frame/staking/reward-curve" } pallet-staking-runtime-api = { path = "../../../substrate/frame/staking/runtime-api", default-features = false } +pallet-delegated-staking = { path = "../../../substrate/frame/delegated-staking", default-features = false } pallet-state-trie-migration = { path = "../../../substrate/frame/state-trie-migration", default-features = false } pallet-sudo = { path = "../../../substrate/frame/sudo", default-features = false } pallet-timestamp = { path = "../../../substrate/frame/timestamp", default-features = false } @@ -189,6 +190,7 @@ std = [ "pallet-society/std", "pallet-staking-runtime-api/std", "pallet-staking/std", + "pallet-delegated-staking/std", "pallet-state-trie-migration/std", "pallet-sudo/std", "pallet-timestamp/std", @@ -269,6 +271,7 @@ runtime-benchmarks = [ "pallet-session-benchmarking/runtime-benchmarks", "pallet-society/runtime-benchmarks", "pallet-staking/runtime-benchmarks", + "pallet-delegated-staking/runtime-benchmarks", "pallet-state-trie-migration/runtime-benchmarks", "pallet-sudo/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index d75c1011d5f3..ca9d59b3bf6c 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -1385,7 +1385,7 @@ impl pallet_nomination_pools::Config for Runtime { type RewardCounter = FixedU128; type BalanceToU256 = BalanceToU256; type U256ToBalance = U256ToBalance; - type Staking = Staking; + type StakeAdapter = pallet_nomination_pools::adapter::DelegateStake; type PostUnbondingPoolsWindow = ConstU32<4>; type MaxMetadataLen = ConstU32<256>; // we use the same number of allowed unlocking chunks as with staking. @@ -1394,6 +1394,19 @@ impl pallet_nomination_pools::Config for Runtime { type MaxPointsToBalance = MaxPointsToBalance; } +parameter_types! { + pub const DelegatedStakingPalletId: PalletId = PalletId(*b"py/dlstk"); +} + +impl pallet_delegated_staking::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type PalletId = DelegatedStakingPalletId; + type Currency = Balances; + type OnSlash = (); + type RuntimeHoldReason = RuntimeHoldReason; + type CoreStaking = Staking; +} + impl pallet_root_testing::Config for Runtime { type RuntimeEvent = RuntimeEvent; } @@ -1542,6 +1555,10 @@ mod runtime { #[runtime::pallet_index(37)] pub type Treasury = pallet_treasury; + // Staking extension for delegation + #[runtime::pallet_index(38)] + pub type DelegatedStaking = pallet_delegated_staking; + // Parachains pallets. Start indices at 40 to leave room. #[runtime::pallet_index(41)] pub type ParachainsOrigin = parachains_origin; diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index a9606ac0bb75..9805cb817501 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -903,7 +903,7 @@ impl pallet_nomination_pools::Config for Runtime { type RewardCounter = FixedU128; type BalanceToU256 = BalanceToU256; type U256ToBalance = U256ToBalance; - type Staking = Staking; + type StakeAdapter = pallet_nomination_pools::adapter::TransferStake; type PostUnbondingPoolsWindow = PostUnbondPoolsWindow; type MaxMetadataLen = ConstU32<256>; type MaxUnbonding = ConstU32<8>; diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs index 7efcc4701e27..c33de4461925 100644 --- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs +++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs @@ -275,7 +275,7 @@ impl pallet_nomination_pools::Config for Runtime { type RewardCounter = sp_runtime::FixedU128; type BalanceToU256 = BalanceToU256; type U256ToBalance = U256ToBalance; - type Staking = Staking; + type StakeAdapter = pallet_nomination_pools::adapter::TransferStake; type PostUnbondingPoolsWindow = ConstU32<2>; type PalletId = PoolsPalletId; type MaxMetadataLen = ConstU32<256>; diff --git a/substrate/frame/nomination-pools/benchmarking/src/mock.rs b/substrate/frame/nomination-pools/benchmarking/src/mock.rs index 1c513a1007cb..5034d43b969e 100644 --- a/substrate/frame/nomination-pools/benchmarking/src/mock.rs +++ b/substrate/frame/nomination-pools/benchmarking/src/mock.rs @@ -166,7 +166,7 @@ impl pallet_nomination_pools::Config for Runtime { type RewardCounter = FixedU128; type BalanceToU256 = BalanceToU256; type U256ToBalance = U256ToBalance; - type Staking = Staking; + type StakeAdapter = pallet_nomination_pools::adapter::TransferStake; type PostUnbondingPoolsWindow = PostUnbondingPoolsWindow; type MaxMetadataLen = ConstU32<256>; type MaxUnbonding = ConstU32<8>; From b1451948f37d581e618dc9b44e480b8a87a85f33 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 31 Mar 2024 15:56:42 +0200 Subject: [PATCH 021/257] fix benchmarks --- .../nomination-pools/benchmarking/src/lib.rs | 63 +++++++++---------- .../frame/nomination-pools/src/adapter.rs | 15 +++++ 2 files changed, 45 insertions(+), 33 deletions(-) diff --git a/substrate/frame/nomination-pools/benchmarking/src/lib.rs b/substrate/frame/nomination-pools/benchmarking/src/lib.rs index 48d7dae29ef0..0adf2c95ece3 100644 --- a/substrate/frame/nomination-pools/benchmarking/src/lib.rs +++ b/substrate/frame/nomination-pools/benchmarking/src/lib.rs @@ -34,17 +34,17 @@ use frame_support::{ }; use frame_system::RawOrigin as RuntimeOrigin; use pallet_nomination_pools::{ - BalanceOf, BondExtra, BondedPoolInner, BondedPools, ClaimPermission, ClaimPermissions, - Commission, CommissionChangeRate, CommissionClaimPermission, ConfigOp, GlobalMaxCommission, - MaxPoolMembers, MaxPoolMembersPerPool, MaxPools, Metadata, MinCreateBond, MinJoinBond, - Pallet as Pools, PoolMembers, PoolRoles, PoolState, RewardPools, SubPoolsStorage, + adapter::StakeStrategy, BalanceOf, BondExtra, BondedPoolInner, BondedPools, ClaimPermission, + ClaimPermissions, Commission, CommissionChangeRate, CommissionClaimPermission, ConfigOp, + GlobalMaxCommission, MaxPoolMembers, MaxPoolMembersPerPool, MaxPools, Metadata, MinCreateBond, + MinJoinBond, Pallet as Pools, PoolMembers, PoolRoles, PoolState, RewardPools, SubPoolsStorage, }; use pallet_staking::MaxNominationsOf; use sp_runtime::{ traits::{Bounded, StaticLookup, Zero}, Perbill, }; -use sp_staking::{EraIndex, StakingInterface}; +use sp_staking::EraIndex; use sp_std::{vec, vec::Vec}; // `frame_benchmarking::benchmarks!` macro needs this use pallet_nomination_pools::Call; @@ -157,8 +157,8 @@ impl ListScenario { let (pool_creator1, pool_origin1) = create_pool_account::(USER_SEED + 1, origin_weight, Some(Perbill::from_percent(50))); - T::Staking::nominate( - &pool_origin1, + T::StakeAdapter::nominate( + 1, // NOTE: these don't really need to be validators. vec![account("random_validator", 0, USER_SEED)], )?; @@ -166,10 +166,7 @@ impl ListScenario { let (_, pool_origin2) = create_pool_account::(USER_SEED + 2, origin_weight, Some(Perbill::from_percent(50))); - T::Staking::nominate( - &pool_origin2, - vec![account("random_validator", 0, USER_SEED)].clone(), - )?; + T::StakeAdapter::nominate(2, vec![account("random_validator", 0, USER_SEED)].clone())?; // Find a destination weight that will trigger the worst case scenario let dest_weight_as_vote = ::VoterList::score_update_worst_case( @@ -184,7 +181,7 @@ impl ListScenario { let (_, pool_dest1) = create_pool_account::(USER_SEED + 3, dest_weight, Some(Perbill::from_percent(50))); - T::Staking::nominate(&pool_dest1, vec![account("random_validator", 0, USER_SEED)])?; + T::StakeAdapter::nominate(3, vec![account("random_validator", 0, USER_SEED)])?; let weight_of = pallet_staking::Pallet::::weight_of_fn(); assert_eq!(vote_to_balance::(weight_of(&pool_origin1)).unwrap(), origin_weight); @@ -210,11 +207,11 @@ impl ListScenario { self.origin1_member = Some(joiner.clone()); CurrencyOf::::set_balance(&joiner, amount * 2u32.into()); - let original_bonded = T::Staking::active_stake(&self.origin1).unwrap(); + let original_bonded = T::StakeAdapter::active_stake(1); // Unbond `amount` from the underlying pool account so when the member joins // we will maintain `current_bonded`. - T::Staking::unbond(&self.origin1, amount).expect("the pool was created in `Self::new`."); + T::StakeAdapter::unbond(1, amount).expect("the pool was created in `Self::new`."); // Account pool points for the unbonded balance. BondedPools::::mutate(&1, |maybe_pool| { @@ -243,7 +240,7 @@ frame_benchmarking::benchmarks! { // setup the worst case list scenario. let scenario = ListScenario::::new(origin_weight, true)?; assert_eq!( - T::Staking::active_stake(&scenario.origin1).unwrap(), + T::StakeAdapter::active_stake(1), origin_weight ); @@ -258,7 +255,7 @@ frame_benchmarking::benchmarks! { verify { assert_eq!(CurrencyOf::::balance(&joiner), joiner_free - max_additional); assert_eq!( - T::Staking::active_stake(&scenario.origin1).unwrap(), + T::StakeAdapter::active_stake(1), scenario.dest_weight ); } @@ -273,7 +270,7 @@ frame_benchmarking::benchmarks! { }: bond_extra(RuntimeOrigin::Signed(scenario.creator1.clone()), BondExtra::FreeBalance(extra)) verify { assert!( - T::Staking::active_stake(&scenario.origin1).unwrap() >= + T::StakeAdapter::active_stake(1) >= scenario.dest_weight ); } @@ -297,7 +294,7 @@ frame_benchmarking::benchmarks! { verify { // commission of 50% deducted here. assert!( - T::Staking::active_stake(&scenario.origin1).unwrap() >= + T::StakeAdapter::active_stake(1) >= scenario.dest_weight / 2u32.into() ); } @@ -351,7 +348,7 @@ frame_benchmarking::benchmarks! { whitelist_account!(member_id); }: _(RuntimeOrigin::Signed(member_id.clone()), member_id_lookup, all_points) verify { - let bonded_after = T::Staking::active_stake(&scenario.origin1).unwrap(); + let bonded_after = T::StakeAdapter::active_stake(1); // We at least went down to the destination bag assert!(bonded_after <= scenario.dest_weight); let member = PoolMembers::::get( @@ -360,7 +357,7 @@ frame_benchmarking::benchmarks! { .unwrap(); assert_eq!( member.unbonding_eras.keys().cloned().collect::>(), - vec![0 + T::Staking::bonding_duration()] + vec![0 + T::StakeAdapter::bonding_duration()] ); assert_eq!( member.unbonding_eras.values().cloned().collect::>(), @@ -382,7 +379,7 @@ frame_benchmarking::benchmarks! { // Sanity check join worked assert_eq!( - T::Staking::active_stake(&pool_account).unwrap(), + T::StakeAdapter::active_stake(1), min_create_bond + min_join_bond ); assert_eq!(CurrencyOf::::balance(&joiner), min_join_bond); @@ -392,7 +389,7 @@ frame_benchmarking::benchmarks! { // Sanity check that unbond worked assert_eq!( - T::Staking::active_stake(&pool_account).unwrap(), + T::StakeAdapter::active_stake(1), min_create_bond ); assert_eq!(pallet_staking::Ledger::::get(&pool_account).unwrap().unlocking.len(), 1); @@ -425,7 +422,7 @@ frame_benchmarking::benchmarks! { // Sanity check join worked assert_eq!( - T::Staking::active_stake(&pool_account).unwrap(), + T::StakeAdapter::active_stake(1), min_create_bond + min_join_bond ); assert_eq!(CurrencyOf::::balance(&joiner), min_join_bond); @@ -436,7 +433,7 @@ frame_benchmarking::benchmarks! { // Sanity check that unbond worked assert_eq!( - T::Staking::active_stake(&pool_account).unwrap(), + T::StakeAdapter::active_stake(1), min_create_bond ); assert_eq!(pallet_staking::Ledger::::get(&pool_account).unwrap().unlocking.len(), 1); @@ -482,7 +479,7 @@ frame_benchmarking::benchmarks! { // Sanity check that unbond worked assert_eq!( - T::Staking::active_stake(&pool_account).unwrap(), + T::StakeAdapter::active_stake(1), Zero::zero() ); assert_eq!( @@ -562,8 +559,8 @@ frame_benchmarking::benchmarks! { } ); assert_eq!( - T::Staking::active_stake(&Pools::::create_bonded_account(1)), - Ok(min_create_bond) + T::StakeAdapter::active_stake(1), + min_create_bond ); } @@ -602,8 +599,8 @@ frame_benchmarking::benchmarks! { } ); assert_eq!( - T::Staking::active_stake(&Pools::::create_bonded_account(1)), - Ok(min_create_bond) + T::StakeAdapter::active_stake(1), + min_create_bond ); } @@ -687,13 +684,13 @@ frame_benchmarking::benchmarks! { .map(|i| account("stash", USER_SEED, i)) .collect(); - assert_ok!(T::Staking::nominate(&pool_account, validators)); - assert!(T::Staking::nominations(&Pools::::create_bonded_account(1)).is_some()); + assert_ok!(T::StakeAdapter::nominate(1, validators)); + assert!(T::StakeAdapter::nominations(1).is_some()); whitelist_account!(depositor); }:_(RuntimeOrigin::Signed(depositor.clone()), 1) verify { - assert!(T::Staking::nominations(&Pools::::create_bonded_account(1)).is_none()); + assert!(T::StakeAdapter::nominations(1).is_none()); } set_commission { @@ -792,7 +789,7 @@ frame_benchmarking::benchmarks! { // Sanity check join worked assert_eq!( - T::Staking::active_stake(&pool_account).unwrap(), + T::StakeAdapter::active_stake(1), min_create_bond + min_join_bond ); }:_(RuntimeOrigin::Signed(joiner.clone()), ClaimPermission::PermissionlessAll) diff --git a/substrate/frame/nomination-pools/src/adapter.rs b/substrate/frame/nomination-pools/src/adapter.rs index 06580393cc17..46b005ce4dae 100644 --- a/substrate/frame/nomination-pools/src/adapter.rs +++ b/substrate/frame/nomination-pools/src/adapter.rs @@ -74,6 +74,9 @@ pub trait StakeStrategy { amount: Self::Balance, maybe_reporter: Option, ) -> DispatchResult; + + #[cfg(feature = "runtime-benchmarks")] + fn nominations(_: PoolId) -> Option>; } /// A staking strategy implementation that supports transfer based staking. @@ -186,6 +189,12 @@ impl, AccountId = T: ) -> DispatchResult { Err(Error::::Defensive(DefensiveError::DelegationUnsupported).into()) } + + #[cfg(feature = "runtime-benchmarks")] + fn nominations(pool: PoolId) -> Option> { + let pool_account = Pallet::::create_bonded_account(pool); + Staking::nominations(&pool_account) + } } /// A staking strategy implementation that supports delegation based staking. @@ -298,4 +307,10 @@ impl< let pool_account = Pallet::::create_bonded_account(pool); Staking::delegator_slash(&pool_account, who, amount, maybe_reporter) } + + #[cfg(feature = "runtime-benchmarks")] + fn nominations(pool: PoolId) -> Option> { + let pool_account = Pallet::::create_bonded_account(pool); + Staking::nominations(&pool_account) + } } From 09851d12e8ddfd5ecbe6d965151d8706ed28c936 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 31 Mar 2024 16:35:06 +0200 Subject: [PATCH 022/257] subscribe delegated staking to listen to staking events --- polkadot/runtime/westend/src/lib.rs | 2 +- .../frame/nomination-pools/test-delegate-stake/src/mock.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index ca9d59b3bf6c..6b4ddad90abf 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -693,7 +693,7 @@ impl pallet_staking::Config for Runtime { type HistoryDepth = frame_support::traits::ConstU32<84>; type MaxControllersInDeprecationBatch = MaxControllersInDeprecationBatch; type BenchmarkingConfig = runtime_common::StakingBenchmarkingConfig; - type EventListeners = NominationPools; + type EventListeners = (NominationPools, DelegatedStaking); type WeightInfo = weights::pallet_staking::WeightInfo; } diff --git a/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs b/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs index 0b4e59f4faa1..6749013aa76b 100644 --- a/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs +++ b/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs @@ -135,7 +135,7 @@ impl pallet_staking::Config for Runtime { type MaxUnlockingChunks = ConstU32<32>; type MaxControllersInDeprecationBatch = ConstU32<100>; type HistoryDepth = ConstU32<84>; - type EventListeners = Pools; + type EventListeners = (Pools, DelegatedStaking); type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; type WeightInfo = (); } From 193029c49058f665cac3de11bd41141d3c3f0cd3 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 31 Mar 2024 16:48:13 +0200 Subject: [PATCH 023/257] add integration tests for pool, staking and delegated staking --- Cargo.lock | 1 + polkadot/runtime/westend/Cargo.toml | 4 +- substrate/frame/delegated-staking/Cargo.toml | 4 + substrate/frame/delegated-staking/src/mock.rs | 33 +- .../frame/delegated-staking/src/tests.rs | 499 ++++++++++++++++++ .../frame/delegated-staking/src/types.rs | 2 - 6 files changed, 535 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5ba89d974485..cab9eb45cda5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9706,6 +9706,7 @@ dependencies = [ "frame-support", "frame-system", "pallet-balances", + "pallet-nomination-pools", "pallet-staking", "pallet-staking-reward-curve", "pallet-timestamp", diff --git a/polkadot/runtime/westend/Cargo.toml b/polkadot/runtime/westend/Cargo.toml index 0aeab51dfec4..c3de4f380705 100644 --- a/polkadot/runtime/westend/Cargo.toml +++ b/polkadot/runtime/westend/Cargo.toml @@ -161,6 +161,7 @@ std = [ "pallet-beefy/std", "pallet-collective/std", "pallet-conviction-voting/std", + "pallet-delegated-staking/std", "pallet-democracy/std", "pallet-election-provider-multi-phase/std", "pallet-election-provider-support-benchmarking?/std", @@ -190,7 +191,6 @@ std = [ "pallet-society/std", "pallet-staking-runtime-api/std", "pallet-staking/std", - "pallet-delegated-staking/std", "pallet-state-trie-migration/std", "pallet-sudo/std", "pallet-timestamp/std", @@ -246,6 +246,7 @@ runtime-benchmarks = [ "pallet-balances/runtime-benchmarks", "pallet-collective/runtime-benchmarks", "pallet-conviction-voting/runtime-benchmarks", + "pallet-delegated-staking/runtime-benchmarks", "pallet-democracy/runtime-benchmarks", "pallet-election-provider-multi-phase/runtime-benchmarks", "pallet-election-provider-support-benchmarking/runtime-benchmarks", @@ -271,7 +272,6 @@ runtime-benchmarks = [ "pallet-session-benchmarking/runtime-benchmarks", "pallet-society/runtime-benchmarks", "pallet-staking/runtime-benchmarks", - "pallet-delegated-staking/runtime-benchmarks", "pallet-state-trie-migration/runtime-benchmarks", "pallet-sudo/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", diff --git a/substrate/frame/delegated-staking/Cargo.toml b/substrate/frame/delegated-staking/Cargo.toml index cecaefbe779f..8e451f9d1c05 100644 --- a/substrate/frame/delegated-staking/Cargo.toml +++ b/substrate/frame/delegated-staking/Cargo.toml @@ -26,6 +26,7 @@ sp-io = { path = "../../primitives/io" } substrate-test-utils = { path = "../../test-utils" } sp-tracing = { path = "../../primitives/tracing" } pallet-staking = { path = "../staking" } +pallet-nomination-pools = { path = "../nomination-pools" } pallet-balances = { path = "../balances" } pallet-timestamp = { path = "../timestamp" } pallet-staking-reward-curve = { path = "../staking/reward-curve" } @@ -39,6 +40,7 @@ std = [ "frame-support/std", "frame-system/std", "pallet-balances/std", + "pallet-nomination-pools/std", "pallet-staking/std", "pallet-timestamp/std", "scale-info/std", @@ -53,6 +55,7 @@ runtime-benchmarks = [ "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", "pallet-balances/runtime-benchmarks", + "pallet-nomination-pools/runtime-benchmarks", "pallet-staking/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "sp-runtime/runtime-benchmarks", @@ -63,6 +66,7 @@ try-runtime = [ "frame-support/try-runtime", "frame-system/try-runtime", "pallet-balances/try-runtime", + "pallet-nomination-pools/try-runtime", "pallet-staking/try-runtime", "pallet-timestamp/try-runtime", "sp-runtime/try-runtime", diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs index f98e0c5843bb..95306398d029 100644 --- a/substrate/frame/delegated-staking/src/mock.rs +++ b/substrate/frame/delegated-staking/src/mock.rs @@ -132,7 +132,7 @@ impl pallet_staking::Config for Runtime { type NominationsQuota = pallet_staking::FixedNominationsQuota<16>; type MaxUnlockingChunks = ConstU32<32>; type MaxControllersInDeprecationBatch = ConstU32<100>; - type EventListeners = DelegatedStaking; + type EventListeners = (Pools, DelegatedStaking); type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; type WeightInfo = (); } @@ -164,6 +164,22 @@ impl Convert for U256ToBalance { parameter_types! { pub static MaxUnbonding: u32 = 8; + pub const PoolsPalletId: PalletId = PalletId(*b"py/nopls"); +} +impl pallet_nomination_pools::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); + type Currency = Balances; + type RuntimeFreezeReason = RuntimeFreezeReason; + type RewardCounter = sp_runtime::FixedU128; + type BalanceToU256 = BalanceToU256; + type U256ToBalance = U256ToBalance; + type PostUnbondingPoolsWindow = ConstU32<2>; + type PalletId = PoolsPalletId; + type MaxMetadataLen = ConstU32<256>; + type MaxUnbonding = MaxUnbonding; + type MaxPointsToBalance = frame_support::traits::ConstU8<10>; + type StakeAdapter = pallet_nomination_pools::adapter::DelegateStake; } frame_support::construct_runtime!( @@ -172,6 +188,7 @@ frame_support::construct_runtime!( Timestamp: pallet_timestamp, Balances: pallet_balances, Staking: pallet_staking, + Pools: pallet_nomination_pools, DelegatedStaking: delegated_staking, } ); @@ -298,16 +315,24 @@ pub(crate) fn get_agent(agent: &AccountId) -> Agent { Agent::::from(agent).expect("delegate should exist") } -#[allow(unused)] pub(crate) fn held_balance(who: &AccountId) -> Balance { Balances::balance_on_hold(&HoldReason::Delegating.into(), who) } parameter_types! { static ObservedEventsDelegatedStaking: usize = 0; + static ObservedEventsPools: usize = 0; +} +pub(crate) fn pool_events_since_last_call() -> Vec> { + let events = System::events() + .into_iter() + .map(|r| r.event) + .filter_map(|e| if let RuntimeEvent::Pools(inner) = e { Some(inner) } else { None }) + .collect::>(); + let already_seen = ObservedEventsPools::get(); + ObservedEventsPools::set(events.len()); + events.into_iter().skip(already_seen).collect() } - -#[allow(unused)] pub(crate) fn events_since_last_call() -> Vec> { let events = System::events() .into_iter() diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs index 715436153081..252ec3c599c3 100644 --- a/substrate/frame/delegated-staking/src/tests.rs +++ b/substrate/frame/delegated-staking/src/tests.rs @@ -20,6 +20,7 @@ use super::*; use crate::mock::*; use frame_support::{assert_noop, assert_ok, traits::fungible::InspectHold}; +use pallet_nomination_pools::{Error as PoolsError, Event as PoolsEvent}; use pallet_staking::Error as StakingError; #[test] @@ -551,3 +552,501 @@ mod staking_integration { }); } } + +// FIMXE(ank4n): Move these integration test to nomination pools. +mod pool_integration { + use super::*; + use pallet_nomination_pools::{BondExtra, BondedPools, PoolState}; + + #[test] + fn create_pool_test() { + ExtBuilder::default().build_and_execute(|| { + let creator: AccountId = 100; + fund(&creator, 500); + let delegate_amount = 200; + + // nothing held initially + assert_eq!(held_balance(&creator), 0); + + // create pool + assert_ok!(Pools::create( + RawOrigin::Signed(creator).into(), + delegate_amount, + creator, + creator, + creator + )); + + // correct amount is locked in depositor's account. + assert_eq!(held_balance(&creator), delegate_amount); + + let pool_account = Pools::create_bonded_account(1); + let delegatee = get_delegatee(&pool_account); + + // verify state + assert_eq!(delegatee.ledger.effective_balance(), delegate_amount); + assert_eq!(delegatee.available_to_bond(), 0); + assert_eq!(delegatee.total_unbonded(), 0); + }); + } + + #[test] + fn join_pool() { + ExtBuilder::default().build_and_execute(|| { + // create a pool + let pool_id = create_pool(100, 200); + // keep track of staked amount. + let mut staked_amount: Balance = 200; + + // fund delegator + let delegator: AccountId = 300; + fund(&delegator, 500); + // nothing held initially + assert_eq!(held_balance(&delegator), 0); + + // delegator joins pool + assert_ok!(Pools::join(RawOrigin::Signed(delegator).into(), 100, pool_id)); + staked_amount += 100; + + // correct amount is locked in depositor's account. + assert_eq!(held_balance(&delegator), 100); + + // delegator is not actively exposed to core staking. + assert_eq!(Staking::status(&delegator), Err(StakingError::::NotStash.into())); + + let pool_delegatee = get_delegatee(&Pools::create_bonded_account(1)); + // verify state + assert_eq!(pool_delegatee.ledger.effective_balance(), staked_amount); + assert_eq!(pool_delegatee.bonded_stake(), staked_amount); + assert_eq!(pool_delegatee.available_to_bond(), 0); + assert_eq!(pool_delegatee.total_unbonded(), 0); + + // let a bunch of delegators join this pool + for i in 301..350 { + fund(&i, 500); + assert_ok!(Pools::join(RawOrigin::Signed(i).into(), (100 + i).into(), pool_id)); + staked_amount += 100 + i; + assert_eq!(held_balance(&i), 100 + i); + } + + let pool_delegatee = pool_delegatee.refresh().unwrap(); + assert_eq!(pool_delegatee.ledger.effective_balance(), staked_amount); + assert_eq!(pool_delegatee.bonded_stake(), staked_amount); + assert_eq!(pool_delegatee.available_to_bond(), 0); + assert_eq!(pool_delegatee.total_unbonded(), 0); + }); + } + + #[test] + fn bond_extra_to_pool() { + ExtBuilder::default().build_and_execute(|| { + let pool_id = create_pool(100, 200); + add_delegators_to_pool(pool_id, (300..310).collect(), 100); + let mut staked_amount = 200 + 100 * 10; + assert_eq!(get_pool_delegatee(pool_id).bonded_stake(), staked_amount); + + // bond extra to pool + for i in 300..310 { + assert_ok!(Pools::bond_extra( + RawOrigin::Signed(i).into(), + BondExtra::FreeBalance(50) + )); + staked_amount += 50; + assert_eq!(get_pool_delegatee(pool_id).bonded_stake(), staked_amount); + } + }); + } + + #[test] + fn claim_pool_rewards() { + ExtBuilder::default().build_and_execute(|| { + let creator = 100; + let creator_stake = 1000; + let pool_id = create_pool(creator, creator_stake); + add_delegators_to_pool(pool_id, (300..310).collect(), 100); + add_delegators_to_pool(pool_id, (310..320).collect(), 200); + let total_staked = creator_stake + 100 * 10 + 200 * 10; + + // give some rewards + let reward_acc = Pools::create_reward_account(pool_id); + let reward_amount = 1000; + fund(&reward_acc, reward_amount); + + // claim rewards + for i in 300..320 { + let pre_balance = Balances::free_balance(i); + let delegator_staked_balance = held_balance(&i); + // payout reward + assert_ok!(Pools::claim_payout(RawOrigin::Signed(i).into())); + + let reward = Balances::free_balance(i) - pre_balance; + assert_eq!(reward, delegator_staked_balance * reward_amount / total_staked); + } + + // payout creator + let pre_balance = Balances::free_balance(creator); + assert_ok!(Pools::claim_payout(RawOrigin::Signed(creator).into())); + // verify they are paid out correctly + let reward = Balances::free_balance(creator) - pre_balance; + assert_eq!(reward, creator_stake * reward_amount / total_staked); + + // reward account should only have left minimum balance after paying out everyone. + assert_eq!(Balances::free_balance(reward_acc), ExistentialDeposit::get()); + }); + } + + #[test] + fn withdraw_from_pool() { + ExtBuilder::default().build_and_execute(|| { + // initial era + start_era(1); + + let pool_id = create_pool(100, 1000); + let bond_amount = 200; + add_delegators_to_pool(pool_id, (300..310).collect(), bond_amount); + let total_staked = 1000 + bond_amount * 10; + let pool_acc = Pools::create_bonded_account(pool_id); + + start_era(2); + // nothing to release yet. + assert_noop!( + Pools::withdraw_unbonded(RawOrigin::Signed(301).into(), 301, 0), + PoolsError::::SubPoolsNotFound + ); + + // 301 wants to unbond 50 in era 2, withdrawable in era 5. + assert_ok!(Pools::unbond(RawOrigin::Signed(301).into(), 301, 50)); + + // 302 wants to unbond 100 in era 3, withdrawable in era 6. + start_era(3); + assert_ok!(Pools::unbond(RawOrigin::Signed(302).into(), 302, 100)); + + // 303 wants to unbond 200 in era 4, withdrawable in era 7. + start_era(4); + assert_ok!(Pools::unbond(RawOrigin::Signed(303).into(), 303, 200)); + + // active stake is now reduced.. + let expected_active = total_staked - (50 + 100 + 200); + assert!(eq_stake(pool_acc, total_staked, expected_active)); + + // nothing to withdraw at era 4 + for i in 301..310 { + assert_noop!( + Pools::withdraw_unbonded(RawOrigin::Signed(i).into(), i, 0), + PoolsError::::CannotWithdrawAny + ); + } + + assert!(eq_stake(pool_acc, total_staked, expected_active)); + + start_era(5); + // at era 5, 301 can withdraw. + + System::reset_events(); + let held_301 = held_balance(&301); + let free_301 = Balances::free_balance(301); + + assert_ok!(Pools::withdraw_unbonded(RawOrigin::Signed(301).into(), 301, 0)); + assert_eq!( + events_since_last_call(), + vec![Event::Released { delegatee: pool_acc, delegator: 301, amount: 50 }] + ); + assert_eq!( + pool_events_since_last_call(), + vec![PoolsEvent::Withdrawn { member: 301, pool_id, balance: 50, points: 50 }] + ); + assert_eq!(held_balance(&301), held_301 - 50); + assert_eq!(Balances::free_balance(301), free_301 + 50); + + start_era(7); + // era 7 both delegators can withdraw + assert_ok!(Pools::withdraw_unbonded(RawOrigin::Signed(302).into(), 302, 0)); + assert_ok!(Pools::withdraw_unbonded(RawOrigin::Signed(303).into(), 303, 0)); + + assert_eq!( + events_since_last_call(), + vec![ + Event::Released { delegatee: pool_acc, delegator: 302, amount: 100 }, + Event::Released { delegatee: pool_acc, delegator: 303, amount: 200 }, + ] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Withdrawn { member: 302, pool_id, balance: 100, points: 100 }, + PoolsEvent::Withdrawn { member: 303, pool_id, balance: 200, points: 200 }, + PoolsEvent::MemberRemoved { pool_id: 1, member: 303 }, + ] + ); + + // 303 is killed + assert!(!Delegators::::contains_key(303)); + }); + } + + #[test] + fn pool_withdraw_unbonded() { + ExtBuilder::default().build_and_execute(|| { + // initial era + start_era(1); + let pool_id = create_pool(100, 1000); + add_delegators_to_pool(pool_id, (300..310).collect(), 200); + + start_era(2); + // 1000 tokens to be unbonded in era 5. + for i in 300..310 { + assert_ok!(Pools::unbond(RawOrigin::Signed(i).into(), i, 100)); + } + + start_era(3); + // 500 tokens to be unbonded in era 6. + for i in 300..310 { + assert_ok!(Pools::unbond(RawOrigin::Signed(i).into(), i, 50)); + } + + start_era(5); + // withdraw pool should withdraw 1000 tokens + assert_ok!(Pools::pool_withdraw_unbonded(RawOrigin::Signed(100).into(), pool_id, 0)); + assert_eq!(get_pool_delegatee(pool_id).total_unbonded(), 1000); + + start_era(6); + // should withdraw 500 more + assert_ok!(Pools::pool_withdraw_unbonded(RawOrigin::Signed(100).into(), pool_id, 0)); + assert_eq!(get_pool_delegatee(pool_id).total_unbonded(), 1000 + 500); + + start_era(7); + // Nothing to withdraw, still at 1500. + assert_ok!(Pools::pool_withdraw_unbonded(RawOrigin::Signed(100).into(), pool_id, 0)); + assert_eq!(get_pool_delegatee(pool_id).total_unbonded(), 1500); + }); + } + + #[test] + fn update_nominations() { + ExtBuilder::default().build_and_execute(|| { + start_era(1); + // can't nominate for non-existent pool + assert_noop!( + Pools::nominate(RawOrigin::Signed(100).into(), 1, vec![99]), + PoolsError::::PoolNotFound + ); + + let pool_id = create_pool(100, 1000); + let pool_acc = Pools::create_bonded_account(pool_id); + assert_ok!(Pools::nominate(RawOrigin::Signed(100).into(), 1, vec![20, 21, 22])); + assert!(Staking::status(&pool_acc) == Ok(StakerStatus::Nominator(vec![20, 21, 22]))); + + start_era(3); + assert_ok!(Pools::nominate(RawOrigin::Signed(100).into(), 1, vec![18, 19, 22])); + assert!(Staking::status(&pool_acc) == Ok(StakerStatus::Nominator(vec![18, 19, 22]))); + }); + } + + #[test] + fn destroy_pool() { + ExtBuilder::default().build_and_execute(|| { + start_era(1); + let creator = 100; + let creator_stake = 1000; + let pool_id = create_pool(creator, creator_stake); + add_delegators_to_pool(pool_id, (300..310).collect(), 200); + + start_era(3); + // lets destroy the pool + assert_ok!(Pools::set_state( + RawOrigin::Signed(creator).into(), + pool_id, + PoolState::Destroying + )); + assert_ok!(Pools::chill(RawOrigin::Signed(creator).into(), pool_id)); + + // unbond all members by the creator/admin + for i in 300..310 { + assert_ok!(Pools::unbond(RawOrigin::Signed(creator).into(), i, 200)); + } + + start_era(6); + // withdraw all members by the creator/admin + for i in 300..310 { + assert_ok!(Pools::withdraw_unbonded(RawOrigin::Signed(creator).into(), i, 0)); + } + + // unbond creator + assert_ok!(Pools::unbond(RawOrigin::Signed(creator).into(), creator, creator_stake)); + + start_era(9); + System::reset_events(); + // Withdraw self + assert_ok!(Pools::withdraw_unbonded(RawOrigin::Signed(creator).into(), creator, 0)); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Withdrawn { + member: creator, + pool_id, + balance: creator_stake, + points: creator_stake, + }, + PoolsEvent::MemberRemoved { pool_id, member: creator }, + PoolsEvent::Destroyed { pool_id }, + ] + ); + + // Make sure all data is cleaned up. + assert_eq!(Delegatees::::contains_key(Pools::create_bonded_account(pool_id)), false); + assert_eq!(Delegators::::contains_key(creator), false); + for i in 300..310 { + assert_eq!(Delegators::::contains_key(i), false); + } + }); + } + + #[test] + fn pool_slashed() { + ExtBuilder::default().build_and_execute(|| { + start_era(1); + let creator = 100; + let creator_stake = 500; + let pool_id = create_pool(creator, creator_stake); + let delegator_stake = 100; + add_delegators_to_pool(pool_id, (300..306).collect(), delegator_stake); + let pool_acc = Pools::create_bonded_account(pool_id); + + let total_staked = creator_stake + delegator_stake * 6; + assert_eq!(Staking::stake(&pool_acc).unwrap().total, total_staked); + + // lets unbond a delegator each in next eras (2, 3, 4). + start_era(2); + assert_ok!(Pools::unbond(RawOrigin::Signed(300).into(), 300, delegator_stake)); + + start_era(3); + assert_ok!(Pools::unbond(RawOrigin::Signed(301).into(), 301, delegator_stake)); + + start_era(4); + assert_ok!(Pools::unbond(RawOrigin::Signed(302).into(), 302, delegator_stake)); + System::reset_events(); + + // slash the pool at era 3 + assert_eq!( + BondedPools::::get(1).unwrap().points, + creator_stake + delegator_stake * 6 - delegator_stake * 3 + ); + pallet_staking::slashing::do_slash::( + &pool_acc, + 500, + &mut Default::default(), + &mut Default::default(), + 3, + ); + + assert_eq!( + pool_events_since_last_call(), + vec![ + // 300 did not get slashed as all as it unbonded in an era before slash. + // 301 got slashed 50% of 100 = 50. + PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 6, balance: 50 }, + // 302 got slashed 50% of 100 = 50. + PoolsEvent::UnbondingPoolSlashed { pool_id: 1, era: 7, balance: 50 }, + // Rest of the pool slashed 50% of 800 = 400. + PoolsEvent::PoolSlashed { pool_id: 1, balance: 400 }, + ] + ); + + // slash is lazy and balance is still locked in user's accounts. + assert_eq!(held_balance(&creator), creator_stake); + for i in 300..306 { + assert_eq!(held_balance(&i), delegator_stake); + } + assert_eq!( + get_pool_delegatee(pool_id).ledger.effective_balance(), + Staking::total_stake(&pool_acc).unwrap() + ); + + // pending slash is book kept. + assert_eq!(get_pool_delegatee(pool_id).ledger.pending_slash, 500); + + // go in some distant future era. + start_era(10); + System::reset_events(); + + // 300 is not slashed and can withdraw all balance. + assert_ok!(Pools::withdraw_unbonded(RawOrigin::Signed(300).into(), 300, 1)); + assert_eq!( + events_since_last_call(), + vec![Event::Released { delegatee: pool_acc, delegator: 300, amount: 100 }] + ); + assert_eq!(get_pool_delegatee(pool_id).ledger.pending_slash, 500); + + // withdraw the other two delegators (301 and 302) who were unbonding. + for i in 301..=302 { + let pre_balance = Balances::free_balance(i); + let pre_pending_slash = get_pool_delegatee(pool_id).ledger.pending_slash; + assert_ok!(Pools::withdraw_unbonded(RawOrigin::Signed(i).into(), i, 0)); + assert_eq!( + events_since_last_call(), + vec![ + Event::Slashed { delegatee: pool_acc, delegator: i, amount: 50 }, + Event::Released { delegatee: pool_acc, delegator: i, amount: 50 }, + ] + ); + assert_eq!( + get_pool_delegatee(pool_id).ledger.pending_slash, + pre_pending_slash - 50 + ); + assert_eq!(held_balance(&i), 0); + assert_eq!(Balances::free_balance(i) - pre_balance, 50); + } + + // let's update all the slash + let slash_reporter = 99; + // give our reporter some balance. + fund(&slash_reporter, 100); + + for i in 303..306 { + let pre_pending_slash = get_pool_delegatee(pool_id).ledger.pending_slash; + assert_ok!(Pools::apply_slash(RawOrigin::Signed(slash_reporter).into(), i)); + + // each member is slashed 50% of 100 = 50. + assert_eq!( + get_pool_delegatee(pool_id).ledger.pending_slash, + pre_pending_slash - 50 + ); + // left with 50. + assert_eq!(held_balance(&i), 50); + } + // reporter is paid SlashRewardFraction of the slash, i.e. 10% of 50 = 5 + assert_eq!(Balances::free_balance(slash_reporter), 100 + 5 * 3); + // slash creator + assert_ok!(Pools::apply_slash(RawOrigin::Signed(slash_reporter).into(), creator)); + // all slash should be applied now. + assert_eq!(get_pool_delegatee(pool_id).ledger.pending_slash, 0); + // for creator, 50% of stake should be slashed (250), 10% of which should go to reporter + // (25). + assert_eq!(Balances::free_balance(slash_reporter), 115 + 25); + }); + } + + fn create_pool(creator: AccountId, amount: Balance) -> u32 { + fund(&creator, amount * 2); + assert_ok!(Pools::create( + RawOrigin::Signed(creator).into(), + amount, + creator, + creator, + creator + )); + + pallet_nomination_pools::LastPoolId::::get() + } + + fn add_delegators_to_pool(pool_id: u32, delegators: Vec, amount: Balance) { + for delegator in delegators { + fund(&delegator, amount * 2); + assert_ok!(Pools::join(RawOrigin::Signed(delegator).into(), amount, pool_id)); + } + } + + fn get_pool_delegatee(pool_id: u32) -> Delegatee { + get_delegatee(&Pools::create_bonded_account(pool_id)) + } +} diff --git a/substrate/frame/delegated-staking/src/types.rs b/substrate/frame/delegated-staking/src/types.rs index 70965374305c..c4b785aa73cc 100644 --- a/substrate/frame/delegated-staking/src/types.rs +++ b/substrate/frame/delegated-staking/src/types.rs @@ -284,7 +284,6 @@ impl Agent { /// Reloads self from storage. #[cfg(test)] - #[allow(unused)] pub(crate) fn refresh(&self) -> Result, DispatchError> { Self::from(&self.key) } @@ -294,7 +293,6 @@ impl Agent { /// This is similar to [Self::available_to_bond] except it also includes `unclaimed_withdrawals` /// of `Agent`. #[cfg(test)] - #[allow(unused)] pub(crate) fn total_unbonded(&self) -> BalanceOf { let bonded_stake = self.bonded_stake(); From 5c5a5d4e59904872fdf1b0b7fb8b93e57c1217a7 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 31 Mar 2024 17:15:15 +0200 Subject: [PATCH 024/257] some comments --- substrate/frame/nomination-pools/src/lib.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs index 9ef052409d17..cca74b4bfa01 100644 --- a/substrate/frame/nomination-pools/src/lib.rs +++ b/substrate/frame/nomination-pools/src/lib.rs @@ -547,6 +547,9 @@ impl PoolMember { /// Total balance of the member, both active and unbonding. /// Doesn't mutate state. + /// + /// Worst case, iterates over [`TotalUnbondingPools`] member unbonding pools to calculate member + /// balance. fn total_balance(&self) -> BalanceOf { let maybe_pool = BondedPool::::get(self.pool_id); if maybe_pool.is_none() { @@ -2211,9 +2214,13 @@ pub mod pallet { /// /// # Note /// - /// If the target is the depositor, the pool will be destroyed. + /// - If the target is the depositor, the pool will be destroyed. + /// - If the pool has any pending slash, we also try to slash the member before letting them + /// withdraw. This calculation can be expensive and is only defensive. In ideal scenario, + /// pool slashes must have been already applied via permissionless [`Call::apply_slash`]. #[pallet::call_index(5)] #[pallet::weight( + // fixme(ank4n): fix weight taking into account potential slashing. T::WeightInfo::withdraw_unbonded_kill(*num_slashing_spans) )] pub fn withdraw_unbonded( @@ -2808,7 +2815,7 @@ pub mod pallet { /// Apply a pending slash on a member. #[pallet::call_index(23)] - // FIXME(ank4n): fix weight info. + // FIXME(ank4n): fix weight. Depends on unbonding pool count for member_account. #[pallet::weight(T::WeightInfo::set_commission_claim_permission())] pub fn apply_slash( origin: OriginFor, @@ -2915,7 +2922,7 @@ impl Pallet { ); // NOTE: Defensively force set balance to zero. T::Currency::set_balance(&reward_account, Zero::zero()); - // fixme(ank4n): Can't really do this with delegated staking? + // With `DelegateStake` strategy, this won't do anything. T::Currency::set_balance(&bonded_pool.bonded_account(), Zero::zero()); Self::deposit_event(Event::::Destroyed { pool_id: bonded_pool.id }); From 6ba6ee1db825c1da076eab9a5a990555f69c4825 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 31 Mar 2024 20:01:40 +0200 Subject: [PATCH 025/257] fix rebase errors --- .../frame/delegated-staking/src/tests.rs | 73 +++++++++---------- .../frame/nomination-pools/src/adapter.rs | 4 +- 2 files changed, 38 insertions(+), 39 deletions(-) diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs index 252ec3c599c3..08856e13e4fa 100644 --- a/substrate/frame/delegated-staking/src/tests.rs +++ b/substrate/frame/delegated-staking/src/tests.rs @@ -553,7 +553,6 @@ mod staking_integration { } } -// FIMXE(ank4n): Move these integration test to nomination pools. mod pool_integration { use super::*; use pallet_nomination_pools::{BondExtra, BondedPools, PoolState}; @@ -581,12 +580,12 @@ mod pool_integration { assert_eq!(held_balance(&creator), delegate_amount); let pool_account = Pools::create_bonded_account(1); - let delegatee = get_delegatee(&pool_account); + let agent = get_agent(&pool_account); // verify state - assert_eq!(delegatee.ledger.effective_balance(), delegate_amount); - assert_eq!(delegatee.available_to_bond(), 0); - assert_eq!(delegatee.total_unbonded(), 0); + assert_eq!(agent.ledger.effective_balance(), delegate_amount); + assert_eq!(agent.available_to_bond(), 0); + assert_eq!(agent.total_unbonded(), 0); }); } @@ -614,12 +613,12 @@ mod pool_integration { // delegator is not actively exposed to core staking. assert_eq!(Staking::status(&delegator), Err(StakingError::::NotStash.into())); - let pool_delegatee = get_delegatee(&Pools::create_bonded_account(1)); + let pool_agent = get_agent(&Pools::create_bonded_account(1)); // verify state - assert_eq!(pool_delegatee.ledger.effective_balance(), staked_amount); - assert_eq!(pool_delegatee.bonded_stake(), staked_amount); - assert_eq!(pool_delegatee.available_to_bond(), 0); - assert_eq!(pool_delegatee.total_unbonded(), 0); + assert_eq!(pool_agent.ledger.effective_balance(), staked_amount); + assert_eq!(pool_agent.bonded_stake(), staked_amount); + assert_eq!(pool_agent.available_to_bond(), 0); + assert_eq!(pool_agent.total_unbonded(), 0); // let a bunch of delegators join this pool for i in 301..350 { @@ -629,11 +628,11 @@ mod pool_integration { assert_eq!(held_balance(&i), 100 + i); } - let pool_delegatee = pool_delegatee.refresh().unwrap(); - assert_eq!(pool_delegatee.ledger.effective_balance(), staked_amount); - assert_eq!(pool_delegatee.bonded_stake(), staked_amount); - assert_eq!(pool_delegatee.available_to_bond(), 0); - assert_eq!(pool_delegatee.total_unbonded(), 0); + let pool_agent = pool_agent.refresh().unwrap(); + assert_eq!(pool_agent.ledger.effective_balance(), staked_amount); + assert_eq!(pool_agent.bonded_stake(), staked_amount); + assert_eq!(pool_agent.available_to_bond(), 0); + assert_eq!(pool_agent.total_unbonded(), 0); }); } @@ -643,7 +642,7 @@ mod pool_integration { let pool_id = create_pool(100, 200); add_delegators_to_pool(pool_id, (300..310).collect(), 100); let mut staked_amount = 200 + 100 * 10; - assert_eq!(get_pool_delegatee(pool_id).bonded_stake(), staked_amount); + assert_eq!(get_pool_agent(pool_id).bonded_stake(), staked_amount); // bond extra to pool for i in 300..310 { @@ -652,7 +651,7 @@ mod pool_integration { BondExtra::FreeBalance(50) )); staked_amount += 50; - assert_eq!(get_pool_delegatee(pool_id).bonded_stake(), staked_amount); + assert_eq!(get_pool_agent(pool_id).bonded_stake(), staked_amount); } }); } @@ -749,7 +748,7 @@ mod pool_integration { assert_ok!(Pools::withdraw_unbonded(RawOrigin::Signed(301).into(), 301, 0)); assert_eq!( events_since_last_call(), - vec![Event::Released { delegatee: pool_acc, delegator: 301, amount: 50 }] + vec![Event::Released { agent: pool_acc, delegator: 301, amount: 50 }] ); assert_eq!( pool_events_since_last_call(), @@ -766,8 +765,8 @@ mod pool_integration { assert_eq!( events_since_last_call(), vec![ - Event::Released { delegatee: pool_acc, delegator: 302, amount: 100 }, - Event::Released { delegatee: pool_acc, delegator: 303, amount: 200 }, + Event::Released { agent: pool_acc, delegator: 302, amount: 100 }, + Event::Released { agent: pool_acc, delegator: 303, amount: 200 }, ] ); assert_eq!( @@ -807,17 +806,17 @@ mod pool_integration { start_era(5); // withdraw pool should withdraw 1000 tokens assert_ok!(Pools::pool_withdraw_unbonded(RawOrigin::Signed(100).into(), pool_id, 0)); - assert_eq!(get_pool_delegatee(pool_id).total_unbonded(), 1000); + assert_eq!(get_pool_agent(pool_id).total_unbonded(), 1000); start_era(6); // should withdraw 500 more assert_ok!(Pools::pool_withdraw_unbonded(RawOrigin::Signed(100).into(), pool_id, 0)); - assert_eq!(get_pool_delegatee(pool_id).total_unbonded(), 1000 + 500); + assert_eq!(get_pool_agent(pool_id).total_unbonded(), 1000 + 500); start_era(7); // Nothing to withdraw, still at 1500. assert_ok!(Pools::pool_withdraw_unbonded(RawOrigin::Signed(100).into(), pool_id, 0)); - assert_eq!(get_pool_delegatee(pool_id).total_unbonded(), 1500); + assert_eq!(get_pool_agent(pool_id).total_unbonded(), 1500); }); } @@ -893,7 +892,7 @@ mod pool_integration { ); // Make sure all data is cleaned up. - assert_eq!(Delegatees::::contains_key(Pools::create_bonded_account(pool_id)), false); + assert_eq!(Agents::::contains_key(Pools::create_bonded_account(pool_id)), false); assert_eq!(Delegators::::contains_key(creator), false); for i in 300..310 { assert_eq!(Delegators::::contains_key(i), false); @@ -958,12 +957,12 @@ mod pool_integration { assert_eq!(held_balance(&i), delegator_stake); } assert_eq!( - get_pool_delegatee(pool_id).ledger.effective_balance(), + get_pool_agent(pool_id).ledger.effective_balance(), Staking::total_stake(&pool_acc).unwrap() ); // pending slash is book kept. - assert_eq!(get_pool_delegatee(pool_id).ledger.pending_slash, 500); + assert_eq!(get_pool_agent(pool_id).ledger.pending_slash, 500); // go in some distant future era. start_era(10); @@ -973,24 +972,24 @@ mod pool_integration { assert_ok!(Pools::withdraw_unbonded(RawOrigin::Signed(300).into(), 300, 1)); assert_eq!( events_since_last_call(), - vec![Event::Released { delegatee: pool_acc, delegator: 300, amount: 100 }] + vec![Event::Released { agent: pool_acc, delegator: 300, amount: 100 }] ); - assert_eq!(get_pool_delegatee(pool_id).ledger.pending_slash, 500); + assert_eq!(get_pool_agent(pool_id).ledger.pending_slash, 500); // withdraw the other two delegators (301 and 302) who were unbonding. for i in 301..=302 { let pre_balance = Balances::free_balance(i); - let pre_pending_slash = get_pool_delegatee(pool_id).ledger.pending_slash; + let pre_pending_slash = get_pool_agent(pool_id).ledger.pending_slash; assert_ok!(Pools::withdraw_unbonded(RawOrigin::Signed(i).into(), i, 0)); assert_eq!( events_since_last_call(), vec![ - Event::Slashed { delegatee: pool_acc, delegator: i, amount: 50 }, - Event::Released { delegatee: pool_acc, delegator: i, amount: 50 }, + Event::Slashed { agent: pool_acc, delegator: i, amount: 50 }, + Event::Released { agent: pool_acc, delegator: i, amount: 50 }, ] ); assert_eq!( - get_pool_delegatee(pool_id).ledger.pending_slash, + get_pool_agent(pool_id).ledger.pending_slash, pre_pending_slash - 50 ); assert_eq!(held_balance(&i), 0); @@ -1003,12 +1002,12 @@ mod pool_integration { fund(&slash_reporter, 100); for i in 303..306 { - let pre_pending_slash = get_pool_delegatee(pool_id).ledger.pending_slash; + let pre_pending_slash = get_pool_agent(pool_id).ledger.pending_slash; assert_ok!(Pools::apply_slash(RawOrigin::Signed(slash_reporter).into(), i)); // each member is slashed 50% of 100 = 50. assert_eq!( - get_pool_delegatee(pool_id).ledger.pending_slash, + get_pool_agent(pool_id).ledger.pending_slash, pre_pending_slash - 50 ); // left with 50. @@ -1019,7 +1018,7 @@ mod pool_integration { // slash creator assert_ok!(Pools::apply_slash(RawOrigin::Signed(slash_reporter).into(), creator)); // all slash should be applied now. - assert_eq!(get_pool_delegatee(pool_id).ledger.pending_slash, 0); + assert_eq!(get_pool_agent(pool_id).ledger.pending_slash, 0); // for creator, 50% of stake should be slashed (250), 10% of which should go to reporter // (25). assert_eq!(Balances::free_balance(slash_reporter), 115 + 25); @@ -1046,7 +1045,7 @@ mod pool_integration { } } - fn get_pool_delegatee(pool_id: u32) -> Delegatee { - get_delegatee(&Pools::create_bonded_account(pool_id)) + fn get_pool_agent(pool_id: u32) -> Agent { + get_agent(&Pools::create_bonded_account(pool_id)) } } diff --git a/substrate/frame/nomination-pools/src/adapter.rs b/substrate/frame/nomination-pools/src/adapter.rs index 46b005ce4dae..f6ae82ec122d 100644 --- a/substrate/frame/nomination-pools/src/adapter.rs +++ b/substrate/frame/nomination-pools/src/adapter.rs @@ -224,12 +224,12 @@ impl< fn transferable_balance(pool: PoolId) -> BalanceOf { let pool_account = Pallet::::create_bonded_account(pool); - Staking::delegatee_balance(&pool_account).saturating_sub(Self::active_stake(pool)) + Staking::agent_balance(&pool_account).saturating_sub(Self::active_stake(pool)) } fn total_balance(pool: PoolId) -> BalanceOf { let pool_account = Pallet::::create_bonded_account(pool); - Staking::delegatee_balance(&pool_account) + Staking::agent_balance(&pool_account) } fn member_delegation_balance(member_account: &T::AccountId) -> Staking::Balance { From cebea1ab09304a90e5fd35c6c7ea97547e2098ac Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 31 Mar 2024 21:31:32 +0200 Subject: [PATCH 026/257] fmt --- substrate/frame/delegated-staking/src/tests.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs index 08856e13e4fa..464a496f6786 100644 --- a/substrate/frame/delegated-staking/src/tests.rs +++ b/substrate/frame/delegated-staking/src/tests.rs @@ -988,10 +988,7 @@ mod pool_integration { Event::Released { agent: pool_acc, delegator: i, amount: 50 }, ] ); - assert_eq!( - get_pool_agent(pool_id).ledger.pending_slash, - pre_pending_slash - 50 - ); + assert_eq!(get_pool_agent(pool_id).ledger.pending_slash, pre_pending_slash - 50); assert_eq!(held_balance(&i), 0); assert_eq!(Balances::free_balance(i) - pre_balance, 50); } @@ -1006,10 +1003,7 @@ mod pool_integration { assert_ok!(Pools::apply_slash(RawOrigin::Signed(slash_reporter).into(), i)); // each member is slashed 50% of 100 = 50. - assert_eq!( - get_pool_agent(pool_id).ledger.pending_slash, - pre_pending_slash - 50 - ); + assert_eq!(get_pool_agent(pool_id).ledger.pending_slash, pre_pending_slash - 50); // left with 50. assert_eq!(held_balance(&i), 50); } From ea0c7e911992f814c9c9260279b6af667f606981 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 31 Mar 2024 21:46:17 +0200 Subject: [PATCH 027/257] clippy warnings --- substrate/frame/delegated-staking/src/tests.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs index 464a496f6786..21ebea813997 100644 --- a/substrate/frame/delegated-staking/src/tests.rs +++ b/substrate/frame/delegated-staking/src/tests.rs @@ -623,7 +623,7 @@ mod pool_integration { // let a bunch of delegators join this pool for i in 301..350 { fund(&i, 500); - assert_ok!(Pools::join(RawOrigin::Signed(i).into(), (100 + i).into(), pool_id)); + assert_ok!(Pools::join(RawOrigin::Signed(i).into(), (100 + i), pool_id)); staked_amount += 100 + i; assert_eq!(held_balance(&i), 100 + i); } @@ -892,10 +892,10 @@ mod pool_integration { ); // Make sure all data is cleaned up. - assert_eq!(Agents::::contains_key(Pools::create_bonded_account(pool_id)), false); - assert_eq!(Delegators::::contains_key(creator), false); + assert!(!Agents::::contains_key(Pools::create_bonded_account(pool_id))); + assert!(!Delegators::::contains_key(creator)); for i in 300..310 { - assert_eq!(Delegators::::contains_key(i), false); + assert!(!Delegators::::contains_key(i)); } }); } From f00352cbc890cae1bbe29bfb0ced8dff79942626 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 31 Mar 2024 21:52:05 +0200 Subject: [PATCH 028/257] fix another clippy warning --- substrate/frame/delegated-staking/src/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs index 21ebea813997..fae0b7e8b743 100644 --- a/substrate/frame/delegated-staking/src/tests.rs +++ b/substrate/frame/delegated-staking/src/tests.rs @@ -623,7 +623,7 @@ mod pool_integration { // let a bunch of delegators join this pool for i in 301..350 { fund(&i, 500); - assert_ok!(Pools::join(RawOrigin::Signed(i).into(), (100 + i), pool_id)); + assert_ok!(Pools::join(RawOrigin::Signed(i).into(), 100 + i, pool_id)); staked_amount += 100 + i; assert_eq!(held_balance(&i), 100 + i); } From 4ca3dec2e7fa88f498d55ad7e73c47e175103eb8 Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 31 Mar 2024 23:05:43 +0200 Subject: [PATCH 029/257] propagate try runtime to delegate staking pallet --- polkadot/runtime/westend/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/polkadot/runtime/westend/Cargo.toml b/polkadot/runtime/westend/Cargo.toml index c3de4f380705..189223eebda5 100644 --- a/polkadot/runtime/westend/Cargo.toml +++ b/polkadot/runtime/westend/Cargo.toml @@ -307,6 +307,7 @@ try-runtime = [ "pallet-beefy/try-runtime", "pallet-collective/try-runtime", "pallet-conviction-voting/try-runtime", + "pallet-delegated-staking/try-runtime", "pallet-democracy/try-runtime", "pallet-election-provider-multi-phase/try-runtime", "pallet-elections-phragmen/try-runtime", From 0cb78680959fc492fd42bb91810a9d0a1d32d11d Mon Sep 17 00:00:00 2001 From: Ankan Date: Sun, 31 Mar 2024 23:30:33 +0200 Subject: [PATCH 030/257] docs --- .../frame/nomination-pools/src/adapter.rs | 32 +++++++++++++++---- substrate/frame/nomination-pools/src/lib.rs | 2 +- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/substrate/frame/nomination-pools/src/adapter.rs b/substrate/frame/nomination-pools/src/adapter.rs index f6ae82ec122d..875098641b5a 100644 --- a/substrate/frame/nomination-pools/src/adapter.rs +++ b/substrate/frame/nomination-pools/src/adapter.rs @@ -27,47 +27,65 @@ pub trait StakeStrategy { type Balance: frame_support::traits::tokens::Balance; type AccountId: Clone + sp_std::fmt::Debug; + /// See [`StakingInterface::bonding_duration`]. fn bonding_duration() -> EraIndex; + + /// See [`StakingInterface::current_era`]. fn current_era() -> EraIndex; + + /// See [`StakingInterface::minimum_nominator_bond`]. fn minimum_nominator_bond() -> Self::Balance; - /// Transferable balance of the pool. - /// - /// This is the amount that can be withdrawn from the pool. + /// Balance that can be transferred from pool account to member. /// - /// Does not include reward account. + /// This is part of the pool balance that is not actively staked. That is, tokens that are + /// in unbonding period or unbonded. fn transferable_balance(id: PoolId) -> Self::Balance; /// Total balance of the pool including amount that is actively staked. fn total_balance(id: PoolId) -> Self::Balance; + + /// Amount of tokens delegated by the member. fn member_delegation_balance(member_account: &Self::AccountId) -> Self::Balance; + /// See [`StakingInterface::active_stake`]. fn active_stake(pool: PoolId) -> Self::Balance; + + /// See [`StakingInterface::total_stake`]. fn total_stake(pool: PoolId) -> Self::Balance; + /// See [`StakingInterface::nominate`]. fn nominate(pool_id: PoolId, validators: Vec) -> DispatchResult; + /// See [`StakingInterface::chill`]. fn chill(pool_id: PoolId) -> DispatchResult; - fn bond( + /// Pledge `amount` towards staking pool with `pool_id` and update the pool bond. Also see + /// [`StakingInterface::bond`]. + fn pledge_bond( who: &Self::AccountId, pool_id: PoolId, amount: Self::Balance, bond_type: BondType, ) -> DispatchResult; + /// See [`StakingInterface::unbond`]. fn unbond(pool_id: PoolId, amount: Self::Balance) -> DispatchResult; + /// See [`StakingInterface::withdraw_unbonded`]. fn withdraw_unbonded(pool_id: PoolId, num_slashing_spans: u32) -> Result; + /// Withdraw funds from pool account to member account. fn member_withdraw( who: &Self::AccountId, pool: PoolId, amount: Self::Balance, ) -> DispatchResult; + /// Check if there is any pending slash for the pool. fn has_pending_slash(pool: PoolId) -> bool; + /// Slash the member account with `amount` against pending slashes for the pool. fn member_slash( who: &Self::AccountId, pool: PoolId, @@ -136,7 +154,7 @@ impl, AccountId = T: Staking::chill(&pool_account) } - fn bond( + fn pledge_bond( who: &T::AccountId, pool: PoolId, amount: BalanceOf, @@ -256,7 +274,7 @@ impl< Staking::chill(&pool_account) } - fn bond( + fn pledge_bond( who: &T::AccountId, pool: PoolId, amount: BalanceOf, diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs index cca74b4bfa01..4d255dae3b02 100644 --- a/substrate/frame/nomination-pools/src/lib.rs +++ b/substrate/frame/nomination-pools/src/lib.rs @@ -1252,7 +1252,7 @@ impl BondedPool { // ratio will be wrong. let points_issued = self.issue(amount); - T::StakeAdapter::bond(who, self.id, amount, ty)?; + T::StakeAdapter::pledge_bond(who, self.id, amount, ty)?; TotalValueLocked::::mutate(|tvl| { tvl.saturating_accrue(amount); }); From fcb5397f888e2a8efb04a8f385f1b1c6a9d60d2f Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 1 Apr 2024 00:11:26 +0200 Subject: [PATCH 031/257] refactor staking strategy --- .../frame/nomination-pools/src/adapter.rs | 233 +++++++----------- substrate/frame/nomination-pools/src/lib.rs | 60 +++-- .../frame/nomination-pools/src/migration.rs | 4 +- 3 files changed, 124 insertions(+), 173 deletions(-) diff --git a/substrate/frame/nomination-pools/src/adapter.rs b/substrate/frame/nomination-pools/src/adapter.rs index 875098641b5a..88a2f4370f9b 100644 --- a/substrate/frame/nomination-pools/src/adapter.rs +++ b/substrate/frame/nomination-pools/src/adapter.rs @@ -26,75 +26,103 @@ use sp_staking::DelegatedStakeInterface; pub trait StakeStrategy { type Balance: frame_support::traits::tokens::Balance; type AccountId: Clone + sp_std::fmt::Debug; + type CoreStaking: StakingInterface; /// See [`StakingInterface::bonding_duration`]. - fn bonding_duration() -> EraIndex; + fn bonding_duration() -> EraIndex { + Self::CoreStaking::bonding_duration() + } /// See [`StakingInterface::current_era`]. - fn current_era() -> EraIndex; + fn current_era() -> EraIndex { + Self::CoreStaking::current_era() + } /// See [`StakingInterface::minimum_nominator_bond`]. - fn minimum_nominator_bond() -> Self::Balance; + fn minimum_nominator_bond() -> Self::Balance { + Self::CoreStaking::minimum_nominator_bond() + } /// Balance that can be transferred from pool account to member. /// /// This is part of the pool balance that is not actively staked. That is, tokens that are /// in unbonding period or unbonded. - fn transferable_balance(id: PoolId) -> Self::Balance; + fn transferable_balance(pool_account: &Self::AccountId) -> Self::Balance; /// Total balance of the pool including amount that is actively staked. - fn total_balance(id: PoolId) -> Self::Balance; + fn total_balance(pool_account: &Self::AccountId) -> Self::Balance; /// Amount of tokens delegated by the member. fn member_delegation_balance(member_account: &Self::AccountId) -> Self::Balance; /// See [`StakingInterface::active_stake`]. - fn active_stake(pool: PoolId) -> Self::Balance; + fn active_stake(pool_account: &Self::AccountId) -> Self::Balance { + Self::CoreStaking::active_stake(pool_account).unwrap_or_default() + } /// See [`StakingInterface::total_stake`]. - fn total_stake(pool: PoolId) -> Self::Balance; + fn total_stake(pool_account: &Self::AccountId) -> Self::Balance { + Self::CoreStaking::total_stake(pool_account).unwrap_or_default() + } /// See [`StakingInterface::nominate`]. - fn nominate(pool_id: PoolId, validators: Vec) -> DispatchResult; + fn nominate( + pool_account: &Self::AccountId, + validators: Vec, + ) -> DispatchResult { + Self::CoreStaking::nominate(pool_account, validators) + } /// See [`StakingInterface::chill`]. - fn chill(pool_id: PoolId) -> DispatchResult; + fn chill(pool_account: &Self::AccountId) -> DispatchResult { + Self::CoreStaking::chill(pool_account) + } /// Pledge `amount` towards staking pool with `pool_id` and update the pool bond. Also see /// [`StakingInterface::bond`]. fn pledge_bond( who: &Self::AccountId, - pool_id: PoolId, + pool_account: &Self::AccountId, + reward_account: &Self::AccountId, amount: Self::Balance, bond_type: BondType, ) -> DispatchResult; /// See [`StakingInterface::unbond`]. - fn unbond(pool_id: PoolId, amount: Self::Balance) -> DispatchResult; + fn unbond(pool_account: &Self::AccountId, amount: Self::Balance) -> DispatchResult { + Self::CoreStaking::unbond(pool_account, amount) + } /// See [`StakingInterface::withdraw_unbonded`]. - fn withdraw_unbonded(pool_id: PoolId, num_slashing_spans: u32) -> Result; + fn withdraw_unbonded( + pool_account: &Self::AccountId, + num_slashing_spans: u32, + ) -> Result { + Self::CoreStaking::withdraw_unbonded(pool_account.clone(), num_slashing_spans) + } /// Withdraw funds from pool account to member account. fn member_withdraw( who: &Self::AccountId, - pool: PoolId, + pool_account: &Self::AccountId, amount: Self::Balance, ) -> DispatchResult; /// Check if there is any pending slash for the pool. - fn has_pending_slash(pool: PoolId) -> bool; + fn has_pending_slash(pool_account: &Self::AccountId) -> bool; /// Slash the member account with `amount` against pending slashes for the pool. fn member_slash( who: &Self::AccountId, - pool: PoolId, + pool_account: &Self::AccountId, amount: Self::Balance, maybe_reporter: Option, ) -> DispatchResult; #[cfg(feature = "runtime-benchmarks")] - fn nominations(_: PoolId) -> Option>; + fn nominations(pool_account: &Self::AccountId) -> Option> { + Self::CoreStaking::nominations(pool_account) + } } /// A staking strategy implementation that supports transfer based staking. @@ -108,25 +136,14 @@ impl, AccountId = T: { type Balance = BalanceOf; type AccountId = T::AccountId; + type CoreStaking = Staking; - fn bonding_duration() -> EraIndex { - Staking::bonding_duration() - } - fn current_era() -> EraIndex { - Staking::current_era() - } - fn minimum_nominator_bond() -> Staking::Balance { - Staking::minimum_nominator_bond() + fn transferable_balance(pool_account: &Self::AccountId) -> BalanceOf { + T::Currency::balance(pool_account).saturating_sub(Self::active_stake(pool_account)) } - fn transferable_balance(pool: PoolId) -> BalanceOf { - let pool_account = Pallet::::create_bonded_account(pool); - T::Currency::balance(&pool_account).saturating_sub(Self::active_stake(pool)) - } - - fn total_balance(pool: PoolId) -> BalanceOf { - let pool_account = Pallet::::create_bonded_account(pool); - T::Currency::total_balance(&pool_account) + fn total_balance(pool_account: &Self::AccountId) -> BalanceOf { + T::Currency::total_balance(pool_account) } fn member_delegation_balance(_member_account: &T::AccountId) -> Staking::Balance { @@ -134,85 +151,50 @@ impl, AccountId = T: Zero::zero() } - fn active_stake(pool: PoolId) -> BalanceOf { - let pool_account = Pallet::::create_bonded_account(pool); - Staking::active_stake(&pool_account).unwrap_or_default() - } - - fn total_stake(pool: PoolId) -> Staking::Balance { - let pool_account = Pallet::::create_bonded_account(pool); - Staking::total_stake(&pool_account).unwrap_or_default() - } - - fn nominate(pool_id: PoolId, validators: Vec) -> DispatchResult { - let pool_account = Pallet::::create_bonded_account(pool_id); - Staking::nominate(&pool_account, validators) - } - - fn chill(pool_id: PoolId) -> DispatchResult { - let pool_account = Pallet::::create_bonded_account(pool_id); - Staking::chill(&pool_account) - } - fn pledge_bond( who: &T::AccountId, - pool: PoolId, + pool_account: &Self::AccountId, + reward_account: &Self::AccountId, amount: BalanceOf, bond_type: BondType, ) -> DispatchResult { - let pool_account = Pallet::::create_bonded_account(pool); - let reward_account = Pallet::::create_reward_account(pool); - match bond_type { BondType::Create => { // first bond - T::Currency::transfer(who, &pool_account, amount, Preservation::Expendable)?; - Staking::bond(&pool_account, amount, &reward_account) + T::Currency::transfer(who, pool_account, amount, Preservation::Expendable)?; + Staking::bond(pool_account, amount, &reward_account) }, BondType::Later => { // additional bond - T::Currency::transfer(who, &pool_account, amount, Preservation::Preserve)?; - Staking::bond_extra(&pool_account, amount) + T::Currency::transfer(who, pool_account, amount, Preservation::Preserve)?; + Staking::bond_extra(pool_account, amount) }, } } - fn unbond(pool_id: PoolId, amount: Staking::Balance) -> DispatchResult { - let pool_account = Pallet::::create_bonded_account(pool_id); - Staking::unbond(&pool_account, amount) - } - - fn withdraw_unbonded(pool_id: PoolId, num_slashing_spans: u32) -> Result { - let pool_account = Pallet::::create_bonded_account(pool_id); - Staking::withdraw_unbonded(pool_account, num_slashing_spans) - } - - fn member_withdraw(who: &T::AccountId, pool: PoolId, amount: BalanceOf) -> DispatchResult { - let pool_account = Pallet::::create_bonded_account(pool); - T::Currency::transfer(&pool_account, &who, amount, Preservation::Expendable)?; + fn member_withdraw( + who: &T::AccountId, + pool_account: &Self::AccountId, + amount: BalanceOf, + ) -> DispatchResult { + T::Currency::transfer(pool_account, &who, amount, Preservation::Expendable)?; Ok(()) } - fn has_pending_slash(_pool: PoolId) -> bool { - // for transfer stake strategy, slashing is greedy + fn has_pending_slash(_: &Self::AccountId) -> bool { + // for transfer stake strategy, slashing is greedy and never deferred. false } fn member_slash( _who: &T::AccountId, - _pool: PoolId, + _pool: &Self::AccountId, _amount: Staking::Balance, _maybe_reporter: Option, ) -> DispatchResult { Err(Error::::Defensive(DefensiveError::DelegationUnsupported).into()) } - - #[cfg(feature = "runtime-benchmarks")] - fn nominations(pool: PoolId) -> Option> { - let pool_account = Pallet::::create_bonded_account(pool); - Staking::nominations(&pool_account) - } } /// A staking strategy implementation that supports delegation based staking. @@ -229,106 +211,57 @@ impl< { type Balance = BalanceOf; type AccountId = T::AccountId; + type CoreStaking = Staking; - fn bonding_duration() -> EraIndex { - Staking::bonding_duration() - } - fn current_era() -> EraIndex { - Staking::current_era() - } - fn minimum_nominator_bond() -> Staking::Balance { - Staking::minimum_nominator_bond() - } - - fn transferable_balance(pool: PoolId) -> BalanceOf { - let pool_account = Pallet::::create_bonded_account(pool); - Staking::agent_balance(&pool_account).saturating_sub(Self::active_stake(pool)) + fn transferable_balance(pool_account: &Self::AccountId) -> BalanceOf { + Staking::agent_balance(pool_account).saturating_sub(Self::active_stake(pool_account)) } - fn total_balance(pool: PoolId) -> BalanceOf { - let pool_account = Pallet::::create_bonded_account(pool); - Staking::agent_balance(&pool_account) + fn total_balance(pool_account: &Self::AccountId) -> BalanceOf { + Staking::agent_balance(pool_account) } fn member_delegation_balance(member_account: &T::AccountId) -> Staking::Balance { Staking::delegator_balance(member_account) } - fn active_stake(pool: PoolId) -> BalanceOf { - let pool_account = Pallet::::create_bonded_account(pool); - Staking::active_stake(&pool_account).unwrap_or_default() - } - - fn total_stake(pool: PoolId) -> Staking::Balance { - let pool_account = Pallet::::create_bonded_account(pool); - Staking::total_stake(&pool_account).unwrap_or_default() - } - - fn nominate(pool_id: PoolId, validators: Vec) -> DispatchResult { - let pool_account = Pallet::::create_bonded_account(pool_id); - Staking::nominate(&pool_account, validators) - } - - fn chill(pool_id: PoolId) -> DispatchResult { - let pool_account = Pallet::::create_bonded_account(pool_id); - Staking::chill(&pool_account) - } - fn pledge_bond( who: &T::AccountId, - pool: PoolId, + pool_account: &Self::AccountId, + reward_account: &Self::AccountId, amount: BalanceOf, bond_type: BondType, ) -> DispatchResult { - let pool_account = Pallet::::create_bonded_account(pool); - match bond_type { BondType::Create => { // first delegation - let reward_account = Pallet::::create_reward_account(pool); - Staking::delegate(who, &pool_account, &reward_account, amount) + Staking::delegate(who, pool_account, reward_account, amount) }, BondType::Later => { // additional delegation - Staking::delegate_extra(who, &pool_account, amount) + Staking::delegate_extra(who, pool_account, amount) }, } } - fn unbond(pool_id: PoolId, amount: Staking::Balance) -> DispatchResult { - let pool_account = Pallet::::create_bonded_account(pool_id); - Staking::unbond(&pool_account, amount) - } - - fn withdraw_unbonded(pool_id: PoolId, num_slashing_spans: u32) -> Result { - let pool_account = Pallet::::create_bonded_account(pool_id); - Staking::withdraw_unbonded(pool_account, num_slashing_spans) - } - - fn member_withdraw(who: &T::AccountId, pool: PoolId, amount: BalanceOf) -> DispatchResult { - let pool_account = Pallet::::create_bonded_account(pool); - Staking::withdraw_delegation(&who, &pool_account, amount) + fn member_withdraw( + who: &T::AccountId, + pool_account: &Self::AccountId, + amount: BalanceOf, + ) -> DispatchResult { + Staking::withdraw_delegation(&who, pool_account, amount) } - fn has_pending_slash(pool: PoolId) -> bool { - // for transfer stake strategy, slashing is greedy - let pool_account = Pallet::::create_bonded_account(pool); - Staking::has_pending_slash(&pool_account) + fn has_pending_slash(pool_account: &Self::AccountId) -> bool { + Staking::has_pending_slash(pool_account) } fn member_slash( who: &T::AccountId, - pool: PoolId, + pool_account: &Self::AccountId, amount: Staking::Balance, maybe_reporter: Option, ) -> DispatchResult { - let pool_account = Pallet::::create_bonded_account(pool); - Staking::delegator_slash(&pool_account, who, amount, maybe_reporter) - } - - #[cfg(feature = "runtime-benchmarks")] - fn nominations(pool: PoolId) -> Option> { - let pool_account = Pallet::::create_bonded_account(pool); - Staking::nominations(&pool_account) + Staking::delegator_slash(pool_account, who, amount, maybe_reporter) } } diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs index 4d255dae3b02..8d87fe8d492d 100644 --- a/substrate/frame/nomination-pools/src/lib.rs +++ b/substrate/frame/nomination-pools/src/lib.rs @@ -1001,7 +1001,7 @@ impl BondedPool { /// /// This is often used for bonding and issuing new funds into the pool. fn balance_to_point(&self, new_funds: BalanceOf) -> BalanceOf { - let bonded_balance = T::StakeAdapter::active_stake(self.id); + let bonded_balance = T::StakeAdapter::active_stake(&self.bonded_account()); Pallet::::balance_to_point(bonded_balance, self.points, new_funds) } @@ -1009,7 +1009,7 @@ impl BondedPool { /// /// This is often used for unbonding. fn points_to_balance(&self, points: BalanceOf) -> BalanceOf { - let bonded_balance = T::StakeAdapter::active_stake(self.id); + let bonded_balance = T::StakeAdapter::active_stake(&self.bonded_account()); Pallet::::point_to_balance(bonded_balance, self.points, points) } @@ -1119,7 +1119,7 @@ impl BondedPool { fn ok_to_be_open(&self) -> Result<(), DispatchError> { ensure!(!self.is_destroying(), Error::::CanNotChangeState); - let bonded_balance = T::StakeAdapter::active_stake(self.id); + let bonded_balance = T::StakeAdapter::active_stake(&self.bonded_account()); ensure!(!bonded_balance.is_zero(), Error::::OverflowRisk); let points_to_balance_ratio_floor = self @@ -1252,7 +1252,13 @@ impl BondedPool { // ratio will be wrong. let points_issued = self.issue(amount); - T::StakeAdapter::pledge_bond(who, self.id, amount, ty)?; + T::StakeAdapter::pledge_bond( + who, + &self.bonded_account(), + &self.reward_account(), + amount, + ty, + )?; TotalValueLocked::::mutate(|tvl| { tvl.saturating_accrue(amount); }); @@ -1264,7 +1270,7 @@ impl BondedPool { /// /// Can only happen when slashes are lazy, such as in `delegate and stake` strategy. fn has_pending_slash(&self) -> bool { - T::StakeAdapter::has_pending_slash(self.id) + T::StakeAdapter::has_pending_slash(&self.bonded_account()) } // Set the state of `self`, and deposit an event if the state changed. State should never be set @@ -2128,7 +2134,7 @@ pub mod pallet { // Unbond in the actual underlying nominator. let unbonding_balance = bonded_pool.dissolve(unbonding_points); - T::StakeAdapter::unbond(bonded_pool.id, unbonding_balance)?; + T::StakeAdapter::unbond(&bonded_pool.bonded_account(), unbonding_balance)?; // Note that we lazily create the unbonding pools here if they don't already exist let mut sub_pools = SubPoolsStorage::::get(member.pool_id) @@ -2191,7 +2197,7 @@ pub mod pallet { // For now we only allow a pool to withdraw unbonded if its not destroying. If the pool // is destroying then `withdraw_unbonded` can be used. ensure!(pool.state != PoolState::Destroying, Error::::NotDestroying); - T::StakeAdapter::withdraw_unbonded(pool_id, num_slashing_spans)?; + T::StakeAdapter::withdraw_unbonded(&pool.bonded_account(), num_slashing_spans)?; Ok(()) } @@ -2252,8 +2258,10 @@ pub mod pallet { // Before calculating the `balance_to_unbond`, we call withdraw unbonded to ensure the // `transferrable_balance` is correct. - let stash_killed = - T::StakeAdapter::withdraw_unbonded(bonded_pool.id, num_slashing_spans)?; + let stash_killed = T::StakeAdapter::withdraw_unbonded( + &bonded_pool.bonded_account(), + num_slashing_spans, + )?; // defensive-only: the depositor puts enough funds into the stash so that it will only // be destroyed when they are leaving. @@ -2286,10 +2294,14 @@ pub mod pallet { // don't exist. This check is also defensive in cases where the unbond pool does not // update its balance (e.g. a bug in the slashing hook.) We gracefully proceed in // order to ensure members can leave the pool and it can be destroyed. - .min(T::StakeAdapter::transferable_balance(bonded_pool.id)); + .min(T::StakeAdapter::transferable_balance(&bonded_pool.bonded_account())); - T::StakeAdapter::member_withdraw(&member_account, bonded_pool.id, balance_to_unbond) - .defensive()?; + T::StakeAdapter::member_withdraw( + &member_account, + &bonded_pool.bonded_account(), + balance_to_unbond, + ) + .defensive()?; Self::deposit_event(Event::::Withdrawn { member: member_account.clone(), @@ -2419,7 +2431,7 @@ pub mod pallet { Error::::MinimumBondNotMet ); - T::StakeAdapter::nominate(bonded_pool.id, validators) + T::StakeAdapter::nominate(&bonded_pool.bonded_account(), validators) } /// Set a new state for the pool. @@ -2612,7 +2624,7 @@ pub mod pallet { ensure!(bonded_pool.can_nominate(&who), Error::::NotNominator); } - T::StakeAdapter::chill(bonded_pool.id) + T::StakeAdapter::chill(&bonded_pool.bonded_account()) } /// `origin` bonds funds from `extra` for some pool member `member` into their respective @@ -2894,7 +2906,7 @@ impl Pallet { "bonded account of dissolving pool should have no consumers" ); defensive_assert!( - T::StakeAdapter::total_stake(bonded_pool.id) == Zero::zero(), + T::StakeAdapter::total_stake(&bonded_pool.bonded_account()) == Zero::zero(), "dissolving pool should not have any stake in the staking pallet" ); @@ -2917,7 +2929,7 @@ impl Pallet { "could not transfer all amount to depositor while dissolving pool" ); defensive_assert!( - T::StakeAdapter::total_balance(bonded_pool.id) == Zero::zero(), + T::StakeAdapter::total_balance(&bonded_pool.bonded_account()) == Zero::zero(), "dissolving pool should not have any balance" ); // NOTE: Defensively force set balance to zero. @@ -3313,7 +3325,9 @@ impl Pallet { // calculate points to be slashed. let member = PoolMembers::::get(&member_account).ok_or(Error::::PoolMemberNotFound)?; - ensure!(T::StakeAdapter::has_pending_slash(member.pool_id), Error::::NothingToSlash); + + let pool_account = Pallet::::create_bonded_account(member.pool_id); + ensure!(T::StakeAdapter::has_pending_slash(&pool_account), Error::::NothingToSlash); let unslashed_balance = T::StakeAdapter::member_delegation_balance(&member_account); let slashed_balance = member.total_balance(); @@ -3327,7 +3341,7 @@ impl Pallet { T::StakeAdapter::member_slash( &member_account, - member.pool_id, + &pool_account, unslashed_balance.defensive_saturating_sub(slashed_balance), reporter, ) @@ -3496,7 +3510,7 @@ impl Pallet { pool is being destroyed and the depositor is the last member", ); - expected_tvl += T::StakeAdapter::total_stake(bonded_pool.id); + expected_tvl += T::StakeAdapter::total_stake(&bonded_pool.bonded_account()); Ok(()) })?; @@ -3521,11 +3535,12 @@ impl Pallet { } for (pool_id, _pool) in BondedPools::::iter() { + let pool_account = Pallet::::create_bonded_account(pool_id); let subs = SubPoolsStorage::::get(pool_id).unwrap_or_default(); let sum_unbonding_balance = subs.sum_unbonding_balance(); - let bonded_balance = T::StakeAdapter::active_stake(pool_id); - let total_balance = T::StakeAdapter::total_balance(pool_id); + let bonded_balance = T::StakeAdapter::active_stake(&pool_account); + let total_balance = T::StakeAdapter::total_balance(&pool_account); assert!( total_balance >= bonded_balance + sum_unbonding_balance, @@ -3628,7 +3643,8 @@ impl Pallet { /// If the pool ID does not exist, returns 0 ratio balance to points. Used by runtime API. pub fn api_balance_to_points(pool_id: PoolId, new_funds: BalanceOf) -> BalanceOf { if let Some(pool) = BondedPool::::get(pool_id) { - let bonded_balance = T::StakeAdapter::active_stake(pool.id); + let bonded_balance = + T::StakeAdapter::active_stake(&Self::create_bonded_account(pool_id)); Pallet::::balance_to_point(bonded_balance, pool.points, new_funds) } else { Zero::zero() diff --git a/substrate/frame/nomination-pools/src/migration.rs b/substrate/frame/nomination-pools/src/migration.rs index ba62ff96011b..5a97d380ac71 100644 --- a/substrate/frame/nomination-pools/src/migration.rs +++ b/substrate/frame/nomination-pools/src/migration.rs @@ -1023,7 +1023,9 @@ mod helpers { pub(crate) fn calculate_tvl_by_total_stake() -> BalanceOf { BondedPools::::iter() - .map(|(id, _inner)| T::StakeAdapter::total_stake(id)) + .map(|(id, _inner)| { + T::StakeAdapter::total_stake(&Pallet::::create_bonded_account(id)) + }) .reduce(|acc, total_balance| acc + total_balance) .unwrap_or_default() } From bd070501a6d487fffc6f9b3b3bb6cafa78e8f8a5 Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 1 Apr 2024 00:24:27 +0200 Subject: [PATCH 032/257] fix bench --- .../nomination-pools/benchmarking/src/lib.rs | 46 ++++++++++--------- .../frame/nomination-pools/src/adapter.rs | 2 +- 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/substrate/frame/nomination-pools/benchmarking/src/lib.rs b/substrate/frame/nomination-pools/benchmarking/src/lib.rs index 0adf2c95ece3..7d8a629c38f5 100644 --- a/substrate/frame/nomination-pools/benchmarking/src/lib.rs +++ b/substrate/frame/nomination-pools/benchmarking/src/lib.rs @@ -158,7 +158,7 @@ impl ListScenario { create_pool_account::(USER_SEED + 1, origin_weight, Some(Perbill::from_percent(50))); T::StakeAdapter::nominate( - 1, + &pool_origin1, // NOTE: these don't really need to be validators. vec![account("random_validator", 0, USER_SEED)], )?; @@ -166,7 +166,10 @@ impl ListScenario { let (_, pool_origin2) = create_pool_account::(USER_SEED + 2, origin_weight, Some(Perbill::from_percent(50))); - T::StakeAdapter::nominate(2, vec![account("random_validator", 0, USER_SEED)].clone())?; + T::StakeAdapter::nominate( + &pool_origin2, + vec![account("random_validator", 0, USER_SEED)].clone(), + )?; // Find a destination weight that will trigger the worst case scenario let dest_weight_as_vote = ::VoterList::score_update_worst_case( @@ -181,7 +184,7 @@ impl ListScenario { let (_, pool_dest1) = create_pool_account::(USER_SEED + 3, dest_weight, Some(Perbill::from_percent(50))); - T::StakeAdapter::nominate(3, vec![account("random_validator", 0, USER_SEED)])?; + T::StakeAdapter::nominate(&pool_dest1, vec![account("random_validator", 0, USER_SEED)])?; let weight_of = pallet_staking::Pallet::::weight_of_fn(); assert_eq!(vote_to_balance::(weight_of(&pool_origin1)).unwrap(), origin_weight); @@ -207,11 +210,12 @@ impl ListScenario { self.origin1_member = Some(joiner.clone()); CurrencyOf::::set_balance(&joiner, amount * 2u32.into()); - let original_bonded = T::StakeAdapter::active_stake(1); + let original_bonded = T::StakeAdapter::active_stake(&self.origin1); // Unbond `amount` from the underlying pool account so when the member joins // we will maintain `current_bonded`. - T::StakeAdapter::unbond(1, amount).expect("the pool was created in `Self::new`."); + T::StakeAdapter::unbond(&self.origin1, amount) + .expect("the pool was created in `Self::new`."); // Account pool points for the unbonded balance. BondedPools::::mutate(&1, |maybe_pool| { @@ -240,7 +244,7 @@ frame_benchmarking::benchmarks! { // setup the worst case list scenario. let scenario = ListScenario::::new(origin_weight, true)?; assert_eq!( - T::StakeAdapter::active_stake(1), + T::StakeAdapter::active_stake(&scenario.origin1), origin_weight ); @@ -255,7 +259,7 @@ frame_benchmarking::benchmarks! { verify { assert_eq!(CurrencyOf::::balance(&joiner), joiner_free - max_additional); assert_eq!( - T::StakeAdapter::active_stake(1), + T::StakeAdapter::active_stake(&scenario.origin1), scenario.dest_weight ); } @@ -270,7 +274,7 @@ frame_benchmarking::benchmarks! { }: bond_extra(RuntimeOrigin::Signed(scenario.creator1.clone()), BondExtra::FreeBalance(extra)) verify { assert!( - T::StakeAdapter::active_stake(1) >= + T::StakeAdapter::active_stake(&scenario.origin1) >= scenario.dest_weight ); } @@ -294,7 +298,7 @@ frame_benchmarking::benchmarks! { verify { // commission of 50% deducted here. assert!( - T::StakeAdapter::active_stake(1) >= + T::StakeAdapter::active_stake(&scenario.origin1) >= scenario.dest_weight / 2u32.into() ); } @@ -348,7 +352,7 @@ frame_benchmarking::benchmarks! { whitelist_account!(member_id); }: _(RuntimeOrigin::Signed(member_id.clone()), member_id_lookup, all_points) verify { - let bonded_after = T::StakeAdapter::active_stake(1); + let bonded_after = T::StakeAdapter::active_stake(&scenario.origin1); // We at least went down to the destination bag assert!(bonded_after <= scenario.dest_weight); let member = PoolMembers::::get( @@ -379,7 +383,7 @@ frame_benchmarking::benchmarks! { // Sanity check join worked assert_eq!( - T::StakeAdapter::active_stake(1), + T::StakeAdapter::active_stake(&pool_account), min_create_bond + min_join_bond ); assert_eq!(CurrencyOf::::balance(&joiner), min_join_bond); @@ -389,7 +393,7 @@ frame_benchmarking::benchmarks! { // Sanity check that unbond worked assert_eq!( - T::StakeAdapter::active_stake(1), + T::StakeAdapter::active_stake(&pool_account), min_create_bond ); assert_eq!(pallet_staking::Ledger::::get(&pool_account).unwrap().unlocking.len(), 1); @@ -422,7 +426,7 @@ frame_benchmarking::benchmarks! { // Sanity check join worked assert_eq!( - T::StakeAdapter::active_stake(1), + T::StakeAdapter::active_stake(&pool_account), min_create_bond + min_join_bond ); assert_eq!(CurrencyOf::::balance(&joiner), min_join_bond); @@ -433,7 +437,7 @@ frame_benchmarking::benchmarks! { // Sanity check that unbond worked assert_eq!( - T::StakeAdapter::active_stake(1), + T::StakeAdapter::active_stake(&pool_account), min_create_bond ); assert_eq!(pallet_staking::Ledger::::get(&pool_account).unwrap().unlocking.len(), 1); @@ -479,7 +483,7 @@ frame_benchmarking::benchmarks! { // Sanity check that unbond worked assert_eq!( - T::StakeAdapter::active_stake(1), + T::StakeAdapter::active_stake(&pool_account), Zero::zero() ); assert_eq!( @@ -559,7 +563,7 @@ frame_benchmarking::benchmarks! { } ); assert_eq!( - T::StakeAdapter::active_stake(1), + T::StakeAdapter::active_stake(&Pools::::create_bonded_account(1)), min_create_bond ); } @@ -599,7 +603,7 @@ frame_benchmarking::benchmarks! { } ); assert_eq!( - T::StakeAdapter::active_stake(1), + T::StakeAdapter::active_stake(&Pools::::create_bonded_account(1)), min_create_bond ); } @@ -684,13 +688,13 @@ frame_benchmarking::benchmarks! { .map(|i| account("stash", USER_SEED, i)) .collect(); - assert_ok!(T::StakeAdapter::nominate(1, validators)); - assert!(T::StakeAdapter::nominations(1).is_some()); + assert_ok!(T::StakeAdapter::nominate(&pool_account, validators)); + assert!(T::StakeAdapter::nominations(&Pools::::create_bonded_account(1)).is_some()); whitelist_account!(depositor); }:_(RuntimeOrigin::Signed(depositor.clone()), 1) verify { - assert!(T::StakeAdapter::nominations(1).is_none()); + assert!(T::StakeAdapter::nominations(&Pools::::create_bonded_account(1)).is_none()); } set_commission { @@ -789,7 +793,7 @@ frame_benchmarking::benchmarks! { // Sanity check join worked assert_eq!( - T::StakeAdapter::active_stake(1), + T::StakeAdapter::active_stake(&pool_account), min_create_bond + min_join_bond ); }:_(RuntimeOrigin::Signed(joiner.clone()), ClaimPermission::PermissionlessAll) diff --git a/substrate/frame/nomination-pools/src/adapter.rs b/substrate/frame/nomination-pools/src/adapter.rs index 88a2f4370f9b..b3b3c6a367c6 100644 --- a/substrate/frame/nomination-pools/src/adapter.rs +++ b/substrate/frame/nomination-pools/src/adapter.rs @@ -78,7 +78,7 @@ pub trait StakeStrategy { Self::CoreStaking::chill(pool_account) } - /// Pledge `amount` towards staking pool with `pool_id` and update the pool bond. Also see + /// Pledge `amount` towards `pool_account` and update the pool bond. Also see /// [`StakingInterface::bond`]. fn pledge_bond( who: &Self::AccountId, From b87fc08489dad3ee736235af3a894f753fd86957 Mon Sep 17 00:00:00 2001 From: Ankan Date: Mon, 1 Apr 2024 12:01:51 +0200 Subject: [PATCH 033/257] remove fixme --- substrate/frame/delegated-staking/src/types.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/substrate/frame/delegated-staking/src/types.rs b/substrate/frame/delegated-staking/src/types.rs index 70965374305c..d48579226574 100644 --- a/substrate/frame/delegated-staking/src/types.rs +++ b/substrate/frame/delegated-staking/src/types.rs @@ -107,7 +107,6 @@ pub struct AgentLedger { /// /// We need this register to ensure that the `Agent` does not bond funds from delegated /// funds that are withdrawn and should be claimed by delegators. - // FIXME(ank4n): Check/test about rebond: where delegator rebond what is unlocking. #[codec(compact)] pub unclaimed_withdrawals: BalanceOf, /// Slashes that are not yet applied. This affects the effective balance of the `Agent`. From 3988cff3d7dfc891ea754107e5e42e8769350693 Mon Sep 17 00:00:00 2001 From: Ankan Date: Tue, 2 Apr 2024 11:35:45 +0200 Subject: [PATCH 034/257] Make DelegationInterface independent --- polkadot/runtime/westend/src/lib.rs | 3 +- .../frame/delegated-staking/src/impls.rs | 179 ++---------------- substrate/frame/delegated-staking/src/lib.rs | 8 +- substrate/frame/delegated-staking/src/mock.rs | 3 +- .../frame/nomination-pools/src/adapter.rs | 49 +++-- .../test-delegate-stake/src/mock.rs | 3 +- substrate/primitives/staking/src/lib.rs | 27 ++- 7 files changed, 82 insertions(+), 190 deletions(-) diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 6b4ddad90abf..2eea144cc1e7 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -1385,7 +1385,8 @@ impl pallet_nomination_pools::Config for Runtime { type RewardCounter = FixedU128; type BalanceToU256 = BalanceToU256; type U256ToBalance = U256ToBalance; - type StakeAdapter = pallet_nomination_pools::adapter::DelegateStake; + type StakeAdapter = + pallet_nomination_pools::adapter::DelegateStake; type PostUnbondingPoolsWindow = ConstU32<4>; type MaxMetadataLen = ConstU32<256>; // we use the same number of allowed unlocking chunks as with staking. diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs index 72884718dfde..d44d023d04e0 100644 --- a/substrate/frame/delegated-staking/src/impls.rs +++ b/substrate/frame/delegated-staking/src/impls.rs @@ -16,178 +16,16 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -//! Implementations of public traits, namely [StakingInterface], [DelegatedStakeInterface] and +//! Implementations of public traits, namely [StakingInterface], [DelegationInterface] and //! [OnStakingUpdate]. use super::*; -use sp_staking::{DelegatedStakeInterface, OnStakingUpdate}; +use sp_staking::{DelegationInterface, OnStakingUpdate}; -/// Wrapper `StakingInterface` implementation for `Agents`. -impl StakingInterface for Pallet { +impl DelegationInterface for Pallet { type Balance = BalanceOf; type AccountId = T::AccountId; - type CurrencyToVote = ::CurrencyToVote; - fn minimum_nominator_bond() -> Self::Balance { - T::CoreStaking::minimum_nominator_bond() - } - - fn minimum_validator_bond() -> Self::Balance { - T::CoreStaking::minimum_validator_bond() - } - - fn stash_by_ctrl(_controller: &Self::AccountId) -> Result { - // ctrl are deprecated, just return err. - Err(Error::::NotSupported.into()) - } - - fn bonding_duration() -> EraIndex { - T::CoreStaking::bonding_duration() - } - - fn current_era() -> EraIndex { - T::CoreStaking::current_era() - } - - fn stake(who: &Self::AccountId) -> Result, DispatchError> { - ensure!(Self::is_agent(who), Error::::NotSupported); - T::CoreStaking::stake(who) - } - - fn total_stake(who: &Self::AccountId) -> Result { - if Self::is_agent(who) { - return T::CoreStaking::total_stake(who); - } - - if Self::is_delegator(who) { - let delegation = Delegation::::get(who).defensive_ok_or(Error::::BadState)?; - return Ok(delegation.amount); - } - - Err(Error::::NotSupported.into()) - } - - fn active_stake(who: &Self::AccountId) -> Result { - T::CoreStaking::active_stake(who) - } - - fn is_unbonding(who: &Self::AccountId) -> Result { - T::CoreStaking::is_unbonding(who) - } - - fn fully_unbond(who: &Self::AccountId) -> DispatchResult { - ensure!(Self::is_agent(who), Error::::NotSupported); - T::CoreStaking::fully_unbond(who) - } - - fn bond( - who: &Self::AccountId, - value: Self::Balance, - payee: &Self::AccountId, - ) -> DispatchResult { - // ensure who is not already staked - ensure!(T::CoreStaking::status(who).is_err(), Error::::AlreadyStaking); - let agent = Agent::::from(who)?; - - ensure!(agent.available_to_bond() >= value, Error::::NotEnoughFunds); - ensure!(agent.ledger.payee == *payee, Error::::InvalidRewardDestination); - - T::CoreStaking::virtual_bond(who, value, payee) - } - - fn nominate(who: &Self::AccountId, validators: Vec) -> DispatchResult { - ensure!(Self::is_agent(who), Error::::NotAgent); - T::CoreStaking::nominate(who, validators) - } - - fn chill(who: &Self::AccountId) -> DispatchResult { - ensure!(Self::is_agent(who), Error::::NotAgent); - T::CoreStaking::chill(who) - } - - fn bond_extra(who: &Self::AccountId, extra: Self::Balance) -> DispatchResult { - let ledger = >::get(who).ok_or(Error::::NotAgent)?; - ensure!(ledger.stakeable_balance() >= extra, Error::::NotEnoughFunds); - - T::CoreStaking::bond_extra(who, extra) - } - - fn unbond(stash: &Self::AccountId, value: Self::Balance) -> DispatchResult { - let agent = Agent::::from(stash)?; - ensure!(agent.bonded_stake() >= value, Error::::NotEnoughFunds); - - T::CoreStaking::unbond(stash, value) - } - - fn update_payee(stash: &Self::AccountId, reward_acc: &Self::AccountId) -> DispatchResult { - T::CoreStaking::update_payee(stash, reward_acc) - } - - /// Withdraw unbonding funds until current era. - /// - /// Funds are moved to unclaimed_withdrawals register of the `AgentLedger`. - fn withdraw_unbonded( - agent_acc: Self::AccountId, - num_slashing_spans: u32, - ) -> Result { - Pallet::::withdraw_unbonded(&agent_acc, num_slashing_spans) - .map(|agent| agent.ledger.total_delegated.is_zero()) - } - - fn desired_validator_count() -> u32 { - T::CoreStaking::desired_validator_count() - } - - fn election_ongoing() -> bool { - T::CoreStaking::election_ongoing() - } - - fn force_unstake(_who: Self::AccountId) -> DispatchResult { - Err(Error::::NotSupported.into()) - } - - fn is_exposed_in_era(who: &Self::AccountId, era: &EraIndex) -> bool { - T::CoreStaking::is_exposed_in_era(who, era) - } - - fn status(who: &Self::AccountId) -> Result, DispatchError> { - ensure!(Self::is_agent(who), Error::::NotAgent); - T::CoreStaking::status(who) - } - - fn is_validator(who: &Self::AccountId) -> bool { - T::CoreStaking::is_validator(who) - } - - fn nominations(who: &Self::AccountId) -> Option> { - T::CoreStaking::nominations(who) - } - - fn slash_reward_fraction() -> Perbill { - T::CoreStaking::slash_reward_fraction() - } - - #[cfg(feature = "runtime-benchmarks")] - fn max_exposure_page_size() -> sp_staking::Page { - T::CoreStaking::max_exposure_page_size() - } - - #[cfg(feature = "runtime-benchmarks")] - fn add_era_stakers( - current_era: &EraIndex, - stash: &Self::AccountId, - exposures: Vec<(Self::AccountId, Self::Balance)>, - ) { - T::CoreStaking::add_era_stakers(current_era, stash, exposures) - } - - #[cfg(feature = "runtime-benchmarks")] - fn set_current_era(era: EraIndex) { - T::CoreStaking::set_current_era(era) - } -} - -impl DelegatedStakeInterface for Pallet { /// Effective balance of the `Agent` account. fn agent_balance(who: &Self::AccountId) -> Self::Balance { Agent::::from(who) @@ -242,6 +80,17 @@ impl DelegatedStakeInterface for Pallet { ) } + /// Withdraw unbonding funds until current era. + /// + /// Funds are moved to unclaimed_withdrawals register of the `AgentLedger`. + fn withdraw_unclaimed( + agent_acc: Self::AccountId, + num_slashing_spans: u32, + ) -> Result { + Pallet::::withdraw_unbonded(&agent_acc, num_slashing_spans) + .map(|agent| agent.ledger.total_delegated.is_zero()) + } + /// Returns true if the `Agent` have any slash pending to be applied. fn has_pending_slash(agent: &Self::AccountId) -> bool { Agent::::from(agent) diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs index 2de5ae44b85b..89a6a581ca35 100644 --- a/substrate/frame/delegated-staking/src/lib.rs +++ b/substrate/frame/delegated-staking/src/lib.rs @@ -17,7 +17,7 @@ //! # Delegated Staking Pallet //! -//! This pallet implements [`sp_staking::DelegatedStakeInterface`] that extends [`StakingInterface`] +//! This pallet implements [`sp_staking::DelegationInterface`] that extends [`StakingInterface`] //! to support delegation of stake. It consumes [`Config::CoreStaking`] to provide primitive staking //! functions and only implements the delegation features. //! @@ -86,7 +86,7 @@ //! slashes are cleared. //! //! The user of this pallet can apply slash using -//! [DelegatedStakeInterface::delegator_slash](sp_staking::DelegatedStakeInterface::delegator_slash). +//! [DelegationInterface::delegator_slash](sp_staking::DelegationInterface::delegator_slash). //! //! ## Migration from Nominator to Agent //! More details [here](https://hackmd.io/@ak0n/np-delegated-staking-migration). @@ -157,9 +157,9 @@ use frame_support::{ use sp_runtime::{ traits::{AccountIdConversion, CheckedAdd, CheckedSub, Zero}, - ArithmeticError, DispatchResult, Perbill, RuntimeDebug, Saturating, + ArithmeticError, DispatchResult, RuntimeDebug, Saturating, }; -use sp_staking::{EraIndex, Stake, StakerStatus, StakingInterface, StakingUnsafe}; +use sp_staking::{EraIndex, StakerStatus, StakingInterface, StakingUnsafe}; use sp_std::{convert::TryInto, prelude::*}; pub type BalanceOf = diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs index 95306398d029..1ba82b69195b 100644 --- a/substrate/frame/delegated-staking/src/mock.rs +++ b/substrate/frame/delegated-staking/src/mock.rs @@ -179,7 +179,8 @@ impl pallet_nomination_pools::Config for Runtime { type MaxMetadataLen = ConstU32<256>; type MaxUnbonding = MaxUnbonding; type MaxPointsToBalance = frame_support::traits::ConstU8<10>; - type StakeAdapter = pallet_nomination_pools::adapter::DelegateStake; + type StakeAdapter = + pallet_nomination_pools::adapter::DelegateStake; } frame_support::construct_runtime!( diff --git a/substrate/frame/nomination-pools/src/adapter.rs b/substrate/frame/nomination-pools/src/adapter.rs index b3b3c6a367c6..e1a692b5d3d5 100644 --- a/substrate/frame/nomination-pools/src/adapter.rs +++ b/substrate/frame/nomination-pools/src/adapter.rs @@ -16,7 +16,7 @@ // limitations under the License. use crate::*; -use sp_staking::DelegatedStakeInterface; +use sp_staking::DelegationInterface; /// An adapter trait that can support multiple staking strategies. /// @@ -97,9 +97,7 @@ pub trait StakeStrategy { fn withdraw_unbonded( pool_account: &Self::AccountId, num_slashing_spans: u32, - ) -> Result { - Self::CoreStaking::withdraw_unbonded(pool_account.clone(), num_slashing_spans) - } + ) -> Result; /// Withdraw funds from pool account to member account. fn member_withdraw( @@ -172,6 +170,13 @@ impl, AccountId = T: } } + fn withdraw_unbonded( + pool_account: &Self::AccountId, + num_slashing_spans: u32, + ) -> Result { + Staking::withdraw_unbonded(pool_account.clone(), num_slashing_spans) + } + fn member_withdraw( who: &T::AccountId, pool_account: &Self::AccountId, @@ -202,27 +207,30 @@ impl, AccountId = T: /// In this approach, first the funds are delegated from delegator to the pool account and later /// staked with `Staking`. The advantage of this approach is that the funds are held in the /// user account itself and not in the pool account. -pub struct DelegateStake(PhantomData<(T, Staking)>); +pub struct DelegateStake( + PhantomData<(T, Staking, Delegation)>, +); impl< T: Config, - Staking: DelegatedStakeInterface, AccountId = T::AccountId>, - > StakeStrategy for DelegateStake + Staking: StakingInterface, AccountId = T::AccountId>, + Delegation: DelegationInterface, AccountId = T::AccountId>, + > StakeStrategy for DelegateStake { type Balance = BalanceOf; type AccountId = T::AccountId; type CoreStaking = Staking; fn transferable_balance(pool_account: &Self::AccountId) -> BalanceOf { - Staking::agent_balance(pool_account).saturating_sub(Self::active_stake(pool_account)) + Delegation::agent_balance(pool_account).saturating_sub(Self::active_stake(pool_account)) } fn total_balance(pool_account: &Self::AccountId) -> BalanceOf { - Staking::agent_balance(pool_account) + Delegation::agent_balance(pool_account) } - fn member_delegation_balance(member_account: &T::AccountId) -> Staking::Balance { - Staking::delegator_balance(member_account) + fn member_delegation_balance(member_account: &T::AccountId) -> Delegation::Balance { + Delegation::delegator_balance(member_account) } fn pledge_bond( @@ -235,33 +243,40 @@ impl< match bond_type { BondType::Create => { // first delegation - Staking::delegate(who, pool_account, reward_account, amount) + Delegation::delegate(who, pool_account, reward_account, amount) }, BondType::Later => { // additional delegation - Staking::delegate_extra(who, pool_account, amount) + Delegation::delegate_extra(who, pool_account, amount) }, } } + fn withdraw_unbonded( + pool_account: &Self::AccountId, + num_slashing_spans: u32, + ) -> Result { + Delegation::withdraw_unclaimed(pool_account.clone(), num_slashing_spans) + } + fn member_withdraw( who: &T::AccountId, pool_account: &Self::AccountId, amount: BalanceOf, ) -> DispatchResult { - Staking::withdraw_delegation(&who, pool_account, amount) + Delegation::withdraw_delegation(&who, pool_account, amount) } fn has_pending_slash(pool_account: &Self::AccountId) -> bool { - Staking::has_pending_slash(pool_account) + Delegation::has_pending_slash(pool_account) } fn member_slash( who: &T::AccountId, pool_account: &Self::AccountId, - amount: Staking::Balance, + amount: Delegation::Balance, maybe_reporter: Option, ) -> DispatchResult { - Staking::delegator_slash(pool_account, who, amount, maybe_reporter) + Delegation::delegator_slash(pool_account, who, amount, maybe_reporter) } } diff --git a/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs b/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs index 6749013aa76b..9f5a531390a4 100644 --- a/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs +++ b/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs @@ -180,7 +180,8 @@ impl pallet_nomination_pools::Config for Runtime { type RewardCounter = FixedU128; type BalanceToU256 = BalanceToU256; type U256ToBalance = U256ToBalance; - type StakeAdapter = pallet_nomination_pools::adapter::DelegateStake; + type StakeAdapter = + pallet_nomination_pools::adapter::DelegateStake; type PostUnbondingPoolsWindow = PostUnbondingPoolsWindow; type MaxMetadataLen = ConstU32<256>; type MaxUnbonding = ConstU32<8>; diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index 13cfbe8e326d..eed739c0df59 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -458,7 +458,21 @@ pub struct PagedExposureMetadata { /// /// The `Agent` is responsible for managing rewards and slashing for all the `Delegators` that /// have delegated funds to it. -pub trait DelegatedStakeInterface: StakingInterface { +pub trait DelegationInterface { + /// Balance type used by the staking system. + type Balance: Sub + + Ord + + PartialEq + + Default + + Copy + + MaxEncodedLen + + FullCodec + + TypeInfo + + Saturating; + + /// AccountId type used by the staking system. + type AccountId: Clone + core::fmt::Debug; + /// Effective balance of the `Agent` account. /// /// This takes into account any pending slashes to `Agent`. @@ -496,6 +510,17 @@ pub trait DelegatedStakeInterface: StakingInterface { amount: Self::Balance, ) -> DispatchResult; + /// Withdraw any unlocking funds in `CoreStaking` that can be claimed later by a delegator. + /// + /// `CoreStaking` has a limitation on maximum unlocking chunks at any given time. If the limit + /// is reached, we want to implicitly unlock these funds even though a delegator is not + /// present to claim it. Not doing this would block any unbonding until unlocking funds are + /// claimed. + fn withdraw_unclaimed( + agent: Self::AccountId, + num_slashing_spans: u32, + ) -> Result; + /// Returns true if there are pending slashes posted to the `Agent` account. /// /// Slashes to `Agent` account are not immediate and are applied lazily. Since `Agent` From bfd34343ebd24f061a055049bb182ad316e2a882 Mon Sep 17 00:00:00 2001 From: Ankan Date: Tue, 2 Apr 2024 11:50:10 +0200 Subject: [PATCH 035/257] Make delegation interface independent --- .../frame/delegated-staking/src/impls.rs | 179 ++---------------- substrate/frame/delegated-staking/src/lib.rs | 8 +- .../frame/delegated-staking/src/tests.rs | 10 +- substrate/primitives/staking/src/lib.rs | 27 ++- 4 files changed, 49 insertions(+), 175 deletions(-) diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs index 72884718dfde..56ad399ef494 100644 --- a/substrate/frame/delegated-staking/src/impls.rs +++ b/substrate/frame/delegated-staking/src/impls.rs @@ -16,178 +16,16 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -//! Implementations of public traits, namely [StakingInterface], [DelegatedStakeInterface] and +//! Implementations of public traits, namely [DelegationInterface] and //! [OnStakingUpdate]. use super::*; -use sp_staking::{DelegatedStakeInterface, OnStakingUpdate}; +use sp_staking::{DelegationInterface, OnStakingUpdate}; -/// Wrapper `StakingInterface` implementation for `Agents`. -impl StakingInterface for Pallet { +impl DelegationInterface for Pallet { type Balance = BalanceOf; type AccountId = T::AccountId; - type CurrencyToVote = ::CurrencyToVote; - fn minimum_nominator_bond() -> Self::Balance { - T::CoreStaking::minimum_nominator_bond() - } - - fn minimum_validator_bond() -> Self::Balance { - T::CoreStaking::minimum_validator_bond() - } - - fn stash_by_ctrl(_controller: &Self::AccountId) -> Result { - // ctrl are deprecated, just return err. - Err(Error::::NotSupported.into()) - } - - fn bonding_duration() -> EraIndex { - T::CoreStaking::bonding_duration() - } - - fn current_era() -> EraIndex { - T::CoreStaking::current_era() - } - - fn stake(who: &Self::AccountId) -> Result, DispatchError> { - ensure!(Self::is_agent(who), Error::::NotSupported); - T::CoreStaking::stake(who) - } - - fn total_stake(who: &Self::AccountId) -> Result { - if Self::is_agent(who) { - return T::CoreStaking::total_stake(who); - } - - if Self::is_delegator(who) { - let delegation = Delegation::::get(who).defensive_ok_or(Error::::BadState)?; - return Ok(delegation.amount); - } - - Err(Error::::NotSupported.into()) - } - - fn active_stake(who: &Self::AccountId) -> Result { - T::CoreStaking::active_stake(who) - } - - fn is_unbonding(who: &Self::AccountId) -> Result { - T::CoreStaking::is_unbonding(who) - } - - fn fully_unbond(who: &Self::AccountId) -> DispatchResult { - ensure!(Self::is_agent(who), Error::::NotSupported); - T::CoreStaking::fully_unbond(who) - } - - fn bond( - who: &Self::AccountId, - value: Self::Balance, - payee: &Self::AccountId, - ) -> DispatchResult { - // ensure who is not already staked - ensure!(T::CoreStaking::status(who).is_err(), Error::::AlreadyStaking); - let agent = Agent::::from(who)?; - - ensure!(agent.available_to_bond() >= value, Error::::NotEnoughFunds); - ensure!(agent.ledger.payee == *payee, Error::::InvalidRewardDestination); - - T::CoreStaking::virtual_bond(who, value, payee) - } - - fn nominate(who: &Self::AccountId, validators: Vec) -> DispatchResult { - ensure!(Self::is_agent(who), Error::::NotAgent); - T::CoreStaking::nominate(who, validators) - } - - fn chill(who: &Self::AccountId) -> DispatchResult { - ensure!(Self::is_agent(who), Error::::NotAgent); - T::CoreStaking::chill(who) - } - - fn bond_extra(who: &Self::AccountId, extra: Self::Balance) -> DispatchResult { - let ledger = >::get(who).ok_or(Error::::NotAgent)?; - ensure!(ledger.stakeable_balance() >= extra, Error::::NotEnoughFunds); - - T::CoreStaking::bond_extra(who, extra) - } - - fn unbond(stash: &Self::AccountId, value: Self::Balance) -> DispatchResult { - let agent = Agent::::from(stash)?; - ensure!(agent.bonded_stake() >= value, Error::::NotEnoughFunds); - - T::CoreStaking::unbond(stash, value) - } - - fn update_payee(stash: &Self::AccountId, reward_acc: &Self::AccountId) -> DispatchResult { - T::CoreStaking::update_payee(stash, reward_acc) - } - - /// Withdraw unbonding funds until current era. - /// - /// Funds are moved to unclaimed_withdrawals register of the `AgentLedger`. - fn withdraw_unbonded( - agent_acc: Self::AccountId, - num_slashing_spans: u32, - ) -> Result { - Pallet::::withdraw_unbonded(&agent_acc, num_slashing_spans) - .map(|agent| agent.ledger.total_delegated.is_zero()) - } - - fn desired_validator_count() -> u32 { - T::CoreStaking::desired_validator_count() - } - - fn election_ongoing() -> bool { - T::CoreStaking::election_ongoing() - } - - fn force_unstake(_who: Self::AccountId) -> DispatchResult { - Err(Error::::NotSupported.into()) - } - - fn is_exposed_in_era(who: &Self::AccountId, era: &EraIndex) -> bool { - T::CoreStaking::is_exposed_in_era(who, era) - } - - fn status(who: &Self::AccountId) -> Result, DispatchError> { - ensure!(Self::is_agent(who), Error::::NotAgent); - T::CoreStaking::status(who) - } - - fn is_validator(who: &Self::AccountId) -> bool { - T::CoreStaking::is_validator(who) - } - - fn nominations(who: &Self::AccountId) -> Option> { - T::CoreStaking::nominations(who) - } - - fn slash_reward_fraction() -> Perbill { - T::CoreStaking::slash_reward_fraction() - } - - #[cfg(feature = "runtime-benchmarks")] - fn max_exposure_page_size() -> sp_staking::Page { - T::CoreStaking::max_exposure_page_size() - } - - #[cfg(feature = "runtime-benchmarks")] - fn add_era_stakers( - current_era: &EraIndex, - stash: &Self::AccountId, - exposures: Vec<(Self::AccountId, Self::Balance)>, - ) { - T::CoreStaking::add_era_stakers(current_era, stash, exposures) - } - - #[cfg(feature = "runtime-benchmarks")] - fn set_current_era(era: EraIndex) { - T::CoreStaking::set_current_era(era) - } -} - -impl DelegatedStakeInterface for Pallet { /// Effective balance of the `Agent` account. fn agent_balance(who: &Self::AccountId) -> Self::Balance { Agent::::from(who) @@ -242,6 +80,17 @@ impl DelegatedStakeInterface for Pallet { ) } + /// Withdraw unbonding funds until current era. + /// + /// Funds are moved to unclaimed_withdrawals register of the `AgentLedger`. + fn withdraw_unclaimed( + agent_acc: Self::AccountId, + num_slashing_spans: u32, + ) -> Result { + Pallet::::withdraw_unbonded(&agent_acc, num_slashing_spans) + .map(|agent| agent.ledger.total_delegated.is_zero()) + } + /// Returns true if the `Agent` have any slash pending to be applied. fn has_pending_slash(agent: &Self::AccountId) -> bool { Agent::::from(agent) diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs index 2de5ae44b85b..89a6a581ca35 100644 --- a/substrate/frame/delegated-staking/src/lib.rs +++ b/substrate/frame/delegated-staking/src/lib.rs @@ -17,7 +17,7 @@ //! # Delegated Staking Pallet //! -//! This pallet implements [`sp_staking::DelegatedStakeInterface`] that extends [`StakingInterface`] +//! This pallet implements [`sp_staking::DelegationInterface`] that extends [`StakingInterface`] //! to support delegation of stake. It consumes [`Config::CoreStaking`] to provide primitive staking //! functions and only implements the delegation features. //! @@ -86,7 +86,7 @@ //! slashes are cleared. //! //! The user of this pallet can apply slash using -//! [DelegatedStakeInterface::delegator_slash](sp_staking::DelegatedStakeInterface::delegator_slash). +//! [DelegationInterface::delegator_slash](sp_staking::DelegationInterface::delegator_slash). //! //! ## Migration from Nominator to Agent //! More details [here](https://hackmd.io/@ak0n/np-delegated-staking-migration). @@ -157,9 +157,9 @@ use frame_support::{ use sp_runtime::{ traits::{AccountIdConversion, CheckedAdd, CheckedSub, Zero}, - ArithmeticError, DispatchResult, Perbill, RuntimeDebug, Saturating, + ArithmeticError, DispatchResult, RuntimeDebug, Saturating, }; -use sp_staking::{EraIndex, Stake, StakerStatus, StakingInterface, StakingUnsafe}; +use sp_staking::{EraIndex, StakerStatus, StakingInterface, StakingUnsafe}; use sp_std::{convert::TryInto, prelude::*}; pub type BalanceOf = diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs index 715436153081..3abc9e4a6d67 100644 --- a/substrate/frame/delegated-staking/src/tests.rs +++ b/substrate/frame/delegated-staking/src/tests.rs @@ -270,13 +270,13 @@ mod staking_integration { assert!(eq_stake(agent, total_staked, total_staked)); // 305 wants to unbond 50 in era 2, withdrawable in era 5. - assert_ok!(DelegatedStaking::unbond(&agent, 50)); + assert_ok!(Staking::unbond(RawOrigin::Signed(agent).into(), 50)); // 310 wants to unbond 100 in era 3, withdrawable in era 6. start_era(3); - assert_ok!(DelegatedStaking::unbond(&agent, 100)); + assert_ok!(Staking::unbond(RawOrigin::Signed(agent).into(), 100)); // 320 wants to unbond 200 in era 4, withdrawable in era 7. start_era(4); - assert_ok!(DelegatedStaking::unbond(&agent, 200)); + assert_ok!(Staking::unbond(RawOrigin::Signed(agent).into(), 200)); // active stake is now reduced.. let expected_active = total_staked - (50 + 100 + 200); @@ -511,7 +511,7 @@ mod staking_integration { Balances::free_balance(200), 5000 - staked_amount - ExistentialDeposit::get() ); - assert_eq!(DelegatedStaking::stake(&200).unwrap(), init_stake); + assert_eq!(Staking::stake(&200).unwrap(), init_stake); assert_eq!(get_agent(&200).ledger.effective_balance(), 4000); assert_eq!(get_agent(&200).available_to_bond(), 0); @@ -538,7 +538,7 @@ mod staking_integration { ); // delegate stake is unchanged. - assert_eq!(DelegatedStaking::stake(&200).unwrap(), init_stake); + assert_eq!(Staking::stake(&200).unwrap(), init_stake); assert_eq!(get_agent(&200).ledger.effective_balance(), 4000); assert_eq!(get_agent(&200).available_to_bond(), 0); } diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index 13cfbe8e326d..eed739c0df59 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -458,7 +458,21 @@ pub struct PagedExposureMetadata { /// /// The `Agent` is responsible for managing rewards and slashing for all the `Delegators` that /// have delegated funds to it. -pub trait DelegatedStakeInterface: StakingInterface { +pub trait DelegationInterface { + /// Balance type used by the staking system. + type Balance: Sub + + Ord + + PartialEq + + Default + + Copy + + MaxEncodedLen + + FullCodec + + TypeInfo + + Saturating; + + /// AccountId type used by the staking system. + type AccountId: Clone + core::fmt::Debug; + /// Effective balance of the `Agent` account. /// /// This takes into account any pending slashes to `Agent`. @@ -496,6 +510,17 @@ pub trait DelegatedStakeInterface: StakingInterface { amount: Self::Balance, ) -> DispatchResult; + /// Withdraw any unlocking funds in `CoreStaking` that can be claimed later by a delegator. + /// + /// `CoreStaking` has a limitation on maximum unlocking chunks at any given time. If the limit + /// is reached, we want to implicitly unlock these funds even though a delegator is not + /// present to claim it. Not doing this would block any unbonding until unlocking funds are + /// claimed. + fn withdraw_unclaimed( + agent: Self::AccountId, + num_slashing_spans: u32, + ) -> Result; + /// Returns true if there are pending slashes posted to the `Agent` account. /// /// Slashes to `Agent` account are not immediate and are applied lazily. Since `Agent` From 7104fafa86a541d09cb4bae21b0531abfef4cc84 Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 3 Apr 2024 07:01:43 +0200 Subject: [PATCH 036/257] move reward account check to caller --- substrate/frame/staking/src/ledger.rs | 10 -------- substrate/frame/staking/src/pallet/impls.rs | 26 +++++++-------------- 2 files changed, 8 insertions(+), 28 deletions(-) diff --git a/substrate/frame/staking/src/ledger.rs b/substrate/frame/staking/src/ledger.rs index 4d3bfe980482..01531703c316 100644 --- a/substrate/frame/staking/src/ledger.rs +++ b/substrate/frame/staking/src/ledger.rs @@ -210,11 +210,6 @@ impl StakingLedger { return Err(Error::::AlreadyBonded) } - // check if the payee is ok. - if Pallet::::restrict_reward_destination(&self.stash, payee.clone()) { - return Err(Error::::RewardDestinationRestricted); - } - >::insert(&self.stash, payee); >::insert(&self.stash, &self.stash); self.update() @@ -226,11 +221,6 @@ impl StakingLedger { return Err(Error::::NotStash) } - // check if the payee is ok. - if Pallet::::restrict_reward_destination(&self.stash, payee.clone()) { - return Err(Error::::RewardDestinationRestricted); - } - >::insert(&self.stash, payee); Ok(()) } diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 5fda07fecf4a..bd27a328aa21 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -1168,24 +1168,6 @@ impl Pallet { EraInfo::::get_full_exposure(era, account) } - /// Whether the passed reward destination is restricted for the given account. - /// - /// virtual stakers are not allowed to compound their rewards as this pallet does not manage - /// locks for them. For external pallets that manage the virtual bond, it is their - /// responsibility to distribute the reward and re-bond them. - /// - /// Conservatively, we expect them to always set the reward destination to a non stash account. - pub(crate) fn restrict_reward_destination( - who: &T::AccountId, - reward_destination: RewardDestination, - ) -> bool { - Self::is_virtual_staker(who) && - match reward_destination { - RewardDestination::Account(payee) => payee == *who, - _ => true, - } - } - /// Whether `who` is a virtual staker whose funds are managed by another pallet. pub(crate) fn is_virtual_staker(who: &T::AccountId) -> bool { VirtualStakers::::contains_key(who) @@ -1827,6 +1809,14 @@ impl StakingInterface for Pallet { } fn update_payee(stash: &Self::AccountId, reward_acc: &Self::AccountId) -> DispatchResult { + // Since virtual stakers are not allowed to compound their rewards as this pallet does not + // manage their locks, we do not allow reward account to be set same as stash. For + // external pallets that manage the virtual bond, they can claim rewards and re-bond them. + ensure!( + !Self::is_virtual_staker(stash) || stash != reward_acc, + Error::::RewardDestinationRestricted + ); + // since controller is deprecated and this function is never used for old ledgers with // distinct controllers, we can safely assume that stash is the controller. Self::set_payee( From aed693c14b97d4c6f40a5d45306ed22f612f18e6 Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 3 Apr 2024 07:11:53 +0200 Subject: [PATCH 037/257] virtual staker cannot bond again --- substrate/frame/staking/src/tests.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index bde67760cb0e..094de96f19a5 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -6943,6 +6943,32 @@ mod staking_unsafe { ); }); } + + #[test] + fn virtual_staker_cannot_bond_again() { + ExtBuilder::default().build_and_execute(|| { + // 10 virtual bonds + assert_ok!(::virtual_bond(&10, 100, &11)); + + // Tries bonding again + assert_noop!( + ::virtual_bond(&10, 20, &11), + Error::::AlreadyBonded + ); + + // And again with a different reward destination. + assert_noop!( + ::virtual_bond(&10, 20, &12), + Error::::AlreadyBonded + ); + + // Direct bond is not allowed as well. + assert_noop!( + ::bond(&10, 20, &12), + Error::::AlreadyBonded + ); + }); + } } mod ledger { From 989bc500b4ba6a6174441c02ec462d7142232a28 Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 3 Apr 2024 07:19:46 +0200 Subject: [PATCH 038/257] release all becomes migrate_to_virtual_staker --- substrate/frame/staking/src/pallet/impls.rs | 5 +++-- substrate/frame/staking/src/tests.rs | 5 +++++ substrate/primitives/staking/src/lib.rs | 4 ++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index bd27a328aa21..029146935861 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -1942,8 +1942,9 @@ impl StakingInterface for Pallet { } impl sp_staking::StakingUnsafe for Pallet { - fn force_release(who: &Self::AccountId) { - T::Currency::remove_lock(crate::STAKING_ID, who) + fn migrate_to_virtual_staker(who: &Self::AccountId) { + T::Currency::remove_lock(crate::STAKING_ID, who); + VirtualStakers::::insert(who, ()); } fn virtual_bond( diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 094de96f19a5..67cc5b54b1a8 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -6969,6 +6969,11 @@ mod staking_unsafe { ); }); } + + #[test] + fn migrate_virtual_staker(){ + // TODO(ank4n) test migration integrity + } } mod ledger { diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index 0e1812e10ab2..fec915587d40 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -317,8 +317,8 @@ pub trait StakingInterface { pub trait StakingUnsafe: StakingInterface { /// Release all funds bonded for stake without unbonding the ledger. /// - /// Unsafe, only used for migration of `nominator` to `virtual_nominator`. - fn force_release(who: &Self::AccountId); + /// Unsafe, should only used for migration of `nominator` to `virtual_nominator`. + fn migrate_to_virtual_staker(who: &Self::AccountId); /// Book-keep a new bond for `who` without applying any locks (hence virtual). /// From 4226b9b4a124f8e2dfb64ada2c98f9ceabc2d155 Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 3 Apr 2024 07:37:37 +0200 Subject: [PATCH 039/257] fix function call --- substrate/frame/delegated-staking/src/lib.rs | 2 +- substrate/frame/delegated-staking/src/tests.rs | 10 +++------- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs index 89a6a581ca35..10992a0177ca 100644 --- a/substrate/frame/delegated-staking/src/lib.rs +++ b/substrate/frame/delegated-staking/src/lib.rs @@ -493,7 +493,7 @@ impl Pallet { let stake = T::CoreStaking::stake(who)?; // release funds from core staking. - T::CoreStaking::force_release(who); + T::CoreStaking::migrate_to_virtual_staker(who); // transferring just released staked amount. This should never fail but if it does, it // indicates bad state and we abort. diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs index 3abc9e4a6d67..0f4903377f48 100644 --- a/substrate/frame/delegated-staking/src/tests.rs +++ b/substrate/frame/delegated-staking/src/tests.rs @@ -411,18 +411,14 @@ mod staking_integration { 100 )); - // if delegate calls Staking pallet directly with a different reward destination, it - // fails. + // update_payee to self fails. assert_noop!( - Staking::set_payee(RuntimeOrigin::signed(200), RewardDestination::Stash), + ::update_payee(&200, &200), StakingError::::RewardDestinationRestricted ); // passing correct reward destination works - assert_ok!(Staking::set_payee( - RuntimeOrigin::signed(200), - RewardDestination::Account(201) - )); + assert_ok!(::update_payee(&200, &201)); // amount is staked correctly assert!(eq_stake(200, 100, 100)); From 6f05a52049aa91dd56547a435202f5c06193bf0f Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 3 Apr 2024 07:54:09 +0200 Subject: [PATCH 040/257] add test --- substrate/frame/staking/src/tests.rs | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 67cc5b54b1a8..108cfe3dd0bc 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -6971,11 +6971,26 @@ mod staking_unsafe { } #[test] - fn migrate_virtual_staker(){ - // TODO(ank4n) test migration integrity + fn migrate_virtual_staker() { + ExtBuilder::default().build_and_execute(|| { + // give some balance to 200 + Balances::make_free_balance_be(&200, 2000); + + // stake + assert_ok!(Staking::bond(RuntimeOrigin::signed(200), 1000, RewardDestination::Staked)); + assert_eq!(Balances::balance_locked(crate::STAKING_ID, &200), 1000); + + // migrate them to virtual staker + ::migrate_to_virtual_staker(&200); + + // ensure the balance is not locked anymore + assert_eq!(Balances::balance_locked(crate::STAKING_ID, &200), 0); + + // and they are marked as virtual stakers + assert_eq!(Pallet::::is_virtual_staker(&200), true); + }); } } - mod ledger { use super::*; From 4d00b043a7c1353b3c0254e73b1d0db682f6a852 Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 3 Apr 2024 07:58:03 +0200 Subject: [PATCH 041/257] remove benchmarking file --- .../delegated-staking/src/benchmarking.rs | 20 ------------------- 1 file changed, 20 deletions(-) delete mode 100644 substrate/frame/delegated-staking/src/benchmarking.rs diff --git a/substrate/frame/delegated-staking/src/benchmarking.rs b/substrate/frame/delegated-staking/src/benchmarking.rs deleted file mode 100644 index 808d19a5ce9a..000000000000 --- a/substrate/frame/delegated-staking/src/benchmarking.rs +++ /dev/null @@ -1,20 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Benchmarking for pallet-delegated-staking. - -#![cfg(feature = "runtime-benchmarks")] From 264f71a255972c1b35fb521a8fb95a25681f559c Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 3 Apr 2024 08:24:36 +0200 Subject: [PATCH 042/257] small refactors --- substrate/frame/staking/src/mock.rs | 7 +++++++ substrate/frame/staking/src/tests.rs | 10 +++++----- substrate/primitives/staking/src/lib.rs | 4 ++-- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 6db462c1a70f..11546e7971a1 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -598,6 +598,13 @@ pub(crate) fn bond_nominator(who: AccountId, val: Balance, target: Vec) { + // who is provided by another pallet in a real scenario. + System::inc_providers(&who); + assert_ok!(::virtual_bond(&who, val, &payee)); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(who), target)); +} + /// Progress to the given block, triggering session and era changes as we progress. /// /// This will finalize the previous block, initialize up to the given block, essentially simulating diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 108cfe3dd0bc..5be7b9c999b9 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -6947,24 +6947,24 @@ mod staking_unsafe { #[test] fn virtual_staker_cannot_bond_again() { ExtBuilder::default().build_and_execute(|| { - // 10 virtual bonds - assert_ok!(::virtual_bond(&10, 100, &11)); + // 200 virtual bonds + bond_virtual_nominator(200, 201, 500, vec![11, 21]); // Tries bonding again assert_noop!( - ::virtual_bond(&10, 20, &11), + ::virtual_bond(&200, 200, &201), Error::::AlreadyBonded ); // And again with a different reward destination. assert_noop!( - ::virtual_bond(&10, 20, &12), + ::virtual_bond(&200, 200, &202), Error::::AlreadyBonded ); // Direct bond is not allowed as well. assert_noop!( - ::bond(&10, 20, &12), + ::bond(&200, 200, &202), Error::::AlreadyBonded ); }); diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index fec915587d40..9939860d5da8 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -315,9 +315,9 @@ pub trait StakingInterface { /// These apis bypass some or all safety checks and should only be used if you know what you are /// doing. pub trait StakingUnsafe: StakingInterface { - /// Release all funds bonded for stake without unbonding the ledger. + /// Migrate an existing staker to a virtual staker. /// - /// Unsafe, should only used for migration of `nominator` to `virtual_nominator`. + /// It would release all funds held by the implementation pallet. fn migrate_to_virtual_staker(who: &Self::AccountId); /// Book-keep a new bond for `who` without applying any locks (hence virtual). From f9a52f181499a738a5afced6cba1983a8264c590 Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 3 Apr 2024 08:24:59 +0200 Subject: [PATCH 043/257] fmt --- substrate/frame/staking/src/mock.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 11546e7971a1..718ee697faed 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -598,7 +598,12 @@ pub(crate) fn bond_nominator(who: AccountId, val: Balance, target: Vec) { +pub(crate) fn bond_virtual_nominator( + who: AccountId, + payee: AccountId, + val: Balance, + target: Vec, +) { // who is provided by another pallet in a real scenario. System::inc_providers(&who); assert_ok!(::virtual_bond(&who, val, &payee)); From df61e32c2d5436ba4242407a3175b43bbe1d6541 Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 3 Apr 2024 09:44:54 +0200 Subject: [PATCH 044/257] doc updates --- substrate/frame/nomination-pools/src/adapter.rs | 7 +++++++ substrate/frame/nomination-pools/src/lib.rs | 2 ++ 2 files changed, 9 insertions(+) diff --git a/substrate/frame/nomination-pools/src/adapter.rs b/substrate/frame/nomination-pools/src/adapter.rs index e1a692b5d3d5..59e4e75d27be 100644 --- a/substrate/frame/nomination-pools/src/adapter.rs +++ b/substrate/frame/nomination-pools/src/adapter.rs @@ -127,6 +127,9 @@ pub trait StakeStrategy { /// /// In order to stake, this adapter transfers the funds from the member/delegator account to the /// pool account and stakes through the pool account on `Staking`. +/// +/// This is the older Staking strategy used by pools. To switch to the newer [`DelegateStake`] +/// strategy, storage migration is required. pub struct TransferStake(PhantomData<(T, Staking)>); impl, AccountId = T::AccountId>> @@ -207,6 +210,10 @@ impl, AccountId = T: /// In this approach, first the funds are delegated from delegator to the pool account and later /// staked with `Staking`. The advantage of this approach is that the funds are held in the /// user account itself and not in the pool account. +/// +/// This is the newer staking strategy used by pools. Once switched to this and migrated, ideally +/// the `TransferStake` strategy should not be used. Or a separate migration would be required for +/// it which is not provided by this pallet. pub struct DelegateStake( PhantomData<(T, Staking, Delegation)>, ); diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs index 8d87fe8d492d..09e18a60abed 100644 --- a/substrate/frame/nomination-pools/src/lib.rs +++ b/substrate/frame/nomination-pools/src/lib.rs @@ -1633,6 +1633,8 @@ pub mod pallet { type U256ToBalance: Convert>; /// The interface for nominating. + /// + /// Note: Switching to a new StakeStrategy might require a migration of the storage. type StakeAdapter: StakeStrategy>; /// The amount of eras a `SubPools::with_era` pool can exist before it gets merged into the From 7bf4d34ab6e3dafc7b81ffd56be19b141d748dc8 Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 3 Apr 2024 11:47:32 +0200 Subject: [PATCH 045/257] remove mod bench --- substrate/frame/delegated-staking/src/lib.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs index 10992a0177ca..126433590792 100644 --- a/substrate/frame/delegated-staking/src/lib.rs +++ b/substrate/frame/delegated-staking/src/lib.rs @@ -138,9 +138,6 @@ use types::*; mod impls; -#[cfg(feature = "runtime-benchmarks")] -mod benchmarking; - use frame_support::{ pallet_prelude::*, traits::{ From 40a5132e23b778be85a326d84624838b0ff3c804 Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 3 Apr 2024 15:04:04 +0200 Subject: [PATCH 046/257] add pool migration function to Delegation Interface --- substrate/frame/delegated-staking/src/impls.rs | 10 ++++++++++ substrate/primitives/staking/src/lib.rs | 9 +++++++++ 2 files changed, 19 insertions(+) diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs index 56ad399ef494..c31f6a3028a7 100644 --- a/substrate/frame/delegated-staking/src/impls.rs +++ b/substrate/frame/delegated-staking/src/impls.rs @@ -106,6 +106,16 @@ impl DelegationInterface for Pallet { ) -> sp_runtime::DispatchResult { Pallet::::do_slash(agent.clone(), delegator.clone(), value, maybe_reporter) } + + fn migrate_nominator_to_agent( + agent: &Self::AccountId, + reward_account: &Self::AccountId, + ) -> DispatchResult { + Pallet::::migrate_to_agent( + RawOrigin::Signed(agent.clone()).into(), + reward_account.clone(), + ) + } } impl OnStakingUpdate> for Pallet { diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index 1cf889413291..adb4ac35bf10 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -536,6 +536,15 @@ pub trait DelegationInterface { value: Self::Balance, maybe_reporter: Option, ) -> sp_runtime::DispatchResult; + + /// Migrate an existing `Nominator` to `Agent` account. + /// + /// The implementation should ensure the `Nominator` account funds are moved to a temporary + /// `delegator` account from which funds can be later claimed as existing `Delegators`. + fn migrate_nominator_to_agent( + agent: &Self::AccountId, + reward_account: &Self::AccountId, + ) -> DispatchResult; } sp_core::generate_feature_enabled_macro!(runtime_benchmarks_enabled, feature = "runtime-benchmarks", $); From bbb3bb696bc8252e33618e1fe023317ef227b61d Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 3 Apr 2024 14:52:32 +0200 Subject: [PATCH 047/257] basic migration of pools to delegate stake --- substrate/frame/nomination-pools/src/lib.rs | 13 +++++ .../frame/nomination-pools/src/migration.rs | 57 ++++++++++++++++++- 2 files changed, 68 insertions(+), 2 deletions(-) diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs index 09e18a60abed..b2ba3157e348 100644 --- a/substrate/frame/nomination-pools/src/lib.rs +++ b/substrate/frame/nomination-pools/src/lib.rs @@ -2951,6 +2951,19 @@ impl Pallet { T::PalletId::get().into_sub_account_truncating((AccountType::Bonded, id)) } + pub fn migrate_to_delegate_stake(_id: PoolId) -> DispatchResult { + // TODO(ank4n): implement this. + Ok(()) + } + + /// Useful for tests. + #[cfg(test)] + #[allow(unused)] + pub fn migrate_to_transfer_stake(_id: PoolId) -> DispatchResult { + // TODO(ank4n): implement this. + Ok(()) + } + /// Create the reward account of a pool with the given id. pub fn create_reward_account(id: PoolId) -> T::AccountId { // NOTE: in order to have a distinction in the test account id type (u128), we put diff --git a/substrate/frame/nomination-pools/src/migration.rs b/substrate/frame/nomination-pools/src/migration.rs index 5a97d380ac71..cc1b58b1e5b9 100644 --- a/substrate/frame/nomination-pools/src/migration.rs +++ b/substrate/frame/nomination-pools/src/migration.rs @@ -107,6 +107,59 @@ pub mod unversioned { Ok(()) } } + + /// Migrate existing pools from [`adapter::TransferStake`] to [`adapter::DelegateStake`]. + /// + /// Note: This only migrates the pools, the members are not migrated. They can use the + /// permission-less [`Call::claim_delegation()`] to migrate their funds. + pub struct DelegationStakeMigration(sp_std::marker::PhantomData); + + // FIXME(ank4n) convert to MBM. + impl OnRuntimeUpgrade for DelegationStakeMigration { + fn on_runtime_upgrade() -> Weight { + let mut migrate_count: u32 = 0; + let mut fail_count: u32 = 0; + BondedPools::::iter() + .for_each(|(id, _inner)| { + if Pallet::::migrate_to_delegate_stake(id).is_ok() { + migrate_count.saturating_inc(); + } else { + fail_count.saturating_inc(); + } + }); + + // TODO(ank4n) bench `migrate_to_delegate_stake`. + Weight::default() + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, TryRuntimeError> { + let mut pool_balances: Vec> = Vec::new(); + BondedPools::::iter_keys().for_each(|id| { + pool_balances.push(T::Currency::total_balance(&Pallet::::create_bonded_account(id))); + }); + + Ok(pool_balances.encode()) + + } + #[cfg(feature = "try-runtime")] + fn post_upgrade(data: Vec) -> Result<(), TryRuntimeError> { + let expected_pool_balances: Vec> = Decode::decode(&mut &data[..]).unwrap(); + + for (index, id) in BondedPools::::iter_keys().enumerate() { + let actual_balance = T::StakeAdapter::total_balance(&Pallet::::create_bonded_account(id)); + let expected_balance = expected_pool_balances.get(index).unwrap(); + + if actual_balance != *expected_balance { + log!(error, "Pool {} balance mismatch. Expected: {:?}, Actual: {:?}", id, expected_balance, actual_balance); + return Err(TryRuntimeError::Other("Pool balance mismatch")); + } + }; + + Ok(()) + } + } + } pub mod v8 { @@ -1022,8 +1075,8 @@ mod helpers { use super::*; pub(crate) fn calculate_tvl_by_total_stake() -> BalanceOf { - BondedPools::::iter() - .map(|(id, _inner)| { + BondedPools::::iter_keys() + .map(|id| { T::StakeAdapter::total_stake(&Pallet::::create_bonded_account(id)) }) .reduce(|acc, total_balance| acc + total_balance) From fa58b3651bca8a69f1f4fb82ea49b89318212ed9 Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 3 Apr 2024 15:04:04 +0200 Subject: [PATCH 048/257] add pool migration function to Delegation Interface --- substrate/frame/delegated-staking/src/impls.rs | 10 ++++++++++ substrate/primitives/staking/src/lib.rs | 9 +++++++++ 2 files changed, 19 insertions(+) diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs index 63132540ea7d..354cc5e35e27 100644 --- a/substrate/frame/delegated-staking/src/impls.rs +++ b/substrate/frame/delegated-staking/src/impls.rs @@ -105,6 +105,16 @@ impl DelegationInterface for Pallet { ) -> sp_runtime::DispatchResult { Pallet::::do_slash(agent.clone(), delegator.clone(), value, maybe_reporter) } + + fn migrate_nominator_to_agent( + agent: &Self::AccountId, + reward_account: &Self::AccountId, + ) -> DispatchResult { + Pallet::::migrate_to_agent( + RawOrigin::Signed(agent.clone()).into(), + reward_account.clone(), + ) + } } impl OnStakingUpdate> for Pallet { diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index 1cf889413291..adb4ac35bf10 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -536,6 +536,15 @@ pub trait DelegationInterface { value: Self::Balance, maybe_reporter: Option, ) -> sp_runtime::DispatchResult; + + /// Migrate an existing `Nominator` to `Agent` account. + /// + /// The implementation should ensure the `Nominator` account funds are moved to a temporary + /// `delegator` account from which funds can be later claimed as existing `Delegators`. + fn migrate_nominator_to_agent( + agent: &Self::AccountId, + reward_account: &Self::AccountId, + ) -> DispatchResult; } sp_core::generate_feature_enabled_macro!(runtime_benchmarks_enabled, feature = "runtime-benchmarks", $); From 26d3cce64afd0c351910ed91e411205342b4b7c3 Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 3 Apr 2024 15:16:58 +0200 Subject: [PATCH 049/257] basic migration --- substrate/frame/nomination-pools/src/adapter.rs | 16 ++++++++++++++++ substrate/frame/nomination-pools/src/lib.rs | 13 ++----------- .../frame/nomination-pools/src/migration.rs | 7 +++++++ 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/substrate/frame/nomination-pools/src/adapter.rs b/substrate/frame/nomination-pools/src/adapter.rs index 59e4e75d27be..1bbdc4dfd096 100644 --- a/substrate/frame/nomination-pools/src/adapter.rs +++ b/substrate/frame/nomination-pools/src/adapter.rs @@ -117,6 +117,8 @@ pub trait StakeStrategy { maybe_reporter: Option, ) -> DispatchResult; + fn migrate_nominator_to_agent(agent: &Self::AccountId, reward_account: &Self::AccountId) -> DispatchResult; + #[cfg(feature = "runtime-benchmarks")] fn nominations(pool_account: &Self::AccountId) -> Option> { Self::CoreStaking::nominations(pool_account) @@ -203,6 +205,13 @@ impl, AccountId = T: ) -> DispatchResult { Err(Error::::Defensive(DefensiveError::DelegationUnsupported).into()) } + + fn migrate_nominator_to_agent( + _agent: &Self::AccountId, + _reward_account: &Self::AccountId, + ) -> DispatchResult { + Err(Error::::Defensive(DefensiveError::DelegationUnsupported).into()) + } } /// A staking strategy implementation that supports delegation based staking. @@ -286,4 +295,11 @@ impl< ) -> DispatchResult { Delegation::delegator_slash(pool_account, who, amount, maybe_reporter) } + + fn migrate_nominator_to_agent( + agent: &Self::AccountId, + reward_account: &Self::AccountId, + ) -> DispatchResult { + Delegation::migrate_nominator_to_agent(agent, reward_account) + } } diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs index b2ba3157e348..b9eaceff66df 100644 --- a/substrate/frame/nomination-pools/src/lib.rs +++ b/substrate/frame/nomination-pools/src/lib.rs @@ -2951,17 +2951,8 @@ impl Pallet { T::PalletId::get().into_sub_account_truncating((AccountType::Bonded, id)) } - pub fn migrate_to_delegate_stake(_id: PoolId) -> DispatchResult { - // TODO(ank4n): implement this. - Ok(()) - } - - /// Useful for tests. - #[cfg(test)] - #[allow(unused)] - pub fn migrate_to_transfer_stake(_id: PoolId) -> DispatchResult { - // TODO(ank4n): implement this. - Ok(()) + pub fn migrate_to_delegate_stake(id: PoolId) -> DispatchResult { + T::StakeAdapter::migrate_nominator_to_agent(&Self::create_bonded_account(id), &Self::create_reward_account(id)) } /// Create the reward account of a pool with the given id. diff --git a/substrate/frame/nomination-pools/src/migration.rs b/substrate/frame/nomination-pools/src/migration.rs index cc1b58b1e5b9..df01919fb34d 100644 --- a/substrate/frame/nomination-pools/src/migration.rs +++ b/substrate/frame/nomination-pools/src/migration.rs @@ -154,6 +154,13 @@ pub mod unversioned { log!(error, "Pool {} balance mismatch. Expected: {:?}, Actual: {:?}", id, expected_balance, actual_balance); return Err(TryRuntimeError::Other("Pool balance mismatch")); } + + // account balance should be zero. + let pool_account_balance = T::Currency::total_balance(&Pallet::::create_bonded_account(id)); + if pool_account_balance != Zero::zero() { + log!(error, "Pool account balance was expected to be zero. Pool: {}, Balance: {:?}", id, pool_account_balance); + return Err(TryRuntimeError::Other("Pool account balance not migrated")); + } }; Ok(()) From e2c17f4e9f4deb1f7111783703eeb9710214a2d2 Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 3 Apr 2024 15:17:28 +0200 Subject: [PATCH 050/257] fmt --- .../frame/nomination-pools/src/adapter.rs | 5 +- substrate/frame/nomination-pools/src/lib.rs | 5 +- .../frame/nomination-pools/src/migration.rs | 47 +++++++++++-------- 3 files changed, 36 insertions(+), 21 deletions(-) diff --git a/substrate/frame/nomination-pools/src/adapter.rs b/substrate/frame/nomination-pools/src/adapter.rs index 1bbdc4dfd096..5729cd5d9050 100644 --- a/substrate/frame/nomination-pools/src/adapter.rs +++ b/substrate/frame/nomination-pools/src/adapter.rs @@ -117,7 +117,10 @@ pub trait StakeStrategy { maybe_reporter: Option, ) -> DispatchResult; - fn migrate_nominator_to_agent(agent: &Self::AccountId, reward_account: &Self::AccountId) -> DispatchResult; + fn migrate_nominator_to_agent( + agent: &Self::AccountId, + reward_account: &Self::AccountId, + ) -> DispatchResult; #[cfg(feature = "runtime-benchmarks")] fn nominations(pool_account: &Self::AccountId) -> Option> { diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs index b9eaceff66df..47bf35c6584b 100644 --- a/substrate/frame/nomination-pools/src/lib.rs +++ b/substrate/frame/nomination-pools/src/lib.rs @@ -2952,7 +2952,10 @@ impl Pallet { } pub fn migrate_to_delegate_stake(id: PoolId) -> DispatchResult { - T::StakeAdapter::migrate_nominator_to_agent(&Self::create_bonded_account(id), &Self::create_reward_account(id)) + T::StakeAdapter::migrate_nominator_to_agent( + &Self::create_bonded_account(id), + &Self::create_reward_account(id), + ) } /// Create the reward account of a pool with the given id. diff --git a/substrate/frame/nomination-pools/src/migration.rs b/substrate/frame/nomination-pools/src/migration.rs index df01919fb34d..7cb50927b3cd 100644 --- a/substrate/frame/nomination-pools/src/migration.rs +++ b/substrate/frame/nomination-pools/src/migration.rs @@ -119,14 +119,13 @@ pub mod unversioned { fn on_runtime_upgrade() -> Weight { let mut migrate_count: u32 = 0; let mut fail_count: u32 = 0; - BondedPools::::iter() - .for_each(|(id, _inner)| { - if Pallet::::migrate_to_delegate_stake(id).is_ok() { - migrate_count.saturating_inc(); - } else { - fail_count.saturating_inc(); - } - }); + BondedPools::::iter().for_each(|(id, _inner)| { + if Pallet::::migrate_to_delegate_stake(id).is_ok() { + migrate_count.saturating_inc(); + } else { + fail_count.saturating_inc(); + } + }); // TODO(ank4n) bench `migrate_to_delegate_stake`. Weight::default() @@ -136,37 +135,49 @@ pub mod unversioned { fn pre_upgrade() -> Result, TryRuntimeError> { let mut pool_balances: Vec> = Vec::new(); BondedPools::::iter_keys().for_each(|id| { - pool_balances.push(T::Currency::total_balance(&Pallet::::create_bonded_account(id))); + pool_balances + .push(T::Currency::total_balance(&Pallet::::create_bonded_account(id))); }); Ok(pool_balances.encode()) - } #[cfg(feature = "try-runtime")] fn post_upgrade(data: Vec) -> Result<(), TryRuntimeError> { let expected_pool_balances: Vec> = Decode::decode(&mut &data[..]).unwrap(); for (index, id) in BondedPools::::iter_keys().enumerate() { - let actual_balance = T::StakeAdapter::total_balance(&Pallet::::create_bonded_account(id)); + let actual_balance = + T::StakeAdapter::total_balance(&Pallet::::create_bonded_account(id)); let expected_balance = expected_pool_balances.get(index).unwrap(); if actual_balance != *expected_balance { - log!(error, "Pool {} balance mismatch. Expected: {:?}, Actual: {:?}", id, expected_balance, actual_balance); + log!( + error, + "Pool {} balance mismatch. Expected: {:?}, Actual: {:?}", + id, + expected_balance, + actual_balance + ); return Err(TryRuntimeError::Other("Pool balance mismatch")); } // account balance should be zero. - let pool_account_balance = T::Currency::total_balance(&Pallet::::create_bonded_account(id)); + let pool_account_balance = + T::Currency::total_balance(&Pallet::::create_bonded_account(id)); if pool_account_balance != Zero::zero() { - log!(error, "Pool account balance was expected to be zero. Pool: {}, Balance: {:?}", id, pool_account_balance); + log!( + error, + "Pool account balance was expected to be zero. Pool: {}, Balance: {:?}", + id, + pool_account_balance + ); return Err(TryRuntimeError::Other("Pool account balance not migrated")); } - }; + } Ok(()) } } - } pub mod v8 { @@ -1083,9 +1094,7 @@ mod helpers { pub(crate) fn calculate_tvl_by_total_stake() -> BalanceOf { BondedPools::::iter_keys() - .map(|id| { - T::StakeAdapter::total_stake(&Pallet::::create_bonded_account(id)) - }) + .map(|id| T::StakeAdapter::total_stake(&Pallet::::create_bonded_account(id))) .reduce(|acc, total_balance| acc + total_balance) .unwrap_or_default() } From e8e498cfd682f2b4799bcc2a8f43e0ad21ddd619 Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 3 Apr 2024 15:51:53 +0200 Subject: [PATCH 051/257] add migrate delegation to delegation interface --- substrate/frame/delegated-staking/src/impls.rs | 12 ++++++++++++ substrate/primitives/staking/src/lib.rs | 14 ++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs index c31f6a3028a7..46f78700dc65 100644 --- a/substrate/frame/delegated-staking/src/impls.rs +++ b/substrate/frame/delegated-staking/src/impls.rs @@ -116,6 +116,18 @@ impl DelegationInterface for Pallet { reward_account.clone(), ) } + + fn migrate_delegation( + agent: &Self::AccountId, + delegator: &Self::AccountId, + value: Self::Balance, + ) -> DispatchResult { + Pallet::::claim_delegation( + RawOrigin::Signed(agent.clone()).into(), + delegator.clone(), + value, + ) + } } impl OnStakingUpdate> for Pallet { diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index adb4ac35bf10..bb57468aa456 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -539,12 +539,22 @@ pub trait DelegationInterface { /// Migrate an existing `Nominator` to `Agent` account. /// - /// The implementation should ensure the `Nominator` account funds are moved to a temporary - /// `delegator` account from which funds can be later claimed as existing `Delegators`. + /// The implementation should ensure the `Nominator` account funds are moved to an escrow + /// from which `Agents` can later release funds to its `Delegators`. fn migrate_nominator_to_agent( agent: &Self::AccountId, reward_account: &Self::AccountId, ) -> DispatchResult; + + /// Migrate `value` of delegation to `delegator` from a migrating agent. + /// + /// When a direct `Nominator` migrates to `Agent`, the funds are kept in escrow. This function + /// allows the `Agent` to release the funds to the `delegator`. + fn migrate_delegation( + agent: &Self::AccountId, + delegator: &Self::AccountId, + value: Self::Balance, + ) -> DispatchResult; } sp_core::generate_feature_enabled_macro!(runtime_benchmarks_enabled, feature = "runtime-benchmarks", $); From 004f2d319d48e59ee527bd7ddab504ad0abcae9a Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 3 Apr 2024 16:03:01 +0200 Subject: [PATCH 052/257] add a way for members to claim delegation --- .../frame/nomination-pools/src/adapter.rs | 22 +++++++++++ substrate/frame/nomination-pools/src/lib.rs | 38 ++++++++++++++++++- 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/substrate/frame/nomination-pools/src/adapter.rs b/substrate/frame/nomination-pools/src/adapter.rs index 5729cd5d9050..fb79bb9b9ddc 100644 --- a/substrate/frame/nomination-pools/src/adapter.rs +++ b/substrate/frame/nomination-pools/src/adapter.rs @@ -122,6 +122,12 @@ pub trait StakeStrategy { reward_account: &Self::AccountId, ) -> DispatchResult; + fn migrate_delegation( + agent: &Self::AccountId, + delegator: &Self::AccountId, + value: Self::Balance, + ) -> DispatchResult; + #[cfg(feature = "runtime-benchmarks")] fn nominations(pool_account: &Self::AccountId) -> Option> { Self::CoreStaking::nominations(pool_account) @@ -215,6 +221,14 @@ impl, AccountId = T: ) -> DispatchResult { Err(Error::::Defensive(DefensiveError::DelegationUnsupported).into()) } + + fn migrate_delegation( + _agent: &Self::AccountId, + _delegator: &Self::AccountId, + _value: Self::Balance, + ) -> DispatchResult { + Err(Error::::Defensive(DefensiveError::DelegationUnsupported).into()) + } } /// A staking strategy implementation that supports delegation based staking. @@ -305,4 +319,12 @@ impl< ) -> DispatchResult { Delegation::migrate_nominator_to_agent(agent, reward_account) } + + fn migrate_delegation( + agent: &Self::AccountId, + delegator: &Self::AccountId, + value: Self::Balance, + ) -> DispatchResult { + Delegation::migrate_delegation(agent, delegator, value) + } } diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs index 47bf35c6584b..fa78fac46034 100644 --- a/substrate/frame/nomination-pools/src/lib.rs +++ b/substrate/frame/nomination-pools/src/lib.rs @@ -1938,6 +1938,8 @@ pub mod pallet { NothingToAdjust, /// No slash pending that can be applied to the member. NothingToSlash, + /// No delegation to claim. + NoDelegationToClaim, } #[derive(Encode, Decode, PartialEq, TypeInfo, PalletError, RuntimeDebug)] @@ -2830,7 +2832,7 @@ pub mod pallet { /// Apply a pending slash on a member. #[pallet::call_index(23)] // FIXME(ank4n): fix weight. Depends on unbonding pool count for member_account. - #[pallet::weight(T::WeightInfo::set_commission_claim_permission())] + #[pallet::weight(Weight::default())] pub fn apply_slash( origin: OriginFor, member_account: AccountIdLookupOf, @@ -2839,6 +2841,40 @@ pub mod pallet { let member_account = T::Lookup::lookup(member_account)?; Self::do_apply_slash(&member_account, Some(who)) } + + /// Allows a pool member to claim their delegation in their own account. + /// + /// This is a permission-less call and refunds any fee if claim is successful. + /// + /// If the pool has migrated to delegation based staking, the staked tokens of pool members + /// can be moved and held in their own account. See [`adapter::DelegateStake`] + #[pallet::call_index(24)] + // FIXME(ank4n): Bench and migration tests for pool. + #[pallet::weight(Weight::default())] + pub fn claim_delegation( + origin: OriginFor, + member_account: AccountIdLookupOf, + ) -> DispatchResultWithPostInfo { + let _caller = ensure_signed(origin)?; + + let member_account = T::Lookup::lookup(member_account)?; + let member = + PoolMembers::::get(&member_account).ok_or(Error::::PoolMemberNotFound)?; + let pool_contribution = member.total_balance(); + ensure!(pool_contribution >= MinJoinBond::::get(), Error::::MinimumBondNotMet); + + let delegation = T::StakeAdapter::member_delegation_balance(&member_account); + ensure!(pool_contribution > delegation, Error::::NoDelegationToClaim); + + let diff = pool_contribution.defensive_saturating_sub(delegation); + T::StakeAdapter::migrate_delegation( + &Pallet::::create_bonded_account(member.pool_id), + &member_account, + diff, + )?; + + Ok(Pays::No.into()) + } } #[pallet::hooks] From f5208f6d9a6301d8ba877ae5280eb02420458a6f Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 3 Apr 2024 16:57:00 +0200 Subject: [PATCH 053/257] wip --- Cargo.lock | 1 + substrate/frame/delegated-staking/src/lib.rs | 6 +++--- .../nomination-pools/benchmarking/Cargo.toml | 3 +++ .../nomination-pools/benchmarking/src/lib.rs | 2 +- .../nomination-pools/benchmarking/src/mock.rs | 20 ++++++++++++++++--- .../test-delegate-stake/src/mock.rs | 2 +- 6 files changed, 26 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cab9eb45cda5..9c052d132efd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10366,6 +10366,7 @@ dependencies = [ "frame-system", "pallet-bags-list", "pallet-balances", + "pallet-delegated-staking", "pallet-nomination-pools", "pallet-staking", "pallet-staking-reward-curve", diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs index 126433590792..68839db4d42c 100644 --- a/substrate/frame/delegated-staking/src/lib.rs +++ b/substrate/frame/delegated-staking/src/lib.rs @@ -390,9 +390,6 @@ pub mod pallet { ) -> DispatchResult { let delegator = ensure_signed(origin)?; - // ensure amount is over minimum to delegate - ensure!(amount > T::Currency::minimum_balance(), Error::::NotEnoughFunds); - // ensure delegator is sane. ensure!( Delegation::::can_delegate(&delegator, &agent), @@ -534,6 +531,9 @@ impl Pallet { amount }; + // ensure amount is at least minimum to delegate. + ensure!(new_delegation_amount >= T::Currency::minimum_balance(), Error::::NotEnoughFunds); + Delegation::::from(agent, new_delegation_amount).save_or_kill(delegator); ledger.total_delegated = ledger.total_delegated.checked_add(&amount).ok_or(ArithmeticError::Overflow)?; diff --git a/substrate/frame/nomination-pools/benchmarking/Cargo.toml b/substrate/frame/nomination-pools/benchmarking/Cargo.toml index 3693ad1866dd..c6f274340974 100644 --- a/substrate/frame/nomination-pools/benchmarking/Cargo.toml +++ b/substrate/frame/nomination-pools/benchmarking/Cargo.toml @@ -27,6 +27,7 @@ frame-support = { path = "../../support", default-features = false } frame-system = { path = "../../system", default-features = false } pallet-bags-list = { path = "../../bags-list", default-features = false } pallet-staking = { path = "../../staking", default-features = false } +pallet-delegated-staking = { path = "../../delegated-staking", default-features = false } pallet-nomination-pools = { path = "..", default-features = false } # Substrate Primitives @@ -55,6 +56,7 @@ std = [ "pallet-balances/std", "pallet-nomination-pools/std", "pallet-staking/std", + "pallet-delegated-staking/std", "pallet-timestamp/std", "scale-info/std", "sp-core/std", @@ -74,6 +76,7 @@ runtime-benchmarks = [ "pallet-balances/runtime-benchmarks", "pallet-nomination-pools/runtime-benchmarks", "pallet-staking/runtime-benchmarks", + "pallet-delegated-staking/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "sp-staking/runtime-benchmarks", diff --git a/substrate/frame/nomination-pools/benchmarking/src/lib.rs b/substrate/frame/nomination-pools/benchmarking/src/lib.rs index 7d8a629c38f5..57265d4838f5 100644 --- a/substrate/frame/nomination-pools/benchmarking/src/lib.rs +++ b/substrate/frame/nomination-pools/benchmarking/src/lib.rs @@ -487,7 +487,7 @@ frame_benchmarking::benchmarks! { Zero::zero() ); assert_eq!( - CurrencyOf::::balance(&pool_account), + T::StakeAdapter::total_balance(&pool_account), min_create_bond ); assert_eq!(pallet_staking::Ledger::::get(&pool_account).unwrap().unlocking.len(), 1); diff --git a/substrate/frame/nomination-pools/benchmarking/src/mock.rs b/substrate/frame/nomination-pools/benchmarking/src/mock.rs index 5034d43b969e..5606d63db2ad 100644 --- a/substrate/frame/nomination-pools/benchmarking/src/mock.rs +++ b/substrate/frame/nomination-pools/benchmarking/src/mock.rs @@ -77,7 +77,7 @@ impl pallet_balances::Config for Runtime { type WeightInfo = (); type FreezeIdentifier = RuntimeFreezeReason; type MaxFreezes = ConstU32<1>; - type RuntimeHoldReason = (); + type RuntimeHoldReason = RuntimeHoldReason; type RuntimeFreezeReason = (); } @@ -121,7 +121,7 @@ impl pallet_staking::Config for Runtime { type MaxControllersInDeprecationBatch = ConstU32<100>; type MaxUnlockingChunks = ConstU32<32>; type HistoryDepth = ConstU32<84>; - type EventListeners = Pools; + type EventListeners = (Pools, DelegatedStaking); type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; type WeightInfo = (); } @@ -166,7 +166,8 @@ impl pallet_nomination_pools::Config for Runtime { type RewardCounter = FixedU128; type BalanceToU256 = BalanceToU256; type U256ToBalance = U256ToBalance; - type StakeAdapter = pallet_nomination_pools::adapter::TransferStake; + type StakeAdapter = + pallet_nomination_pools::adapter::DelegateStake; type PostUnbondingPoolsWindow = PostUnbondingPoolsWindow; type MaxMetadataLen = ConstU32<256>; type MaxUnbonding = ConstU32<8>; @@ -174,6 +175,18 @@ impl pallet_nomination_pools::Config for Runtime { type MaxPointsToBalance = MaxPointsToBalance; } +parameter_types! { + pub const DelegatedStakingPalletId: PalletId = PalletId(*b"py/dlstk"); +} +impl pallet_delegated_staking::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type PalletId = DelegatedStakingPalletId; + type Currency = Balances; + type OnSlash = (); + type RuntimeHoldReason = RuntimeHoldReason; + type CoreStaking = Staking; +} + impl crate::Config for Runtime {} type Block = frame_system::mocking::MockBlock; @@ -186,6 +199,7 @@ frame_support::construct_runtime!( Staking: pallet_staking, VoterList: pallet_bags_list::, Pools: pallet_nomination_pools, + DelegatedStaking: pallet_delegated_staking, } ); diff --git a/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs b/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs index 9f5a531390a4..399b6a26eb0d 100644 --- a/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs +++ b/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs @@ -209,8 +209,8 @@ frame_support::construct_runtime!( Balances: pallet_balances, Staking: pallet_staking, VoterList: pallet_bags_list::, - DelegatedStaking: pallet_delegated_staking, Pools: pallet_nomination_pools, + DelegatedStaking: pallet_delegated_staking, } ); From 536f2fbf76783be717a0140feda8c140a3368e38 Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 3 Apr 2024 17:38:06 +0200 Subject: [PATCH 054/257] give np some extra balance --- substrate/frame/nomination-pools/benchmarking/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/frame/nomination-pools/benchmarking/src/lib.rs b/substrate/frame/nomination-pools/benchmarking/src/lib.rs index 57265d4838f5..50df89961afc 100644 --- a/substrate/frame/nomination-pools/benchmarking/src/lib.rs +++ b/substrate/frame/nomination-pools/benchmarking/src/lib.rs @@ -529,8 +529,8 @@ frame_benchmarking::benchmarks! { let depositor_lookup = T::Lookup::unlookup(depositor.clone()); // Give the depositor some balance to bond - CurrencyOf::::set_balance(&depositor, min_create_bond * 2u32.into()); - + // it needs to transfer min balance to reward account as well so give additional min balance. + CurrencyOf::::set_balance(&depositor, min_create_bond + CurrencyOf::::minimum_balance() * 2u32.into()); // Make sure no Pools exist at a pre-condition for our verify checks assert_eq!(RewardPools::::count(), 0); assert_eq!(BondedPools::::count(), 0); From 63fad76b3c4b30e6ff3249179de9ee8953ba7471 Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 3 Apr 2024 17:38:27 +0200 Subject: [PATCH 055/257] fmt --- substrate/frame/delegated-staking/src/lib.rs | 5 ++++- substrate/frame/nomination-pools/benchmarking/src/mock.rs | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs index 68839db4d42c..3f1fde6803dd 100644 --- a/substrate/frame/delegated-staking/src/lib.rs +++ b/substrate/frame/delegated-staking/src/lib.rs @@ -532,7 +532,10 @@ impl Pallet { }; // ensure amount is at least minimum to delegate. - ensure!(new_delegation_amount >= T::Currency::minimum_balance(), Error::::NotEnoughFunds); + ensure!( + new_delegation_amount >= T::Currency::minimum_balance(), + Error::::NotEnoughFunds + ); Delegation::::from(agent, new_delegation_amount).save_or_kill(delegator); ledger.total_delegated = diff --git a/substrate/frame/nomination-pools/benchmarking/src/mock.rs b/substrate/frame/nomination-pools/benchmarking/src/mock.rs index 5606d63db2ad..039bcc8725b3 100644 --- a/substrate/frame/nomination-pools/benchmarking/src/mock.rs +++ b/substrate/frame/nomination-pools/benchmarking/src/mock.rs @@ -167,7 +167,7 @@ impl pallet_nomination_pools::Config for Runtime { type BalanceToU256 = BalanceToU256; type U256ToBalance = U256ToBalance; type StakeAdapter = - pallet_nomination_pools::adapter::DelegateStake; + pallet_nomination_pools::adapter::DelegateStake; type PostUnbondingPoolsWindow = PostUnbondingPoolsWindow; type MaxMetadataLen = ConstU32<256>; type MaxUnbonding = ConstU32<8>; From 5ece9c7000635b5dfde7f2cd95c4d55b2e15a176 Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 3 Apr 2024 17:46:59 +0200 Subject: [PATCH 056/257] dec provider if agent is killed --- substrate/frame/delegated-staking/src/lib.rs | 9 ++++++--- substrate/frame/delegated-staking/src/types.rs | 13 +++++++------ 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs index 126433590792..80355eee5860 100644 --- a/substrate/frame/delegated-staking/src/lib.rs +++ b/substrate/frame/delegated-staking/src/lib.rs @@ -572,9 +572,12 @@ impl Pallet { // if we still do not have enough funds to release, abort. ensure!(agent.ledger.unclaimed_withdrawals >= amount, Error::::NotEnoughFunds); - // claim withdraw from agent. - agent.remove_unclaimed_withdraw(amount)?.save_or_kill()?; - + // claim withdraw from agent. Kill agent if no delegation left. + // TODO(ank4n): Ideally if there is a register, there should be an unregister that should + // clean up the agent. Need to improve this. + if agent.remove_unclaimed_withdraw(amount)?.save_or_kill()? { + let _ = frame_system::Pallet::::dec_providers(who).defensive(); + } // book keep delegation delegation.amount = delegation .amount diff --git a/substrate/frame/delegated-staking/src/types.rs b/substrate/frame/delegated-staking/src/types.rs index d48579226574..9eee2e61016d 100644 --- a/substrate/frame/delegated-staking/src/types.rs +++ b/substrate/frame/delegated-staking/src/types.rs @@ -263,8 +263,10 @@ impl Agent { /// Save self and remove if no delegation left. /// - /// Returns error if the delegate is in an unexpected state. - pub(crate) fn save_or_kill(self) -> Result<(), DispatchError> { + /// Returns: + /// - true if agent killed. + /// - error if the delegate is in an unexpected state. + pub(crate) fn save_or_kill(self) -> Result { let key = self.key; // see if delegate can be killed if self.ledger.total_delegated == Zero::zero() { @@ -274,11 +276,10 @@ impl Agent { Error::::BadState ); >::remove(key); - } else { - self.ledger.save(&key) + return Ok(true) } - - Ok(()) + self.ledger.save(&key); + Ok(false) } /// Reloads self from storage. From 65693d1b7461d6a1d23819547d6b770626638623 Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 3 Apr 2024 18:06:56 +0200 Subject: [PATCH 057/257] fix doc link --- substrate/frame/nomination-pools/src/migration.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/nomination-pools/src/migration.rs b/substrate/frame/nomination-pools/src/migration.rs index 7cb50927b3cd..d19e46c49d0b 100644 --- a/substrate/frame/nomination-pools/src/migration.rs +++ b/substrate/frame/nomination-pools/src/migration.rs @@ -111,7 +111,7 @@ pub mod unversioned { /// Migrate existing pools from [`adapter::TransferStake`] to [`adapter::DelegateStake`]. /// /// Note: This only migrates the pools, the members are not migrated. They can use the - /// permission-less [`Call::claim_delegation()`] to migrate their funds. + /// permission-less [`Pallet::claim_delegation()`] to migrate their funds. pub struct DelegationStakeMigration(sp_std::marker::PhantomData); // FIXME(ank4n) convert to MBM. From ff3630259558ce63580cc3f396e77d03a682aa12 Mon Sep 17 00:00:00 2001 From: Ankan Date: Wed, 3 Apr 2024 18:12:05 +0200 Subject: [PATCH 058/257] taplo fix --- substrate/frame/nomination-pools/benchmarking/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/frame/nomination-pools/benchmarking/Cargo.toml b/substrate/frame/nomination-pools/benchmarking/Cargo.toml index c6f274340974..8123e1c6f566 100644 --- a/substrate/frame/nomination-pools/benchmarking/Cargo.toml +++ b/substrate/frame/nomination-pools/benchmarking/Cargo.toml @@ -54,9 +54,9 @@ std = [ "frame-system/std", "pallet-bags-list/std", "pallet-balances/std", + "pallet-delegated-staking/std", "pallet-nomination-pools/std", "pallet-staking/std", - "pallet-delegated-staking/std", "pallet-timestamp/std", "scale-info/std", "sp-core/std", @@ -74,9 +74,9 @@ runtime-benchmarks = [ "frame-system/runtime-benchmarks", "pallet-bags-list/runtime-benchmarks", "pallet-balances/runtime-benchmarks", + "pallet-delegated-staking/runtime-benchmarks", "pallet-nomination-pools/runtime-benchmarks", "pallet-staking/runtime-benchmarks", - "pallet-delegated-staking/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "sp-staking/runtime-benchmarks", From 23c65c46b42f95a85a605cafa331b187861a6d97 Mon Sep 17 00:00:00 2001 From: Ankan Date: Thu, 4 Apr 2024 11:25:20 +0200 Subject: [PATCH 059/257] doc updates --- substrate/frame/delegated-staking/src/impls.rs | 3 +-- substrate/frame/delegated-staking/src/lib.rs | 14 ++++---------- substrate/primitives/staking/src/lib.rs | 8 +++++--- 3 files changed, 10 insertions(+), 15 deletions(-) diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs index 46f78700dc65..8e052223460e 100644 --- a/substrate/frame/delegated-staking/src/impls.rs +++ b/substrate/frame/delegated-staking/src/impls.rs @@ -16,8 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -//! Implementations of public traits, namely [DelegationInterface] and -//! [OnStakingUpdate]. +//! Implementations of public traits, namely [DelegationInterface] and [OnStakingUpdate]. use super::*; use sp_staking::{DelegationInterface, OnStakingUpdate}; diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs index 80355eee5860..b683ed03001b 100644 --- a/substrate/frame/delegated-staking/src/lib.rs +++ b/substrate/frame/delegated-staking/src/lib.rs @@ -17,9 +17,9 @@ //! # Delegated Staking Pallet //! -//! This pallet implements [`sp_staking::DelegationInterface`] that extends [`StakingInterface`] -//! to support delegation of stake. It consumes [`Config::CoreStaking`] to provide primitive staking -//! functions and only implements the delegation features. +//! This pallet implements [`sp_staking::DelegationInterface`] that provides delegation functionality +//! to `delegators` and `agents`. It is designed to be used in conjunction with [`StakingInterface`] +//! and relies on [`Config::CoreStaking`] to provide primitive staking functions. //! //! Currently, it does not expose any dispatchable calls but is written with a vision to expose them //! in the future such that it can be utilised by any external account, off-chain entity or xcm @@ -68,12 +68,6 @@ //! agent, the funds are held in a proxy account. This function allows the delegator to claim their //! share of the funds from the proxy account. See [`Pallet::claim_delegation`]. //! -//! #### [Staking Interface](StakingInterface) -//! This pallet reimplements the staking interface as a wrapper implementation over -//! [Config::CoreStaking] to provide delegation based staking. Concretely, a pallet like -//! `NominationPools` can switch to this pallet as its Staking provider to support delegation based -//! staking from pool accounts, allowing its members to lock funds in their own account. -//! //! ## Lazy Slashing //! One of the reasons why direct nominators on staking pallet cannot scale well is because all //! nominators are slashed at the same time. This is expensive and needs to be bounded operation. @@ -89,7 +83,7 @@ //! [DelegationInterface::delegator_slash](sp_staking::DelegationInterface::delegator_slash). //! //! ## Migration from Nominator to Agent -//! More details [here](https://hackmd.io/@ak0n/np-delegated-staking-migration). +//! More details [here](https://hackmd.io/@ak0n/454-np-governance). //! //! ## Nomination Pool vs Delegation Staking //! This pallet is not a replacement for Nomination Pool but adds a new primitive over staking diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index bb57468aa456..6e128b460569 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -449,12 +449,14 @@ pub struct PagedExposureMetadata { pub page_count: Page, } -/// Extension of [`StakingInterface`] with delegation functionality. +/// Trait to provide delegation functionality for stakers. /// -/// Introduces two new actors: +/// Introduces two new terms to the staking system: /// - `Delegator`: An account that delegates funds to a `Agent`. /// - `Agent`: An account that receives delegated funds from `Delegators`. It can then use these -/// funds to participate in the staking system. It can never use its own funds to stake. +/// funds to participate in the staking system. It can never use its own funds to stake. They +/// (virtually bond)[`StakingUnsafe::virtual_bond`] into the staking system and can also be termed +/// as `Virtual Nominators`. /// /// The `Agent` is responsible for managing rewards and slashing for all the `Delegators` that /// have delegated funds to it. From 4f441d5e28dfabd1b89d88e8b124ff9f9f5d25e3 Mon Sep 17 00:00:00 2001 From: Ankan Date: Thu, 4 Apr 2024 12:10:04 +0200 Subject: [PATCH 060/257] doc updates --- substrate/frame/delegated-staking/src/lib.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs index b683ed03001b..d76e292e2696 100644 --- a/substrate/frame/delegated-staking/src/lib.rs +++ b/substrate/frame/delegated-staking/src/lib.rs @@ -690,6 +690,7 @@ impl Pallet { ensure!(delegation.agent == agent_acc, Error::::NotAgent); ensure!(delegation.amount >= amount, Error::::NotEnoughFunds); + // slash delegator let (mut credit, missing) = T::Currency::slash(&HoldReason::Delegating.into(), &delegator, amount); @@ -709,9 +710,11 @@ impl Pallet { let reward_payout: BalanceOf = T::CoreStaking::slash_reward_fraction() * actual_slash; let (reporter_reward, rest) = credit.split(reward_payout); + + // credit is the amount that we provide to `T::OnSlash`. credit = rest; - // fixme(ank4n): handle error + // reward reporter or drop it. let _ = T::Currency::resolve(&reporter, reporter_reward); } From 58b50c9f4e66e2009fdf0b37504982fbe8566de8 Mon Sep 17 00:00:00 2001 From: Ankan Date: Thu, 4 Apr 2024 12:19:25 +0200 Subject: [PATCH 061/257] test for bonders cannot virtual bond --- substrate/frame/staking/src/pallet/mod.rs | 3 ++- substrate/frame/staking/src/tests.rs | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 8f18102175c0..6d6b993fe211 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -385,7 +385,8 @@ pub mod pallet { /// are expected to be keyless accounts and hence should not be allowed to mutate their ledger /// directly via this pallet. Instead, these accounts are managed by other pallets and accessed /// via low level apis. We keep track of them to do minimal integrity checks. - // TODO(ank4n): Can we keep this entry in `Ledger`? Worth a migration? + // TODO(ank4n): Can we keep this entry in `Ledger`? Or migrate later in conjunction with + // fungible migration? #[pallet::storage] pub type VirtualStakers = CountedStorageMap<_, Twox64Concat, T::AccountId, ()>; diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 5be7b9c999b9..601779f4992c 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -6970,6 +6970,23 @@ mod staking_unsafe { }); } + #[test] + fn normal_staker_cannot_virtual_bond() { + ExtBuilder::default().build_and_execute(|| { + // 101 is a nominator trying to virtual bond + assert_noop!( + ::virtual_bond(&101, 200, &102), + Error::::AlreadyBonded + ); + + // validator 21 tries to virtual bond + assert_noop!( + ::virtual_bond(&21, 200, &22), + Error::::AlreadyBonded + ); + }); + } + #[test] fn migrate_virtual_staker() { ExtBuilder::default().build_and_execute(|| { From b946c4a042f2152f68b4a05d91f8bfc780fe2c1a Mon Sep 17 00:00:00 2001 From: Ankan Date: Thu, 4 Apr 2024 12:38:51 +0200 Subject: [PATCH 062/257] virtual nominators receive rewards --- substrate/frame/staking/src/tests.rs | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 601779f4992c..9300f5ec79fd 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -623,12 +623,8 @@ fn nominating_and_rewards_should_work() { )); assert_ok!(Staking::nominate(RuntimeOrigin::signed(1), vec![11, 21, 31])); - assert_ok!(Staking::bond( - RuntimeOrigin::signed(3), - 1000, - RewardDestination::Account(3) - )); - assert_ok!(Staking::nominate(RuntimeOrigin::signed(3), vec![11, 21, 41])); + // the second nominator is virtual. + bond_virtual_nominator(3, 333, 1000, vec![11, 21, 41]); // the total reward for era 0 let total_payout_0 = current_total_payout_for_duration(reward_time_per_era()); @@ -694,11 +690,10 @@ fn nominating_and_rewards_should_work() { ); // Nominator 3: has [400/1800 ~ 2/9 from 10] + [600/2200 ~ 3/11 from 21]'s reward. ==> // 2/9 + 3/11 + assert_eq!(Balances::total_balance(&3), initial_balance); + /// 333 is the reward destination for 3. assert_eq_error_rate!( - Balances::total_balance(&3), - initial_balance + (2 * payout_for_11 / 9 + 3 * payout_for_21 / 11), - 2, - ); + Balances::total_balance(&333), 2 * payout_for_11 / 9 + 3 * payout_for_21 / 11, 2); // Validator 11: got 800 / 1800 external stake => 8/18 =? 4/9 => Validator's share = 5/9 assert_eq_error_rate!( From 0aa9006542ab02f8a5b999552daf31101cbd9dea Mon Sep 17 00:00:00 2001 From: Ankan Date: Thu, 4 Apr 2024 13:30:52 +0200 Subject: [PATCH 063/257] virtual nominator slashing test --- substrate/frame/staking/src/mock.rs | 9 ++++- substrate/frame/staking/src/tests.rs | 58 +++++++++++++++++++++++++++- 2 files changed, 64 insertions(+), 3 deletions(-) diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 718ee697faed..74762079101e 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -249,17 +249,22 @@ parameter_types! { pub static LedgerSlashPerEra: (BalanceOf, BTreeMap>) = (Zero::zero(), BTreeMap::new()); + pub static SlashObserver: BTreeMap> = BTreeMap::new(); } pub struct EventListenerMock; impl OnStakingUpdate for EventListenerMock { fn on_slash( - _pool_account: &AccountId, + pool_account: &AccountId, slashed_bonded: Balance, slashed_chunks: &BTreeMap, - _total_slashed: Balance, + total_slashed: Balance, ) { LedgerSlashPerEra::set((slashed_bonded, slashed_chunks.clone())); + // update the observer. + let mut slash_observer = SlashObserver::get(); + slash_observer.insert(pool_account.clone(), total_slashed); + SlashObserver::set(slash_observer); } } diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 9300f5ec79fd..b2171d87b32f 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -691,7 +691,7 @@ fn nominating_and_rewards_should_work() { // Nominator 3: has [400/1800 ~ 2/9 from 10] + [600/2200 ~ 3/11 from 21]'s reward. ==> // 2/9 + 3/11 assert_eq!(Balances::total_balance(&3), initial_balance); - /// 333 is the reward destination for 3. + // 333 is the reward destination for 3. assert_eq_error_rate!( Balances::total_balance(&333), 2 * payout_for_11 / 9 + 3 * payout_for_21 / 11, 2); @@ -7002,6 +7002,62 @@ mod staking_unsafe { assert_eq!(Pallet::::is_virtual_staker(&200), true); }); } + + #[test] + fn virtual_nominators_are_lazily_slashed() { + ExtBuilder::default().build_and_execute(|| { + mock::start_active_era(1); + let slash_percent = Perbill::from_percent(5); + let initial_exposure = Staking::eras_stakers(active_era(), &11); + // 101 is a nominator for 11 + assert_eq!(initial_exposure.others.first().unwrap().who, 101); + // make 101 a virtual nominator + ::migrate_to_virtual_staker(&101); + // set payee different to self. + assert_ok!(::update_payee(&101, &102)); + + // cache values + let nominator_stake = Staking::ledger(101.into()).unwrap().active; + let nominator_balance = balances(&101).0; + let validator_stake = Staking::ledger(11.into()).unwrap().active; + let validator_balance = balances(&11).0; + let exposed_stake = initial_exposure.total; + let exposed_validator = initial_exposure.own; + let exposed_nominator = initial_exposure.others.first().unwrap().value; + + // 11 goes offline + on_offence_now( + &[OffenceDetails { offender: (11, initial_exposure.clone()), reporters: vec![] }], + &[slash_percent], + ); + + let slash_amount = slash_percent * exposed_stake; + let validator_share = + Perbill::from_rational(exposed_validator, exposed_stake) * slash_amount; + let nominator_share = + Perbill::from_rational(exposed_nominator, exposed_stake) * slash_amount; + + // both slash amounts need to be positive for the test to make sense. + assert!(validator_share > 0); + assert!(nominator_share > 0); + + // both stakes must have been decreased pro-rata. + assert_eq!(Staking::ledger(101.into()).unwrap().active, nominator_stake - nominator_share); + assert_eq!(Staking::ledger(11.into()).unwrap().active, validator_stake - validator_share); + + // validator balance is slashed as usual + assert_eq!(balances(&11).0, validator_balance - validator_share); + // Because slashing happened. + assert!(is_disabled(11)); + + // but virtual nominator's balance is not slashed. + assert_eq!(Balances::free_balance(&101), nominator_balance); + // but slash is broadcasted to slash observers. + assert_eq!(SlashObserver::get().get(&101).unwrap(), &nominator_share); + + + }) + } } mod ledger { use super::*; From d242356751bbcd140b578d418a4fad67cc47ecde Mon Sep 17 00:00:00 2001 From: Ankan Date: Thu, 4 Apr 2024 13:32:22 +0200 Subject: [PATCH 064/257] fmt --- substrate/frame/staking/src/tests.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index b2171d87b32f..14c740be807c 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -693,7 +693,10 @@ fn nominating_and_rewards_should_work() { assert_eq!(Balances::total_balance(&3), initial_balance); // 333 is the reward destination for 3. assert_eq_error_rate!( - Balances::total_balance(&333), 2 * payout_for_11 / 9 + 3 * payout_for_21 / 11, 2); + Balances::total_balance(&333), + 2 * payout_for_11 / 9 + 3 * payout_for_21 / 11, + 2 + ); // Validator 11: got 800 / 1800 external stake => 8/18 =? 4/9 => Validator's share = 5/9 assert_eq_error_rate!( @@ -7042,8 +7045,14 @@ mod staking_unsafe { assert!(nominator_share > 0); // both stakes must have been decreased pro-rata. - assert_eq!(Staking::ledger(101.into()).unwrap().active, nominator_stake - nominator_share); - assert_eq!(Staking::ledger(11.into()).unwrap().active, validator_stake - validator_share); + assert_eq!( + Staking::ledger(101.into()).unwrap().active, + nominator_stake - nominator_share + ); + assert_eq!( + Staking::ledger(11.into()).unwrap().active, + validator_stake - validator_share + ); // validator balance is slashed as usual assert_eq!(balances(&11).0, validator_balance - validator_share); @@ -7054,8 +7063,6 @@ mod staking_unsafe { assert_eq!(Balances::free_balance(&101), nominator_balance); // but slash is broadcasted to slash observers. assert_eq!(SlashObserver::get().get(&101).unwrap(), &nominator_share); - - }) } } From 6bd5e2ca35ab46457c525f861e9b4ab82baaa545 Mon Sep 17 00:00:00 2001 From: Ankan Date: Thu, 4 Apr 2024 14:29:35 +0200 Subject: [PATCH 065/257] fmt --- substrate/frame/delegated-staking/src/lib.rs | 13 +++- .../frame/delegated-staking/src/tests.rs | 73 ++++++++++++++++++- 2 files changed, 81 insertions(+), 5 deletions(-) diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs index d76e292e2696..99c75bcd7103 100644 --- a/substrate/frame/delegated-staking/src/lib.rs +++ b/substrate/frame/delegated-staking/src/lib.rs @@ -17,9 +17,10 @@ //! # Delegated Staking Pallet //! -//! This pallet implements [`sp_staking::DelegationInterface`] that provides delegation functionality -//! to `delegators` and `agents`. It is designed to be used in conjunction with [`StakingInterface`] -//! and relies on [`Config::CoreStaking`] to provide primitive staking functions. +//! This pallet implements [`sp_staking::DelegationInterface`] that provides delegation +//! functionality to `delegators` and `agents`. It is designed to be used in conjunction with +//! [`StakingInterface`] and relies on [`Config::CoreStaking`] to provide primitive staking +//! functions. //! //! Currently, it does not expose any dispatchable calls but is written with a vision to expose them //! in the future such that it can be utilised by any external account, off-chain entity or xcm @@ -213,6 +214,8 @@ pub mod pallet { BadState, /// Unapplied pending slash restricts operation on `Agent`. UnappliedSlash, + /// `Agent` has no pending slash to be applied. + NothingToSlash, /// Failed to withdraw amount from Core Staking. WithdrawFailed, /// Operation not supported by this pallet. @@ -685,8 +688,10 @@ impl Pallet { maybe_reporter: Option, ) -> DispatchResult { let agent = Agent::::from(&agent_acc)?; - let delegation = >::get(&delegator).ok_or(Error::::NotDelegator)?; + // ensure there is something to slash + ensure!(agent.ledger.pending_slash > Zero::zero(), Error::::NothingToSlash); + let delegation = >::get(&delegator).ok_or(Error::::NotDelegator)?; ensure!(delegation.agent == agent_acc, Error::::NotAgent); ensure!(delegation.amount >= amount, Error::::NotEnoughFunds); diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs index 0f4903377f48..d75bf6507dad 100644 --- a/substrate/frame/delegated-staking/src/tests.rs +++ b/substrate/frame/delegated-staking/src/tests.rs @@ -191,10 +191,81 @@ fn agent_restrictions() { }); } +use sp_staking::DelegationInterface; #[test] fn apply_pending_slash() { ExtBuilder::default().build_and_execute(|| { - // fixme(ank4n): add tests for apply_pending_slash + start_era(1); + let agent: AccountId = 200; + let reward_acc: AccountId = 201; + let delegators: Vec = (301..=350).collect(); + let reporter: AccountId = 400; + + let total_staked = setup_delegation_stake(agent, reward_acc, delegators.clone(), 10, 10); + + start_era(4); + // slash half of the stake + pallet_staking::slashing::do_slash::( + &agent, + total_staked / 2, + &mut Default::default(), + &mut Default::default(), + 3, + ); + + // agent cannot slash an account that is not its delegator. + setup_delegation_stake(210, 211, (351..=352).collect(), 100, 0); + assert_noop!( + ::delegator_slash(&agent, &351, 1, Some(400)), + Error::::NotAgent + ); + // or a non delegator account + fund(&353, 100); + assert_noop!( + ::delegator_slash(&agent, &353, 1, Some(400)), + Error::::NotDelegator + ); + + // ensure bookkept pending slash is correct. + assert_eq!(get_agent(&agent).ledger.pending_slash, total_staked / 2); + let mut old_reporter_balance = Balances::free_balance(reporter); + + // lets apply the pending slash on delegators. + for i in delegators { + // balance before slash + let initial_pending_slash = get_agent(&agent).ledger.pending_slash; + assert!(initial_pending_slash > 0); + let unslashed_balance = held_balance(&i); + let slash = unslashed_balance / 2; + // slash half of delegator's delegation. + assert_ok!(::delegator_slash( + &agent, + &i, + slash, + Some(400) + )); + + // balance after slash. + assert_eq!(held_balance(&i), unslashed_balance - slash); + // pending slash is reduced by the amount slashed. + assert_eq!(get_agent(&agent).ledger.pending_slash, initial_pending_slash - slash); + // reporter get 10% of the slash amount. + assert_eq!( + Balances::free_balance(reporter) - old_reporter_balance, + ::slash_reward_fraction() * slash, + ); + // update old balance + old_reporter_balance = Balances::free_balance(reporter); + } + + // nothing to slash anymore + assert_eq!(get_agent(&agent).ledger.pending_slash, 0); + + // cannot slash anymore + assert_noop!( + ::delegator_slash(&agent, &350, 1, None), + Error::::NothingToSlash + ); }); } From 2fb04c5bc6f70f1d637232645c561ec4a1167219 Mon Sep 17 00:00:00 2001 From: Ankan Date: Thu, 4 Apr 2024 14:48:12 +0200 Subject: [PATCH 066/257] found a bug while unbonding --- substrate/frame/delegated-staking/src/mock.rs | 2 +- .../frame/delegated-staking/src/tests.rs | 34 ++++++++++++------- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs index f98e0c5843bb..d8e7bebdafe9 100644 --- a/substrate/frame/delegated-staking/src/mock.rs +++ b/substrate/frame/delegated-staking/src/mock.rs @@ -130,7 +130,7 @@ impl pallet_staking::Config for Runtime { type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; type TargetList = pallet_staking::UseValidatorsMap; type NominationsQuota = pallet_staking::FixedNominationsQuota<16>; - type MaxUnlockingChunks = ConstU32<32>; + type MaxUnlockingChunks = ConstU32<10>; type MaxControllersInDeprecationBatch = ConstU32<100>; type EventListeners = DelegatedStaking; type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs index d75bf6507dad..3754882b1f94 100644 --- a/substrate/frame/delegated-staking/src/tests.rs +++ b/substrate/frame/delegated-staking/src/tests.rs @@ -432,8 +432,9 @@ mod staking_integration { #[test] fn withdraw_happens_with_unbonded_balance_first() { ExtBuilder::default().build_and_execute(|| { + start_era(1); let agent = 200; - setup_delegation_stake(agent, 201, (300..350).collect(), 100, 0); + setup_delegation_stake(agent, 201, (300..350).collect(), 10, 10); // verify withdraw not possible yet assert_noop!( @@ -441,10 +442,26 @@ mod staking_integration { Error::::NotEnoughFunds ); - // add new delegation that is not staked + // fill up unlocking chunks in core staking. + // 10 is the max chunks + for i in 2..=11 { + start_era(i); + assert_ok!(Staking::unbond(RawOrigin::Signed(agent).into(), 10)); + // no withdrawals from core staking yet. + assert_eq!(get_agent(&agent).ledger.unclaimed_withdrawals, 0); + } + + // another unbond would trigger withdrawal + start_era(12); + assert_ok!(Staking::unbond(RawOrigin::Signed(agent).into(), 10)); + // 8 previous unbonds would be withdrawn as they were already unlocked. Unlocking period + // is 3 eras. + + // FIXME(ank4n): Since staking implicitly withdraws ledger, unclaimed withdrawals are + // not updated. This is bad since it can lead those funds to be re-bonded. + + // assert_eq!(get_agent(&agent).ledger.unclaimed_withdrawals, 8 * 10); - // FIXME(ank4n): add scenario where staked funds are withdrawn from ledger but not - // withdrawn and test its claimed from there first. // fund(&300, 1000); // assert_ok!(DelegatedStaking::delegate_to_agent(RawOrigin::Signed(300.into()), @@ -531,15 +548,6 @@ mod staking_integration { }); } - #[test] - fn slash_works() { - ExtBuilder::default().build_and_execute(|| { - setup_delegation_stake(200, 201, (210..250).collect(), 100, 0); - start_era(1); - // fixme(ank4n): add tests for slashing - }); - } - #[test] fn migration_works() { ExtBuilder::default().build_and_execute(|| { From 7962aac420f79eee700908296fa5769bdfdfbb50 Mon Sep 17 00:00:00 2001 From: Ankan Date: Thu, 4 Apr 2024 15:22:34 +0200 Subject: [PATCH 067/257] test for unclaimed withdrawals --- .../frame/delegated-staking/src/impls.rs | 23 +++++------ substrate/frame/delegated-staking/src/lib.rs | 36 ++---------------- .../frame/delegated-staking/src/tests.rs | 38 +++++++++++-------- .../frame/delegated-staking/src/types.rs | 2 - substrate/primitives/staking/src/lib.rs | 11 ------ 5 files changed, 39 insertions(+), 71 deletions(-) diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs index 8e052223460e..fc7cb1e41acc 100644 --- a/substrate/frame/delegated-staking/src/impls.rs +++ b/substrate/frame/delegated-staking/src/impls.rs @@ -79,17 +79,6 @@ impl DelegationInterface for Pallet { ) } - /// Withdraw unbonding funds until current era. - /// - /// Funds are moved to unclaimed_withdrawals register of the `AgentLedger`. - fn withdraw_unclaimed( - agent_acc: Self::AccountId, - num_slashing_spans: u32, - ) -> Result { - Pallet::::withdraw_unbonded(&agent_acc, num_slashing_spans) - .map(|agent| agent.ledger.total_delegated.is_zero()) - } - /// Returns true if the `Agent` have any slash pending to be applied. fn has_pending_slash(agent: &Self::AccountId) -> bool { Agent::::from(agent) @@ -144,4 +133,16 @@ impl OnStakingUpdate> for Pallet { }, }); } + + fn on_withdraw(stash: &T::AccountId, amount: BalanceOf) { + // if there is a withdraw to the agent, then add it to the unclaimed withdrawals. + if let Ok(agent) = Agent::::from(stash) { + let agent = agent.add_unclaimed_withdraw(amount).defensive(); + + // can't do anything if there is an overflow error. + if agent.is_ok() { + agent.expect("checked above; qed").save(); + } + } + } } diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs index 99c75bcd7103..632de3ea02c4 100644 --- a/substrate/frame/delegated-staking/src/lib.rs +++ b/substrate/frame/delegated-staking/src/lib.rs @@ -562,8 +562,10 @@ impl Pallet { // if we do not already have enough funds to be claimed, try withdraw some more. if agent.ledger.unclaimed_withdrawals < amount { - // get the updated agent. - agent = Self::withdraw_unbonded(who, num_slashing_spans)?; + // withdraw account. + let _ = T::CoreStaking::withdraw_unbonded(who.clone(), num_slashing_spans) + .map_err(|_| Error::::WithdrawFailed)?; + agent = agent.refresh()?; } // if we still do not have enough funds to release, abort. @@ -602,36 +604,6 @@ impl Pallet { Ok(()) } - fn withdraw_unbonded( - agent_acc: &T::AccountId, - num_slashing_spans: u32, - ) -> Result, DispatchError> { - let agent = Agent::::from(agent_acc)?; - let pre_total = T::CoreStaking::stake(agent_acc).defensive()?.total; - - let stash_killed: bool = - T::CoreStaking::withdraw_unbonded(agent_acc.clone(), num_slashing_spans) - .map_err(|_| Error::::WithdrawFailed)?; - - let maybe_post_total = T::CoreStaking::stake(agent_acc); - // One of them should be true - defensive_assert!( - !(stash_killed && maybe_post_total.is_ok()), - "something horrible happened while withdrawing" - ); - - let post_total = maybe_post_total.map_or(Zero::zero(), |s| s.total); - - let new_withdrawn = - pre_total.checked_sub(&post_total).defensive_ok_or(Error::::BadState)?; - - let agent = agent.add_unclaimed_withdraw(new_withdrawn)?; - - agent.clone().save(); - - Ok(agent) - } - /// Migrates delegation of `amount` from `source` account to `destination` account. fn do_migrate_delegation( source_delegator: &T::AccountId, diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs index 3754882b1f94..280996afd2eb 100644 --- a/substrate/frame/delegated-staking/src/tests.rs +++ b/substrate/frame/delegated-staking/src/tests.rs @@ -434,7 +434,7 @@ mod staking_integration { ExtBuilder::default().build_and_execute(|| { start_era(1); let agent = 200; - setup_delegation_stake(agent, 201, (300..350).collect(), 10, 10); + setup_delegation_stake(agent, 201, (300..350).collect(), 100, 0); // verify withdraw not possible yet assert_noop!( @@ -454,25 +454,33 @@ mod staking_integration { // another unbond would trigger withdrawal start_era(12); assert_ok!(Staking::unbond(RawOrigin::Signed(agent).into(), 10)); + // 8 previous unbonds would be withdrawn as they were already unlocked. Unlocking period // is 3 eras. + assert_eq!(get_agent(&agent).ledger.unclaimed_withdrawals, 8 * 10); - // FIXME(ank4n): Since staking implicitly withdraws ledger, unclaimed withdrawals are - // not updated. This is bad since it can lead those funds to be re-bonded. - - // assert_eq!(get_agent(&agent).ledger.unclaimed_withdrawals, 8 * 10); + // release some delegation now. + assert_ok!(DelegatedStaking::release_delegation( + RawOrigin::Signed(agent).into(), + 300, + 40, + 0 + )); + assert_eq!(get_agent(&agent).ledger.unclaimed_withdrawals, 80 - 40); + // cannot release more than available + assert_noop!( + DelegatedStaking::release_delegation(RawOrigin::Signed(agent).into(), 300, 50, 0), + Error::::NotEnoughFunds + ); + assert_ok!(DelegatedStaking::release_delegation( + RawOrigin::Signed(agent).into(), + 300, + 40, + 0 + )); - // fund(&300, 1000); - // assert_ok!(DelegatedStaking::delegate_to_agent(RawOrigin::Signed(300.into()), - // delegate, 100)); - // - // // verify unbonded balance - // assert_eq!(get_agent(&agent).available_to_bond(), 100); - // - // // withdraw works now without unbonding - // assert_ok!(DelegatedStaking::release_delegation(RawOrigin::Signed(agent).into(), 300, - // 100, 0)); assert_eq!(get_agent(&agent).available_to_bond(), 0); + assert_eq!(held_balance(&300), 100 - 80); }); } diff --git a/substrate/frame/delegated-staking/src/types.rs b/substrate/frame/delegated-staking/src/types.rs index 9eee2e61016d..2fe49faf8464 100644 --- a/substrate/frame/delegated-staking/src/types.rs +++ b/substrate/frame/delegated-staking/src/types.rs @@ -283,8 +283,6 @@ impl Agent { } /// Reloads self from storage. - #[cfg(test)] - #[allow(unused)] pub(crate) fn refresh(&self) -> Result, DispatchError> { Self::from(&self.key) } diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index 6e128b460569..f4fbdfa51129 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -512,17 +512,6 @@ pub trait DelegationInterface { amount: Self::Balance, ) -> DispatchResult; - /// Withdraw any unlocking funds in `CoreStaking` that can be claimed later by a delegator. - /// - /// `CoreStaking` has a limitation on maximum unlocking chunks at any given time. If the limit - /// is reached, we want to implicitly unlock these funds even though a delegator is not - /// present to claim it. Not doing this would block any unbonding until unlocking funds are - /// claimed. - fn withdraw_unclaimed( - agent: Self::AccountId, - num_slashing_spans: u32, - ) -> Result; - /// Returns true if there are pending slashes posted to the `Agent` account. /// /// Slashes to `Agent` account are not immediate and are applied lazily. Since `Agent` From 69fddff668c0a4944d7a8b742447c7cbc6d844da Mon Sep 17 00:00:00 2001 From: Ankan Date: Thu, 4 Apr 2024 15:30:23 +0200 Subject: [PATCH 068/257] fix stake adapter --- .../frame/nomination-pools/src/adapter.rs | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/substrate/frame/nomination-pools/src/adapter.rs b/substrate/frame/nomination-pools/src/adapter.rs index fb79bb9b9ddc..3774ce04d21b 100644 --- a/substrate/frame/nomination-pools/src/adapter.rs +++ b/substrate/frame/nomination-pools/src/adapter.rs @@ -97,7 +97,9 @@ pub trait StakeStrategy { fn withdraw_unbonded( pool_account: &Self::AccountId, num_slashing_spans: u32, - ) -> Result; + ) -> Result { + Self::CoreStaking::withdraw_unbonded(pool_account.clone(), num_slashing_spans) + } /// Withdraw funds from pool account to member account. fn member_withdraw( @@ -183,14 +185,6 @@ impl, AccountId = T: }, } } - - fn withdraw_unbonded( - pool_account: &Self::AccountId, - num_slashing_spans: u32, - ) -> Result { - Staking::withdraw_unbonded(pool_account.clone(), num_slashing_spans) - } - fn member_withdraw( who: &T::AccountId, pool_account: &Self::AccountId, @@ -285,13 +279,6 @@ impl< } } - fn withdraw_unbonded( - pool_account: &Self::AccountId, - num_slashing_spans: u32, - ) -> Result { - Delegation::withdraw_unclaimed(pool_account.clone(), num_slashing_spans) - } - fn member_withdraw( who: &T::AccountId, pool_account: &Self::AccountId, From 8bd3bc3b52fd6be1e037d75d4a616d94e1f19f45 Mon Sep 17 00:00:00 2001 From: Ankan Date: Thu, 4 Apr 2024 15:54:37 +0200 Subject: [PATCH 069/257] fix clippy error --- substrate/frame/staking/src/mock.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 74762079101e..42578b1b7a30 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -263,7 +263,7 @@ impl OnStakingUpdate for EventListenerMock { LedgerSlashPerEra::set((slashed_bonded, slashed_chunks.clone())); // update the observer. let mut slash_observer = SlashObserver::get(); - slash_observer.insert(pool_account.clone(), total_slashed); + slash_observer.insert(*pool_account, total_slashed); SlashObserver::set(slash_observer); } } From 15a9fc6ca3232eb1041cdae22950900985fd3f7c Mon Sep 17 00:00:00 2001 From: Ankan Date: Thu, 4 Apr 2024 16:10:10 +0200 Subject: [PATCH 070/257] fix clippy --- substrate/frame/delegated-staking/src/impls.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs index fc7cb1e41acc..2eaa622ea51a 100644 --- a/substrate/frame/delegated-staking/src/impls.rs +++ b/substrate/frame/delegated-staking/src/impls.rs @@ -136,13 +136,10 @@ impl OnStakingUpdate> for Pallet { fn on_withdraw(stash: &T::AccountId, amount: BalanceOf) { // if there is a withdraw to the agent, then add it to the unclaimed withdrawals. - if let Ok(agent) = Agent::::from(stash) { - let agent = agent.add_unclaimed_withdraw(amount).defensive(); - + let _ = Agent::::from(stash) + .map(|agent| agent.add_unclaimed_withdraw(amount)) + .and_then(|agent| agent.save()) // can't do anything if there is an overflow error. - if agent.is_ok() { - agent.expect("checked above; qed").save(); - } - } + .defensive(); } } From 1a34d28912e497b811f8b032093df367cd079a6b Mon Sep 17 00:00:00 2001 From: Ankan Date: Thu, 4 Apr 2024 16:17:12 +0200 Subject: [PATCH 071/257] fix compile --- substrate/frame/delegated-staking/src/impls.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs index 2eaa622ea51a..8e3bca09e0d9 100644 --- a/substrate/frame/delegated-staking/src/impls.rs +++ b/substrate/frame/delegated-staking/src/impls.rs @@ -137,9 +137,10 @@ impl OnStakingUpdate> for Pallet { fn on_withdraw(stash: &T::AccountId, amount: BalanceOf) { // if there is a withdraw to the agent, then add it to the unclaimed withdrawals. let _ = Agent::::from(stash) - .map(|agent| agent.add_unclaimed_withdraw(amount)) - .and_then(|agent| agent.save()) - // can't do anything if there is an overflow error. - .defensive(); + // if not agent, we can ignore + .and_then(|agent| agent.add_unclaimed_withdraw(amount)) + // can't do anything if there is an overflow error. Just raise a defensive error. + .defensive() + .map(|agent| agent.save()); } } From 2a75dc5298eb7414cef7dce90f459859692629ef Mon Sep 17 00:00:00 2001 From: Ankan Date: Thu, 4 Apr 2024 16:18:57 +0200 Subject: [PATCH 072/257] fix defensive trigger --- substrate/frame/delegated-staking/src/impls.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/substrate/frame/delegated-staking/src/impls.rs b/substrate/frame/delegated-staking/src/impls.rs index 8e3bca09e0d9..7edb6e000e16 100644 --- a/substrate/frame/delegated-staking/src/impls.rs +++ b/substrate/frame/delegated-staking/src/impls.rs @@ -137,10 +137,8 @@ impl OnStakingUpdate> for Pallet { fn on_withdraw(stash: &T::AccountId, amount: BalanceOf) { // if there is a withdraw to the agent, then add it to the unclaimed withdrawals. let _ = Agent::::from(stash) - // if not agent, we can ignore - .and_then(|agent| agent.add_unclaimed_withdraw(amount)) // can't do anything if there is an overflow error. Just raise a defensive error. - .defensive() + .and_then(|agent| agent.add_unclaimed_withdraw(amount).defensive()) .map(|agent| agent.save()); } } From c3c274da4eda0abf8b41874ef2e359166695bde0 Mon Sep 17 00:00:00 2001 From: Ankan Date: Thu, 4 Apr 2024 19:15:49 +0200 Subject: [PATCH 073/257] doc --- substrate/frame/nomination-pools/src/adapter.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/substrate/frame/nomination-pools/src/adapter.rs b/substrate/frame/nomination-pools/src/adapter.rs index 3774ce04d21b..07611e779e3f 100644 --- a/substrate/frame/nomination-pools/src/adapter.rs +++ b/substrate/frame/nomination-pools/src/adapter.rs @@ -142,7 +142,8 @@ pub trait StakeStrategy { /// pool account and stakes through the pool account on `Staking`. /// /// This is the older Staking strategy used by pools. To switch to the newer [`DelegateStake`] -/// strategy, storage migration is required. +/// strategy, storage migration is required. See +/// [`migration::unversioned::DelegationStakeMigration`]. pub struct TransferStake(PhantomData<(T, Staking)>); impl, AccountId = T::AccountId>> From 0c85ddeb6d4034daad2e66108282554fd477ddc0 Mon Sep 17 00:00:00 2001 From: Ankan Date: Thu, 4 Apr 2024 19:39:19 +0200 Subject: [PATCH 074/257] wip migration test --- .../frame/nomination-pools/src/adapter.rs | 16 +-- .../test-delegate-stake/src/lib.rs | 56 +++++++++++ .../test-delegate-stake/src/mock.rs | 99 ++++++++++++++++++- 3 files changed, 161 insertions(+), 10 deletions(-) diff --git a/substrate/frame/nomination-pools/src/adapter.rs b/substrate/frame/nomination-pools/src/adapter.rs index 07611e779e3f..f3375209b3dd 100644 --- a/substrate/frame/nomination-pools/src/adapter.rs +++ b/substrate/frame/nomination-pools/src/adapter.rs @@ -120,12 +120,12 @@ pub trait StakeStrategy { ) -> DispatchResult; fn migrate_nominator_to_agent( - agent: &Self::AccountId, + pool_account: &Self::AccountId, reward_account: &Self::AccountId, ) -> DispatchResult; fn migrate_delegation( - agent: &Self::AccountId, + pool: &Self::AccountId, delegator: &Self::AccountId, value: Self::Balance, ) -> DispatchResult; @@ -211,14 +211,14 @@ impl, AccountId = T: } fn migrate_nominator_to_agent( - _agent: &Self::AccountId, + _pool: &Self::AccountId, _reward_account: &Self::AccountId, ) -> DispatchResult { Err(Error::::Defensive(DefensiveError::DelegationUnsupported).into()) } fn migrate_delegation( - _agent: &Self::AccountId, + _pool: &Self::AccountId, _delegator: &Self::AccountId, _value: Self::Balance, ) -> DispatchResult { @@ -302,17 +302,17 @@ impl< } fn migrate_nominator_to_agent( - agent: &Self::AccountId, + pool: &Self::AccountId, reward_account: &Self::AccountId, ) -> DispatchResult { - Delegation::migrate_nominator_to_agent(agent, reward_account) + Delegation::migrate_nominator_to_agent(pool, reward_account) } fn migrate_delegation( - agent: &Self::AccountId, + pool: &Self::AccountId, delegator: &Self::AccountId, value: Self::Balance, ) -> DispatchResult { - Delegation::migrate_delegation(agent, delegator, value) + Delegation::migrate_delegation(pool, delegator, value) } } diff --git a/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs b/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs index 98bff537c908..631c9caa9e16 100644 --- a/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs +++ b/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs @@ -821,3 +821,59 @@ fn pool_slash_non_proportional_bonded_pool_and_chunks() { ); }); } +#[test] +fn pool_migration_e2e() { + new_test_ext().execute_with(|| { + LegacyAdapter::set(true); + assert_eq!(Balances::minimum_balance(), 5); + assert_eq!(Staking::current_era(), None); + + // create the pool with TransferStake strategy. + assert_ok!(Pools::create(RuntimeOrigin::signed(10), 50, 10, 10, 10)); + assert_eq!(LastPoolId::::get(), 1); + + // have the pool nominate. + assert_ok!(Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3])); + + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 50 }] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Created { depositor: 10, pool_id: 1 }, + PoolsEvent::Bonded { member: 10, pool_id: 1, bonded: 50, joined: true }, + ] + ); + + // have two members join + let pre_20 = Balances::free_balance(20); + assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10, 1)); + let pre_21 = Balances::free_balance(21); + assert_ok!(Pools::join(RuntimeOrigin::signed(21), 10, 1)); + + // verify members balance is moved to pool. + assert_eq!(Balances::free_balance(20), pre_20 - 10); + assert_eq!(Balances::free_balance(21), pre_21 - 10); + + assert_eq!( + staking_events_since_last_call(), + vec![ + StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, + StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, + ] + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + PoolsEvent::Bonded { member: 20, pool_id: 1, bonded: 10, joined: true }, + PoolsEvent::Bonded { member: 21, pool_id: 1, bonded: 10, joined: true }, + ] + ); + + // we migrate to the new strategy `DelegateStake` + LegacyAdapter::set(false); + // fixme(ank4n): wip. + }) +} diff --git a/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs b/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs index 399b6a26eb0d..ff99596fcf20 100644 --- a/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs +++ b/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs @@ -23,6 +23,7 @@ use frame_support::{ traits::{ConstU64, ConstU8}, PalletId, }; +use pallet_nomination_pools::BondType; use sp_runtime::{ traits::{Convert, IdentityLookup}, BuildStorage, FixedU128, Perbill, @@ -170,8 +171,103 @@ impl Convert for U256ToBalance { parameter_types! { pub const PostUnbondingPoolsWindow: u32 = 10; pub const PoolsPalletId: PalletId = PalletId(*b"py/nopls"); + pub static LegacyAdapter: bool = false; } +pub struct MockAdapter; +type DelegateStake = + pallet_nomination_pools::adapter::DelegateStake; +type TransferStake = pallet_nomination_pools::adapter::TransferStake; +impl pallet_nomination_pools::adapter::StakeStrategy for MockAdapter { + type Balance = Balance; + type AccountId = AccountId; + type CoreStaking = Staking; + + fn transferable_balance(pool_account: &Self::AccountId) -> Self::Balance { + if LegacyAdapter::get() { + return TransferStake::transferable_balance(pool_account) + } + DelegateStake::transferable_balance(pool_account) + } + + fn total_balance(pool_account: &Self::AccountId) -> Self::Balance { + if LegacyAdapter::get() { + return TransferStake::total_balance(pool_account) + } + DelegateStake::total_balance(pool_account) + } + + fn member_delegation_balance(member_account: &Self::AccountId) -> Self::Balance { + if LegacyAdapter::get() { + return TransferStake::member_delegation_balance(member_account) + } + DelegateStake::member_delegation_balance(member_account) + } + + fn pledge_bond( + who: &Self::AccountId, + pool_account: &Self::AccountId, + reward_account: &Self::AccountId, + amount: Self::Balance, + bond_type: BondType, + ) -> DispatchResult { + if LegacyAdapter::get() { + return TransferStake::pledge_bond(who, pool_account, reward_account, amount, bond_type) + } + DelegateStake::pledge_bond(who, pool_account, reward_account, amount, bond_type) + } + + fn member_withdraw( + who: &Self::AccountId, + pool_account: &Self::AccountId, + amount: Self::Balance, + ) -> DispatchResult { + if LegacyAdapter::get() { + return TransferStake::member_withdraw(who, pool_account, amount) + } + DelegateStake::member_withdraw(who, pool_account, amount) + } + + fn has_pending_slash(pool_account: &Self::AccountId) -> bool { + if LegacyAdapter::get() { + return TransferStake::has_pending_slash(pool_account) + } + DelegateStake::has_pending_slash(pool_account) + } + + fn member_slash( + who: &Self::AccountId, + pool_account: &Self::AccountId, + amount: Self::Balance, + maybe_reporter: Option, + ) -> DispatchResult { + if LegacyAdapter::get() { + return TransferStake::member_slash(who, pool_account, amount, maybe_reporter) + } + DelegateStake::member_slash(who, pool_account, amount, maybe_reporter) + } + + fn migrate_nominator_to_agent( + agent: &Self::AccountId, + reward_account: &Self::AccountId, + ) -> DispatchResult { + if LegacyAdapter::get() { + return TransferStake::migrate_nominator_to_agent(agent, reward_account) + } + DelegateStake::migrate_nominator_to_agent(agent, reward_account) + } + + fn migrate_delegation( + agent: &Self::AccountId, + delegator: &Self::AccountId, + value: Self::Balance, + ) -> DispatchResult { + if LegacyAdapter::get() { + return TransferStake::migrate_delegation(agent, delegator, value) + } + DelegateStake::migrate_delegation(agent, delegator, value) + } +} impl pallet_nomination_pools::Config for Runtime { type RuntimeEvent = RuntimeEvent; type WeightInfo = (); @@ -180,8 +276,7 @@ impl pallet_nomination_pools::Config for Runtime { type RewardCounter = FixedU128; type BalanceToU256 = BalanceToU256; type U256ToBalance = U256ToBalance; - type StakeAdapter = - pallet_nomination_pools::adapter::DelegateStake; + type StakeAdapter = MockAdapter; type PostUnbondingPoolsWindow = PostUnbondingPoolsWindow; type MaxMetadataLen = ConstU32<256>; type MaxUnbonding = ConstU32<8>; From 8f2d412f00624774f894c592886ca7add21c5052 Mon Sep 17 00:00:00 2001 From: Ankan Date: Fri, 5 Apr 2024 00:50:04 +0200 Subject: [PATCH 075/257] migration test --- .../nomination-pools/test-delegate-stake/src/lib.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs b/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs index 631c9caa9e16..66c30d3e0687 100644 --- a/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs +++ b/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs @@ -874,6 +874,13 @@ fn pool_migration_e2e() { // we migrate to the new strategy `DelegateStake` LegacyAdapter::set(false); - // fixme(ank4n): wip. + // migrate the pool. + assert_ok!(Pools::migrate_to_delegate_stake(1)); + assert_ok!(Pools::claim_delegation(RuntimeOrigin::signed(10), 20)); + + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 10)); + + CurrentEra::::set(Some(10)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 10)); }) } From 0bf4dba28f198d2d223b7d29a3281953b8e77cac Mon Sep 17 00:00:00 2001 From: Ankan Date: Fri, 5 Apr 2024 01:00:09 +0200 Subject: [PATCH 076/257] pool does not have to transfer ed to proxy delegator --- substrate/frame/delegated-staking/src/lib.rs | 27 +++++++++---------- .../frame/delegated-staking/src/tests.rs | 7 ++--- 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs index 632de3ea02c4..11babb4f39d8 100644 --- a/substrate/frame/delegated-staking/src/lib.rs +++ b/substrate/frame/delegated-staking/src/lib.rs @@ -470,18 +470,14 @@ impl Pallet { } fn do_migrate_to_agent(who: &T::AccountId, reward_account: &T::AccountId) -> DispatchResult { + Self::do_register_agent(who, reward_account); + // We create a proxy delegator that will keep all the delegation funds until funds are // transferred to actual delegator. let proxy_delegator = Self::sub_account(AccountType::ProxyDelegator, who.clone()); - // Transfer minimum balance to proxy delegator. - T::Currency::transfer( - who, - &proxy_delegator, - T::Currency::minimum_balance(), - Preservation::Protect, - ) - .map_err(|_| Error::::NotEnoughFunds)?; + // Keep proxy delegator alive until all funds are migrated. + frame_system::Pallet::::inc_providers(&proxy_delegator); // Get current stake let stake = T::CoreStaking::stake(who)?; @@ -491,12 +487,10 @@ impl Pallet { // transferring just released staked amount. This should never fail but if it does, it // indicates bad state and we abort. - T::Currency::transfer(who, &proxy_delegator, stake.total, Preservation::Protect) + T::Currency::transfer(who, &proxy_delegator, stake.total, Preservation::Expendable) .map_err(|_| Error::::BadState)?; - Self::do_register_agent(who, reward_account); T::CoreStaking::update_payee(who, reward_account)?; - Self::do_delegate(&proxy_delegator, who, stake.total) } @@ -621,7 +615,6 @@ impl Pallet { // update delegations Delegation::::from(&source_delegation.agent, amount).save_or_kill(destination_delegator); - source_delegation .decrease_delegation(amount) .defensive_ok_or(Error::::BadState)? @@ -638,15 +631,19 @@ impl Pallet { defensive_assert!(released == amount, "hold should have been released fully"); // transfer the released amount to `destination_delegator`. - // Note: The source should have been funded ED in the beginning so it should not be dusted. - T::Currency::transfer( + let post_balance = T::Currency::transfer( source_delegator, destination_delegator, amount, - Preservation::Preserve, + Preservation::Expendable, ) .map_err(|_| Error::::BadState)?; + // if balance is zero, clear provider for source (proxy) delegator. + if post_balance == Zero::zero() { + let _ = frame_system::Pallet::::dec_providers(source_delegator).defensive(); + } + // hold the funds again in the new delegator account. T::Currency::hold(&HoldReason::Delegating.into(), destination_delegator, amount)?; diff --git a/substrate/frame/delegated-staking/src/tests.rs b/substrate/frame/delegated-staking/src/tests.rs index 280996afd2eb..292868cd3374 100644 --- a/substrate/frame/delegated-staking/src/tests.rs +++ b/substrate/frame/delegated-staking/src/tests.rs @@ -589,11 +589,8 @@ mod staking_integration { Balances::balance_on_hold(&HoldReason::Delegating.into(), &proxy_delegator), expected_proxy_delegated_amount ); - // ED + stake amount is transferred from delegate to proxy delegator account. - assert_eq!( - Balances::free_balance(200), - 5000 - staked_amount - ExistentialDeposit::get() - ); + // stake amount is transferred from delegate to proxy delegator account. + assert_eq!(Balances::free_balance(200), 5000 - staked_amount); assert_eq!(Staking::stake(&200).unwrap(), init_stake); assert_eq!(get_agent(&200).ledger.effective_balance(), 4000); assert_eq!(get_agent(&200).available_to_bond(), 0); From 4bd35fe6362d8957b8a7ce1d736a3fd5fc21e6d2 Mon Sep 17 00:00:00 2001 From: Ankan Date: Fri, 5 Apr 2024 01:32:54 +0200 Subject: [PATCH 077/257] finish migration test --- .../test-delegate-stake/src/lib.rs | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs b/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs index 66c30d3e0687..e30fd636e336 100644 --- a/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs +++ b/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs @@ -28,6 +28,7 @@ use pallet_nomination_pools::{ use pallet_staking::{ CurrentEra, Error as StakingError, Event as StakingEvent, Payee, RewardDestination, }; + use sp_runtime::{bounded_btree_map, traits::Zero}; #[test] @@ -876,11 +877,27 @@ fn pool_migration_e2e() { LegacyAdapter::set(false); // migrate the pool. assert_ok!(Pools::migrate_to_delegate_stake(1)); - assert_ok!(Pools::claim_delegation(RuntimeOrigin::signed(10), 20)); - assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 10)); + // progress to a future era where funds are unlocked CurrentEra::::set(Some(10)); + + let pre_claim_balance_20 = Balances::total_balance(&20); + assert_eq!(Balances::total_balance_on_hold(&20), 0); + + // lets claim delegation + assert_ok!(Pools::claim_delegation(RuntimeOrigin::signed(10), 20)); + + // tokens moved to 20's account and held there. + assert_eq!(Balances::total_balance(&20), pre_claim_balance_20 + 10); + use frame_support::traits::fungible::InspectHold; + assert_eq!(Balances::total_balance_on_hold(&20), 10); + + // withdraw works now assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 10)); + + // balance unlocked in 20's account + assert_eq!(Balances::total_balance_on_hold(&20), 0); + assert_eq!(Balances::total_balance(&20), pre_claim_balance_20 + 10); }) } From 5879b7155e4ae9e983b84c5970f250dd125f30fe Mon Sep 17 00:00:00 2001 From: Ankan Date: Fri, 5 Apr 2024 14:37:31 +0200 Subject: [PATCH 078/257] test for withdrawing before migrating delegation --- substrate/frame/nomination-pools/src/lib.rs | 5 +++-- .../frame/nomination-pools/test-delegate-stake/src/lib.rs | 5 +++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs index fa78fac46034..306cf6545d27 100644 --- a/substrate/frame/nomination-pools/src/lib.rs +++ b/substrate/frame/nomination-pools/src/lib.rs @@ -2300,12 +2300,13 @@ pub mod pallet { // order to ensure members can leave the pool and it can be destroyed. .min(T::StakeAdapter::transferable_balance(&bonded_pool.bonded_account())); + // this can fail if the pool uses `DelegateStake` strategy and the member delegation + // is not claimed yet. See `Call::claim_delegation()`. T::StakeAdapter::member_withdraw( &member_account, &bonded_pool.bonded_account(), balance_to_unbond, - ) - .defensive()?; + )?; Self::deposit_event(Event::::Withdrawn { member: member_account.clone(), diff --git a/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs b/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs index e30fd636e336..1719e1c1e74b 100644 --- a/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs +++ b/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs @@ -29,6 +29,8 @@ use pallet_staking::{ CurrentEra, Error as StakingError, Event as StakingEvent, Payee, RewardDestination, }; +use pallet_delegated_staking::Error as DelegatedStakingError; + use sp_runtime::{bounded_btree_map, traits::Zero}; #[test] @@ -882,6 +884,9 @@ fn pool_migration_e2e() { // progress to a future era where funds are unlocked CurrentEra::::set(Some(10)); + // withdraw fails before claiming delegation + assert_noop!(Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 10), DelegatedStakingError::::NotDelegator); + let pre_claim_balance_20 = Balances::total_balance(&20); assert_eq!(Balances::total_balance_on_hold(&20), 0); From e7a3002200a57e5469a8457d9407cbb40337dcea Mon Sep 17 00:00:00 2001 From: Ankan Date: Fri, 5 Apr 2024 18:20:43 +0200 Subject: [PATCH 079/257] fmt --- .../frame/nomination-pools/test-delegate-stake/src/lib.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs b/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs index 1719e1c1e74b..56e0b1b2970f 100644 --- a/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs +++ b/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs @@ -885,7 +885,10 @@ fn pool_migration_e2e() { CurrentEra::::set(Some(10)); // withdraw fails before claiming delegation - assert_noop!(Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 10), DelegatedStakingError::::NotDelegator); + assert_noop!( + Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 10), + DelegatedStakingError::::NotDelegator + ); let pre_claim_balance_20 = Balances::total_balance(&20); assert_eq!(Balances::total_balance_on_hold(&20), 0); From 7800446012e9fcf4c67a7ef6713add90e763258a Mon Sep 17 00:00:00 2001 From: Ankan Date: Tue, 9 Apr 2024 07:11:40 +0200 Subject: [PATCH 080/257] don't check for min balance when delegating to agent. pool should check this --- substrate/frame/delegated-staking/src/lib.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs index 11babb4f39d8..54fd4fe06952 100644 --- a/substrate/frame/delegated-staking/src/lib.rs +++ b/substrate/frame/delegated-staking/src/lib.rs @@ -387,9 +387,6 @@ pub mod pallet { ) -> DispatchResult { let delegator = ensure_signed(origin)?; - // ensure amount is over minimum to delegate - ensure!(amount > T::Currency::minimum_balance(), Error::::NotEnoughFunds); - // ensure delegator is sane. ensure!( Delegation::::can_delegate(&delegator, &agent), From 84fb918d788f3aa10d90205398b87302b3218f95 Mon Sep 17 00:00:00 2001 From: Ankan Date: Tue, 9 Apr 2024 07:29:25 +0200 Subject: [PATCH 081/257] don't check for min balance --- substrate/frame/delegated-staking/src/lib.rs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs index 54fd4fe06952..8bf9a90bb2d3 100644 --- a/substrate/frame/delegated-staking/src/lib.rs +++ b/substrate/frame/delegated-staking/src/lib.rs @@ -397,13 +397,6 @@ pub mod pallet { // ensure agent is sane. ensure!(Self::is_agent(&agent), Error::::NotAgent); - let delegator_balance = T::Currency::reducible_balance( - &delegator, - Preservation::Preserve, - Fortitude::Polite, - ); - ensure!(delegator_balance >= amount, Error::::NotEnoughFunds); - // add to delegation Self::do_delegate(&delegator, &agent, amount)?; @@ -510,6 +503,8 @@ impl Pallet { amount: BalanceOf, ) -> DispatchResult { let mut ledger = AgentLedger::::get(agent).ok_or(Error::::NotAgent)?; + // try to hold the funds. + T::Currency::hold(&HoldReason::Delegating.into(), delegator, amount)?; let new_delegation_amount = if let Some(existing_delegation) = Delegation::::get(delegator) { @@ -527,8 +522,6 @@ impl Pallet { ledger.total_delegated.checked_add(&amount).ok_or(ArithmeticError::Overflow)?; ledger.save(agent); - T::Currency::hold(&HoldReason::Delegating.into(), delegator, amount)?; - Self::deposit_event(Event::::Delegated { agent: agent.clone(), delegator: delegator.clone(), From 1a7446e517691f6887ac942fce55d6356ce438a2 Mon Sep 17 00:00:00 2001 From: Ankan Date: Tue, 9 Apr 2024 07:30:51 +0200 Subject: [PATCH 082/257] no check for minm while delegating to agent --- substrate/frame/delegated-staking/src/lib.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs index 3da643480d88..8bf9a90bb2d3 100644 --- a/substrate/frame/delegated-staking/src/lib.rs +++ b/substrate/frame/delegated-staking/src/lib.rs @@ -517,12 +517,6 @@ impl Pallet { amount }; - // ensure amount is at least minimum to delegate. - ensure!( - new_delegation_amount >= T::Currency::minimum_balance(), - Error::::NotEnoughFunds - ); - Delegation::::from(agent, new_delegation_amount).save_or_kill(delegator); ledger.total_delegated = ledger.total_delegated.checked_add(&amount).ok_or(ArithmeticError::Overflow)?; From e55cea3c0fe1cd7f172d6b97df1558429464999d Mon Sep 17 00:00:00 2001 From: Ankan Date: Tue, 9 Apr 2024 07:43:25 +0200 Subject: [PATCH 083/257] fix imports --- substrate/frame/delegated-staking/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs index 8bf9a90bb2d3..e73df73fbb92 100644 --- a/substrate/frame/delegated-staking/src/lib.rs +++ b/substrate/frame/delegated-staking/src/lib.rs @@ -142,7 +142,7 @@ use frame_support::{ }, Balanced, Inspect as FunInspect, Mutate as FunMutate, }, - tokens::{fungible::Credit, Fortitude, Precision, Preservation}, + tokens::{fungible::Credit, Precision, Preservation}, Defensive, DefensiveOption, Imbalance, OnUnbalanced, }, }; From a48b651612ef56fb55c3ef14e83f9c10b2b9916a Mon Sep 17 00:00:00 2001 From: Ankan Date: Tue, 9 Apr 2024 07:43:25 +0200 Subject: [PATCH 084/257] fix imports --- substrate/frame/delegated-staking/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/delegated-staking/src/lib.rs b/substrate/frame/delegated-staking/src/lib.rs index 8bf9a90bb2d3..e73df73fbb92 100644 --- a/substrate/frame/delegated-staking/src/lib.rs +++ b/substrate/frame/delegated-staking/src/lib.rs @@ -142,7 +142,7 @@ use frame_support::{ }, Balanced, Inspect as FunInspect, Mutate as FunMutate, }, - tokens::{fungible::Credit, Fortitude, Precision, Preservation}, + tokens::{fungible::Credit, Precision, Preservation}, Defensive, DefensiveOption, Imbalance, OnUnbalanced, }, }; From 8df0f0f5b14d58efe002c35f584a67c60cf1150c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Sun, 31 Mar 2024 22:47:01 +0200 Subject: [PATCH 085/257] Revert log level changes (#3913) Closes: https://github.com/paritytech/polkadot-sdk/issues/3906 --- polkadot/node/network/gossip-support/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polkadot/node/network/gossip-support/src/lib.rs b/polkadot/node/network/gossip-support/src/lib.rs index 9f33cd5d8a31..4dfdd1f7208f 100644 --- a/polkadot/node/network/gossip-support/src/lib.rs +++ b/polkadot/node/network/gossip-support/src/lib.rs @@ -508,7 +508,7 @@ where ); } let pretty = PrettyAuthorities(unconnected_authorities); - gum::info!( + gum::debug!( target: LOG_TARGET, ?connected_ratio, ?absolute_connected, From 8cd50d04f6efe1bd8bae433ca080c6b209edfb7c Mon Sep 17 00:00:00 2001 From: gemini132 <164285545+gemini132@users.noreply.github.com> Date: Mon, 1 Apr 2024 06:28:38 +0800 Subject: [PATCH 086/257] Fix two typos (#3812) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bastian Köcher From 398eb180add0e89f56d9a17b297d73824fff27f1 Mon Sep 17 00:00:00 2001 From: Matteo Muraca <56828990+muraca@users.noreply.github.com> Date: Mon, 1 Apr 2024 07:17:20 +0200 Subject: [PATCH 087/257] Removed `pallet::getter` usage from `pallet-alliance` (#3738) Part of #3326 cc @kianenigma @ggwpez @liamaharon polkadot address: 12poSUQPtcF1HUPQGY3zZu2P8emuW9YnsPduA4XG3oCEfJVp --------- Signed-off-by: Matteo Muraca Co-authored-by: Liam Aharon Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- prdoc/pr_3738.prdoc | 14 +++++ substrate/frame/alliance/src/benchmarking.rs | 10 ++-- substrate/frame/alliance/src/lib.rs | 7 --- substrate/frame/alliance/src/migration.rs | 12 ++--- substrate/frame/alliance/src/tests.rs | 55 +++++++++++--------- 5 files changed, 54 insertions(+), 44 deletions(-) create mode 100644 prdoc/pr_3738.prdoc diff --git a/prdoc/pr_3738.prdoc b/prdoc/pr_3738.prdoc new file mode 100644 index 000000000000..cbf19b95c36a --- /dev/null +++ b/prdoc/pr_3738.prdoc @@ -0,0 +1,14 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Removed `pallet::getter` usage from `pallet-alliance` + +doc: + - audience: Runtime Dev + description: | + This PR removes `pallet::getter` usage from `pallet-alliance`, and updates dependant code accordingly. + The syntax `StorageItem::::get()` should be used instead. + +crates: + - name: pallet-alliance + bump: major diff --git a/substrate/frame/alliance/src/benchmarking.rs b/substrate/frame/alliance/src/benchmarking.rs index 4ccd0fc08f6a..710c32a848dd 100644 --- a/substrate/frame/alliance/src/benchmarking.rs +++ b/substrate/frame/alliance/src/benchmarking.rs @@ -505,8 +505,8 @@ mod benchmarks { assert_last_event::( Event::MembersInitialized { fellows: fellows.clone(), allies: allies.clone() }.into(), ); - assert_eq!(Alliance::::members(MemberRole::Fellow), fellows); - assert_eq!(Alliance::::members(MemberRole::Ally), allies); + assert_eq!(Members::::get(MemberRole::Fellow), fellows); + assert_eq!(Members::::get(MemberRole::Ally), allies); Ok(()) } @@ -563,7 +563,7 @@ mod benchmarks { { call.dispatch_bypass_filter(origin)?; } - assert_eq!(Alliance::::rule(), Some(rule.clone())); + assert_eq!(Rule::::get(), Some(rule.clone())); assert_last_event::(Event::NewRuleSet { rule }.into()); Ok(()) } @@ -583,7 +583,7 @@ mod benchmarks { call.dispatch_bypass_filter(origin)?; } - assert!(Alliance::::announcements().contains(&announcement)); + assert!(Announcements::::get().contains(&announcement)); assert_last_event::(Event::Announced { announcement }.into()); Ok(()) } @@ -606,7 +606,7 @@ mod benchmarks { call.dispatch_bypass_filter(origin)?; } - assert!(!Alliance::::announcements().contains(&announcement)); + assert!(!Announcements::::get().contains(&announcement)); assert_last_event::(Event::AnnouncementRemoved { announcement }.into()); Ok(()) } diff --git a/substrate/frame/alliance/src/lib.rs b/substrate/frame/alliance/src/lib.rs index 414d550c53a9..1f06241e9c83 100644 --- a/substrate/frame/alliance/src/lib.rs +++ b/substrate/frame/alliance/src/lib.rs @@ -442,24 +442,20 @@ pub mod pallet { /// The IPFS CID of the alliance rule. /// Fellows can propose a new rule with a super-majority. #[pallet::storage] - #[pallet::getter(fn rule)] pub type Rule, I: 'static = ()> = StorageValue<_, Cid, OptionQuery>; /// The current IPFS CIDs of any announcements. #[pallet::storage] - #[pallet::getter(fn announcements)] pub type Announcements, I: 'static = ()> = StorageValue<_, BoundedVec, ValueQuery>; /// Maps members to their candidacy deposit. #[pallet::storage] - #[pallet::getter(fn deposit_of)] pub type DepositOf, I: 'static = ()> = StorageMap<_, Blake2_128Concat, T::AccountId, BalanceOf, OptionQuery>; /// Maps member type to members of each type. #[pallet::storage] - #[pallet::getter(fn members)] pub type Members, I: 'static = ()> = StorageMap< _, Twox64Concat, @@ -471,20 +467,17 @@ pub mod pallet { /// A set of members who gave a retirement notice. They can retire after the end of retirement /// period stored as a future block number. #[pallet::storage] - #[pallet::getter(fn retiring_members)] pub type RetiringMembers, I: 'static = ()> = StorageMap<_, Blake2_128Concat, T::AccountId, BlockNumberFor, OptionQuery>; /// The current list of accounts deemed unscrupulous. These accounts non grata cannot submit /// candidacy. #[pallet::storage] - #[pallet::getter(fn unscrupulous_accounts)] pub type UnscrupulousAccounts, I: 'static = ()> = StorageValue<_, BoundedVec, ValueQuery>; /// The current list of websites deemed unscrupulous. #[pallet::storage] - #[pallet::getter(fn unscrupulous_websites)] pub type UnscrupulousWebsites, I: 'static = ()> = StorageValue<_, BoundedVec, T::MaxUnscrupulousItems>, ValueQuery>; diff --git a/substrate/frame/alliance/src/migration.rs b/substrate/frame/alliance/src/migration.rs index 432f09a16f47..b4ecc1819447 100644 --- a/substrate/frame/alliance/src/migration.rs +++ b/substrate/frame/alliance/src/migration.rs @@ -162,18 +162,18 @@ pub(crate) mod v1_to_v2 { #[cfg(test)] mod test { use super::*; - use crate::{mock::*, MemberRole}; + use crate::{mock::*, MemberRole, Members}; #[test] fn migration_v1_to_v2_works() { new_test_ext().execute_with(|| { assert_ok!(Alliance::join_alliance(RuntimeOrigin::signed(4))); - assert_eq!(Alliance::members(MemberRole::Ally), vec![4]); - assert_eq!(Alliance::members(MemberRole::Fellow), vec![1, 2, 3]); + assert_eq!(Members::::get(MemberRole::Ally), vec![4]); + assert_eq!(Members::::get(MemberRole::Fellow), vec![1, 2, 3]); v1_to_v2::migrate::(); - assert_eq!(Alliance::members(MemberRole::Fellow), vec![1, 2, 3, 4]); - assert_eq!(Alliance::members(MemberRole::Ally), vec![]); - assert_eq!(Alliance::members(MemberRole::Retiring), vec![]); + assert_eq!(Members::::get(MemberRole::Fellow), vec![1, 2, 3, 4]); + assert_eq!(Members::::get(MemberRole::Ally), vec![]); + assert_eq!(Members::::get(MemberRole::Retiring), vec![]); }); } } diff --git a/substrate/frame/alliance/src/tests.rs b/substrate/frame/alliance/src/tests.rs index c65f10228e77..edb515b8115a 100644 --- a/substrate/frame/alliance/src/tests.rs +++ b/substrate/frame/alliance/src/tests.rs @@ -21,7 +21,7 @@ use frame_support::{assert_noop, assert_ok, error::BadOrigin}; use frame_system::{EventRecord, Phase}; use super::*; -use crate::mock::*; +use crate::{self as alliance, mock::*}; type AllianceMotionEvent = pallet_collective::Event; @@ -118,7 +118,7 @@ fn disband_works() { // join alliance and reserve funds assert_eq!(Balances::free_balance(9), 1000 - id_deposit); assert_ok!(Alliance::join_alliance(RuntimeOrigin::signed(9))); - assert_eq!(Alliance::deposit_of(9), Some(expected_join_deposit)); + assert_eq!(alliance::DepositOf::::get(9), Some(expected_join_deposit)); assert_eq!(Balances::free_balance(9), 1000 - id_deposit - expected_join_deposit); assert!(Alliance::is_member_of(&9, MemberRole::Ally)); @@ -314,7 +314,7 @@ fn set_rule_works() { new_test_ext().execute_with(|| { let cid = test_cid(); assert_ok!(Alliance::set_rule(RuntimeOrigin::signed(1), cid.clone())); - assert_eq!(Alliance::rule(), Some(cid.clone())); + assert_eq!(alliance::Rule::::get(), Some(cid.clone())); System::assert_last_event(mock::RuntimeEvent::Alliance(crate::Event::NewRuleSet { rule: cid, @@ -330,7 +330,7 @@ fn announce_works() { assert_noop!(Alliance::announce(RuntimeOrigin::signed(2), cid.clone()), BadOrigin); assert_ok!(Alliance::announce(RuntimeOrigin::signed(3), cid.clone())); - assert_eq!(Alliance::announcements(), vec![cid.clone()]); + assert_eq!(alliance::Announcements::::get(), vec![cid.clone()]); System::assert_last_event(mock::RuntimeEvent::Alliance(crate::Event::Announced { announcement: cid, @@ -343,7 +343,7 @@ fn remove_announcement_works() { new_test_ext().execute_with(|| { let cid = test_cid(); assert_ok!(Alliance::announce(RuntimeOrigin::signed(3), cid.clone())); - assert_eq!(Alliance::announcements(), vec![cid.clone()]); + assert_eq!(alliance::Announcements::::get(), vec![cid.clone()]); System::assert_last_event(mock::RuntimeEvent::Alliance(crate::Event::Announced { announcement: cid.clone(), })); @@ -351,7 +351,7 @@ fn remove_announcement_works() { System::set_block_number(2); assert_ok!(Alliance::remove_announcement(RuntimeOrigin::signed(3), cid.clone())); - assert_eq!(Alliance::announcements(), vec![]); + assert_eq!(alliance::Announcements::::get(), vec![]); System::assert_last_event(mock::RuntimeEvent::Alliance( crate::Event::AnnouncementRemoved { announcement: cid }, )); @@ -394,8 +394,8 @@ fn join_alliance_works() { // success to submit assert_ok!(Alliance::join_alliance(RuntimeOrigin::signed(4))); assert_eq!(Balances::free_balance(4), 1000 - id_deposit - join_deposit); - assert_eq!(Alliance::deposit_of(4), Some(25)); - assert_eq!(Alliance::members(MemberRole::Ally), vec![4]); + assert_eq!(alliance::DepositOf::::get(4), Some(25)); + assert_eq!(alliance::Members::::get(MemberRole::Ally), vec![4]); // check already member assert_noop!( @@ -449,8 +449,8 @@ fn nominate_ally_works() { // success to nominate assert_ok!(Alliance::nominate_ally(RuntimeOrigin::signed(1), 4)); - assert_eq!(Alliance::deposit_of(4), None); - assert_eq!(Alliance::members(MemberRole::Ally), vec![4]); + assert_eq!(alliance::DepositOf::::get(4), None); + assert_eq!(alliance::Members::::get(MemberRole::Ally), vec![4]); // check already member assert_noop!( @@ -482,12 +482,12 @@ fn elevate_ally_works() { ); assert_ok!(Alliance::join_alliance(RuntimeOrigin::signed(4))); - assert_eq!(Alliance::members(MemberRole::Ally), vec![4]); - assert_eq!(Alliance::members(MemberRole::Fellow), vec![1, 2, 3]); + assert_eq!(alliance::Members::::get(MemberRole::Ally), vec![4]); + assert_eq!(alliance::Members::::get(MemberRole::Fellow), vec![1, 2, 3]); assert_ok!(Alliance::elevate_ally(RuntimeOrigin::signed(2), 4)); - assert_eq!(Alliance::members(MemberRole::Ally), Vec::::new()); - assert_eq!(Alliance::members(MemberRole::Fellow), vec![1, 2, 3, 4]); + assert_eq!(alliance::Members::::get(MemberRole::Ally), Vec::::new()); + assert_eq!(alliance::Members::::get(MemberRole::Fellow), vec![1, 2, 3, 4]); }); } @@ -499,10 +499,10 @@ fn give_retirement_notice_work() { Error::::NotMember ); - assert_eq!(Alliance::members(MemberRole::Fellow), vec![1, 2, 3]); + assert_eq!(alliance::Members::::get(MemberRole::Fellow), vec![1, 2, 3]); assert_ok!(Alliance::give_retirement_notice(RuntimeOrigin::signed(3))); - assert_eq!(Alliance::members(MemberRole::Fellow), vec![1, 2]); - assert_eq!(Alliance::members(MemberRole::Retiring), vec![3]); + assert_eq!(alliance::Members::::get(MemberRole::Fellow), vec![1, 2]); + assert_eq!(alliance::Members::::get(MemberRole::Retiring), vec![3]); System::assert_last_event(mock::RuntimeEvent::Alliance( crate::Event::MemberRetirementPeriodStarted { member: (3) }, )); @@ -527,7 +527,7 @@ fn retire_works() { Error::::RetirementNoticeNotGiven ); - assert_eq!(Alliance::members(MemberRole::Fellow), vec![1, 2, 3]); + assert_eq!(alliance::Members::::get(MemberRole::Fellow), vec![1, 2, 3]); assert_ok!(Alliance::give_retirement_notice(RuntimeOrigin::signed(3))); assert_noop!( Alliance::retire(RuntimeOrigin::signed(3)), @@ -535,7 +535,7 @@ fn retire_works() { ); System::set_block_number(System::block_number() + RetirementPeriod::get()); assert_ok!(Alliance::retire(RuntimeOrigin::signed(3))); - assert_eq!(Alliance::members(MemberRole::Fellow), vec![1, 2]); + assert_eq!(alliance::Members::::get(MemberRole::Fellow), vec![1, 2]); System::assert_last_event(mock::RuntimeEvent::Alliance(crate::Event::MemberRetired { member: (3), unreserved: None, @@ -551,7 +551,7 @@ fn retire_works() { #[test] fn abdicate_works() { new_test_ext().execute_with(|| { - assert_eq!(Alliance::members(MemberRole::Fellow), vec![1, 2, 3]); + assert_eq!(alliance::Members::::get(MemberRole::Fellow), vec![1, 2, 3]); assert_ok!(Alliance::abdicate_fellow_status(RuntimeOrigin::signed(3))); System::assert_last_event(mock::RuntimeEvent::Alliance(crate::Event::FellowAbdicated { @@ -573,9 +573,9 @@ fn kick_member_works() { ); >::insert(2, 25); - assert_eq!(Alliance::members(MemberRole::Fellow), vec![1, 2, 3]); + assert_eq!(alliance::Members::::get(MemberRole::Fellow), vec![1, 2, 3]); assert_ok!(Alliance::kick_member(RuntimeOrigin::signed(2), 2)); - assert_eq!(Alliance::members(MemberRole::Fellow), vec![1, 3]); + assert_eq!(alliance::Members::::get(MemberRole::Fellow), vec![1, 3]); assert_eq!(>::get(2), None); System::assert_last_event(mock::RuntimeEvent::Alliance(crate::Event::MemberKicked { member: (2), @@ -596,8 +596,11 @@ fn add_unscrupulous_items_works() { UnscrupulousItem::Website("abc".as_bytes().to_vec().try_into().unwrap()) ] )); - assert_eq!(Alliance::unscrupulous_accounts().into_inner(), vec![3]); - assert_eq!(Alliance::unscrupulous_websites().into_inner(), vec!["abc".as_bytes().to_vec()]); + assert_eq!(alliance::UnscrupulousAccounts::::get().into_inner(), vec![3]); + assert_eq!( + alliance::UnscrupulousWebsites::::get().into_inner(), + vec!["abc".as_bytes().to_vec()] + ); assert_noop!( Alliance::add_unscrupulous_items( @@ -629,12 +632,12 @@ fn remove_unscrupulous_items_works() { RuntimeOrigin::signed(3), vec![UnscrupulousItem::AccountId(3)] )); - assert_eq!(Alliance::unscrupulous_accounts(), vec![3]); + assert_eq!(alliance::UnscrupulousAccounts::::get(), vec![3]); assert_ok!(Alliance::remove_unscrupulous_items( RuntimeOrigin::signed(3), vec![UnscrupulousItem::AccountId(3)] )); - assert_eq!(Alliance::unscrupulous_accounts(), Vec::::new()); + assert_eq!(alliance::UnscrupulousAccounts::::get(), Vec::::new()); }); } From 140b0f56fc3867687bb1e5a210dfc9e9bb03e14e Mon Sep 17 00:00:00 2001 From: Alexandru Gheorghe <49718502+alexggh@users.noreply.github.com> Date: Mon, 1 Apr 2024 09:29:22 +0300 Subject: [PATCH 088/257] network:bridge: fix peer_count metric (#3711) The metric records the current protocol_version of the validator that just connected with the peer_map.len(), which contains all peers that connected, that has the effect the metric will be wrong since it won't tell us how many peers we have connected per version because it will always record the total number of peers Fix this by counting by version inside peer_map, additionally because that might be a bit heavier than len(), publish it only on-active leaves. --------- Signed-off-by: Alexandru Gheorghe --- polkadot/node/network/bridge/src/lib.rs | 24 ++++++++++++++++++++++ polkadot/node/network/bridge/src/rx/mod.rs | 6 +----- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/polkadot/node/network/bridge/src/lib.rs b/polkadot/node/network/bridge/src/lib.rs index ddce99d5c2a8..0305aaa067cc 100644 --- a/polkadot/node/network/bridge/src/lib.rs +++ b/polkadot/node/network/bridge/src/lib.rs @@ -102,6 +102,30 @@ struct SharedInner { collation_peers: HashMap, } +// Counts the number of peers that are connectioned using `version` +fn count_peers_by_version(peers: &HashMap) -> HashMap { + let mut by_version_count = HashMap::new(); + for peer in peers.values() { + *(by_version_count.entry(peer.version).or_default()) += 1; + } + by_version_count +} + +// Notes the peer count +fn note_peers_count(metrics: &Metrics, shared: &Shared) { + let guard = shared.0.lock(); + let validation_stats = count_peers_by_version(&guard.validation_peers); + let collation_stats = count_peers_by_version(&guard.collation_peers); + + for (version, count) in validation_stats { + metrics.note_peer_count(PeerSet::Validation, version, count) + } + + for (version, count) in collation_stats { + metrics.note_peer_count(PeerSet::Collation, version, count) + } +} + pub(crate) enum Mode { Syncing(Box), Active, diff --git a/polkadot/node/network/bridge/src/rx/mod.rs b/polkadot/node/network/bridge/src/rx/mod.rs index 11ac73259e3a..0a4497fc4b5a 100644 --- a/polkadot/node/network/bridge/src/rx/mod.rs +++ b/polkadot/node/network/bridge/src/rx/mod.rs @@ -262,7 +262,6 @@ async fn handle_validation_message( } metrics.on_peer_connected(peer_set, version); - metrics.note_peer_count(peer_set, version, peer_map.len()); shared.local_view.clone().unwrap_or(View::default()) }; @@ -320,8 +319,6 @@ async fn handle_validation_message( let w = peer_map.remove(&peer).is_some(); metrics.on_peer_disconnected(peer_set, version); - metrics.note_peer_count(peer_set, version, peer_map.len()); - w }; @@ -524,7 +521,6 @@ async fn handle_collation_message( } metrics.on_peer_connected(peer_set, version); - metrics.note_peer_count(peer_set, version, peer_map.len()); shared.local_view.clone().unwrap_or(View::default()) }; @@ -575,7 +571,6 @@ async fn handle_collation_message( let w = peer_map.remove(&peer).is_some(); metrics.on_peer_disconnected(peer_set, version); - metrics.note_peer_count(peer_set, version, peer_map.len()); w }; @@ -832,6 +827,7 @@ where &metrics, ¬ification_sinks, ); + note_peers_count(&metrics, &shared); } } }, From 01d0b52a5a796844771f4cec11ab899680a3f293 Mon Sep 17 00:00:00 2001 From: Alessandro Siniscalchi Date: Mon, 1 Apr 2024 10:54:23 +0200 Subject: [PATCH 089/257] [parachain-template] pallet configurations into `mod configs` (#3809) This PR introduces a refactor of the parachain runtime configuration by consolidating all pallet configurations into a new module named `configs`. This change aims to improve the readability and maintainability of the runtime configuration by centralizing all configuration parameters. ## Changes - **Creation of `configs.rs`**: A new file `configs.rs` has been added under `templates/parachain/runtime/src/`, containing all the runtime configurations previously scattered across `lib.rs`. - **Refactoring of `lib.rs`**: The `lib.rs` file has been significantly slimmed down by removing the inline pallet configurations and importing them from `configs.rs` instead. - **Optimization of Import Statements**: Reorganized import statements to clarify the runtime's dependency structure. ### Benefits - **Improved Readability**: With configurations being centralized, developers can now easily locate and review runtime parameters without navigating through the `lib.rs` file. This refactor does not introduce any changes to the runtime logic but improves the project structure for better development experience. --------- Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- templates/parachain/runtime/src/apis.rs | 2 +- .../parachain/runtime/src/configs/mod.rs | 311 ++++++++++++++++++ .../runtime/src/{ => configs}/xcm_config.rs | 2 +- templates/parachain/runtime/src/lib.rs | 276 +--------------- 4 files changed, 317 insertions(+), 274 deletions(-) create mode 100644 templates/parachain/runtime/src/configs/mod.rs rename templates/parachain/runtime/src/{ => configs}/xcm_config.rs (99%) diff --git a/templates/parachain/runtime/src/apis.rs b/templates/parachain/runtime/src/apis.rs index aa0cae843c37..74c7476e1520 100644 --- a/templates/parachain/runtime/src/apis.rs +++ b/templates/parachain/runtime/src/apis.rs @@ -193,7 +193,7 @@ impl_runtime_apis! { #[cfg(feature = "try-runtime")] impl frame_try_runtime::TryRuntime for Runtime { fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) { - use super::RuntimeBlockWeights; + use super::configs::RuntimeBlockWeights; let weight = Executive::try_runtime_upgrade(checks).unwrap(); (weight, RuntimeBlockWeights::get().max_block) diff --git a/templates/parachain/runtime/src/configs/mod.rs b/templates/parachain/runtime/src/configs/mod.rs new file mode 100644 index 000000000000..e2c51e07d37b --- /dev/null +++ b/templates/parachain/runtime/src/configs/mod.rs @@ -0,0 +1,311 @@ +// This is free and unencumbered software released into the public domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. +// +// In jurisdictions that recognize copyright laws, the author or authors +// of this software dedicate any and all copyright interest in the +// software to the public domain. We make this dedication for the benefit +// of the public at large and to the detriment of our heirs and +// successors. We intend this dedication to be an overt act of +// relinquishment in perpetuity of all present and future rights to this +// software under copyright law. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// +// For more information, please refer to + +mod xcm_config; + +// Substrate and Polkadot dependencies +use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; +use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; +use frame_support::{ + derive_impl, + dispatch::DispatchClass, + parameter_types, + traits::{ConstBool, ConstU32, ConstU64, ConstU8, EitherOfDiverse, TransformOrigin}, + weights::{ConstantMultiplier, Weight}, + PalletId, +}; +use frame_system::{ + limits::{BlockLength, BlockWeights}, + EnsureRoot, +}; +use pallet_xcm::{EnsureXcm, IsVoiceOfBody}; +use parachains_common::message_queue::{NarrowOriginToSibling, ParaIdToSibling}; +use polkadot_runtime_common::{ + xcm_sender::NoPriceForMessageDelivery, BlockHashCount, SlowAdjustingFeeUpdate, +}; +use sp_consensus_aura::sr25519::AuthorityId as AuraId; +use sp_runtime::Perbill; +use sp_version::RuntimeVersion; +use xcm::latest::prelude::BodyId; + +// Local module imports +use super::{ + weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}, + AccountId, Aura, Balance, Balances, Block, BlockNumber, CollatorSelection, Hash, MessageQueue, + Nonce, PalletInfo, ParachainSystem, Runtime, RuntimeCall, RuntimeEvent, RuntimeFreezeReason, + RuntimeHoldReason, RuntimeOrigin, RuntimeTask, Session, SessionKeys, System, WeightToFee, + XcmpQueue, AVERAGE_ON_INITIALIZE_RATIO, BLOCK_PROCESSING_VELOCITY, EXISTENTIAL_DEPOSIT, HOURS, + MAXIMUM_BLOCK_WEIGHT, MICROUNIT, NORMAL_DISPATCH_RATIO, RELAY_CHAIN_SLOT_DURATION_MILLIS, + SLOT_DURATION, UNINCLUDED_SEGMENT_CAPACITY, VERSION, +}; +use xcm_config::{RelayLocation, XcmOriginToTransactDispatchOrigin}; + +parameter_types! { + pub const Version: RuntimeVersion = VERSION; + + // This part is copied from Substrate's `bin/node/runtime/src/lib.rs`. + // The `RuntimeBlockLength` and `RuntimeBlockWeights` exist here because the + // `DeletionWeightLimit` and `DeletionQueueDepth` depend on those to parameterize + // the lazy contract deletion. + pub RuntimeBlockLength: BlockLength = + BlockLength::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO); + pub RuntimeBlockWeights: BlockWeights = BlockWeights::builder() + .base_block(BlockExecutionWeight::get()) + .for_class(DispatchClass::all(), |weights| { + weights.base_extrinsic = ExtrinsicBaseWeight::get(); + }) + .for_class(DispatchClass::Normal, |weights| { + weights.max_total = Some(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT); + }) + .for_class(DispatchClass::Operational, |weights| { + weights.max_total = Some(MAXIMUM_BLOCK_WEIGHT); + // Operational transactions have some extra reserved space, so that they + // are included even if block reached `MAXIMUM_BLOCK_WEIGHT`. + weights.reserved = Some( + MAXIMUM_BLOCK_WEIGHT - NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT + ); + }) + .avg_block_initialization(AVERAGE_ON_INITIALIZE_RATIO) + .build_or_panic(); + pub const SS58Prefix: u16 = 42; +} + +/// The default types are being injected by [`derive_impl`](`frame_support::derive_impl`) from +/// [`ParaChainDefaultConfig`](`struct@frame_system::config_preludes::ParaChainDefaultConfig`), +/// but overridden as needed. +#[derive_impl(frame_system::config_preludes::ParaChainDefaultConfig)] +impl frame_system::Config for Runtime { + /// The identifier used to distinguish between accounts. + type AccountId = AccountId; + /// The index type for storing how many extrinsics an account has signed. + type Nonce = Nonce; + /// The type for hashing blocks and tries. + type Hash = Hash; + /// The block type. + type Block = Block; + /// Maximum number of block number to block hash mappings to keep (oldest pruned first). + type BlockHashCount = BlockHashCount; + /// Runtime version. + type Version = Version; + /// The data to be stored in an account. + type AccountData = pallet_balances::AccountData; + /// The weight of database operations that the runtime can invoke. + type DbWeight = RocksDbWeight; + /// Block & extrinsics weights: base values and limits. + type BlockWeights = RuntimeBlockWeights; + /// The maximum length of a block (in bytes). + type BlockLength = RuntimeBlockLength; + /// This is used as an identifier of the chain. 42 is the generic substrate prefix. + type SS58Prefix = SS58Prefix; + /// The action to take on a Runtime Upgrade + type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + +impl pallet_timestamp::Config for Runtime { + /// A timestamp: milliseconds since the unix epoch. + type Moment = u64; + type OnTimestampSet = Aura; + type MinimumPeriod = ConstU64<{ SLOT_DURATION / 2 }>; + type WeightInfo = (); +} + +impl pallet_authorship::Config for Runtime { + type FindAuthor = pallet_session::FindAccountFromAuthorIndex; + type EventHandler = (CollatorSelection,); +} + +parameter_types! { + pub const ExistentialDeposit: Balance = EXISTENTIAL_DEPOSIT; +} + +impl pallet_balances::Config for Runtime { + type MaxLocks = ConstU32<50>; + /// The type for recording an account's balance. + type Balance = Balance; + /// The ubiquitous event type. + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = pallet_balances::weights::SubstrateWeight; + type MaxReserves = ConstU32<50>; + type ReserveIdentifier = [u8; 8]; + type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; + type FreezeIdentifier = (); + type MaxFreezes = ConstU32<0>; +} + +parameter_types! { + /// Relay Chain `TransactionByteFee` / 10 + pub const TransactionByteFee: Balance = 10 * MICROUNIT; +} + +impl pallet_transaction_payment::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type OnChargeTransaction = pallet_transaction_payment::CurrencyAdapter; + type WeightToFee = WeightToFee; + type LengthToFee = ConstantMultiplier; + type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; + type OperationalFeeMultiplier = ConstU8<5>; +} + +impl pallet_sudo::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type WeightInfo = (); +} + +parameter_types! { + pub const ReservedXcmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); + pub const ReservedDmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); + pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; +} + +impl cumulus_pallet_parachain_system::Config for Runtime { + type WeightInfo = (); + type RuntimeEvent = RuntimeEvent; + type OnSystemEvent = (); + type SelfParaId = parachain_info::Pallet; + type OutboundXcmpMessageSource = XcmpQueue; + type DmpQueue = frame_support::traits::EnqueueWithOrigin; + type ReservedDmpWeight = ReservedDmpWeight; + type XcmpMessageHandler = XcmpQueue; + type ReservedXcmpWeight = ReservedXcmpWeight; + type CheckAssociatedRelayNumber = RelayNumberStrictlyIncreases; + type ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook< + Runtime, + RELAY_CHAIN_SLOT_DURATION_MILLIS, + BLOCK_PROCESSING_VELOCITY, + UNINCLUDED_SEGMENT_CAPACITY, + >; +} + +impl parachain_info::Config for Runtime {} + +parameter_types! { + pub MessageQueueServiceWeight: Weight = Perbill::from_percent(35) * RuntimeBlockWeights::get().max_block; +} + +impl pallet_message_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); + #[cfg(feature = "runtime-benchmarks")] + type MessageProcessor = pallet_message_queue::mock_helpers::NoopMessageProcessor< + cumulus_primitives_core::AggregateMessageOrigin, + >; + #[cfg(not(feature = "runtime-benchmarks"))] + type MessageProcessor = xcm_builder::ProcessXcmMessage< + AggregateMessageOrigin, + xcm_executor::XcmExecutor, + RuntimeCall, + >; + type Size = u32; + // The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin: + type QueueChangeHandler = NarrowOriginToSibling; + type QueuePausedQuery = NarrowOriginToSibling; + type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; + type MaxStale = sp_core::ConstU32<8>; + type ServiceWeight = MessageQueueServiceWeight; + type IdleMaxServiceWeight = (); +} + +impl cumulus_pallet_aura_ext::Config for Runtime {} + +impl cumulus_pallet_xcmp_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type ChannelInfo = ParachainSystem; + type VersionWrapper = (); + // Enqueue XCMP messages from siblings for later processing. + type XcmpQueue = TransformOrigin; + type MaxInboundSuspended = sp_core::ConstU32<1_000>; + type ControllerOrigin = EnsureRoot; + type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; + type WeightInfo = (); + type PriceForSiblingDelivery = NoPriceForMessageDelivery; +} + +parameter_types! { + pub const Period: u32 = 6 * HOURS; + pub const Offset: u32 = 0; +} + +impl pallet_session::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type ValidatorId = ::AccountId; + // we don't have stash and controller, thus we don't need the convert as well. + type ValidatorIdOf = pallet_collator_selection::IdentityCollator; + type ShouldEndSession = pallet_session::PeriodicSessions; + type NextSessionRotation = pallet_session::PeriodicSessions; + type SessionManager = CollatorSelection; + // Essentially just Aura, but let's be pedantic. + type SessionHandler = ::KeyTypeIdProviders; + type Keys = SessionKeys; + type WeightInfo = (); +} + +impl pallet_aura::Config for Runtime { + type AuthorityId = AuraId; + type DisabledValidators = (); + type MaxAuthorities = ConstU32<100_000>; + type AllowMultipleBlocksPerSlot = ConstBool; + type SlotDuration = pallet_aura::MinimumPeriodTimesTwo; +} + +parameter_types! { + pub const PotId: PalletId = PalletId(*b"PotStake"); + pub const SessionLength: BlockNumber = 6 * HOURS; + // StakingAdmin pluralistic body. + pub const StakingAdminBodyId: BodyId = BodyId::Defense; +} + +/// We allow root and the StakingAdmin to execute privileged collator selection operations. +pub type CollatorSelectionUpdateOrigin = EitherOfDiverse< + EnsureRoot, + EnsureXcm>, +>; + +impl pallet_collator_selection::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type UpdateOrigin = CollatorSelectionUpdateOrigin; + type PotId = PotId; + type MaxCandidates = ConstU32<100>; + type MinEligibleCollators = ConstU32<4>; + type MaxInvulnerables = ConstU32<20>; + // should be a multiple of session or things will get inconsistent + type KickThreshold = Period; + type ValidatorId = ::AccountId; + type ValidatorIdOf = pallet_collator_selection::IdentityCollator; + type ValidatorRegistration = Session; + type WeightInfo = (); +} + +/// Configure the pallet template in pallets/template. +impl pallet_parachain_template::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = pallet_parachain_template::weights::SubstrateWeight; +} diff --git a/templates/parachain/runtime/src/xcm_config.rs b/templates/parachain/runtime/src/configs/xcm_config.rs similarity index 99% rename from templates/parachain/runtime/src/xcm_config.rs rename to templates/parachain/runtime/src/configs/xcm_config.rs index 7dce71648886..13da2363b053 100644 --- a/templates/parachain/runtime/src/xcm_config.rs +++ b/templates/parachain/runtime/src/configs/xcm_config.rs @@ -1,4 +1,4 @@ -use super::{ +use crate::{ AccountId, AllPalletsWithSystem, Balances, ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, WeightToFee, XcmpQueue, }; diff --git a/templates/parachain/runtime/src/lib.rs b/templates/parachain/runtime/src/lib.rs index 5cfee123b01b..e2da9309ecc7 100644 --- a/templates/parachain/runtime/src/lib.rs +++ b/templates/parachain/runtime/src/lib.rs @@ -7,11 +7,9 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); pub mod apis; +mod configs; mod weights; -pub mod xcm_config; -use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; -use polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery; use smallvec::smallvec; use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, @@ -24,38 +22,20 @@ use sp_std::prelude::*; use sp_version::NativeVersion; use sp_version::RuntimeVersion; -use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; use frame_support::{ - construct_runtime, derive_impl, - dispatch::DispatchClass, - parameter_types, - traits::{ConstBool, ConstU32, ConstU64, ConstU8, EitherOfDiverse, TransformOrigin}, + construct_runtime, weights::{ - constants::WEIGHT_REF_TIME_PER_SECOND, ConstantMultiplier, Weight, WeightToFeeCoefficient, + constants::WEIGHT_REF_TIME_PER_SECOND, Weight, WeightToFeeCoefficient, WeightToFeeCoefficients, WeightToFeePolynomial, }, - PalletId, }; -use frame_system::{ - limits::{BlockLength, BlockWeights}, - EnsureRoot, -}; -use pallet_xcm::{EnsureXcm, IsVoiceOfBody}; -use parachains_common::message_queue::{NarrowOriginToSibling, ParaIdToSibling}; pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; pub use sp_runtime::{MultiAddress, Perbill, Permill}; -use xcm_config::{RelayLocation, XcmOriginToTransactDispatchOrigin}; #[cfg(any(feature = "std", test))] pub use sp_runtime::BuildStorage; -// Polkadot imports -use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; - -use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; - -// XCM Imports -use xcm::latest::prelude::BodyId; +use weights::ExtrinsicBaseWeight; /// Import the template pallet. pub use pallet_parachain_template; @@ -241,254 +221,6 @@ pub fn native_version() -> NativeVersion { NativeVersion { runtime_version: VERSION, can_author_with: Default::default() } } -parameter_types! { - pub const Version: RuntimeVersion = VERSION; - - // This part is copied from Substrate's `bin/node/runtime/src/lib.rs`. - // The `RuntimeBlockLength` and `RuntimeBlockWeights` exist here because the - // `DeletionWeightLimit` and `DeletionQueueDepth` depend on those to parameterize - // the lazy contract deletion. - pub RuntimeBlockLength: BlockLength = - BlockLength::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO); - pub RuntimeBlockWeights: BlockWeights = BlockWeights::builder() - .base_block(BlockExecutionWeight::get()) - .for_class(DispatchClass::all(), |weights| { - weights.base_extrinsic = ExtrinsicBaseWeight::get(); - }) - .for_class(DispatchClass::Normal, |weights| { - weights.max_total = Some(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT); - }) - .for_class(DispatchClass::Operational, |weights| { - weights.max_total = Some(MAXIMUM_BLOCK_WEIGHT); - // Operational transactions have some extra reserved space, so that they - // are included even if block reached `MAXIMUM_BLOCK_WEIGHT`. - weights.reserved = Some( - MAXIMUM_BLOCK_WEIGHT - NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT - ); - }) - .avg_block_initialization(AVERAGE_ON_INITIALIZE_RATIO) - .build_or_panic(); - pub const SS58Prefix: u16 = 42; -} - -/// The default types are being injected by [`derive_impl`](`frame_support::derive_impl`) from -/// [`ParaChainDefaultConfig`](`struct@frame_system::config_preludes::ParaChainDefaultConfig`), -/// but overridden as needed. -#[derive_impl(frame_system::config_preludes::ParaChainDefaultConfig)] -impl frame_system::Config for Runtime { - /// The identifier used to distinguish between accounts. - type AccountId = AccountId; - /// The index type for storing how many extrinsics an account has signed. - type Nonce = Nonce; - /// The type for hashing blocks and tries. - type Hash = Hash; - /// The block type. - type Block = Block; - /// Maximum number of block number to block hash mappings to keep (oldest pruned first). - type BlockHashCount = BlockHashCount; - /// Runtime version. - type Version = Version; - /// The data to be stored in an account. - type AccountData = pallet_balances::AccountData; - /// The weight of database operations that the runtime can invoke. - type DbWeight = RocksDbWeight; - /// Block & extrinsics weights: base values and limits. - type BlockWeights = RuntimeBlockWeights; - /// The maximum length of a block (in bytes). - type BlockLength = RuntimeBlockLength; - /// This is used as an identifier of the chain. 42 is the generic substrate prefix. - type SS58Prefix = SS58Prefix; - /// The action to take on a Runtime Upgrade - type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; - type MaxConsumers = frame_support::traits::ConstU32<16>; -} - -impl pallet_timestamp::Config for Runtime { - /// A timestamp: milliseconds since the unix epoch. - type Moment = u64; - type OnTimestampSet = Aura; - type MinimumPeriod = ConstU64<{ SLOT_DURATION / 2 }>; - type WeightInfo = (); -} - -impl pallet_authorship::Config for Runtime { - type FindAuthor = pallet_session::FindAccountFromAuthorIndex; - type EventHandler = (CollatorSelection,); -} - -parameter_types! { - pub const ExistentialDeposit: Balance = EXISTENTIAL_DEPOSIT; -} - -impl pallet_balances::Config for Runtime { - type MaxLocks = ConstU32<50>; - /// The type for recording an account's balance. - type Balance = Balance; - /// The ubiquitous event type. - type RuntimeEvent = RuntimeEvent; - type DustRemoval = (); - type ExistentialDeposit = ExistentialDeposit; - type AccountStore = System; - type WeightInfo = pallet_balances::weights::SubstrateWeight; - type MaxReserves = ConstU32<50>; - type ReserveIdentifier = [u8; 8]; - type RuntimeHoldReason = RuntimeHoldReason; - type RuntimeFreezeReason = RuntimeFreezeReason; - type FreezeIdentifier = (); - type MaxFreezes = ConstU32<0>; -} - -parameter_types! { - /// Relay Chain `TransactionByteFee` / 10 - pub const TransactionByteFee: Balance = 10 * MICROUNIT; -} - -impl pallet_transaction_payment::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type OnChargeTransaction = pallet_transaction_payment::CurrencyAdapter; - type WeightToFee = WeightToFee; - type LengthToFee = ConstantMultiplier; - type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; - type OperationalFeeMultiplier = ConstU8<5>; -} - -impl pallet_sudo::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type RuntimeCall = RuntimeCall; - type WeightInfo = (); -} - -parameter_types! { - pub const ReservedXcmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); - pub const ReservedDmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); - pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; -} - -impl cumulus_pallet_parachain_system::Config for Runtime { - type WeightInfo = (); - type RuntimeEvent = RuntimeEvent; - type OnSystemEvent = (); - type SelfParaId = parachain_info::Pallet; - type OutboundXcmpMessageSource = XcmpQueue; - type DmpQueue = frame_support::traits::EnqueueWithOrigin; - type ReservedDmpWeight = ReservedDmpWeight; - type XcmpMessageHandler = XcmpQueue; - type ReservedXcmpWeight = ReservedXcmpWeight; - type CheckAssociatedRelayNumber = RelayNumberStrictlyIncreases; - type ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook< - Runtime, - RELAY_CHAIN_SLOT_DURATION_MILLIS, - BLOCK_PROCESSING_VELOCITY, - UNINCLUDED_SEGMENT_CAPACITY, - >; -} - -impl parachain_info::Config for Runtime {} - -parameter_types! { - pub MessageQueueServiceWeight: Weight = Perbill::from_percent(35) * RuntimeBlockWeights::get().max_block; -} - -impl pallet_message_queue::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type WeightInfo = (); - #[cfg(feature = "runtime-benchmarks")] - type MessageProcessor = pallet_message_queue::mock_helpers::NoopMessageProcessor< - cumulus_primitives_core::AggregateMessageOrigin, - >; - #[cfg(not(feature = "runtime-benchmarks"))] - type MessageProcessor = xcm_builder::ProcessXcmMessage< - AggregateMessageOrigin, - xcm_executor::XcmExecutor, - RuntimeCall, - >; - type Size = u32; - // The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin: - type QueueChangeHandler = NarrowOriginToSibling; - type QueuePausedQuery = NarrowOriginToSibling; - type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>; - type MaxStale = sp_core::ConstU32<8>; - type ServiceWeight = MessageQueueServiceWeight; - type IdleMaxServiceWeight = (); -} - -impl cumulus_pallet_aura_ext::Config for Runtime {} - -impl cumulus_pallet_xcmp_queue::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type ChannelInfo = ParachainSystem; - type VersionWrapper = (); - // Enqueue XCMP messages from siblings for later processing. - type XcmpQueue = TransformOrigin; - type MaxInboundSuspended = sp_core::ConstU32<1_000>; - type ControllerOrigin = EnsureRoot; - type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; - type WeightInfo = (); - type PriceForSiblingDelivery = NoPriceForMessageDelivery; -} - -parameter_types! { - pub const Period: u32 = 6 * HOURS; - pub const Offset: u32 = 0; -} - -impl pallet_session::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type ValidatorId = ::AccountId; - // we don't have stash and controller, thus we don't need the convert as well. - type ValidatorIdOf = pallet_collator_selection::IdentityCollator; - type ShouldEndSession = pallet_session::PeriodicSessions; - type NextSessionRotation = pallet_session::PeriodicSessions; - type SessionManager = CollatorSelection; - // Essentially just Aura, but let's be pedantic. - type SessionHandler = ::KeyTypeIdProviders; - type Keys = SessionKeys; - type WeightInfo = (); -} - -impl pallet_aura::Config for Runtime { - type AuthorityId = AuraId; - type DisabledValidators = (); - type MaxAuthorities = ConstU32<100_000>; - type AllowMultipleBlocksPerSlot = ConstBool; - type SlotDuration = pallet_aura::MinimumPeriodTimesTwo; -} - -parameter_types! { - pub const PotId: PalletId = PalletId(*b"PotStake"); - pub const SessionLength: BlockNumber = 6 * HOURS; - // StakingAdmin pluralistic body. - pub const StakingAdminBodyId: BodyId = BodyId::Defense; -} - -/// We allow root and the StakingAdmin to execute privileged collator selection operations. -pub type CollatorSelectionUpdateOrigin = EitherOfDiverse< - EnsureRoot, - EnsureXcm>, ->; - -impl pallet_collator_selection::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type UpdateOrigin = CollatorSelectionUpdateOrigin; - type PotId = PotId; - type MaxCandidates = ConstU32<100>; - type MinEligibleCollators = ConstU32<4>; - type MaxInvulnerables = ConstU32<20>; - // should be a multiple of session or things will get inconsistent - type KickThreshold = Period; - type ValidatorId = ::AccountId; - type ValidatorIdOf = pallet_collator_selection::IdentityCollator; - type ValidatorRegistration = Session; - type WeightInfo = (); -} - -/// Configure the pallet template in pallets/template. -impl pallet_parachain_template::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type WeightInfo = pallet_parachain_template::weights::SubstrateWeight; -} - // Create the runtime by composing the FRAME pallets that were previously configured. construct_runtime!( pub enum Runtime { From c861b78ae35e7621809252f3642a7559016c291d Mon Sep 17 00:00:00 2001 From: Andrei Sandu <54316454+sandreim@users.noreply.github.com> Date: Mon, 1 Apr 2024 12:23:44 +0300 Subject: [PATCH 090/257] Improve `HostConfiguration` consistency check (#3897) fixes https://github.com/paritytech/polkadot-sdk/issues/3886 --------- Signed-off-by: Andrei Sandu --- polkadot/runtime/parachains/src/configuration.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/polkadot/runtime/parachains/src/configuration.rs b/polkadot/runtime/parachains/src/configuration.rs index b7635dcd7b22..17022272c0c4 100644 --- a/polkadot/runtime/parachains/src/configuration.rs +++ b/polkadot/runtime/parachains/src/configuration.rs @@ -187,7 +187,7 @@ pub struct HostConfiguration { /// /// Must be at least 1. pub no_show_slots: u32, - /// The number of delay tranches in total. + /// The number of delay tranches in total. Must be at least 1. pub n_delay_tranches: u32, /// The width of the zeroth delay tranche for approval assignments. This many delay tranches /// beyond 0 are all consolidated to form a wide 0 tranche. @@ -247,7 +247,7 @@ impl> Default for HostConfiguration { LookaheadExceedsTTL, /// Passed in queue size for on-demand was too large. OnDemandQueueSizeTooLarge, + /// Number of delay tranches cannot be 0. + ZeroDelayTranches, } impl HostConfiguration @@ -412,6 +414,10 @@ where return Err(OnDemandQueueSizeTooLarge) } + if self.n_delay_tranches.is_zero() { + return Err(ZeroDelayTranches) + } + Ok(()) } From 2d82d2b698b95dc3b73b42822a24f3e02b6cce92 Mon Sep 17 00:00:00 2001 From: Ross Bulat Date: Mon, 1 Apr 2024 16:35:36 +0700 Subject: [PATCH 091/257] Pools: Make `PermissionlessWithdraw` the default claim permission (#3438) Related Issue https://github.com/paritytech/polkadot-sdk/issues/3398 This PR makes permissionless withdrawing the default option, giving any network participant access to claim pool rewards on member's behalf. Of course, members can still opt out of this by setting a `Permissioned` claim permission. Permissionless claiming has been a part of the nomination pool pallet for around 9 months now, with very limited uptake (~4% of total pool members). 1.6% of pool members are using `PermissionlessAll`, strongly suggesting it is not wanted - it is too ambiguous and doesn't provide guidance to claimers. Stakers expect rewards to be claimed on their behalf by default - I have expanded upon this in detail within the [accompanying issue's discussion](https://github.com/paritytech/polkadot-sdk/issues/3398). Other protocols have this behaviour, whereby staking rewards are received without the staker having to take any action. From this perspective, permissionless claiming is not intuitive for pool members. As evidence of this, over 150,000 DOT is currently unclaimed on Polkadot, and is growing at a non-linear rate. --- prdoc/pr_3438.prdoc | 13 +++++++ .../nomination-pools/benchmarking/src/lib.rs | 4 +- substrate/frame/nomination-pools/src/lib.rs | 31 ++++++++------- substrate/frame/nomination-pools/src/tests.rs | 39 +++++++------------ 4 files changed, 45 insertions(+), 42 deletions(-) create mode 100644 prdoc/pr_3438.prdoc diff --git a/prdoc/pr_3438.prdoc b/prdoc/pr_3438.prdoc new file mode 100644 index 000000000000..5f4a0e3d57af --- /dev/null +++ b/prdoc/pr_3438.prdoc @@ -0,0 +1,13 @@ +title: "Pools: Make PermissionlessWithdraw the default claim permission" + +doc: + - audience: Runtime User + description: | + Makes permissionless withdrawing the default claim permission, giving any network participant + access to claim pool rewards on member's behalf, by default. + +crates: + - name: pallet-nomination-pools + bump: minor + - name: pallet-nomination-pools-benchmarking + bump: minor diff --git a/substrate/frame/nomination-pools/benchmarking/src/lib.rs b/substrate/frame/nomination-pools/benchmarking/src/lib.rs index 50df89961afc..636e8209b33a 100644 --- a/substrate/frame/nomination-pools/benchmarking/src/lib.rs +++ b/substrate/frame/nomination-pools/benchmarking/src/lib.rs @@ -796,9 +796,9 @@ frame_benchmarking::benchmarks! { T::StakeAdapter::active_stake(&pool_account), min_create_bond + min_join_bond ); - }:_(RuntimeOrigin::Signed(joiner.clone()), ClaimPermission::PermissionlessAll) + }:_(RuntimeOrigin::Signed(joiner.clone()), ClaimPermission::Permissioned) verify { - assert_eq!(ClaimPermissions::::get(joiner), ClaimPermission::PermissionlessAll); + assert_eq!(ClaimPermissions::::get(joiner), ClaimPermission::Permissioned); } claim_commission { diff --git a/substrate/frame/nomination-pools/src/lib.rs b/substrate/frame/nomination-pools/src/lib.rs index 306cf6545d27..bd34d7fe090a 100644 --- a/substrate/frame/nomination-pools/src/lib.rs +++ b/substrate/frame/nomination-pools/src/lib.rs @@ -463,22 +463,26 @@ pub enum ClaimPermission { PermissionlessAll, } +impl Default for ClaimPermission { + fn default() -> Self { + Self::PermissionlessWithdraw + } +} + impl ClaimPermission { + /// Permissionless compounding of pool rewards is allowed if the current permission is + /// `PermissionlessCompound`, or permissionless. fn can_bond_extra(&self) -> bool { matches!(self, ClaimPermission::PermissionlessAll | ClaimPermission::PermissionlessCompound) } + /// Permissionless payout claiming is allowed if the current permission is + /// `PermissionlessWithdraw`, or permissionless. fn can_claim_payout(&self) -> bool { matches!(self, ClaimPermission::PermissionlessAll | ClaimPermission::PermissionlessWithdraw) } } -impl Default for ClaimPermission { - fn default() -> Self { - Self::Permissioned - } -} - /// A member in a pool. #[derive( Encode, @@ -2640,7 +2644,7 @@ pub mod pallet { /// /// In the case of `origin != other`, `origin` can only bond extra pending rewards of /// `other` members assuming set_claim_permission for the given member is - /// `PermissionlessAll` or `PermissionlessCompound`. + /// `PermissionlessCompound` or `PermissionlessAll`. #[pallet::call_index(14)] #[pallet::weight( T::WeightInfo::bond_extra_transfer() @@ -2658,15 +2662,10 @@ pub mod pallet { /// Allows a pool member to set a claim permission to allow or disallow permissionless /// bonding and withdrawing. /// - /// By default, this is `Permissioned`, which implies only the pool member themselves can - /// claim their pending rewards. If a pool member wishes so, they can set this to - /// `PermissionlessAll` to allow any account to claim their rewards and bond extra to the - /// pool. - /// /// # Arguments /// /// * `origin` - Member of a pool. - /// * `actor` - Account to claim reward. // improve this + /// * `permission` - The permission to be applied. #[pallet::call_index(15)] #[pallet::weight(T::DbWeight::get().reads_writes(1, 1))] pub fn set_claim_permission( @@ -2676,16 +2675,18 @@ pub mod pallet { let who = ensure_signed(origin)?; ensure!(PoolMembers::::contains_key(&who), Error::::PoolMemberNotFound); + ClaimPermissions::::mutate(who, |source| { *source = permission; }); + Ok(()) } /// `origin` can claim payouts on some pool member `other`'s behalf. /// - /// Pool member `other` must have a `PermissionlessAll` or `PermissionlessWithdraw` in order - /// for this call to be successful. + /// Pool member `other` must have a `PermissionlessWithdraw` or `PermissionlessAll` claim + /// permission for this call to be successful. #[pallet::call_index(16)] #[pallet::weight(T::WeightInfo::claim_payout())] pub fn claim_payout_other(origin: OriginFor, other: T::AccountId) -> DispatchResult { diff --git a/substrate/frame/nomination-pools/src/tests.rs b/substrate/frame/nomination-pools/src/tests.rs index 8fb2b41b88a1..32b3e9af3cd6 100644 --- a/substrate/frame/nomination-pools/src/tests.rs +++ b/substrate/frame/nomination-pools/src/tests.rs @@ -2441,16 +2441,10 @@ mod claim_payout { // given assert_eq!(Currency::free_balance(&10), 35); - // Permissioned by default - assert_noop!( - Pools::claim_payout_other(RuntimeOrigin::signed(80), 10), - Error::::DoesNotHavePermission - ); + // when - assert_ok!(Pools::set_claim_permission( - RuntimeOrigin::signed(10), - ClaimPermission::PermissionlessWithdraw - )); + // NOTE: Claim permission of `PermissionlessWithdraw` allows payout claiming as default, + // so a claim permission does not need to be set for non-pool members prior to claiming. assert_ok!(Pools::claim_payout_other(RuntimeOrigin::signed(80), 10)); // then @@ -2489,7 +2483,6 @@ mod unbond { ); // Make permissionless - assert_eq!(ClaimPermissions::::get(10), ClaimPermission::Permissioned); assert_ok!(Pools::set_claim_permission( RuntimeOrigin::signed(20), ClaimPermission::PermissionlessAll @@ -4563,12 +4556,11 @@ mod withdraw_unbonded { CurrentEra::set(1); assert_eq!(PoolMembers::::get(20).unwrap().points, 20); - assert_ok!(Pools::set_claim_permission( - RuntimeOrigin::signed(20), - ClaimPermission::PermissionlessAll - )); assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 20)); - assert_eq!(ClaimPermissions::::get(20), ClaimPermission::PermissionlessAll); + assert_eq!( + ClaimPermissions::::get(20), + ClaimPermission::PermissionlessWithdraw + ); assert_eq!( pool_events_since_last_call(), @@ -4792,7 +4784,7 @@ mod create { } #[test] -fn set_claimable_actor_works() { +fn set_claim_permission_works() { ExtBuilder::default().build_and_execute(|| { // Given Currency::set_balance(&11, ExistentialDeposit::get() + 2); @@ -4811,22 +4803,19 @@ fn set_claimable_actor_works() { ] ); - // Make permissionless - assert_eq!(ClaimPermissions::::get(11), ClaimPermission::Permissioned); + // Make permissioned + assert_eq!(ClaimPermissions::::get(11), ClaimPermission::PermissionlessWithdraw); assert_noop!( - Pools::set_claim_permission( - RuntimeOrigin::signed(12), - ClaimPermission::PermissionlessAll - ), + Pools::set_claim_permission(RuntimeOrigin::signed(12), ClaimPermission::Permissioned), Error::::PoolMemberNotFound ); assert_ok!(Pools::set_claim_permission( RuntimeOrigin::signed(11), - ClaimPermission::PermissionlessAll + ClaimPermission::Permissioned )); // then - assert_eq!(ClaimPermissions::::get(11), ClaimPermission::PermissionlessAll); + assert_eq!(ClaimPermissions::::get(11), ClaimPermission::Permissioned); }); } @@ -5224,7 +5213,7 @@ mod bond_extra { assert_ok!(Pools::set_claim_permission( RuntimeOrigin::signed(10), - ClaimPermission::PermissionlessAll + ClaimPermission::PermissionlessCompound )); assert_ok!(Pools::bond_extra_other(RuntimeOrigin::signed(50), 10, BondExtra::Rewards)); assert_eq!(Currency::free_balance(&default_reward_account()), 7); From 780e29d372fd39f3d0ad23a10508e95b403d97c8 Mon Sep 17 00:00:00 2001 From: Alexandru Gheorghe <49718502+alexggh@users.noreply.github.com> Date: Mon, 1 Apr 2024 13:23:29 +0300 Subject: [PATCH 092/257] Fix 0007-dispute-freshly-finalized.zndsl failing (#3893) Test started failing after https://github.com/paritytech/polkadot-sdk/commit/66051adb619d2119771920218e2de75fa037d7e8 which enabled approval coalescing, that was expected to happen because the test required an polkadot_parachain_approval_checking_finality_lag of 0, which can't happen with max_approval_coalesce_count greater than 1 because we always delay the approval for no_show_duration_ticks/2 in case we can coalesce it with other approvals. So relax a bit the restrictions, since we don't actually care that the lags are 0, but the fact the finalities are progressing and are not stuck. Signed-off-by: Alexandru Gheorghe --- .../functional/0007-dispute-freshly-finalized.zndsl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/polkadot/zombienet_tests/functional/0007-dispute-freshly-finalized.zndsl b/polkadot/zombienet_tests/functional/0007-dispute-freshly-finalized.zndsl index 62d5a9768f9e..d1ed0250d4da 100644 --- a/polkadot/zombienet_tests/functional/0007-dispute-freshly-finalized.zndsl +++ b/polkadot/zombienet_tests/functional/0007-dispute-freshly-finalized.zndsl @@ -21,9 +21,9 @@ honest: reports polkadot_parachain_candidate_dispute_concluded{validity="valid"} honest: reports polkadot_parachain_candidate_dispute_concluded{validity="invalid"} is 0 within 100 seconds # Check lag - approval -honest: reports polkadot_parachain_approval_checking_finality_lag is 0 +honest: reports polkadot_parachain_approval_checking_finality_lag is lower than 2 # Check lag - dispute conclusion -honest: reports polkadot_parachain_disputes_finality_lag is 0 +honest: reports polkadot_parachain_disputes_finality_lag is lower than 2 From 5a8f14b4418f469edfff44025372d2eb224d5d61 Mon Sep 17 00:00:00 2001 From: Alexandru Gheorghe <49718502+alexggh@users.noreply.github.com> Date: Mon, 1 Apr 2024 16:03:26 +0300 Subject: [PATCH 093/257] primitives: Move out of staging released APIs (#3925) Runtime release 1.2 includes bumping of the ParachainHost APIs up to v10, so let's move all the released APIs out of vstaging folder, this PR does not include any logic changes only renaming of the modules and some moving around. Signed-off-by: Alexandru Gheorghe --- .../src/blockchain_rpc_client.rs | 4 +- .../src/rpc_client.rs | 13 +++-- .../node/core/approval-voting/src/import.rs | 8 +-- polkadot/node/core/approval-voting/src/lib.rs | 8 +-- .../node/core/approval-voting/src/tests.rs | 4 +- polkadot/node/core/backing/src/lib.rs | 11 ++-- polkadot/node/core/backing/src/tests/mod.rs | 4 +- .../core/dispute-coordinator/src/tests.rs | 6 +-- polkadot/node/core/provisioner/src/lib.rs | 6 +-- polkadot/node/core/runtime-api/src/cache.rs | 25 ++++----- polkadot/node/core/runtime-api/src/tests.rs | 14 +++-- .../src/pov_requester/mod.rs | 4 +- .../src/requester/tests.rs | 2 +- .../src/tests/state.rs | 4 +- .../src/collator_side/tests/mod.rs | 5 +- .../dispute-distribution/src/tests/mod.rs | 4 +- .../src/legacy_v1/tests.rs | 2 +- .../src/v2/statement_store.rs | 2 +- polkadot/node/service/src/chain_spec.rs | 4 +- .../src/lib/approval/message_generator.rs | 4 +- .../src/lib/mock/runtime_api.rs | 2 +- polkadot/node/subsystem-types/src/messages.rs | 18 +++---- .../subsystem-types/src/runtime_client.rs | 20 +++---- .../node/subsystem-util/src/runtime/mod.rs | 11 ++-- polkadot/primitives/src/lib.rs | 37 ++++++------- polkadot/primitives/src/runtime_api.rs | 14 +++-- .../src/{v6 => v7}/async_backing.rs | 0 .../src/{v6 => v7}/executor_params.rs | 0 polkadot/primitives/src/{v6 => v7}/metrics.rs | 0 polkadot/primitives/src/{v6 => v7}/mod.rs | 51 +++++++++++++++++- polkadot/primitives/src/{v6 => v7}/signed.rs | 0 .../primitives/src/{v6 => v7}/slashing.rs | 0 polkadot/primitives/src/vstaging/mod.rs | 53 +------------------ polkadot/runtime/parachains/src/builder.rs | 14 ++--- .../runtime/parachains/src/configuration.rs | 7 ++- .../src/configuration/migration/v10.rs | 2 +- .../src/configuration/migration/v11.rs | 3 +- polkadot/runtime/parachains/src/disputes.rs | 10 ++-- .../src/paras_inherent/benchmarking.rs | 2 +- .../parachains/src/paras_inherent/mod.rs | 6 +-- .../parachains/src/runtime_api_impl/mod.rs | 2 +- .../src/runtime_api_impl/{v7.rs => v10.rs} | 34 +++++++++--- .../src/runtime_api_impl/vstaging.rs | 33 ++---------- polkadot/runtime/rococo/src/lib.rs | 23 ++++---- polkadot/runtime/test-runtime/src/lib.rs | 19 ++++--- polkadot/runtime/westend/src/lib.rs | 24 ++++----- 46 files changed, 240 insertions(+), 279 deletions(-) rename polkadot/primitives/src/{v6 => v7}/async_backing.rs (100%) rename polkadot/primitives/src/{v6 => v7}/executor_params.rs (100%) rename polkadot/primitives/src/{v6 => v7}/metrics.rs (100%) rename polkadot/primitives/src/{v6 => v7}/mod.rs (97%) rename polkadot/primitives/src/{v6 => v7}/signed.rs (100%) rename polkadot/primitives/src/{v6 => v7}/slashing.rs (100%) rename polkadot/runtime/parachains/src/runtime_api_impl/{v7.rs => v10.rs} (93%) diff --git a/cumulus/client/relay-chain-minimal-node/src/blockchain_rpc_client.rs b/cumulus/client/relay-chain-minimal-node/src/blockchain_rpc_client.rs index 8d8a2920b4ef..aa5e67e453f6 100644 --- a/cumulus/client/relay-chain-minimal-node/src/blockchain_rpc_client.rs +++ b/cumulus/client/relay-chain-minimal-node/src/blockchain_rpc_client.rs @@ -26,9 +26,7 @@ use polkadot_core_primitives::{Block, BlockNumber, Hash, Header}; use polkadot_overseer::{ChainApiBackend, RuntimeApiSubsystemClient}; use polkadot_primitives::{ async_backing::{AsyncBackingParams, BackingState}, - slashing, - vstaging::{ApprovalVotingParams, NodeFeatures}, - CoreIndex, + slashing, ApprovalVotingParams, CoreIndex, NodeFeatures, }; use sc_authority_discovery::{AuthorityDiscovery, Error as AuthorityDiscoveryError}; use sc_client_api::AuxStore; diff --git a/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs b/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs index 8cf5ccf0c707..547803865c28 100644 --- a/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs +++ b/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs @@ -32,13 +32,12 @@ use parity_scale_codec::{Decode, Encode}; use cumulus_primitives_core::{ relay_chain::{ async_backing::{AsyncBackingParams, BackingState}, - slashing, - vstaging::{ApprovalVotingParams, NodeFeatures}, - BlockNumber, CandidateCommitments, CandidateEvent, CandidateHash, - CommittedCandidateReceipt, CoreIndex, CoreState, DisputeState, ExecutorParams, - GroupRotationInfo, Hash as RelayHash, Header as RelayHeader, InboundHrmpMessage, - OccupiedCoreAssumption, PvfCheckStatement, ScrapedOnChainVotes, SessionIndex, SessionInfo, - ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, + slashing, ApprovalVotingParams, BlockNumber, CandidateCommitments, CandidateEvent, + CandidateHash, CommittedCandidateReceipt, CoreIndex, CoreState, DisputeState, + ExecutorParams, GroupRotationInfo, Hash as RelayHash, Header as RelayHeader, + InboundHrmpMessage, NodeFeatures, OccupiedCoreAssumption, PvfCheckStatement, + ScrapedOnChainVotes, SessionIndex, SessionInfo, ValidationCode, ValidationCodeHash, + ValidatorId, ValidatorIndex, ValidatorSignature, }, InboundDownwardMessage, ParaId, PersistedValidationData, }; diff --git a/polkadot/node/core/approval-voting/src/import.rs b/polkadot/node/core/approval-voting/src/import.rs index d34191fba31d..f4be42a48450 100644 --- a/polkadot/node/core/approval-voting/src/import.rs +++ b/polkadot/node/core/approval-voting/src/import.rs @@ -45,8 +45,8 @@ use polkadot_node_subsystem::{ }; use polkadot_node_subsystem_util::{determine_new_blocks, runtime::RuntimeInfo}; use polkadot_primitives::{ - vstaging::node_features, BlockNumber, CandidateEvent, CandidateHash, CandidateReceipt, - ConsensusLog, CoreIndex, GroupIndex, Hash, Header, SessionIndex, + node_features, BlockNumber, CandidateEvent, CandidateHash, CandidateReceipt, ConsensusLog, + CoreIndex, GroupIndex, Hash, Header, SessionIndex, }; use sc_keystore::LocalKeystore; use sp_consensus_slots::Slot; @@ -619,8 +619,8 @@ pub(crate) mod tests { use polkadot_node_subsystem_test_helpers::make_subsystem_context; use polkadot_node_subsystem_util::database::Database; use polkadot_primitives::{ - vstaging::{node_features::FeatureIndex, NodeFeatures}, - ExecutorParams, Id as ParaId, IndexedVec, SessionInfo, ValidatorId, ValidatorIndex, + node_features::FeatureIndex, ExecutorParams, Id as ParaId, IndexedVec, NodeFeatures, + SessionInfo, ValidatorId, ValidatorIndex, }; pub(crate) use sp_consensus_babe::{ digests::{CompatibleDigestItem, PreDigest, SecondaryVRFPreDigest}, diff --git a/polkadot/node/core/approval-voting/src/lib.rs b/polkadot/node/core/approval-voting/src/lib.rs index 76b3d476e28f..57e9af4a518a 100644 --- a/polkadot/node/core/approval-voting/src/lib.rs +++ b/polkadot/node/core/approval-voting/src/lib.rs @@ -54,10 +54,10 @@ use polkadot_node_subsystem_util::{ TimeoutExt, }; use polkadot_primitives::{ - vstaging::{ApprovalVoteMultipleCandidates, ApprovalVotingParams}, - BlockNumber, CandidateHash, CandidateIndex, CandidateReceipt, CoreIndex, DisputeStatement, - ExecutorParams, GroupIndex, Hash, PvfExecKind, SessionIndex, SessionInfo, - ValidDisputeStatementKind, ValidatorId, ValidatorIndex, ValidatorPair, ValidatorSignature, + ApprovalVoteMultipleCandidates, ApprovalVotingParams, BlockNumber, CandidateHash, + CandidateIndex, CandidateReceipt, CoreIndex, DisputeStatement, ExecutorParams, GroupIndex, + Hash, PvfExecKind, SessionIndex, SessionInfo, ValidDisputeStatementKind, ValidatorId, + ValidatorIndex, ValidatorPair, ValidatorSignature, }; use sc_keystore::LocalKeystore; use sp_application_crypto::Pair; diff --git a/polkadot/node/core/approval-voting/src/tests.rs b/polkadot/node/core/approval-voting/src/tests.rs index 1483af565853..f7bbbca4b8a1 100644 --- a/polkadot/node/core/approval-voting/src/tests.rs +++ b/polkadot/node/core/approval-voting/src/tests.rs @@ -37,8 +37,8 @@ use polkadot_node_subsystem_test_helpers as test_helpers; use polkadot_node_subsystem_util::TimeoutExt; use polkadot_overseer::HeadSupportsParachains; use polkadot_primitives::{ - vstaging::NodeFeatures, ApprovalVote, CandidateCommitments, CandidateEvent, CoreIndex, - GroupIndex, Header, Id as ParaId, IndexedVec, ValidationCode, ValidatorSignature, + ApprovalVote, CandidateCommitments, CandidateEvent, CoreIndex, GroupIndex, Header, + Id as ParaId, IndexedVec, NodeFeatures, ValidationCode, ValidatorSignature, }; use std::time::Duration; diff --git a/polkadot/node/core/backing/src/lib.rs b/polkadot/node/core/backing/src/lib.rs index b5cad4cf5f05..23acb0450944 100644 --- a/polkadot/node/core/backing/src/lib.rs +++ b/polkadot/node/core/backing/src/lib.rs @@ -105,12 +105,11 @@ use polkadot_node_subsystem_util::{ Validator, }; use polkadot_primitives::{ - vstaging::{node_features::FeatureIndex, NodeFeatures}, - BackedCandidate, CandidateCommitments, CandidateHash, CandidateReceipt, - CommittedCandidateReceipt, CoreIndex, CoreState, ExecutorParams, GroupIndex, GroupRotationInfo, - Hash, Id as ParaId, IndexedVec, PersistedValidationData, PvfExecKind, SessionIndex, - SigningContext, ValidationCode, ValidatorId, ValidatorIndex, ValidatorSignature, - ValidityAttestation, + node_features::FeatureIndex, BackedCandidate, CandidateCommitments, CandidateHash, + CandidateReceipt, CommittedCandidateReceipt, CoreIndex, CoreState, ExecutorParams, GroupIndex, + GroupRotationInfo, Hash, Id as ParaId, IndexedVec, NodeFeatures, PersistedValidationData, + PvfExecKind, SessionIndex, SigningContext, ValidationCode, ValidatorId, ValidatorIndex, + ValidatorSignature, ValidityAttestation, }; use sp_keystore::KeystorePtr; use statement_table::{ diff --git a/polkadot/node/core/backing/src/tests/mod.rs b/polkadot/node/core/backing/src/tests/mod.rs index fdb47581ea3a..d1969e656db6 100644 --- a/polkadot/node/core/backing/src/tests/mod.rs +++ b/polkadot/node/core/backing/src/tests/mod.rs @@ -33,8 +33,8 @@ use polkadot_node_subsystem::{ }; use polkadot_node_subsystem_test_helpers as test_helpers; use polkadot_primitives::{ - vstaging::node_features, CandidateDescriptor, GroupRotationInfo, HeadData, - PersistedValidationData, PvfExecKind, ScheduledCore, SessionIndex, LEGACY_MIN_BACKING_VOTES, + node_features, CandidateDescriptor, GroupRotationInfo, HeadData, PersistedValidationData, + PvfExecKind, ScheduledCore, SessionIndex, LEGACY_MIN_BACKING_VOTES, }; use rstest::rstest; use sp_application_crypto::AppCrypto; diff --git a/polkadot/node/core/dispute-coordinator/src/tests.rs b/polkadot/node/core/dispute-coordinator/src/tests.rs index 7c1f4ff241d3..13cf2df88223 100644 --- a/polkadot/node/core/dispute-coordinator/src/tests.rs +++ b/polkadot/node/core/dispute-coordinator/src/tests.rs @@ -61,9 +61,9 @@ use polkadot_node_subsystem_test_helpers::{ make_buffered_subsystem_context, mock::new_leaf, TestSubsystemContextHandle, }; use polkadot_primitives::{ - vstaging::NodeFeatures, ApprovalVote, BlockNumber, CandidateCommitments, CandidateEvent, - CandidateHash, CandidateReceipt, CoreIndex, DisputeStatement, ExecutorParams, GroupIndex, Hash, - HeadData, Header, IndexedVec, MultiDisputeStatementSet, ScrapedOnChainVotes, SessionIndex, + ApprovalVote, BlockNumber, CandidateCommitments, CandidateEvent, CandidateHash, + CandidateReceipt, CoreIndex, DisputeStatement, ExecutorParams, GroupIndex, Hash, HeadData, + Header, IndexedVec, MultiDisputeStatementSet, NodeFeatures, ScrapedOnChainVotes, SessionIndex, SessionInfo, SigningContext, ValidDisputeStatementKind, ValidatorId, ValidatorIndex, ValidatorSignature, }; diff --git a/polkadot/node/core/provisioner/src/lib.rs b/polkadot/node/core/provisioner/src/lib.rs index 3ccf499f325b..5cfcb96dc2bc 100644 --- a/polkadot/node/core/provisioner/src/lib.rs +++ b/polkadot/node/core/provisioner/src/lib.rs @@ -42,9 +42,9 @@ use polkadot_node_subsystem_util::{ TimeoutExt, }; use polkadot_primitives::{ - vstaging::{node_features::FeatureIndex, NodeFeatures}, - BackedCandidate, BlockNumber, CandidateHash, CandidateReceipt, CoreIndex, CoreState, Hash, - Id as ParaId, OccupiedCoreAssumption, SessionIndex, SignedAvailabilityBitfield, ValidatorIndex, + node_features::FeatureIndex, BackedCandidate, BlockNumber, CandidateHash, CandidateReceipt, + CoreIndex, CoreState, Hash, Id as ParaId, NodeFeatures, OccupiedCoreAssumption, SessionIndex, + SignedAvailabilityBitfield, ValidatorIndex, }; use std::collections::{BTreeMap, HashMap}; diff --git a/polkadot/node/core/runtime-api/src/cache.rs b/polkadot/node/core/runtime-api/src/cache.rs index 9674cda98385..acdb256ab36c 100644 --- a/polkadot/node/core/runtime-api/src/cache.rs +++ b/polkadot/node/core/runtime-api/src/cache.rs @@ -20,14 +20,12 @@ use schnellru::{ByLength, LruMap}; use sp_consensus_babe::Epoch; use polkadot_primitives::{ - async_backing, slashing, - vstaging::{self, ApprovalVotingParams}, - AuthorityDiscoveryId, BlockNumber, CandidateCommitments, CandidateEvent, CandidateHash, - CommittedCandidateReceipt, CoreIndex, CoreState, DisputeState, ExecutorParams, - GroupRotationInfo, Hash, Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, - OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes, - SessionIndex, SessionInfo, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, - ValidatorSignature, + async_backing, slashing, ApprovalVotingParams, AuthorityDiscoveryId, BlockNumber, + CandidateCommitments, CandidateEvent, CandidateHash, CommittedCandidateReceipt, CoreIndex, + CoreState, DisputeState, ExecutorParams, GroupRotationInfo, Hash, Id as ParaId, + InboundDownwardMessage, InboundHrmpMessage, NodeFeatures, OccupiedCoreAssumption, + PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes, SessionIndex, SessionInfo, + ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, }; /// For consistency we have the same capacity for all caches. We use 128 as we'll only need that @@ -69,7 +67,7 @@ pub(crate) struct RequestResultCache { disabled_validators: LruMap>, para_backing_state: LruMap<(Hash, ParaId), Option>, async_backing_params: LruMap, - node_features: LruMap, + node_features: LruMap, approval_voting_params: LruMap, claim_queue: LruMap>>, } @@ -454,17 +452,14 @@ impl RequestResultCache { self.minimum_backing_votes.insert(session_index, minimum_backing_votes); } - pub(crate) fn node_features( - &mut self, - session_index: SessionIndex, - ) -> Option<&vstaging::NodeFeatures> { + pub(crate) fn node_features(&mut self, session_index: SessionIndex) -> Option<&NodeFeatures> { self.node_features.get(&session_index).map(|f| &*f) } pub(crate) fn cache_node_features( &mut self, session_index: SessionIndex, - features: vstaging::NodeFeatures, + features: NodeFeatures, ) { self.node_features.insert(session_index, features); } @@ -594,6 +589,6 @@ pub(crate) enum RequestResult { DisabledValidators(Hash, Vec), ParaBackingState(Hash, ParaId, Option), AsyncBackingParams(Hash, async_backing::AsyncBackingParams), - NodeFeatures(SessionIndex, vstaging::NodeFeatures), + NodeFeatures(SessionIndex, NodeFeatures), ClaimQueue(Hash, BTreeMap>), } diff --git a/polkadot/node/core/runtime-api/src/tests.rs b/polkadot/node/core/runtime-api/src/tests.rs index b51682aa0f4c..73c661c40762 100644 --- a/polkadot/node/core/runtime-api/src/tests.rs +++ b/polkadot/node/core/runtime-api/src/tests.rs @@ -20,14 +20,12 @@ use polkadot_node_primitives::{BabeAllowedSlots, BabeEpoch, BabeEpochConfigurati use polkadot_node_subsystem::SpawnGlue; use polkadot_node_subsystem_test_helpers::make_subsystem_context; use polkadot_primitives::{ - async_backing, slashing, - vstaging::{ApprovalVotingParams, NodeFeatures}, - AuthorityDiscoveryId, BlockNumber, CandidateCommitments, CandidateEvent, CandidateHash, - CommittedCandidateReceipt, CoreIndex, CoreState, DisputeState, ExecutorParams, - GroupRotationInfo, Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, - OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes, - SessionIndex, SessionInfo, Slot, ValidationCode, ValidationCodeHash, ValidatorId, - ValidatorIndex, ValidatorSignature, + async_backing, slashing, ApprovalVotingParams, AuthorityDiscoveryId, BlockNumber, + CandidateCommitments, CandidateEvent, CandidateHash, CommittedCandidateReceipt, CoreIndex, + CoreState, DisputeState, ExecutorParams, GroupRotationInfo, Id as ParaId, + InboundDownwardMessage, InboundHrmpMessage, NodeFeatures, OccupiedCoreAssumption, + PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes, SessionIndex, SessionInfo, + Slot, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, }; use sp_api::ApiError; use sp_core::testing::TaskExecutor; diff --git a/polkadot/node/network/availability-distribution/src/pov_requester/mod.rs b/polkadot/node/network/availability-distribution/src/pov_requester/mod.rs index 4e23030aa499..f99002d4188b 100644 --- a/polkadot/node/network/availability-distribution/src/pov_requester/mod.rs +++ b/polkadot/node/network/availability-distribution/src/pov_requester/mod.rs @@ -147,9 +147,7 @@ mod tests { AllMessages, AvailabilityDistributionMessage, RuntimeApiMessage, RuntimeApiRequest, }; use polkadot_node_subsystem_test_helpers as test_helpers; - use polkadot_primitives::{ - vstaging::NodeFeatures, CandidateHash, ExecutorParams, Hash, ValidatorIndex, - }; + use polkadot_primitives::{CandidateHash, ExecutorParams, Hash, NodeFeatures, ValidatorIndex}; use test_helpers::mock::make_ferdie_keystore; use super::*; diff --git a/polkadot/node/network/availability-distribution/src/requester/tests.rs b/polkadot/node/network/availability-distribution/src/requester/tests.rs index 2f5d900b037e..0dedd4f091ac 100644 --- a/polkadot/node/network/availability-distribution/src/requester/tests.rs +++ b/polkadot/node/network/availability-distribution/src/requester/tests.rs @@ -25,7 +25,7 @@ use polkadot_node_primitives::{BlockData, ErasureChunk, PoV}; use polkadot_node_subsystem_test_helpers::mock::new_leaf; use polkadot_node_subsystem_util::runtime::RuntimeInfo; use polkadot_primitives::{ - vstaging::NodeFeatures, BlockNumber, CoreState, ExecutorParams, GroupIndex, Hash, Id as ParaId, + BlockNumber, CoreState, ExecutorParams, GroupIndex, Hash, Id as ParaId, NodeFeatures, ScheduledCore, SessionIndex, SessionInfo, }; use sp_core::traits::SpawnNamed; diff --git a/polkadot/node/network/availability-distribution/src/tests/state.rs b/polkadot/node/network/availability-distribution/src/tests/state.rs index 66a8d8fcdcf9..1d814b4fd0ed 100644 --- a/polkadot/node/network/availability-distribution/src/tests/state.rs +++ b/polkadot/node/network/availability-distribution/src/tests/state.rs @@ -47,8 +47,8 @@ use polkadot_node_subsystem::{ }; use polkadot_node_subsystem_test_helpers as test_helpers; use polkadot_primitives::{ - vstaging::NodeFeatures, CandidateHash, CoreState, ExecutorParams, GroupIndex, Hash, - Id as ParaId, ScheduledCore, SessionInfo, ValidatorIndex, + CandidateHash, CoreState, ExecutorParams, GroupIndex, Hash, Id as ParaId, NodeFeatures, + ScheduledCore, SessionInfo, ValidatorIndex, }; use test_helpers::mock::{make_ferdie_keystore, new_leaf}; diff --git a/polkadot/node/network/collator-protocol/src/collator_side/tests/mod.rs b/polkadot/node/network/collator-protocol/src/collator_side/tests/mod.rs index bcf0b34e631f..de561e9f77fc 100644 --- a/polkadot/node/network/collator-protocol/src/collator_side/tests/mod.rs +++ b/polkadot/node/network/collator-protocol/src/collator_side/tests/mod.rs @@ -45,9 +45,8 @@ use polkadot_node_subsystem::{ use polkadot_node_subsystem_test_helpers as test_helpers; use polkadot_node_subsystem_util::{reputation::add_reputation, TimeoutExt}; use polkadot_primitives::{ - vstaging::NodeFeatures, AuthorityDiscoveryId, CollatorPair, ExecutorParams, GroupIndex, - GroupRotationInfo, IndexedVec, ScheduledCore, SessionIndex, SessionInfo, ValidatorId, - ValidatorIndex, + AuthorityDiscoveryId, CollatorPair, ExecutorParams, GroupIndex, GroupRotationInfo, IndexedVec, + NodeFeatures, ScheduledCore, SessionIndex, SessionInfo, ValidatorId, ValidatorIndex, }; use polkadot_primitives_test_helpers::TestCandidateBuilder; use test_helpers::mock::new_leaf; diff --git a/polkadot/node/network/dispute-distribution/src/tests/mod.rs b/polkadot/node/network/dispute-distribution/src/tests/mod.rs index 880d1b18032c..5ad790fb01c2 100644 --- a/polkadot/node/network/dispute-distribution/src/tests/mod.rs +++ b/polkadot/node/network/dispute-distribution/src/tests/mod.rs @@ -57,8 +57,8 @@ use polkadot_node_subsystem_test_helpers::{ subsystem_test_harness, TestSubsystemContextHandle, }; use polkadot_primitives::{ - vstaging::NodeFeatures, AuthorityDiscoveryId, CandidateHash, CandidateReceipt, ExecutorParams, - Hash, SessionIndex, SessionInfo, + AuthorityDiscoveryId, CandidateHash, CandidateReceipt, ExecutorParams, Hash, NodeFeatures, + SessionIndex, SessionInfo, }; use self::mock::{ diff --git a/polkadot/node/network/statement-distribution/src/legacy_v1/tests.rs b/polkadot/node/network/statement-distribution/src/legacy_v1/tests.rs index 08e9d69d8ee6..7d355cc88725 100644 --- a/polkadot/node/network/statement-distribution/src/legacy_v1/tests.rs +++ b/polkadot/node/network/statement-distribution/src/legacy_v1/tests.rs @@ -43,7 +43,7 @@ use polkadot_node_subsystem::{ }; use polkadot_node_subsystem_test_helpers::mock::{make_ferdie_keystore, new_leaf}; use polkadot_primitives::{ - vstaging::NodeFeatures, ExecutorParams, GroupIndex, Hash, HeadData, Id as ParaId, IndexedVec, + ExecutorParams, GroupIndex, Hash, HeadData, Id as ParaId, IndexedVec, NodeFeatures, SessionInfo, ValidationCode, }; use polkadot_primitives_test_helpers::{ diff --git a/polkadot/node/network/statement-distribution/src/v2/statement_store.rs b/polkadot/node/network/statement-distribution/src/v2/statement_store.rs index 022461e55511..a3b2636d2ffc 100644 --- a/polkadot/node/network/statement-distribution/src/v2/statement_store.rs +++ b/polkadot/node/network/statement-distribution/src/v2/statement_store.rs @@ -292,7 +292,7 @@ impl GroupStatements { mod tests { use super::*; - use polkadot_primitives::v6::{Hash, SigningContext, ValidatorPair}; + use polkadot_primitives::v7::{Hash, SigningContext, ValidatorPair}; use sp_application_crypto::Pair as PairT; #[test] diff --git a/polkadot/node/service/src/chain_spec.rs b/polkadot/node/service/src/chain_spec.rs index c03ce1db0943..1b6ba99777b0 100644 --- a/polkadot/node/service/src/chain_spec.rs +++ b/polkadot/node/service/src/chain_spec.rs @@ -123,8 +123,8 @@ fn default_parachains_host_configuration( ) -> polkadot_runtime_parachains::configuration::HostConfiguration { use polkadot_primitives::{ - vstaging::{node_features::FeatureIndex, ApprovalVotingParams}, - AsyncBackingParams, MAX_CODE_SIZE, MAX_POV_SIZE, + node_features::FeatureIndex, ApprovalVotingParams, AsyncBackingParams, MAX_CODE_SIZE, + MAX_POV_SIZE, }; polkadot_runtime_parachains::configuration::HostConfiguration { diff --git a/polkadot/node/subsystem-bench/src/lib/approval/message_generator.rs b/polkadot/node/subsystem-bench/src/lib/approval/message_generator.rs index 3b08d0ed8615..619a3617ca4d 100644 --- a/polkadot/node/subsystem-bench/src/lib/approval/message_generator.rs +++ b/polkadot/node/subsystem-bench/src/lib/approval/message_generator.rs @@ -41,8 +41,8 @@ use polkadot_node_primitives::approval::{ v2::{CoreBitfield, IndirectAssignmentCertV2, IndirectSignedApprovalVoteV2}, }; use polkadot_primitives::{ - vstaging::ApprovalVoteMultipleCandidates, CandidateEvent, CandidateHash, CandidateIndex, - CoreIndex, Hash, SessionInfo, Slot, ValidatorId, ValidatorIndex, ASSIGNMENT_KEY_TYPE_ID, + ApprovalVoteMultipleCandidates, CandidateEvent, CandidateHash, CandidateIndex, CoreIndex, Hash, + SessionInfo, Slot, ValidatorId, ValidatorIndex, ASSIGNMENT_KEY_TYPE_ID, }; use rand::{seq::SliceRandom, RngCore, SeedableRng}; use rand_chacha::ChaCha20Rng; diff --git a/polkadot/node/subsystem-bench/src/lib/mock/runtime_api.rs b/polkadot/node/subsystem-bench/src/lib/mock/runtime_api.rs index 3c39de870a28..b73d61321cd3 100644 --- a/polkadot/node/subsystem-bench/src/lib/mock/runtime_api.rs +++ b/polkadot/node/subsystem-bench/src/lib/mock/runtime_api.rs @@ -26,7 +26,7 @@ use polkadot_node_subsystem::{ }; use polkadot_node_subsystem_types::OverseerSignal; use polkadot_primitives::{ - vstaging::NodeFeatures, CandidateEvent, CandidateReceipt, CoreState, GroupIndex, IndexedVec, + CandidateEvent, CandidateReceipt, CoreState, GroupIndex, IndexedVec, NodeFeatures, OccupiedCore, SessionIndex, SessionInfo, ValidatorIndex, }; use sp_consensus_babe::Epoch as BabeEpoch; diff --git a/polkadot/node/subsystem-types/src/messages.rs b/polkadot/node/subsystem-types/src/messages.rs index d84b0b6dd141..2ca6728af012 100644 --- a/polkadot/node/subsystem-types/src/messages.rs +++ b/polkadot/node/subsystem-types/src/messages.rs @@ -42,16 +42,14 @@ use polkadot_node_primitives::{ ValidationResult, }; use polkadot_primitives::{ - async_backing, slashing, - vstaging::{ApprovalVotingParams, NodeFeatures}, - AuthorityDiscoveryId, BackedCandidate, BlockNumber, CandidateEvent, CandidateHash, - CandidateIndex, CandidateReceipt, CollatorId, CommittedCandidateReceipt, CoreIndex, CoreState, - DisputeState, ExecutorParams, GroupIndex, GroupRotationInfo, Hash, HeadData, - Header as BlockHeader, Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, - MultiDisputeStatementSet, OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, - PvfExecKind, SessionIndex, SessionInfo, SignedAvailabilityBitfield, - SignedAvailabilityBitfields, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, - ValidatorSignature, + async_backing, slashing, ApprovalVotingParams, AuthorityDiscoveryId, BackedCandidate, + BlockNumber, CandidateEvent, CandidateHash, CandidateIndex, CandidateReceipt, CollatorId, + CommittedCandidateReceipt, CoreIndex, CoreState, DisputeState, ExecutorParams, GroupIndex, + GroupRotationInfo, Hash, HeadData, Header as BlockHeader, Id as ParaId, InboundDownwardMessage, + InboundHrmpMessage, MultiDisputeStatementSet, NodeFeatures, OccupiedCoreAssumption, + PersistedValidationData, PvfCheckStatement, PvfExecKind, SessionIndex, SessionInfo, + SignedAvailabilityBitfield, SignedAvailabilityBitfields, ValidationCode, ValidationCodeHash, + ValidatorId, ValidatorIndex, ValidatorSignature, }; use polkadot_statement_table::v2::Misbehavior; use std::{ diff --git a/polkadot/node/subsystem-types/src/runtime_client.rs b/polkadot/node/subsystem-types/src/runtime_client.rs index 7474b4120cc9..664d10ed1af5 100644 --- a/polkadot/node/subsystem-types/src/runtime_client.rs +++ b/polkadot/node/subsystem-types/src/runtime_client.rs @@ -16,16 +16,12 @@ use async_trait::async_trait; use polkadot_primitives::{ - async_backing, - runtime_api::ParachainHost, - slashing, - vstaging::{self, ApprovalVotingParams}, - Block, BlockNumber, CandidateCommitments, CandidateEvent, CandidateHash, - CommittedCandidateReceipt, CoreIndex, CoreState, DisputeState, ExecutorParams, - GroupRotationInfo, Hash, Header, Id, InboundDownwardMessage, InboundHrmpMessage, - OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes, - SessionIndex, SessionInfo, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, - ValidatorSignature, + async_backing, runtime_api::ParachainHost, slashing, ApprovalVotingParams, Block, BlockNumber, + CandidateCommitments, CandidateEvent, CandidateHash, CommittedCandidateReceipt, CoreIndex, + CoreState, DisputeState, ExecutorParams, GroupRotationInfo, Hash, Header, Id, + InboundDownwardMessage, InboundHrmpMessage, NodeFeatures, OccupiedCoreAssumption, + PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes, SessionIndex, SessionInfo, + ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, }; use sc_client_api::{AuxStore, HeaderBackend}; use sc_transaction_pool_api::OffchainTransactionPoolFactory; @@ -324,7 +320,7 @@ pub trait RuntimeApiSubsystemClient { // === v9 === /// Get the node features. - async fn node_features(&self, at: Hash) -> Result; + async fn node_features(&self, at: Hash) -> Result; // == v10: Approval voting params == /// Approval voting configuration parameters @@ -586,7 +582,7 @@ where self.client.runtime_api().async_backing_params(at) } - async fn node_features(&self, at: Hash) -> Result { + async fn node_features(&self, at: Hash) -> Result { self.client.runtime_api().node_features(at) } diff --git a/polkadot/node/subsystem-util/src/runtime/mod.rs b/polkadot/node/subsystem-util/src/runtime/mod.rs index 481625acb321..714384b32e37 100644 --- a/polkadot/node/subsystem-util/src/runtime/mod.rs +++ b/polkadot/node/subsystem-util/src/runtime/mod.rs @@ -30,12 +30,11 @@ use polkadot_node_subsystem::{ }; use polkadot_node_subsystem_types::UnpinHandle; use polkadot_primitives::{ - slashing, - vstaging::{node_features::FeatureIndex, NodeFeatures}, - AsyncBackingParams, CandidateEvent, CandidateHash, CoreState, EncodeAs, ExecutorParams, - GroupIndex, GroupRotationInfo, Hash, IndexedVec, OccupiedCore, ScrapedOnChainVotes, - SessionIndex, SessionInfo, Signed, SigningContext, UncheckedSigned, ValidationCode, - ValidationCodeHash, ValidatorId, ValidatorIndex, LEGACY_MIN_BACKING_VOTES, + node_features::FeatureIndex, slashing, AsyncBackingParams, CandidateEvent, CandidateHash, + CoreState, EncodeAs, ExecutorParams, GroupIndex, GroupRotationInfo, Hash, IndexedVec, + NodeFeatures, OccupiedCore, ScrapedOnChainVotes, SessionIndex, SessionInfo, Signed, + SigningContext, UncheckedSigned, ValidationCode, ValidationCodeHash, ValidatorId, + ValidatorIndex, LEGACY_MIN_BACKING_VOTES, }; use crate::{ diff --git a/polkadot/primitives/src/lib.rs b/polkadot/primitives/src/lib.rs index 745195ce092a..d4eeb3cc3d29 100644 --- a/polkadot/primitives/src/lib.rs +++ b/polkadot/primitives/src/lib.rs @@ -20,7 +20,7 @@ #![cfg_attr(not(feature = "std"), no_std)] // `v6` is currently the latest stable version of the runtime API. -pub mod v6; +pub mod v7; // The 'staging' version is special - it contains primitives which are // still in development. Once they are considered stable, they will be @@ -33,26 +33,27 @@ pub mod runtime_api; // Current primitives not requiring versioning are exported here. // Primitives requiring versioning must not be exported and must be referred by an exact version. -pub use v6::{ +pub use v7::{ async_backing, byzantine_threshold, check_candidate_backing, collator_signature_payload, - effective_minimum_backing_votes, executor_params, metric_definitions, slashing, + effective_minimum_backing_votes, executor_params, metric_definitions, node_features, slashing, supermajority_threshold, well_known_keys, AbridgedHostConfiguration, AbridgedHrmpChannel, - AccountId, AccountIndex, AccountPublic, ApprovalVote, AssignmentId, AsyncBackingParams, - AuthorityDiscoveryId, AvailabilityBitfield, BackedCandidate, Balance, BlakeTwo256, Block, - BlockId, BlockNumber, CandidateCommitments, CandidateDescriptor, CandidateEvent, CandidateHash, - CandidateIndex, CandidateReceipt, CheckedDisputeStatementSet, CheckedMultiDisputeStatementSet, - CollatorId, CollatorSignature, CommittedCandidateReceipt, CompactStatement, ConsensusLog, - CoreIndex, CoreState, DisputeState, DisputeStatement, DisputeStatementSet, DownwardMessage, - EncodeAs, ExecutorParam, ExecutorParamError, ExecutorParams, ExecutorParamsHash, + AccountId, AccountIndex, AccountPublic, ApprovalVote, ApprovalVoteMultipleCandidates, + ApprovalVotingParams, AssignmentId, AsyncBackingParams, AuthorityDiscoveryId, + AvailabilityBitfield, BackedCandidate, Balance, BlakeTwo256, Block, BlockId, BlockNumber, + CandidateCommitments, CandidateDescriptor, CandidateEvent, CandidateHash, CandidateIndex, + CandidateReceipt, CheckedDisputeStatementSet, CheckedMultiDisputeStatementSet, CollatorId, + CollatorSignature, CommittedCandidateReceipt, CompactStatement, ConsensusLog, CoreIndex, + CoreState, DisputeState, DisputeStatement, DisputeStatementSet, DownwardMessage, EncodeAs, + ExecutorParam, ExecutorParamError, ExecutorParams, ExecutorParamsHash, ExplicitDisputeStatement, GroupIndex, GroupRotationInfo, Hash, HashT, HeadData, Header, HorizontalMessages, HrmpChannelId, Id, InboundDownwardMessage, InboundHrmpMessage, IndexedVec, - InherentData, InvalidDisputeStatementKind, Moment, MultiDisputeStatementSet, Nonce, - OccupiedCore, OccupiedCoreAssumption, OutboundHrmpMessage, ParathreadClaim, ParathreadEntry, - PersistedValidationData, PvfCheckStatement, PvfExecKind, PvfPrepKind, RuntimeMetricLabel, - RuntimeMetricLabelValue, RuntimeMetricLabelValues, RuntimeMetricLabels, RuntimeMetricOp, - RuntimeMetricUpdate, ScheduledCore, ScrapedOnChainVotes, SessionIndex, SessionInfo, Signature, - Signed, SignedAvailabilityBitfield, SignedAvailabilityBitfields, SignedStatement, - SigningContext, Slot, UncheckedSigned, UncheckedSignedAvailabilityBitfield, + InherentData, InvalidDisputeStatementKind, Moment, MultiDisputeStatementSet, NodeFeatures, + Nonce, OccupiedCore, OccupiedCoreAssumption, OutboundHrmpMessage, ParathreadClaim, + ParathreadEntry, PersistedValidationData, PvfCheckStatement, PvfExecKind, PvfPrepKind, + RuntimeMetricLabel, RuntimeMetricLabelValue, RuntimeMetricLabelValues, RuntimeMetricLabels, + RuntimeMetricOp, RuntimeMetricUpdate, ScheduledCore, ScrapedOnChainVotes, SessionIndex, + SessionInfo, Signature, Signed, SignedAvailabilityBitfield, SignedAvailabilityBitfields, + SignedStatement, SigningContext, Slot, UncheckedSigned, UncheckedSignedAvailabilityBitfield, UncheckedSignedAvailabilityBitfields, UncheckedSignedStatement, UpgradeGoAhead, UpgradeRestriction, UpwardMessage, ValidDisputeStatementKind, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, ValidityAttestation, @@ -63,4 +64,4 @@ pub use v6::{ }; #[cfg(feature = "std")] -pub use v6::{AssignmentPair, CollatorPair, ValidatorPair}; +pub use v7::{AssignmentPair, CollatorPair, ValidatorPair}; diff --git a/polkadot/primitives/src/runtime_api.rs b/polkadot/primitives/src/runtime_api.rs index 6dca33f88234..f611936f2701 100644 --- a/polkadot/primitives/src/runtime_api.rs +++ b/polkadot/primitives/src/runtime_api.rs @@ -114,13 +114,11 @@ //! separated from the stable primitives. use crate::{ - async_backing, slashing, - vstaging::{self, ApprovalVotingParams}, - AsyncBackingParams, BlockNumber, CandidateCommitments, CandidateEvent, CandidateHash, - CommittedCandidateReceipt, CoreIndex, CoreState, DisputeState, ExecutorParams, - GroupRotationInfo, Hash, OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, - ScrapedOnChainVotes, SessionIndex, SessionInfo, ValidatorId, ValidatorIndex, - ValidatorSignature, + async_backing, slashing, ApprovalVotingParams, AsyncBackingParams, BlockNumber, + CandidateCommitments, CandidateEvent, CandidateHash, CommittedCandidateReceipt, CoreIndex, + CoreState, DisputeState, ExecutorParams, GroupRotationInfo, Hash, NodeFeatures, + OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes, + SessionIndex, SessionInfo, ValidatorId, ValidatorIndex, ValidatorSignature, }; use polkadot_core_primitives as pcp; @@ -279,7 +277,7 @@ sp_api::decl_runtime_apis! { /// Get node features. /// This is a staging method! Do not use on production runtimes! #[api_version(9)] - fn node_features() -> vstaging::NodeFeatures; + fn node_features() -> NodeFeatures; /***** Added in v10 *****/ /// Approval voting configuration parameters diff --git a/polkadot/primitives/src/v6/async_backing.rs b/polkadot/primitives/src/v7/async_backing.rs similarity index 100% rename from polkadot/primitives/src/v6/async_backing.rs rename to polkadot/primitives/src/v7/async_backing.rs diff --git a/polkadot/primitives/src/v6/executor_params.rs b/polkadot/primitives/src/v7/executor_params.rs similarity index 100% rename from polkadot/primitives/src/v6/executor_params.rs rename to polkadot/primitives/src/v7/executor_params.rs diff --git a/polkadot/primitives/src/v6/metrics.rs b/polkadot/primitives/src/v7/metrics.rs similarity index 100% rename from polkadot/primitives/src/v6/metrics.rs rename to polkadot/primitives/src/v7/metrics.rs diff --git a/polkadot/primitives/src/v6/mod.rs b/polkadot/primitives/src/v7/mod.rs similarity index 97% rename from polkadot/primitives/src/v6/mod.rs rename to polkadot/primitives/src/v7/mod.rs index 21cee7532652..d4f4a6335772 100644 --- a/polkadot/primitives/src/v6/mod.rs +++ b/polkadot/primitives/src/v7/mod.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! `V6` Primitives. +//! `V7` Primitives. use bitvec::{field::BitField, slice::BitSlice, vec::BitVec}; use parity_scale_codec::{Decode, Encode}; @@ -1184,6 +1184,32 @@ impl<'a> ApprovalVoteMultipleCandidates<'a> { } } +/// Approval voting configuration parameters +#[derive( + RuntimeDebug, + Copy, + Clone, + PartialEq, + Encode, + Decode, + TypeInfo, + serde::Serialize, + serde::Deserialize, +)] +pub struct ApprovalVotingParams { + /// The maximum number of candidates `approval-voting` can vote for with + /// a single signatures. + /// + /// Setting it to 1, means we send the approval as soon as we have it available. + pub max_approval_coalesce_count: u32, +} + +impl Default for ApprovalVotingParams { + fn default() -> Self { + Self { max_approval_coalesce_count: 1 } + } +} + /// Custom validity errors used in Polkadot while validating transactions. #[repr(u8)] pub enum ValidityError { @@ -1947,6 +1973,29 @@ pub enum PvfExecKind { Approval, } +/// Bit indices in the `HostConfiguration.node_features` that correspond to different node features. +pub type NodeFeatures = BitVec; + +/// Module containing feature-specific bit indices into the `NodeFeatures` bitvec. +pub mod node_features { + /// A feature index used to identify a bit into the node_features array stored + /// in the HostConfiguration. + #[repr(u8)] + pub enum FeatureIndex { + /// Tells if tranch0 assignments could be sent in a single certificate. + /// Reserved for: `` + EnableAssignmentsV2 = 0, + /// This feature enables the extension of `BackedCandidate::validator_indices` by 8 bits. + /// The value stored there represents the assumed core index where the candidates + /// are backed. This is needed for the elastic scaling MVP. + ElasticScalingMVP = 1, + /// First unassigned feature bit. + /// Every time a new feature flag is assigned it should take this value. + /// and this should be incremented. + FirstUnassigned = 2, + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/polkadot/primitives/src/v6/signed.rs b/polkadot/primitives/src/v7/signed.rs similarity index 100% rename from polkadot/primitives/src/v6/signed.rs rename to polkadot/primitives/src/v7/signed.rs diff --git a/polkadot/primitives/src/v6/slashing.rs b/polkadot/primitives/src/v7/slashing.rs similarity index 100% rename from polkadot/primitives/src/v6/slashing.rs rename to polkadot/primitives/src/v7/slashing.rs diff --git a/polkadot/primitives/src/vstaging/mod.rs b/polkadot/primitives/src/vstaging/mod.rs index 94e9e8920298..1af73993f640 100644 --- a/polkadot/primitives/src/vstaging/mod.rs +++ b/polkadot/primitives/src/vstaging/mod.rs @@ -17,7 +17,7 @@ //! Staging Primitives. // Put any primitives used by staging APIs functions here -pub use crate::v6::*; +use crate::v7::*; use sp_std::prelude::*; use parity_scale_codec::{Decode, Encode}; @@ -25,32 +25,6 @@ use primitives::RuntimeDebug; use scale_info::TypeInfo; use sp_arithmetic::Perbill; -/// Approval voting configuration parameters -#[derive( - RuntimeDebug, - Copy, - Clone, - PartialEq, - Encode, - Decode, - TypeInfo, - serde::Serialize, - serde::Deserialize, -)] -pub struct ApprovalVotingParams { - /// The maximum number of candidates `approval-voting` can vote for with - /// a single signatures. - /// - /// Setting it to 1, means we send the approval as soon as we have it available. - pub max_approval_coalesce_count: u32, -} - -impl Default for ApprovalVotingParams { - fn default() -> Self { - Self { max_approval_coalesce_count: 1 } - } -} - /// Scheduler configuration parameters. All coretime/ondemand parameters are here. #[derive( RuntimeDebug, @@ -125,28 +99,3 @@ impl> Default for SchedulerParams } } } - -use bitvec::vec::BitVec; - -/// Bit indices in the `HostConfiguration.node_features` that correspond to different node features. -pub type NodeFeatures = BitVec; - -/// Module containing feature-specific bit indices into the `NodeFeatures` bitvec. -pub mod node_features { - /// A feature index used to identify a bit into the node_features array stored - /// in the HostConfiguration. - #[repr(u8)] - pub enum FeatureIndex { - /// Tells if tranch0 assignments could be sent in a single certificate. - /// Reserved for: `` - EnableAssignmentsV2 = 0, - /// This feature enables the extension of `BackedCandidate::validator_indices` by 8 bits. - /// The value stored there represents the assumed core index where the candidates - /// are backed. This is needed for the elastic scaling MVP. - ElasticScalingMVP = 1, - /// First unassigned feature bit. - /// Every time a new feature flag is assigned it should take this value. - /// and this should be incremented. - FirstUnassigned = 2, - } -} diff --git a/polkadot/runtime/parachains/src/builder.rs b/polkadot/runtime/parachains/src/builder.rs index 73617010f6de..e29c2e218ed9 100644 --- a/polkadot/runtime/parachains/src/builder.rs +++ b/polkadot/runtime/parachains/src/builder.rs @@ -25,13 +25,13 @@ use bitvec::{order::Lsb0 as BitOrderLsb0, vec::BitVec}; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; use primitives::{ - collator_signature_payload, vstaging::node_features::FeatureIndex, AvailabilityBitfield, - BackedCandidate, CandidateCommitments, CandidateDescriptor, CandidateHash, CollatorId, - CollatorSignature, CommittedCandidateReceipt, CompactStatement, CoreIndex, DisputeStatement, - DisputeStatementSet, GroupIndex, HeadData, Id as ParaId, IndexedVec, - InherentData as ParachainsInherentData, InvalidDisputeStatementKind, PersistedValidationData, - SessionIndex, SigningContext, UncheckedSigned, ValidDisputeStatementKind, ValidationCode, - ValidatorId, ValidatorIndex, ValidityAttestation, + collator_signature_payload, node_features::FeatureIndex, AvailabilityBitfield, BackedCandidate, + CandidateCommitments, CandidateDescriptor, CandidateHash, CollatorId, CollatorSignature, + CommittedCandidateReceipt, CompactStatement, CoreIndex, DisputeStatement, DisputeStatementSet, + GroupIndex, HeadData, Id as ParaId, IndexedVec, InherentData as ParachainsInherentData, + InvalidDisputeStatementKind, PersistedValidationData, SessionIndex, SigningContext, + UncheckedSigned, ValidDisputeStatementKind, ValidationCode, ValidatorId, ValidatorIndex, + ValidityAttestation, }; use sp_core::{sr25519, H256}; use sp_runtime::{ diff --git a/polkadot/runtime/parachains/src/configuration.rs b/polkadot/runtime/parachains/src/configuration.rs index 17022272c0c4..e1246fb88975 100644 --- a/polkadot/runtime/parachains/src/configuration.rs +++ b/polkadot/runtime/parachains/src/configuration.rs @@ -26,10 +26,9 @@ use polkadot_parachain_primitives::primitives::{ MAX_HORIZONTAL_MESSAGE_NUM, MAX_UPWARD_MESSAGE_NUM, }; use primitives::{ - vstaging::{ApprovalVotingParams, NodeFeatures}, - AsyncBackingParams, Balance, ExecutorParamError, ExecutorParams, SessionIndex, - LEGACY_MIN_BACKING_VOTES, MAX_CODE_SIZE, MAX_HEAD_DATA_SIZE, MAX_POV_SIZE, - ON_DEMAND_MAX_QUEUE_MAX_SIZE, + ApprovalVotingParams, AsyncBackingParams, Balance, ExecutorParamError, ExecutorParams, + NodeFeatures, SessionIndex, LEGACY_MIN_BACKING_VOTES, MAX_CODE_SIZE, MAX_HEAD_DATA_SIZE, + MAX_POV_SIZE, ON_DEMAND_MAX_QUEUE_MAX_SIZE, }; use sp_runtime::{traits::Zero, Perbill}; use sp_std::prelude::*; diff --git a/polkadot/runtime/parachains/src/configuration/migration/v10.rs b/polkadot/runtime/parachains/src/configuration/migration/v10.rs index cf228610e5c9..3c8d6084ace7 100644 --- a/polkadot/runtime/parachains/src/configuration/migration/v10.rs +++ b/polkadot/runtime/parachains/src/configuration/migration/v10.rs @@ -20,7 +20,7 @@ use crate::configuration::{Config, Pallet}; use frame_support::{pallet_prelude::*, traits::Defensive, weights::Weight}; use frame_system::pallet_prelude::BlockNumberFor; use primitives::{ - vstaging::NodeFeatures, AsyncBackingParams, Balance, ExecutorParams, SessionIndex, + AsyncBackingParams, Balance, ExecutorParams, NodeFeatures, SessionIndex, LEGACY_MIN_BACKING_VOTES, ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE, }; use sp_runtime::Perbill; diff --git a/polkadot/runtime/parachains/src/configuration/migration/v11.rs b/polkadot/runtime/parachains/src/configuration/migration/v11.rs index f6e0e0431640..7ed9d0868855 100644 --- a/polkadot/runtime/parachains/src/configuration/migration/v11.rs +++ b/polkadot/runtime/parachains/src/configuration/migration/v11.rs @@ -22,14 +22,13 @@ use frame_support::{ }; use frame_system::pallet_prelude::BlockNumberFor; use primitives::{ - vstaging::ApprovalVotingParams, AsyncBackingParams, ExecutorParams, SessionIndex, + ApprovalVotingParams, AsyncBackingParams, ExecutorParams, NodeFeatures, SessionIndex, LEGACY_MIN_BACKING_VOTES, ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE, }; use sp_std::vec::Vec; use frame_support::traits::OnRuntimeUpgrade; use polkadot_core_primitives::Balance; -use primitives::vstaging::NodeFeatures; use sp_arithmetic::Perbill; use super::v10::V10HostConfiguration; diff --git a/polkadot/runtime/parachains/src/disputes.rs b/polkadot/runtime/parachains/src/disputes.rs index cffad42e0ec9..8bba97ce4bcc 100644 --- a/polkadot/runtime/parachains/src/disputes.rs +++ b/polkadot/runtime/parachains/src/disputes.rs @@ -25,11 +25,11 @@ use frame_system::pallet_prelude::*; use parity_scale_codec::{Decode, Encode}; use polkadot_runtime_metrics::get_current_time; use primitives::{ - byzantine_threshold, supermajority_threshold, vstaging::ApprovalVoteMultipleCandidates, - ApprovalVote, CandidateHash, CheckedDisputeStatementSet, CheckedMultiDisputeStatementSet, - CompactStatement, ConsensusLog, DisputeState, DisputeStatement, DisputeStatementSet, - ExplicitDisputeStatement, InvalidDisputeStatementKind, MultiDisputeStatementSet, SessionIndex, - SigningContext, ValidDisputeStatementKind, ValidatorId, ValidatorIndex, ValidatorSignature, + byzantine_threshold, supermajority_threshold, ApprovalVote, ApprovalVoteMultipleCandidates, + CandidateHash, CheckedDisputeStatementSet, CheckedMultiDisputeStatementSet, CompactStatement, + ConsensusLog, DisputeState, DisputeStatement, DisputeStatementSet, ExplicitDisputeStatement, + InvalidDisputeStatementKind, MultiDisputeStatementSet, SessionIndex, SigningContext, + ValidDisputeStatementKind, ValidatorId, ValidatorIndex, ValidatorSignature, }; use scale_info::TypeInfo; use sp_runtime::{ diff --git a/polkadot/runtime/parachains/src/paras_inherent/benchmarking.rs b/polkadot/runtime/parachains/src/paras_inherent/benchmarking.rs index 1b07acffb154..8f6f2166a66a 100644 --- a/polkadot/runtime/parachains/src/paras_inherent/benchmarking.rs +++ b/polkadot/runtime/parachains/src/paras_inherent/benchmarking.rs @@ -20,7 +20,7 @@ use frame_benchmarking::{benchmarks, impl_benchmark_test_suite}; use frame_system::RawOrigin; use sp_std::{cmp::min, collections::btree_map::BTreeMap}; -use primitives::v6::GroupIndex; +use primitives::v7::GroupIndex; use crate::builder::BenchBuilder; diff --git a/polkadot/runtime/parachains/src/paras_inherent/mod.rs b/polkadot/runtime/parachains/src/paras_inherent/mod.rs index 6a20a10a8d75..31c9ab84b60c 100644 --- a/polkadot/runtime/parachains/src/paras_inherent/mod.rs +++ b/polkadot/runtime/parachains/src/paras_inherent/mod.rs @@ -43,9 +43,9 @@ use frame_support::{ use frame_system::pallet_prelude::*; use pallet_babe::{self, ParentBlockRandomness}; use primitives::{ - effective_minimum_backing_votes, vstaging::node_features::FeatureIndex, BackedCandidate, - CandidateHash, CandidateReceipt, CheckedDisputeStatementSet, CheckedMultiDisputeStatementSet, - CoreIndex, DisputeStatementSet, HeadData, InherentData as ParachainsInherentData, + effective_minimum_backing_votes, node_features::FeatureIndex, BackedCandidate, CandidateHash, + CandidateReceipt, CheckedDisputeStatementSet, CheckedMultiDisputeStatementSet, CoreIndex, + DisputeStatementSet, HeadData, InherentData as ParachainsInherentData, MultiDisputeStatementSet, ScrapedOnChainVotes, SessionIndex, SignedAvailabilityBitfields, SigningContext, UncheckedSignedAvailabilityBitfield, UncheckedSignedAvailabilityBitfields, ValidatorId, ValidatorIndex, ValidityAttestation, PARACHAINS_INHERENT_IDENTIFIER, diff --git a/polkadot/runtime/parachains/src/runtime_api_impl/mod.rs b/polkadot/runtime/parachains/src/runtime_api_impl/mod.rs index ba74e488cd3b..ed2e95b3cfa9 100644 --- a/polkadot/runtime/parachains/src/runtime_api_impl/mod.rs +++ b/polkadot/runtime/parachains/src/runtime_api_impl/mod.rs @@ -26,5 +26,5 @@ //! 2. Move methods from `vstaging` to `v3`. The new stable version should include all methods from //! `vstaging` tagged with the new version number (e.g. all `v3` methods). -pub mod v7; +pub mod v10; pub mod vstaging; diff --git a/polkadot/runtime/parachains/src/runtime_api_impl/v7.rs b/polkadot/runtime/parachains/src/runtime_api_impl/v10.rs similarity index 93% rename from polkadot/runtime/parachains/src/runtime_api_impl/v7.rs rename to polkadot/runtime/parachains/src/runtime_api_impl/v10.rs index 171f3f746a82..21f54121ab18 100644 --- a/polkadot/runtime/parachains/src/runtime_api_impl/v7.rs +++ b/polkadot/runtime/parachains/src/runtime_api_impl/v10.rs @@ -14,7 +14,7 @@ //! A module exporting runtime API implementation functions for all runtime APIs using `v5` //! primitives. //! -//! Runtimes implementing the v2 runtime API are recommended to forward directly to these +//! Runtimes implementing the v10 runtime API are recommended to forward directly to these //! functions. use crate::{ @@ -29,11 +29,12 @@ use primitives::{ AsyncBackingParams, BackingState, CandidatePendingAvailability, Constraints, InboundHrmpLimitations, OutboundHrmpChannelLimitations, }, - slashing, AuthorityDiscoveryId, CandidateEvent, CandidateHash, CommittedCandidateReceipt, - CoreIndex, CoreState, DisputeState, ExecutorParams, GroupIndex, GroupRotationInfo, Hash, - Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, OccupiedCore, OccupiedCoreAssumption, - PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes, SessionIndex, SessionInfo, - ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, + slashing, ApprovalVotingParams, AuthorityDiscoveryId, CandidateEvent, CandidateHash, + CommittedCandidateReceipt, CoreIndex, CoreState, DisputeState, ExecutorParams, GroupIndex, + GroupRotationInfo, Hash, Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, + NodeFeatures, OccupiedCore, OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, + ScrapedOnChainVotes, SessionIndex, SessionInfo, ValidationCode, ValidationCodeHash, + ValidatorId, ValidatorIndex, ValidatorSignature, }; use sp_runtime::traits::One; use sp_std::{collections::btree_map::BTreeMap, prelude::*}; @@ -517,3 +518,24 @@ pub fn backing_state( pub fn async_backing_params() -> AsyncBackingParams { >::config().async_backing_params } + +/// Implementation for `DisabledValidators` +// CAVEAT: this should only be called on the node side +// as it might produce incorrect results on session boundaries +pub fn disabled_validators() -> Vec +where + T: shared::Config, +{ + >::disabled_validators() +} + +/// Returns the current state of the node features. +pub fn node_features() -> NodeFeatures { + >::config().node_features +} + +/// Approval voting subsystem configuration parameters +pub fn approval_voting_params() -> ApprovalVotingParams { + let config = >::config(); + config.approval_voting_params +} diff --git a/polkadot/runtime/parachains/src/runtime_api_impl/vstaging.rs b/polkadot/runtime/parachains/src/runtime_api_impl/vstaging.rs index 296b872e8d41..28be3f53863b 100644 --- a/polkadot/runtime/parachains/src/runtime_api_impl/vstaging.rs +++ b/polkadot/runtime/parachains/src/runtime_api_impl/vstaging.rs @@ -16,36 +16,9 @@ //! Put implementations of functions from staging APIs here. -use crate::{configuration, initializer, scheduler, shared}; -use primitives::{ - vstaging::{ApprovalVotingParams, NodeFeatures}, - CoreIndex, Id as ParaId, ValidatorIndex, -}; -use sp_std::{ - collections::{btree_map::BTreeMap, vec_deque::VecDeque}, - prelude::Vec, -}; - -/// Implementation for `DisabledValidators` -// CAVEAT: this should only be called on the node side -// as it might produce incorrect results on session boundaries -pub fn disabled_validators() -> Vec -where - T: shared::Config, -{ - >::disabled_validators() -} - -/// Returns the current state of the node features. -pub fn node_features() -> NodeFeatures { - >::config().node_features -} - -/// Approval voting subsystem configuration parameters -pub fn approval_voting_params() -> ApprovalVotingParams { - let config = >::config(); - config.approval_voting_params -} +use crate::scheduler; +use primitives::{CoreIndex, Id as ParaId}; +use sp_std::collections::{btree_map::BTreeMap, vec_deque::VecDeque}; /// Returns the claimqueue from the scheduler pub fn claim_queue() -> BTreeMap> { diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index f37c901475a8..84f98a3dba14 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -23,13 +23,12 @@ use pallet_nis::WithMaximumOf; use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; use primitives::{ - slashing, - vstaging::{ApprovalVotingParams, NodeFeatures}, - AccountId, AccountIndex, Balance, BlockNumber, CandidateEvent, CandidateHash, - CommittedCandidateReceipt, CoreState, DisputeState, ExecutorParams, GroupRotationInfo, Hash, - Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, Moment, Nonce, - OccupiedCoreAssumption, PersistedValidationData, ScrapedOnChainVotes, SessionInfo, Signature, - ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, PARACHAIN_KEY_TYPE_ID, + slashing, AccountId, AccountIndex, ApprovalVotingParams, Balance, BlockNumber, CandidateEvent, + CandidateHash, CommittedCandidateReceipt, CoreState, DisputeState, ExecutorParams, + GroupRotationInfo, Hash, Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, Moment, + NodeFeatures, Nonce, OccupiedCoreAssumption, PersistedValidationData, ScrapedOnChainVotes, + SessionInfo, Signature, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, + PARACHAIN_KEY_TYPE_ID, }; use rococo_runtime_constants::system_parachain::BROKER_ID; use runtime_common::{ @@ -53,9 +52,7 @@ use runtime_parachains::{ inclusion::{AggregateMessageOrigin, UmpQueueId}, initializer as parachains_initializer, origin as parachains_origin, paras as parachains_paras, paras_inherent as parachains_paras_inherent, - runtime_api_impl::{ - v7 as parachains_runtime_api_impl, vstaging as parachains_staging_runtime_api_impl, - }, + runtime_api_impl::v10 as parachains_runtime_api_impl, scheduler as parachains_scheduler, session_info as parachains_session_info, shared as parachains_shared, }; @@ -2017,15 +2014,15 @@ sp_api::impl_runtime_apis! { } fn approval_voting_params() -> ApprovalVotingParams { - parachains_staging_runtime_api_impl::approval_voting_params::() + parachains_runtime_api_impl::approval_voting_params::() } fn disabled_validators() -> Vec { - parachains_staging_runtime_api_impl::disabled_validators::() + parachains_runtime_api_impl::disabled_validators::() } fn node_features() -> NodeFeatures { - parachains_staging_runtime_api_impl::node_features::() + parachains_runtime_api_impl::node_features::() } } diff --git a/polkadot/runtime/test-runtime/src/lib.rs b/polkadot/runtime/test-runtime/src/lib.rs index 62c3741c56d6..446cd101efff 100644 --- a/polkadot/runtime/test-runtime/src/lib.rs +++ b/polkadot/runtime/test-runtime/src/lib.rs @@ -27,11 +27,10 @@ use sp_std::{collections::btree_map::BTreeMap, prelude::*}; use polkadot_runtime_parachains::{ assigner_parachains as parachains_assigner_parachains, configuration as parachains_configuration, disputes as parachains_disputes, - disputes::slashing as parachains_slashing, - dmp as parachains_dmp, hrmp as parachains_hrmp, inclusion as parachains_inclusion, - initializer as parachains_initializer, origin as parachains_origin, paras as parachains_paras, - paras_inherent as parachains_paras_inherent, - runtime_api_impl::{v7 as runtime_impl, vstaging as staging_runtime_impl}, + disputes::slashing as parachains_slashing, dmp as parachains_dmp, hrmp as parachains_hrmp, + inclusion as parachains_inclusion, initializer as parachains_initializer, + origin as parachains_origin, paras as parachains_paras, + paras_inherent as parachains_paras_inherent, runtime_api_impl::v10 as runtime_impl, scheduler as parachains_scheduler, session_info as parachains_session_info, shared as parachains_shared, }; @@ -971,16 +970,16 @@ sp_api::impl_runtime_apis! { runtime_impl::async_backing_params::() } - fn approval_voting_params() -> primitives::vstaging::ApprovalVotingParams { - staging_runtime_impl::approval_voting_params::() + fn approval_voting_params() -> primitives::ApprovalVotingParams { + runtime_impl::approval_voting_params::() } fn disabled_validators() -> Vec { - staging_runtime_impl::disabled_validators::() + runtime_impl::disabled_validators::() } - fn node_features() -> primitives::vstaging::NodeFeatures { - staging_runtime_impl::node_features::() + fn node_features() -> primitives::NodeFeatures { + runtime_impl::node_features::() } } diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 2eea144cc1e7..37d236464c0a 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -45,14 +45,12 @@ use pallet_session::historical as session_historical; use pallet_transaction_payment::{CurrencyAdapter, FeeDetails, RuntimeDispatchInfo}; use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; use primitives::{ - slashing, - vstaging::{ApprovalVotingParams, NodeFeatures}, - AccountId, AccountIndex, Balance, BlockNumber, CandidateEvent, CandidateHash, - CommittedCandidateReceipt, CoreState, DisputeState, ExecutorParams, GroupRotationInfo, Hash, - Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, Moment, Nonce, - OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes, - SessionInfo, Signature, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, - ValidatorSignature, PARACHAIN_KEY_TYPE_ID, + slashing, AccountId, AccountIndex, ApprovalVotingParams, Balance, BlockNumber, CandidateEvent, + CandidateHash, CommittedCandidateReceipt, CoreState, DisputeState, ExecutorParams, + GroupRotationInfo, Hash, Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, Moment, + NodeFeatures, Nonce, OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, + ScrapedOnChainVotes, SessionInfo, Signature, ValidationCode, ValidationCodeHash, ValidatorId, + ValidatorIndex, ValidatorSignature, PARACHAIN_KEY_TYPE_ID, }; use runtime_common::{ assigned_slots, auctions, crowdloan, @@ -75,9 +73,7 @@ use runtime_parachains::{ inclusion::{AggregateMessageOrigin, UmpQueueId}, initializer as parachains_initializer, origin as parachains_origin, paras as parachains_paras, paras_inherent as parachains_paras_inherent, reward_points as parachains_reward_points, - runtime_api_impl::{ - v7 as parachains_runtime_api_impl, vstaging as parachains_staging_runtime_api_impl, - }, + runtime_api_impl::v10 as parachains_runtime_api_impl, scheduler as parachains_scheduler, session_info as parachains_session_info, shared as parachains_shared, }; @@ -2098,15 +2094,15 @@ sp_api::impl_runtime_apis! { } fn approval_voting_params() -> ApprovalVotingParams { - parachains_staging_runtime_api_impl::approval_voting_params::() + parachains_runtime_api_impl::approval_voting_params::() } fn disabled_validators() -> Vec { - parachains_staging_runtime_api_impl::disabled_validators::() + parachains_runtime_api_impl::disabled_validators::() } fn node_features() -> NodeFeatures { - parachains_staging_runtime_api_impl::node_features::() + parachains_runtime_api_impl::node_features::() } } From b4cb8d1edfce8cc1059319e8e5620f0776e4ba45 Mon Sep 17 00:00:00 2001 From: Serban Iorga Date: Mon, 1 Apr 2024 23:18:57 +0300 Subject: [PATCH 094/257] Fix links (#3928) Fix links Related CI failure: https://github.com/paritytech/polkadot-sdk/actions/runs/8455425042/job/23162858534?pr=3859 --- .github/workflows/check-links.yml | 4 ++-- docs/sdk/src/polkadot_sdk/substrate.rs | 2 +- docs/sdk/src/polkadot_sdk/templates.rs | 5 ++--- docs/sdk/src/reference_docs/runtime_vs_smart_contract.rs | 2 +- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/.github/workflows/check-links.yml b/.github/workflows/check-links.yml index 903d7a3fcb3d..58065f369c9c 100644 --- a/.github/workflows/check-links.yml +++ b/.github/workflows/check-links.yml @@ -3,8 +3,8 @@ name: Check links on: pull_request: paths: - - "*.rs" - - "*.prdoc" + - "**.rs" + - "**.prdoc" - ".github/workflows/check-links.yml" - ".config/lychee.toml" types: [opened, synchronize, reopened, ready_for_review] diff --git a/docs/sdk/src/polkadot_sdk/substrate.rs b/docs/sdk/src/polkadot_sdk/substrate.rs index 5021c55e581f..69d74d86db1b 100644 --- a/docs/sdk/src/polkadot_sdk/substrate.rs +++ b/docs/sdk/src/polkadot_sdk/substrate.rs @@ -99,7 +99,7 @@ //! demonstration. //! * [`chain_spec_builder`]: Utility to build more detailed chain-specs for the aforementioned //! node. Other projects typically contain a `build-spec` subcommand that does the same. -//! * [`node_template`](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/bin/node-template): +//! * [`node_template`](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/bin/node): //! a template node that contains a minimal set of features and can act as a starting point of a //! project. //! * [`subkey`]: Substrate's key management utility. diff --git a/docs/sdk/src/polkadot_sdk/templates.rs b/docs/sdk/src/polkadot_sdk/templates.rs index f60c75b8f219..4bf0e839c798 100644 --- a/docs/sdk/src/polkadot_sdk/templates.rs +++ b/docs/sdk/src/polkadot_sdk/templates.rs @@ -22,9 +22,8 @@ //! - [`frontier-parachain-template`](https://github.com/paritytech/frontier-parachain-template): A //! parachain template for launching EVM-compatible parachains. //! -//! [`substrate-node-template`]: https://github.com/paritytech/polkadot-sdk/blob/master/substrate/bin/node-template/ -//! [`substrate-minimal-template`]: https://github.com/paritytech/polkadot-sdk/blob/master/substrate/bin/minimal/ -//! [`cumulus-parachain-template`]: https://github.com/paritytech/polkadot-sdk/blob/master/cumulus/parachain-template/ +//! [`minimal-template`]: https://github.com/paritytech/polkadot-sdk/blob/master/templates/minimal/ +//! [`parachain-template`]: https://github.com/paritytech/polkadot-sdk/blob/master/templates/parachain/ // TODO: in general, we need to make a deliberate choice here of moving a few key templates to this // repo (nothing stays in `substrate-developer-hub`) and the everything else should be community diff --git a/docs/sdk/src/reference_docs/runtime_vs_smart_contract.rs b/docs/sdk/src/reference_docs/runtime_vs_smart_contract.rs index 099512cf4ee1..379b0c11b2ad 100644 --- a/docs/sdk/src/reference_docs/runtime_vs_smart_contract.rs +++ b/docs/sdk/src/reference_docs/runtime_vs_smart_contract.rs @@ -117,7 +117,7 @@ //! - **Contract Code Updates**: Once deployed, although typically immutable, Smart Contracts can be //! upgraded, but lack of migration logic. The [pallet_contracts](../../../pallet_contracts/index.html) //! allows for contracts to be upgraded by exposing the `set_code` dispatchable. More details on this -//! can be found in [Ink! documentation on upgradeable contracts](https://use.ink/5.x/basics/upgradeable-contracts). +//! can be found in [Ink! documentation on upgradeable contracts](https://use.ink/basics/upgradeable-contracts). //! - **Isolated Impact**: Upgrades or changes to a smart contract generally impact only that //! contract and its users, unlike Runtime upgrades that have a network-wide effect. //! - **Simplicity and Rapid Development**: The development cycle for Smart Contracts is usually From be8bd2dc754780c757d9d8fee285b6ec2dcf609f Mon Sep 17 00:00:00 2001 From: Andrei Sandu <54316454+sandreim@users.noreply.github.com> Date: Tue, 2 Apr 2024 00:36:18 +0300 Subject: [PATCH 095/257] pallet-scheduler: fix test (#3923) fix https://github.com/paritytech/polkadot-sdk/issues/3921 --------- Signed-off-by: Andrei Sandu --- substrate/frame/scheduler/src/tests.rs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/substrate/frame/scheduler/src/tests.rs b/substrate/frame/scheduler/src/tests.rs index 440355336396..f251dde99a86 100644 --- a/substrate/frame/scheduler/src/tests.rs +++ b/substrate/frame/scheduler/src/tests.rs @@ -2285,9 +2285,18 @@ fn postponed_named_task_cannot_be_rescheduled() { // Run to a very large block. run_to_block(10); + // It was not executed. assert!(logger::log().is_empty()); - assert!(Preimage::is_requested(&hash)); + + // Preimage was not available + assert_eq!( + System::events().last().unwrap().event, + crate::Event::CallUnavailable { task: (4, 0), id: Some(name) }.into() + ); + + // So it should not be requested. + assert!(!Preimage::is_requested(&hash)); // Postponing removes the lookup. assert!(!Lookup::::contains_key(name)); @@ -2307,11 +2316,12 @@ fn postponed_named_task_cannot_be_rescheduled() { ); // Finally add the preimage. - assert_ok!(Preimage::note(call.encode().into())); + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(0), call.encode())); + run_to_block(1000); // It did not execute. assert!(logger::log().is_empty()); - assert!(Preimage::is_requested(&hash)); + assert!(!Preimage::is_requested(&hash)); // Manually re-schedule the call by name does not work. assert_err!( From 5e3d97e1ccb27077bd9a39d2d14ee226830d0bee Mon Sep 17 00:00:00 2001 From: s0me0ne-unkn0wn <48632512+s0me0ne-unkn0wn@users.noreply.github.com> Date: Mon, 1 Apr 2024 23:40:38 +0200 Subject: [PATCH 096/257] `im-online` removal final cleanup (#3902) Rejoice! Rejoice! The story is nearly over. This PR removes stale migrations, auxiliary structures, and package dependencies, thus making Rococo and Westend totally free from any `im-online`-related stuff. `im-online` still stays a part of the Substrate node and its runtime: https://github.com/paritytech/polkadot-sdk/blob/0d9324847391e902bb42f84f0e76096b1f764efe/substrate/bin/node/runtime/src/lib.rs#L2276-L2277 I'm not sure if it makes sense to remove it from there considering that we're not removing `im-online` from FRAME. Please share your opinion. --- Cargo.lock | 4 - cumulus/test/service/Cargo.toml | 2 - polkadot/node/service/Cargo.toml | 3 - polkadot/runtime/rococo/Cargo.toml | 4 - polkadot/runtime/rococo/src/lib.rs | 137 +-------------------------- polkadot/runtime/westend/Cargo.toml | 4 - polkadot/runtime/westend/src/lib.rs | 139 +--------------------------- 7 files changed, 2 insertions(+), 291 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9c052d132efd..7d2063b68f50 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4322,7 +4322,6 @@ dependencies = [ "frame-system-rpc-runtime-api", "futures", "jsonrpsee", - "pallet-im-online", "pallet-timestamp", "pallet-transaction-payment", "parachains-common", @@ -13499,7 +13498,6 @@ dependencies = [ "log", "mmr-gadget", "pallet-babe", - "pallet-im-online", "pallet-staking", "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", @@ -15103,7 +15101,6 @@ dependencies = [ "pallet-elections-phragmen", "pallet-grandpa", "pallet-identity", - "pallet-im-online", "pallet-indices", "pallet-membership", "pallet-message-queue", @@ -21955,7 +21952,6 @@ dependencies = [ "pallet-fast-unstake", "pallet-grandpa", "pallet-identity", - "pallet-im-online", "pallet-indices", "pallet-membership", "pallet-message-queue", diff --git a/cumulus/test/service/Cargo.toml b/cumulus/test/service/Cargo.toml index 45e21432f5b8..113e0aca68a8 100644 --- a/cumulus/test/service/Cargo.toml +++ b/cumulus/test/service/Cargo.toml @@ -88,7 +88,6 @@ pallet-timestamp = { path = "../../../substrate/frame/timestamp" } futures = "0.3.28" portpicker = "0.1.1" rococo-parachain-runtime = { path = "../../parachains/runtimes/testing/rococo-parachain" } -pallet-im-online = { path = "../../../substrate/frame/im-online" } sp-consensus-grandpa = { path = "../../../substrate/primitives/consensus/grandpa" } sp-authority-discovery = { path = "../../../substrate/primitives/authority-discovery" } cumulus-test-client = { path = "../client" } @@ -106,7 +105,6 @@ runtime-benchmarks = [ "cumulus-primitives-core/runtime-benchmarks", "cumulus-test-client/runtime-benchmarks", "frame-system/runtime-benchmarks", - "pallet-im-online/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "parachains-common/runtime-benchmarks", "polkadot-cli/runtime-benchmarks", diff --git a/polkadot/node/service/Cargo.toml b/polkadot/node/service/Cargo.toml index 5a42443c84c8..932f3e679f41 100644 --- a/polkadot/node/service/Cargo.toml +++ b/polkadot/node/service/Cargo.toml @@ -65,7 +65,6 @@ sp-version = { path = "../../../substrate/primitives/version" } # Substrate Pallets pallet-babe = { path = "../../../substrate/frame/babe" } -pallet-im-online = { path = "../../../substrate/frame/im-online" } pallet-staking = { path = "../../../substrate/frame/staking" } pallet-transaction-payment-rpc-runtime-api = { path = "../../../substrate/frame/transaction-payment/rpc/runtime-api" } frame-system = { path = "../../../substrate/frame/system" } @@ -197,7 +196,6 @@ runtime-benchmarks = [ "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", "pallet-babe/runtime-benchmarks", - "pallet-im-online/runtime-benchmarks", "pallet-staking/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-primitives/runtime-benchmarks", @@ -213,7 +211,6 @@ try-runtime = [ "frame-support/try-runtime", "frame-system/try-runtime", "pallet-babe/try-runtime", - "pallet-im-online/try-runtime", "pallet-staking/try-runtime", "pallet-transaction-payment/try-runtime", "polkadot-runtime-parachains/try-runtime", diff --git a/polkadot/runtime/rococo/Cargo.toml b/polkadot/runtime/rococo/Cargo.toml index 6f63a93cebe5..ff178b17070e 100644 --- a/polkadot/runtime/rococo/Cargo.toml +++ b/polkadot/runtime/rococo/Cargo.toml @@ -60,7 +60,6 @@ pallet-asset-rate = { path = "../../../substrate/frame/asset-rate", default-feat frame-executive = { path = "../../../substrate/frame/executive", default-features = false } pallet-grandpa = { path = "../../../substrate/frame/grandpa", default-features = false } pallet-identity = { path = "../../../substrate/frame/identity", default-features = false } -pallet-im-online = { path = "../../../substrate/frame/im-online", default-features = false } pallet-indices = { path = "../../../substrate/frame/indices", default-features = false } pallet-membership = { path = "../../../substrate/frame/membership", default-features = false } pallet-message-queue = { path = "../../../substrate/frame/message-queue", default-features = false } @@ -153,7 +152,6 @@ std = [ "pallet-elections-phragmen/std", "pallet-grandpa/std", "pallet-identity/std", - "pallet-im-online/std", "pallet-indices/std", "pallet-membership/std", "pallet-message-queue/std", @@ -228,7 +226,6 @@ runtime-benchmarks = [ "pallet-elections-phragmen/runtime-benchmarks", "pallet-grandpa/runtime-benchmarks", "pallet-identity/runtime-benchmarks", - "pallet-im-online/runtime-benchmarks", "pallet-indices/runtime-benchmarks", "pallet-membership/runtime-benchmarks", "pallet-message-queue/runtime-benchmarks", @@ -284,7 +281,6 @@ try-runtime = [ "pallet-elections-phragmen/try-runtime", "pallet-grandpa/try-runtime", "pallet-identity/try-runtime", - "pallet-im-online/try-runtime", "pallet-indices/try-runtime", "pallet-membership/try-runtime", "pallet-message-queue/try-runtime", diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index 84f98a3dba14..7d16d2dbf165 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -88,8 +88,7 @@ use sp_runtime::{ IdentityLookup, Keccak256, OpaqueKeys, SaturatedConversion, Verify, }, transaction_validity::{TransactionPriority, TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, BoundToRuntimeAppPublic, FixedU128, KeyTypeId, Perbill, Percent, Permill, - RuntimeAppPublic, RuntimeDebug, + ApplyExtrinsicResult, FixedU128, KeyTypeId, Perbill, Percent, Permill, RuntimeDebug, }; use sp_staking::SessionIndex; #[cfg(any(feature = "std", test))] @@ -347,46 +346,6 @@ impl pallet_authorship::Config for Runtime { type EventHandler = (); } -#[derive(Clone, Debug, PartialEq, Eq, Encode, Decode)] -pub struct OldSessionKeys { - pub grandpa: ::Public, - pub babe: ::Public, - pub im_online: pallet_im_online::sr25519::AuthorityId, - pub para_validator: ::Public, - pub para_assignment: ::Public, - pub authority_discovery: ::Public, - pub beefy: ::Public, -} - -impl OpaqueKeys for OldSessionKeys { - type KeyTypeIdProviders = (); - fn key_ids() -> &'static [KeyTypeId] { - &[ - <::Public>::ID, - <::Public>::ID, - sp_core::crypto::key_types::IM_ONLINE, - <::Public>::ID, - <::Public>::ID, - <::Public>::ID, - <::Public>::ID, - ] - } - fn get_raw(&self, i: KeyTypeId) -> &[u8] { - match i { - <::Public>::ID => self.grandpa.as_ref(), - <::Public>::ID => self.babe.as_ref(), - sp_core::crypto::key_types::IM_ONLINE => self.im_online.as_ref(), - <::Public>::ID => self.para_validator.as_ref(), - <::Public>::ID => - self.para_assignment.as_ref(), - <::Public>::ID => - self.authority_discovery.as_ref(), - <::Public>::ID => self.beefy.as_ref(), - _ => &[], - } - } -} - impl_opaque_keys! { pub struct SessionKeys { pub grandpa: Grandpa, @@ -398,18 +357,6 @@ impl_opaque_keys! { } } -// remove this when removing `OldSessionKeys` -fn transform_session_keys(_val: AccountId, old: OldSessionKeys) -> SessionKeys { - SessionKeys { - grandpa: old.grandpa, - babe: old.babe, - para_validator: old.para_validator, - para_assignment: old.para_assignment, - authority_discovery: old.authority_discovery, - beefy: old.beefy, - } -} - /// Special `ValidatorIdOf` implementation that is just returning the input as result. pub struct ValidatorIdOf; impl sp_runtime::traits::Convert> for ValidatorIdOf { @@ -1486,8 +1433,6 @@ pub mod migrations { use frame_support::traits::LockIdentifier; use frame_system::pallet_prelude::BlockNumberFor; - #[cfg(feature = "try-runtime")] - use sp_core::crypto::ByteArray; pub struct GetLegacyLeaseImpl; impl coretime::migration::GetLegacyLease for GetLegacyLeaseImpl { @@ -1514,7 +1459,6 @@ pub mod migrations { pub const PhragmenElectionPalletName: &'static str = "PhragmenElection"; pub const TechnicalMembershipPalletName: &'static str = "TechnicalMembership"; pub const TipsPalletName: &'static str = "Tips"; - pub const ImOnlinePalletName: &'static str = "ImOnline"; pub const PhragmenElectionPalletId: LockIdentifier = *b"phrelect"; } @@ -1551,79 +1495,6 @@ pub mod migrations { type PalletName = TipsPalletName; } - /// Upgrade Session keys to exclude `ImOnline` key. - /// When this is removed, should also remove `OldSessionKeys`. - pub struct UpgradeSessionKeys; - const UPGRADE_SESSION_KEYS_FROM_SPEC: u32 = 104000; - - impl frame_support::traits::OnRuntimeUpgrade for UpgradeSessionKeys { - #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { - if System::last_runtime_upgrade_spec_version() > UPGRADE_SESSION_KEYS_FROM_SPEC { - log::warn!(target: "runtime::session_keys", "Skipping session keys migration pre-upgrade check due to spec version (already applied?)"); - return Ok(Vec::new()); - } - - log::info!(target: "runtime::session_keys", "Collecting pre-upgrade session keys state"); - let key_ids = SessionKeys::key_ids(); - frame_support::ensure!( - key_ids.into_iter().find(|&k| *k == sp_core::crypto::key_types::IM_ONLINE) == None, - "New session keys contain the ImOnline key that should have been removed", - ); - let storage_key = pallet_session::QueuedKeys::::hashed_key(); - let mut state: Vec = Vec::new(); - frame_support::storage::unhashed::get::>( - &storage_key, - ) - .ok_or::("Queued keys are not available".into())? - .into_iter() - .for_each(|(id, keys)| { - state.extend_from_slice(id.as_slice()); - for key_id in key_ids { - state.extend_from_slice(keys.get_raw(*key_id)); - } - }); - frame_support::ensure!(state.len() > 0, "Queued keys are not empty before upgrade"); - Ok(state) - } - - fn on_runtime_upgrade() -> Weight { - if System::last_runtime_upgrade_spec_version() > UPGRADE_SESSION_KEYS_FROM_SPEC { - log::info!("Skipping session keys upgrade: already applied"); - return ::DbWeight::get().reads(1); - } - log::trace!("Upgrading session keys"); - Session::upgrade_keys::(transform_session_keys); - Perbill::from_percent(50) * BlockWeights::get().max_block - } - - #[cfg(feature = "try-runtime")] - fn post_upgrade( - old_state: sp_std::vec::Vec, - ) -> Result<(), sp_runtime::TryRuntimeError> { - if System::last_runtime_upgrade_spec_version() > UPGRADE_SESSION_KEYS_FROM_SPEC { - log::warn!(target: "runtime::session_keys", "Skipping session keys migration post-upgrade check due to spec version (already applied?)"); - return Ok(()); - } - - let key_ids = SessionKeys::key_ids(); - let mut new_state: Vec = Vec::new(); - pallet_session::QueuedKeys::::get().into_iter().for_each(|(id, keys)| { - new_state.extend_from_slice(id.as_slice()); - for key_id in key_ids { - new_state.extend_from_slice(keys.get_raw(*key_id)); - } - }); - frame_support::ensure!(new_state.len() > 0, "Queued keys are not empty after upgrade"); - frame_support::ensure!( - old_state == new_state, - "Pre-upgrade and post-upgrade keys do not match!" - ); - log::info!(target: "runtime::session_keys", "Session keys migrated successfully"); - Ok(()) - } - } - // We don't have a limit in the Relay Chain. const IDENTITY_MIGRATION_KEY_LIMIT: u64 = u64::MAX; @@ -1657,12 +1528,6 @@ pub mod migrations { pallet_grandpa::migrations::MigrateV4ToV5, parachains_configuration::migration::v10::MigrateToV10, - // Upgrade `SessionKeys` to exclude `ImOnline` - UpgradeSessionKeys, - - // Remove `im-online` pallet on-chain storage - frame_support::migrations::RemovePallet::DbWeight>, - // Migrate Identity pallet for Usernames pallet_identity::migration::versioned::V0ToV1, parachains_configuration::migration::v11::MigrateToV11, diff --git a/polkadot/runtime/westend/Cargo.toml b/polkadot/runtime/westend/Cargo.toml index 189223eebda5..a265901c5e9b 100644 --- a/polkadot/runtime/westend/Cargo.toml +++ b/polkadot/runtime/westend/Cargo.toml @@ -64,7 +64,6 @@ pallet-election-provider-multi-phase = { path = "../../../substrate/frame/electi pallet-fast-unstake = { path = "../../../substrate/frame/fast-unstake", default-features = false } pallet-grandpa = { path = "../../../substrate/frame/grandpa", default-features = false } pallet-identity = { path = "../../../substrate/frame/identity", default-features = false } -pallet-im-online = { path = "../../../substrate/frame/im-online", default-features = false } pallet-indices = { path = "../../../substrate/frame/indices", default-features = false } pallet-membership = { path = "../../../substrate/frame/membership", default-features = false } pallet-message-queue = { path = "../../../substrate/frame/message-queue", default-features = false } @@ -169,7 +168,6 @@ std = [ "pallet-fast-unstake/std", "pallet-grandpa/std", "pallet-identity/std", - "pallet-im-online/std", "pallet-indices/std", "pallet-membership/std", "pallet-message-queue/std", @@ -254,7 +252,6 @@ runtime-benchmarks = [ "pallet-fast-unstake/runtime-benchmarks", "pallet-grandpa/runtime-benchmarks", "pallet-identity/runtime-benchmarks", - "pallet-im-online/runtime-benchmarks", "pallet-indices/runtime-benchmarks", "pallet-membership/runtime-benchmarks", "pallet-message-queue/runtime-benchmarks", @@ -314,7 +311,6 @@ try-runtime = [ "pallet-fast-unstake/try-runtime", "pallet-grandpa/try-runtime", "pallet-identity/try-runtime", - "pallet-im-online/try-runtime", "pallet-indices/try-runtime", "pallet-membership/try-runtime", "pallet-message-queue/try-runtime", diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 37d236464c0a..926659b7a3fd 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -88,8 +88,7 @@ use sp_runtime::{ Keccak256, OpaqueKeys, SaturatedConversion, Verify, }, transaction_validity::{TransactionPriority, TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, BoundToRuntimeAppPublic, FixedU128, KeyTypeId, Perbill, Percent, Permill, - RuntimeAppPublic, + ApplyExtrinsicResult, FixedU128, KeyTypeId, Perbill, Percent, Permill, }; use sp_staking::SessionIndex; use sp_std::{collections::btree_map::BTreeMap, prelude::*}; @@ -405,46 +404,6 @@ parameter_types! { pub const Offset: BlockNumber = 0; } -#[derive(Clone, Debug, PartialEq, Eq, Encode, Decode)] -pub struct OldSessionKeys { - pub grandpa: ::Public, - pub babe: ::Public, - pub im_online: pallet_im_online::sr25519::AuthorityId, - pub para_validator: ::Public, - pub para_assignment: ::Public, - pub authority_discovery: ::Public, - pub beefy: ::Public, -} - -impl OpaqueKeys for OldSessionKeys { - type KeyTypeIdProviders = (); - fn key_ids() -> &'static [KeyTypeId] { - &[ - <::Public>::ID, - <::Public>::ID, - sp_core::crypto::key_types::IM_ONLINE, - <::Public>::ID, - <::Public>::ID, - <::Public>::ID, - <::Public>::ID, - ] - } - fn get_raw(&self, i: KeyTypeId) -> &[u8] { - match i { - <::Public>::ID => self.grandpa.as_ref(), - <::Public>::ID => self.babe.as_ref(), - sp_core::crypto::key_types::IM_ONLINE => self.im_online.as_ref(), - <::Public>::ID => self.para_validator.as_ref(), - <::Public>::ID => - self.para_assignment.as_ref(), - <::Public>::ID => - self.authority_discovery.as_ref(), - <::Public>::ID => self.beefy.as_ref(), - _ => &[], - } - } -} - impl_opaque_keys! { pub struct SessionKeys { pub grandpa: Grandpa, @@ -456,18 +415,6 @@ impl_opaque_keys! { } } -// remove this when removing `OldSessionKeys` -fn transform_session_keys(_v: AccountId, old: OldSessionKeys) -> SessionKeys { - SessionKeys { - grandpa: old.grandpa, - babe: old.babe, - para_validator: old.para_validator, - para_assignment: old.para_assignment, - authority_discovery: old.authority_discovery, - beefy: old.beefy, - } -} - impl pallet_session::Config for Runtime { type RuntimeEvent = RuntimeEvent; type ValidatorId = AccountId; @@ -1675,8 +1622,6 @@ pub type Migrations = migrations::Unreleased; #[allow(deprecated, missing_docs)] pub mod migrations { use super::*; - #[cfg(feature = "try-runtime")] - use sp_core::crypto::ByteArray; pub struct GetLegacyLeaseImpl; impl coretime::migration::GetLegacyLease for GetLegacyLeaseImpl { @@ -1696,83 +1641,6 @@ pub mod migrations { } } - parameter_types! { - pub const ImOnlinePalletName: &'static str = "ImOnline"; - } - - /// Upgrade Session keys to exclude `ImOnline` key. - /// When this is removed, should also remove `OldSessionKeys`. - pub struct UpgradeSessionKeys; - const UPGRADE_SESSION_KEYS_FROM_SPEC: u32 = 104000; - - impl frame_support::traits::OnRuntimeUpgrade for UpgradeSessionKeys { - #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { - if System::last_runtime_upgrade_spec_version() > UPGRADE_SESSION_KEYS_FROM_SPEC { - log::warn!(target: "runtime::session_keys", "Skipping session keys migration pre-upgrade check due to spec version (already applied?)"); - return Ok(Vec::new()); - } - - log::info!(target: "runtime::session_keys", "Collecting pre-upgrade session keys state"); - let key_ids = SessionKeys::key_ids(); - frame_support::ensure!( - key_ids.into_iter().find(|&k| *k == sp_core::crypto::key_types::IM_ONLINE) == None, - "New session keys contain the ImOnline key that should have been removed", - ); - let storage_key = pallet_session::QueuedKeys::::hashed_key(); - let mut state: Vec = Vec::new(); - frame_support::storage::unhashed::get::>( - &storage_key, - ) - .ok_or::("Queued keys are not available".into())? - .into_iter() - .for_each(|(id, keys)| { - state.extend_from_slice(id.as_slice()); - for key_id in key_ids { - state.extend_from_slice(keys.get_raw(*key_id)); - } - }); - frame_support::ensure!(state.len() > 0, "Queued keys are not empty before upgrade"); - Ok(state) - } - - fn on_runtime_upgrade() -> Weight { - if System::last_runtime_upgrade_spec_version() > UPGRADE_SESSION_KEYS_FROM_SPEC { - log::warn!("Skipping session keys upgrade: already applied"); - return ::DbWeight::get().reads(1); - } - log::info!("Upgrading session keys"); - Session::upgrade_keys::(transform_session_keys); - Perbill::from_percent(50) * BlockWeights::get().max_block - } - - #[cfg(feature = "try-runtime")] - fn post_upgrade( - old_state: sp_std::vec::Vec, - ) -> Result<(), sp_runtime::TryRuntimeError> { - if System::last_runtime_upgrade_spec_version() > UPGRADE_SESSION_KEYS_FROM_SPEC { - log::warn!(target: "runtime::session_keys", "Skipping session keys migration post-upgrade check due to spec version (already applied?)"); - return Ok(()); - } - - let key_ids = SessionKeys::key_ids(); - let mut new_state: Vec = Vec::new(); - pallet_session::QueuedKeys::::get().into_iter().for_each(|(id, keys)| { - new_state.extend_from_slice(id.as_slice()); - for key_id in key_ids { - new_state.extend_from_slice(keys.get_raw(*key_id)); - } - }); - frame_support::ensure!(new_state.len() > 0, "Queued keys are not empty after upgrade"); - frame_support::ensure!( - old_state == new_state, - "Pre-upgrade and post-upgrade keys do not match!" - ); - log::info!(target: "runtime::session_keys", "Session keys migrated successfully"); - Ok(()) - } - } - // We don't have a limit in the Relay Chain. const IDENTITY_MIGRATION_KEY_LIMIT: u64 = u64::MAX; @@ -1789,11 +1657,6 @@ pub mod migrations { pallet_grandpa::migrations::MigrateV4ToV5, parachains_configuration::migration::v10::MigrateToV10, pallet_nomination_pools::migration::unversioned::TotalValueLockedSync, - UpgradeSessionKeys, - frame_support::migrations::RemovePallet< - ImOnlinePalletName, - ::DbWeight, - >, // Migrate Identity pallet for Usernames pallet_identity::migration::versioned::V0ToV1, parachains_configuration::migration::v11::MigrateToV11, From 8f2e65413d2937b7d521264ba56391dc189261f2 Mon Sep 17 00:00:00 2001 From: Sam Johnson Date: Tue, 2 Apr 2024 01:53:51 -0400 Subject: [PATCH 097/257] Update derive syn parse 0.2.0 (+ docify) (#3920) derive-syn-parse v0.2.0 came out recently which (finally) adds support for syn 2x. Upgrading to this will remove many of the places where syn 1x was still compiling alongside syn 2x in the polkadot-sdk workspace. This also upgrades `docify` to 0.2.8 which is the version that upgrades derive-syn-pasre to 0.2.0. Additionally, this consolidates the `docify` versions in the repo to all use the latest, and in one case upgrades to the 0.2x syntax where 0.1.x was still being used. --------- Co-authored-by: Liam Aharon --- Cargo.lock | 95 ++++++++----------- .../storage-weight-reclaim/Cargo.toml | 2 +- docs/sdk/Cargo.toml | 2 +- substrate/client/chain-spec/Cargo.toml | 2 +- substrate/frame/Cargo.toml | 2 +- substrate/frame/bags-list/Cargo.toml | 2 +- substrate/frame/balances/Cargo.toml | 2 +- .../single-block-migrations/Cargo.toml | 2 +- substrate/frame/fast-unstake/Cargo.toml | 2 +- substrate/frame/migrations/Cargo.toml | 2 +- substrate/frame/migrations/src/lib.rs | 2 +- substrate/frame/paged-list/Cargo.toml | 2 +- substrate/frame/parameters/Cargo.toml | 2 +- substrate/frame/safe-mode/Cargo.toml | 2 +- substrate/frame/scheduler/Cargo.toml | 2 +- substrate/frame/sudo/Cargo.toml | 2 +- substrate/frame/support/Cargo.toml | 2 +- substrate/frame/support/procedural/Cargo.toml | 2 +- substrate/frame/system/Cargo.toml | 2 +- substrate/frame/timestamp/Cargo.toml | 2 +- substrate/frame/treasury/Cargo.toml | 2 +- substrate/frame/tx-pause/Cargo.toml | 2 +- substrate/primitives/arithmetic/Cargo.toml | 2 +- substrate/primitives/runtime/Cargo.toml | 2 +- 24 files changed, 63 insertions(+), 78 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7d2063b68f50..fa07524cbf20 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4049,7 +4049,7 @@ dependencies = [ "cumulus-primitives-core", "cumulus-primitives-proof-size-hostfunction", "cumulus-test-runtime", - "docify 0.2.7", + "docify", "frame-support", "frame-system", "log", @@ -4571,6 +4571,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "derive-syn-parse" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d65d7ce8132b7c0e54497a4d9a55a1c2a0912a0d786cf894472ba818fba45762" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.53", +] + [[package]] name = "derive_more" version = "0.99.17" @@ -4718,47 +4729,21 @@ checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" [[package]] name = "docify" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af1b04e6ef3d21119d3eb7b032bca17f99fe041e9c072f30f32cc0e1a2b1f3c4" -dependencies = [ - "docify_macros 0.1.16", -] - -[[package]] -name = "docify" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cc4fd38aaa9fb98ac70794c82a00360d1e165a87fbf96a8a91f9dfc602aaee2" +checksum = "43a2f138ad521dc4a2ced1a4576148a6a610b4c5923933b062a263130a6802ce" dependencies = [ - "docify_macros 0.2.7", + "docify_macros", ] [[package]] name = "docify_macros" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b5610df7f2acf89a1bb5d1a66ae56b1c7fcdcfe3948856fb3ace3f644d70eb7" -dependencies = [ - "common-path", - "derive-syn-parse", - "lazy_static", - "proc-macro2", - "quote", - "regex", - "syn 2.0.53", - "termcolor", - "walkdir", -] - -[[package]] -name = "docify_macros" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63fa215f3a0d40fb2a221b3aa90d8e1fbb8379785a990cb60d62ac71ebdc6460" +checksum = "1a081e51fb188742f5a7a1164ad752121abcb22874b21e2c3b0dd040c515fdad" dependencies = [ "common-path", - "derive-syn-parse", + "derive-syn-parse 0.2.0", "once_cell", "proc-macro2", "quote", @@ -5454,7 +5439,7 @@ checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" name = "frame" version = "0.0.1-dev" dependencies = [ - "docify 0.2.7", + "docify", "frame-executive", "frame-support", "frame-system", @@ -5683,7 +5668,7 @@ dependencies = [ "array-bytes 6.1.0", "assert_matches", "bitflags 1.3.2", - "docify 0.2.7", + "docify", "environmental", "frame-metadata", "frame-support-procedural", @@ -5726,7 +5711,7 @@ version = "23.0.0" dependencies = [ "Inflector", "cfg-expr", - "derive-syn-parse", + "derive-syn-parse 0.2.0", "expander 2.0.0", "frame-support-procedural-tools", "itertools 0.10.5", @@ -5827,7 +5812,7 @@ version = "28.0.0" dependencies = [ "cfg-if", "criterion 0.4.0", - "docify 0.2.7", + "docify", "frame-support", "log", "parity-scale-codec", @@ -7944,7 +7929,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "468155613a44cfd825f1fb0ffa532b018253920d404e6fca1e8d43155198a46d" dependencies = [ "const-random", - "derive-syn-parse", + "derive-syn-parse 0.1.5", "macro_magic_core_macros", "proc-macro2", "quote", @@ -9216,7 +9201,7 @@ name = "pallet-bags-list" version = "27.0.0" dependencies = [ "aquamarine 0.5.0", - "docify 0.2.7", + "docify", "frame-benchmarking", "frame-election-provider-support", "frame-support", @@ -9264,7 +9249,7 @@ dependencies = [ name = "pallet-balances" version = "28.0.0" dependencies = [ - "docify 0.2.7", + "docify", "frame-benchmarking", "frame-support", "frame-system", @@ -9906,7 +9891,7 @@ dependencies = [ name = "pallet-example-single-block-migrations" version = "0.0.1" dependencies = [ - "docify 0.2.7", + "docify", "frame-executive", "frame-support", "frame-system", @@ -9972,7 +9957,7 @@ dependencies = [ name = "pallet-fast-unstake" version = "27.0.0" dependencies = [ - "docify 0.2.7", + "docify", "frame-benchmarking", "frame-election-provider-support", "frame-support", @@ -10173,7 +10158,7 @@ dependencies = [ name = "pallet-migrations" version = "1.0.0" dependencies = [ - "docify 0.1.16", + "docify", "frame-benchmarking", "frame-executive", "frame-support", @@ -10503,7 +10488,7 @@ dependencies = [ name = "pallet-paged-list" version = "0.6.0" dependencies = [ - "docify 0.2.7", + "docify", "frame-benchmarking", "frame-support", "frame-system", @@ -10545,7 +10530,7 @@ dependencies = [ name = "pallet-parameters" version = "0.0.1" dependencies = [ - "docify 0.2.7", + "docify", "frame-benchmarking", "frame-support", "frame-system", @@ -10706,7 +10691,7 @@ dependencies = [ name = "pallet-safe-mode" version = "9.0.0" dependencies = [ - "docify 0.2.7", + "docify", "frame-benchmarking", "frame-support", "frame-system", @@ -10763,7 +10748,7 @@ dependencies = [ name = "pallet-scheduler" version = "29.0.0" dependencies = [ - "docify 0.2.7", + "docify", "frame-benchmarking", "frame-support", "frame-system", @@ -10976,7 +10961,7 @@ dependencies = [ name = "pallet-sudo" version = "28.0.0" dependencies = [ - "docify 0.2.7", + "docify", "frame-benchmarking", "frame-support", "frame-system", @@ -11006,7 +10991,7 @@ dependencies = [ name = "pallet-timestamp" version = "27.0.0" dependencies = [ - "docify 0.2.7", + "docify", "frame-benchmarking", "frame-support", "frame-system", @@ -11110,7 +11095,7 @@ dependencies = [ name = "pallet-treasury" version = "27.0.0" dependencies = [ - "docify 0.2.7", + "docify", "frame-benchmarking", "frame-support", "frame-system", @@ -11130,7 +11115,7 @@ dependencies = [ name = "pallet-tx-pause" version = "9.0.0" dependencies = [ - "docify 0.2.7", + "docify", "frame-benchmarking", "frame-support", "frame-system", @@ -13419,7 +13404,7 @@ version = "0.0.1" dependencies = [ "cumulus-pallet-aura-ext", "cumulus-pallet-parachain-system", - "docify 0.2.7", + "docify", "frame", "frame-executive", "frame-support", @@ -15681,7 +15666,7 @@ name = "sc-chain-spec" version = "27.0.0" dependencies = [ "array-bytes 6.1.0", - "docify 0.2.7", + "docify", "log", "memmap2 0.9.3", "parity-scale-codec", @@ -18458,7 +18443,7 @@ name = "sp-arithmetic" version = "23.0.0" dependencies = [ "criterion 0.4.0", - "docify 0.2.7", + "docify", "integer-sqrt", "num-traits", "parity-scale-codec", @@ -19008,7 +18993,7 @@ dependencies = [ name = "sp-runtime" version = "31.0.1" dependencies = [ - "docify 0.2.7", + "docify", "either", "hash256-std-hasher", "impl-trait-for-tuples", diff --git a/cumulus/primitives/storage-weight-reclaim/Cargo.toml b/cumulus/primitives/storage-weight-reclaim/Cargo.toml index 73e0f03cd375..54eec3ffb5e3 100644 --- a/cumulus/primitives/storage-weight-reclaim/Cargo.toml +++ b/cumulus/primitives/storage-weight-reclaim/Cargo.toml @@ -22,7 +22,7 @@ sp-std = { path = "../../../substrate/primitives/std", default-features = false cumulus-primitives-core = { path = "../core", default-features = false } cumulus-primitives-proof-size-hostfunction = { path = "../proof-size-hostfunction", default-features = false } -docify = "0.2.7" +docify = "0.2.8" [dev-dependencies] sp-trie = { path = "../../../substrate/primitives/trie", default-features = false } diff --git a/docs/sdk/Cargo.toml b/docs/sdk/Cargo.toml index 3b8f45d7756e..64b23866f0cd 100644 --- a/docs/sdk/Cargo.toml +++ b/docs/sdk/Cargo.toml @@ -27,7 +27,7 @@ pallet-example-offchain-worker = { path = "../../substrate/frame/examples/offcha # How we build docs in rust-docs simple-mermaid = "0.1.1" -docify = "0.2.7" +docify = "0.2.8" # Polkadot SDK deps, typically all should only be in scope such that we can link to their doc item. node-cli = { package = "staging-node-cli", path = "../../substrate/bin/node/cli" } diff --git a/substrate/client/chain-spec/Cargo.toml b/substrate/client/chain-spec/Cargo.toml index f2138c07d71a..f569b5f14a66 100644 --- a/substrate/client/chain-spec/Cargo.toml +++ b/substrate/client/chain-spec/Cargo.toml @@ -34,7 +34,7 @@ sp-runtime = { path = "../../primitives/runtime" } sp-state-machine = { path = "../../primitives/state-machine" } log = { workspace = true } array-bytes = { version = "6.1" } -docify = "0.2.7" +docify = "0.2.8" [dev-dependencies] substrate-test-runtime = { path = "../../test-utils/runtime" } diff --git a/substrate/frame/Cargo.toml b/substrate/frame/Cargo.toml index 6746723e72f7..ab394592071d 100644 --- a/substrate/frame/Cargo.toml +++ b/substrate/frame/Cargo.toml @@ -51,7 +51,7 @@ sp-inherents = { default-features = false, path = "../primitives/inherents", opt frame-executive = { default-features = false, path = "../frame/executive", optional = true } frame-system-rpc-runtime-api = { default-features = false, path = "../frame/system/rpc/runtime-api", optional = true } -docify = "0.2.7" +docify = "0.2.8" log = { workspace = true } [dev-dependencies] diff --git a/substrate/frame/bags-list/Cargo.toml b/substrate/frame/bags-list/Cargo.toml index f9ae462e16d7..49d28482c329 100644 --- a/substrate/frame/bags-list/Cargo.toml +++ b/substrate/frame/bags-list/Cargo.toml @@ -34,7 +34,7 @@ frame-election-provider-support = { path = "../election-provider-support", defau # third party log = { workspace = true } -docify = "0.2.7" +docify = "0.2.8" aquamarine = { version = "0.5.0" } # Optional imports for benchmarking diff --git a/substrate/frame/balances/Cargo.toml b/substrate/frame/balances/Cargo.toml index 64ae90c67575..b27a5bb24787 100644 --- a/substrate/frame/balances/Cargo.toml +++ b/substrate/frame/balances/Cargo.toml @@ -24,7 +24,7 @@ frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } sp-runtime = { path = "../../primitives/runtime", default-features = false } sp-std = { path = "../../primitives/std", default-features = false } -docify = "0.2.6" +docify = "0.2.8" [dev-dependencies] pallet-transaction-payment = { path = "../transaction-payment" } diff --git a/substrate/frame/examples/single-block-migrations/Cargo.toml b/substrate/frame/examples/single-block-migrations/Cargo.toml index 613742a6787c..1020cc9e2bb9 100644 --- a/substrate/frame/examples/single-block-migrations/Cargo.toml +++ b/substrate/frame/examples/single-block-migrations/Cargo.toml @@ -13,7 +13,7 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -docify = { version = "0.2.3", default-features = false } +docify = "0.2.8" log = { version = "0.4.21", default-features = false } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } diff --git a/substrate/frame/fast-unstake/Cargo.toml b/substrate/frame/fast-unstake/Cargo.toml index eca8247845e2..fb425dc310d4 100644 --- a/substrate/frame/fast-unstake/Cargo.toml +++ b/substrate/frame/fast-unstake/Cargo.toml @@ -30,7 +30,7 @@ frame-election-provider-support = { path = "../election-provider-support", defau frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } -docify = "0.2.7" +docify = "0.2.8" [dev-dependencies] pallet-staking-reward-curve = { path = "../staking/reward-curve" } diff --git a/substrate/frame/migrations/Cargo.toml b/substrate/frame/migrations/Cargo.toml index 40059fb9ec43..0a91d2f94c4c 100644 --- a/substrate/frame/migrations/Cargo.toml +++ b/substrate/frame/migrations/Cargo.toml @@ -12,7 +12,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -docify = "0.1.14" +docify = "0.2.8" impl-trait-for-tuples = "0.2.2" log = "0.4.21" scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } diff --git a/substrate/frame/migrations/src/lib.rs b/substrate/frame/migrations/src/lib.rs index cd57d89f440f..30ed9c08830c 100644 --- a/substrate/frame/migrations/src/lib.rs +++ b/substrate/frame/migrations/src/lib.rs @@ -35,7 +35,7 @@ //! succeeding after two steps. A runtime upgrade is then enacted and the block number is advanced //! until all migrations finish executing. Afterwards, the recorded historic migrations are //! checked and events are asserted. -#![doc = docify::embed!("substrate/frame/migrations/src/tests.rs", simple_works)] +#![doc = docify::embed!("src/tests.rs", simple_works)] //! //! ## Pallet API //! diff --git a/substrate/frame/paged-list/Cargo.toml b/substrate/frame/paged-list/Cargo.toml index 6a2af120f32a..bbe8e33d484d 100644 --- a/substrate/frame/paged-list/Cargo.toml +++ b/substrate/frame/paged-list/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -docify = "0.2.7" +docify = "0.2.8" scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } diff --git a/substrate/frame/parameters/Cargo.toml b/substrate/frame/parameters/Cargo.toml index 07ebeea52d52..ab93be14e6c3 100644 --- a/substrate/frame/parameters/Cargo.toml +++ b/substrate/frame/parameters/Cargo.toml @@ -12,7 +12,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.1.2", default-features = false, features = ["derive"] } paste = { version = "1.0.14", default-features = false } serde = { features = ["derive"], optional = true, workspace = true, default-features = true } -docify = "0.2.5" +docify = "0.2.8" frame-support = { path = "../support", default-features = false, features = ["experimental"] } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/safe-mode/Cargo.toml b/substrate/frame/safe-mode/Cargo.toml index 0c59740bef30..6ddeff263c1a 100644 --- a/substrate/frame/safe-mode/Cargo.toml +++ b/substrate/frame/safe-mode/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } -docify = "0.2.7" +docify = "0.2.8" frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/scheduler/Cargo.toml b/substrate/frame/scheduler/Cargo.toml index f50f6afdc063..a3e684a20836 100644 --- a/substrate/frame/scheduler/Cargo.toml +++ b/substrate/frame/scheduler/Cargo.toml @@ -23,7 +23,7 @@ sp-io = { path = "../../primitives/io", default-features = false } sp-runtime = { path = "../../primitives/runtime", default-features = false } sp-std = { path = "../../primitives/std", default-features = false } sp-weights = { path = "../../primitives/weights", default-features = false } -docify = "0.2.7" +docify = "0.2.8" [dev-dependencies] pallet-preimage = { path = "../preimage" } diff --git a/substrate/frame/sudo/Cargo.toml b/substrate/frame/sudo/Cargo.toml index 409104aeca11..a60324847f1a 100644 --- a/substrate/frame/sudo/Cargo.toml +++ b/substrate/frame/sudo/Cargo.toml @@ -25,7 +25,7 @@ sp-io = { path = "../../primitives/io", default-features = false } sp-runtime = { path = "../../primitives/runtime", default-features = false } sp-std = { path = "../../primitives/std", default-features = false } -docify = "0.2.7" +docify = "0.2.8" [dev-dependencies] sp-core = { path = "../../primitives/core" } diff --git a/substrate/frame/support/Cargo.toml b/substrate/frame/support/Cargo.toml index be60068f1220..3a61cfa6fac6 100644 --- a/substrate/frame/support/Cargo.toml +++ b/substrate/frame/support/Cargo.toml @@ -58,7 +58,7 @@ k256 = { version = "0.13.1", default-features = false, features = ["ecdsa"] } environmental = { version = "1.1.4", default-features = false } sp-genesis-builder = { path = "../../primitives/genesis-builder", default-features = false } serde_json = { features = ["alloc"], workspace = true } -docify = "0.2.7" +docify = "0.2.8" static_assertions = "1.1.0" aquamarine = { version = "0.5.0" } diff --git a/substrate/frame/support/procedural/Cargo.toml b/substrate/frame/support/procedural/Cargo.toml index dd0688f2ad06..9f8727f7adef 100644 --- a/substrate/frame/support/procedural/Cargo.toml +++ b/substrate/frame/support/procedural/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] proc-macro = true [dependencies] -derive-syn-parse = "0.1.5" +derive-syn-parse = "0.2.0" Inflector = "0.11.4" cfg-expr = "0.15.5" itertools = "0.10.3" diff --git a/substrate/frame/system/Cargo.toml b/substrate/frame/system/Cargo.toml index 416969e9c477..d094c6bf9849 100644 --- a/substrate/frame/system/Cargo.toml +++ b/substrate/frame/system/Cargo.toml @@ -28,7 +28,7 @@ sp-runtime = { path = "../../primitives/runtime", default-features = false, feat sp-std = { path = "../../primitives/std", default-features = false } sp-version = { path = "../../primitives/version", default-features = false, features = ["serde"] } sp-weights = { path = "../../primitives/weights", default-features = false, features = ["serde"] } -docify = "0.2.7" +docify = "0.2.8" [dev-dependencies] criterion = "0.4.0" diff --git a/substrate/frame/timestamp/Cargo.toml b/substrate/frame/timestamp/Cargo.toml index 28e57fcab0a7..d8ba45a2ad28 100644 --- a/substrate/frame/timestamp/Cargo.toml +++ b/substrate/frame/timestamp/Cargo.toml @@ -30,7 +30,7 @@ sp-std = { path = "../../primitives/std", default-features = false } sp-storage = { path = "../../primitives/storage", default-features = false } sp-timestamp = { path = "../../primitives/timestamp", default-features = false } -docify = "0.2.7" +docify = "0.2.8" [dev-dependencies] sp-core = { path = "../../primitives/core" } diff --git a/substrate/frame/treasury/Cargo.toml b/substrate/frame/treasury/Cargo.toml index 5f90904123d9..16bb4e92520b 100644 --- a/substrate/frame/treasury/Cargo.toml +++ b/substrate/frame/treasury/Cargo.toml @@ -20,7 +20,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "derive", "max-encoded-len", ] } -docify = "0.2.7" +docify = "0.2.8" impl-trait-for-tuples = "0.2.2" scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } serde = { features = ["derive"], optional = true, workspace = true, default-features = true } diff --git a/substrate/frame/tx-pause/Cargo.toml b/substrate/frame/tx-pause/Cargo.toml index ace2172454eb..a5916c048f46 100644 --- a/substrate/frame/tx-pause/Cargo.toml +++ b/substrate/frame/tx-pause/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } -docify = "0.2.7" +docify = "0.2.8" frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/primitives/arithmetic/Cargo.toml b/substrate/primitives/arithmetic/Cargo.toml index 120edd06a660..45f48d77a311 100644 --- a/substrate/primitives/arithmetic/Cargo.toml +++ b/substrate/primitives/arithmetic/Cargo.toml @@ -27,7 +27,7 @@ scale-info = { version = "2.10.0", default-features = false, features = ["derive serde = { features = ["alloc", "derive"], optional = true, workspace = true } static_assertions = "1.1.0" sp-std = { path = "../std", default-features = false } -docify = "0.2.7" +docify = "0.2.8" [dev-dependencies] criterion = "0.4.0" diff --git a/substrate/primitives/runtime/Cargo.toml b/substrate/primitives/runtime/Cargo.toml index cacfc0597229..3128ebce8f7a 100644 --- a/substrate/primitives/runtime/Cargo.toml +++ b/substrate/primitives/runtime/Cargo.toml @@ -32,7 +32,7 @@ sp-core = { path = "../core", default-features = false } sp-io = { path = "../io", default-features = false } sp-std = { path = "../std", default-features = false } sp-weights = { path = "../weights", default-features = false } -docify = { version = "0.2.7" } +docify = "0.2.8" simple-mermaid = { version = "0.1.1", optional = true } From 00529bce647edfe5e637d1c096bcd175854d57ed Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Tue, 2 Apr 2024 10:57:35 +0300 Subject: [PATCH 098/257] pallet-xcm: fix weights for all XTs and deprecate unlimited weight ones (#3927) Fix "double-weights" for extrinsics, use only the ones benchmarked in the runtime. Deprecate extrinsics that don't specify WeightLimit, remove their usage across the repo. --------- Signed-off-by: Adrian Catangiu Co-authored-by: command-bot <> --- .../asset-hub-rococo/src/tests/teleport.rs | 143 ------------------ .../asset-hub-westend/src/tests/teleport.rs | 143 ------------------ .../bridge-hub-rococo/src/tests/snowbridge.rs | 3 +- .../src/weights/pallet_xcm.rs | 92 +++++------ .../parachains/runtimes/test-utils/src/lib.rs | 3 +- polkadot/runtime/westend/src/tests.rs | 3 +- polkadot/xcm/pallet-xcm/src/lib.rs | 131 ++-------------- .../pallet-xcm/src/tests/assets_transfer.rs | 81 +++------- polkadot/xcm/xcm-simulator/example/src/lib.rs | 3 +- prdoc/pr_3927.prdoc | 13 ++ 10 files changed, 103 insertions(+), 512 deletions(-) create mode 100644 prdoc/pr_3927.prdoc diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs index 4432999aa955..1cbb7fb8c193 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/teleport.rs @@ -245,16 +245,6 @@ fn relay_limited_teleport_assets(t: RelayToSystemParaTest) -> DispatchResult { ) } -fn relay_teleport_assets(t: RelayToSystemParaTest) -> DispatchResult { - ::XcmPallet::teleport_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - ) -} - fn system_para_limited_teleport_assets(t: SystemParaToRelayTest) -> DispatchResult { ::PolkadotXcm::limited_teleport_assets( t.signed_origin, @@ -266,16 +256,6 @@ fn system_para_limited_teleport_assets(t: SystemParaToRelayTest) -> DispatchResu ) } -fn system_para_teleport_assets(t: SystemParaToRelayTest) -> DispatchResult { - ::PolkadotXcm::teleport_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - ) -} - fn para_to_system_para_transfer_assets(t: ParaToSystemParaTest) -> DispatchResult { ::PolkadotXcm::transfer_assets( t.signed_origin, @@ -421,129 +401,6 @@ fn limited_teleport_native_assets_from_system_para_to_relay_fails() { assert_eq!(receiver_balance_after, receiver_balance_before); } -/// Teleport of native asset from Relay Chain to the System Parachain should work -#[test] -fn teleport_native_assets_from_relay_to_system_para_works() { - // Init values for Relay Chain - let amount_to_send: Balance = ROCOCO_ED * 1000; - let dest = Rococo::child_location_of(AssetHubRococo::para_id()); - let beneficiary_id = AssetHubRococoReceiver::get(); - let test_args = TestContext { - sender: RococoSender::get(), - receiver: AssetHubRococoReceiver::get(), - args: TestArgs::new_relay(dest, beneficiary_id, amount_to_send), - }; - - let mut test = RelayToSystemParaTest::new(test_args); - - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; - - test.set_assertion::(relay_origin_assertions); - test.set_assertion::(para_dest_assertions); - test.set_dispatchable::(relay_teleport_assets); - test.assert(); - - let delivery_fees = Rococo::execute_with(|| { - xcm_helpers::teleport_assets_delivery_fees::< - ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); - - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); - // Receiver's balance is increased - assert!(receiver_balance_after > receiver_balance_before); -} - -/// Teleport of native asset from System Parachains to the Relay Chain -/// should work when there is enough balance in Relay Chain's `CheckAccount` -#[test] -fn teleport_native_assets_back_from_system_para_to_relay_works() { - // Dependency - Relay Chain's `CheckAccount` should have enough balance - teleport_native_assets_from_relay_to_system_para_works(); - - // Init values for Relay Chain - let amount_to_send: Balance = ASSET_HUB_ROCOCO_ED * 1000; - let destination = AssetHubRococo::parent_location(); - let beneficiary_id = RococoReceiver::get(); - let assets = (Parent, amount_to_send).into(); - - let test_args = TestContext { - sender: AssetHubRococoSender::get(), - receiver: RococoReceiver::get(), - args: TestArgs::new_para(destination, beneficiary_id, amount_to_send, assets, None, 0), - }; - - let mut test = SystemParaToRelayTest::new(test_args); - - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; - - test.set_assertion::(para_origin_assertions); - test.set_assertion::(relay_dest_assertions); - test.set_dispatchable::(system_para_teleport_assets); - test.assert(); - - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - let delivery_fees = AssetHubRococo::execute_with(|| { - xcm_helpers::teleport_assets_delivery_fees::< - ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); - - // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); - // Receiver's balance is increased - assert!(receiver_balance_after > receiver_balance_before); -} - -/// Teleport of native asset from System Parachain to Relay Chain -/// shouldn't work when there is not enough balance in Relay Chain's `CheckAccount` -#[test] -fn teleport_native_assets_from_system_para_to_relay_fails() { - // Init values for Relay Chain - let amount_to_send: Balance = ASSET_HUB_ROCOCO_ED * 1000; - let destination = AssetHubRococo::parent_location(); - let beneficiary_id = RococoReceiver::get(); - let assets = (Parent, amount_to_send).into(); - - let test_args = TestContext { - sender: AssetHubRococoSender::get(), - receiver: RococoReceiver::get(), - args: TestArgs::new_para(destination, beneficiary_id, amount_to_send, assets, None, 0), - }; - - let mut test = SystemParaToRelayTest::new(test_args); - - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; - - test.set_assertion::(para_origin_assertions); - test.set_assertion::(relay_dest_assertions_fail); - test.set_dispatchable::(system_para_teleport_assets); - test.assert(); - - let delivery_fees = AssetHubRococo::execute_with(|| { - xcm_helpers::teleport_assets_delivery_fees::< - ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); - - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); - // Receiver's balance does not change - assert_eq!(receiver_balance_after, receiver_balance_before); -} - #[test] fn teleport_to_other_system_parachains_works() { let amount = ASSET_HUB_ROCOCO_ED * 100; diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs index aba05ea4322c..ac518d2ed4a4 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/teleport.rs @@ -245,16 +245,6 @@ fn relay_limited_teleport_assets(t: RelayToSystemParaTest) -> DispatchResult { ) } -fn relay_teleport_assets(t: RelayToSystemParaTest) -> DispatchResult { - ::XcmPallet::teleport_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - ) -} - fn system_para_limited_teleport_assets(t: SystemParaToRelayTest) -> DispatchResult { ::PolkadotXcm::limited_teleport_assets( t.signed_origin, @@ -266,16 +256,6 @@ fn system_para_limited_teleport_assets(t: SystemParaToRelayTest) -> DispatchResu ) } -fn system_para_teleport_assets(t: SystemParaToRelayTest) -> DispatchResult { - ::PolkadotXcm::teleport_assets( - t.signed_origin, - bx!(t.args.dest.into()), - bx!(t.args.beneficiary.into()), - bx!(t.args.assets.into()), - t.args.fee_asset_item, - ) -} - fn para_to_system_para_transfer_assets(t: ParaToSystemParaTest) -> DispatchResult { ::PolkadotXcm::transfer_assets( t.signed_origin, @@ -421,129 +401,6 @@ fn limited_teleport_native_assets_from_system_para_to_relay_fails() { assert_eq!(receiver_balance_after, receiver_balance_before); } -/// Teleport of native asset from Relay Chain to the System Parachain should work -#[test] -fn teleport_native_assets_from_relay_to_system_para_works() { - // Init values for Relay Chain - let amount_to_send: Balance = WESTEND_ED * 1000; - let dest = Westend::child_location_of(AssetHubWestend::para_id()); - let beneficiary_id = AssetHubWestendReceiver::get(); - let test_args = TestContext { - sender: WestendSender::get(), - receiver: AssetHubWestendReceiver::get(), - args: TestArgs::new_relay(dest, beneficiary_id, amount_to_send), - }; - - let mut test = RelayToSystemParaTest::new(test_args); - - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; - - test.set_assertion::(relay_origin_assertions); - test.set_assertion::(para_dest_assertions); - test.set_dispatchable::(relay_teleport_assets); - test.assert(); - - let delivery_fees = Westend::execute_with(|| { - xcm_helpers::teleport_assets_delivery_fees::< - ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); - - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); - // Receiver's balance is increased - assert!(receiver_balance_after > receiver_balance_before); -} - -/// Teleport of native asset from System Parachains to the Relay Chain -/// should work when there is enough balance in Relay Chain's `CheckAccount` -#[test] -fn teleport_native_assets_back_from_system_para_to_relay_works() { - // Dependency - Relay Chain's `CheckAccount` should have enough balance - teleport_native_assets_from_relay_to_system_para_works(); - - // Init values for Relay Chain - let amount_to_send: Balance = ASSET_HUB_WESTEND_ED * 1000; - let destination = AssetHubWestend::parent_location(); - let beneficiary_id = WestendReceiver::get(); - let assets = (Parent, amount_to_send).into(); - - let test_args = TestContext { - sender: AssetHubWestendSender::get(), - receiver: WestendReceiver::get(), - args: TestArgs::new_para(destination, beneficiary_id, amount_to_send, assets, None, 0), - }; - - let mut test = SystemParaToRelayTest::new(test_args); - - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; - - test.set_assertion::(para_origin_assertions); - test.set_assertion::(relay_dest_assertions); - test.set_dispatchable::(system_para_teleport_assets); - test.assert(); - - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - let delivery_fees = AssetHubWestend::execute_with(|| { - xcm_helpers::teleport_assets_delivery_fees::< - ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); - - // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); - // Receiver's balance is increased - assert!(receiver_balance_after > receiver_balance_before); -} - -/// Teleport of native asset from System Parachain to Relay Chain -/// shouldn't work when there is not enough balance in Relay Chain's `CheckAccount` -#[test] -fn teleport_native_assets_from_system_para_to_relay_fails() { - // Init values for Relay Chain - let amount_to_send: Balance = ASSET_HUB_WESTEND_ED * 1000; - let destination = AssetHubWestend::parent_location(); - let beneficiary_id = WestendReceiver::get(); - let assets = (Parent, amount_to_send).into(); - - let test_args = TestContext { - sender: AssetHubWestendSender::get(), - receiver: WestendReceiver::get(), - args: TestArgs::new_para(destination, beneficiary_id, amount_to_send, assets, None, 0), - }; - - let mut test = SystemParaToRelayTest::new(test_args); - - let sender_balance_before = test.sender.balance; - let receiver_balance_before = test.receiver.balance; - - test.set_assertion::(para_origin_assertions); - test.set_assertion::(relay_dest_assertions_fail); - test.set_dispatchable::(system_para_teleport_assets); - test.assert(); - - let delivery_fees = AssetHubWestend::execute_with(|| { - xcm_helpers::teleport_assets_delivery_fees::< - ::XcmSender, - >(test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest) - }); - - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; - - // Sender's balance is reduced - assert_eq!(sender_balance_before - amount_to_send - delivery_fees, sender_balance_after); - // Receiver's balance does not change - assert_eq!(receiver_balance_after, receiver_balance_before); -} - #[test] fn teleport_to_other_system_parachains_works() { let amount = ASSET_HUB_WESTEND_ED * 100; diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs index caaf24e00a8a..1804f9d4b67d 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs @@ -458,12 +458,13 @@ fn send_weth_asset_from_asset_hub_to_ethereum() { AssetHubRococoReceiver::get(), ); // Send the Weth back to Ethereum - ::PolkadotXcm::reserve_transfer_assets( + ::PolkadotXcm::limited_reserve_transfer_assets( RuntimeOrigin::signed(AssetHubRococoReceiver::get()), Box::new(destination), Box::new(beneficiary), Box::new(multi_assets), 0, + Unlimited, ) .unwrap(); let free_balance_after = ::Balances::free_balance( diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs index 299e4b8b3cd1..a36c25f96043 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-04-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-f3xfxtob-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -64,8 +64,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 21_722_000 picoseconds. - Weight::from_parts(22_253_000, 0) + // Minimum execution time: 21_050_000 picoseconds. + Weight::from_parts(21_834_000, 0) .saturating_add(Weight::from_parts(0, 3610)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) @@ -86,8 +86,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 21_694_000 picoseconds. - Weight::from_parts(22_326_000, 0) + // Minimum execution time: 21_164_000 picoseconds. + Weight::from_parts(21_656_000, 0) .saturating_add(Weight::from_parts(0, 3610)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) @@ -112,8 +112,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 94_422_000 picoseconds. - Weight::from_parts(96_997_000, 0) + // Minimum execution time: 92_497_000 picoseconds. + Weight::from_parts(95_473_000, 0) .saturating_add(Weight::from_parts(0, 3610)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) @@ -140,8 +140,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `367` // Estimated: `6196` - // Minimum execution time: 123_368_000 picoseconds. - Weight::from_parts(125_798_000, 0) + // Minimum execution time: 120_059_000 picoseconds. + Weight::from_parts(122_894_000, 0) .saturating_add(Weight::from_parts(0, 6196)) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(5)) @@ -170,8 +170,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `496` // Estimated: `6208` - // Minimum execution time: 142_033_000 picoseconds. - Weight::from_parts(145_702_000, 0) + // Minimum execution time: 141_977_000 picoseconds. + Weight::from_parts(145_981_000, 0) .saturating_add(Weight::from_parts(0, 6208)) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(7)) @@ -180,16 +180,16 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_558_000 picoseconds. - Weight::from_parts(7_916_000, 0) + // Minimum execution time: 7_426_000 picoseconds. + Weight::from_parts(7_791_000, 0) .saturating_add(Weight::from_parts(0, 0)) } fn execute_blob() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_978_000 picoseconds. - Weight::from_parts(8_210_000, 0) + // Minimum execution time: 7_585_000 picoseconds. + Weight::from_parts(7_897_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// Storage: `PolkadotXcm::SupportedVersion` (r:0 w:1) @@ -198,8 +198,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_439_000 picoseconds. - Weight::from_parts(6_711_000, 0) + // Minimum execution time: 6_224_000 picoseconds. + Weight::from_parts(6_793_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -209,8 +209,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_982_000 picoseconds. - Weight::from_parts(2_260_000, 0) + // Minimum execution time: 1_812_000 picoseconds. + Weight::from_parts(2_008_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -236,8 +236,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 27_120_000 picoseconds. - Weight::from_parts(28_048_000, 0) + // Minimum execution time: 26_586_000 picoseconds. + Weight::from_parts(27_181_000, 0) .saturating_add(Weight::from_parts(0, 3610)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(5)) @@ -262,8 +262,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `363` // Estimated: `3828` - // Minimum execution time: 29_354_000 picoseconds. - Weight::from_parts(30_205_000, 0) + // Minimum execution time: 28_295_000 picoseconds. + Weight::from_parts(29_280_000, 0) .saturating_add(Weight::from_parts(0, 3828)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(4)) @@ -274,8 +274,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_926_000 picoseconds. - Weight::from_parts(2_013_000, 0) + // Minimum execution time: 1_803_000 picoseconds. + Weight::from_parts(1_876_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -285,8 +285,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `159` // Estimated: `13524` - // Minimum execution time: 18_611_000 picoseconds. - Weight::from_parts(19_120_000, 0) + // Minimum execution time: 18_946_000 picoseconds. + Weight::from_parts(19_456_000, 0) .saturating_add(Weight::from_parts(0, 13524)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -297,8 +297,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `163` // Estimated: `13528` - // Minimum execution time: 18_373_000 picoseconds. - Weight::from_parts(18_945_000, 0) + // Minimum execution time: 19_080_000 picoseconds. + Weight::from_parts(19_498_000, 0) .saturating_add(Weight::from_parts(0, 13528)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -309,8 +309,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `173` // Estimated: `16013` - // Minimum execution time: 20_459_000 picoseconds. - Weight::from_parts(20_951_000, 0) + // Minimum execution time: 20_637_000 picoseconds. + Weight::from_parts(21_388_000, 0) .saturating_add(Weight::from_parts(0, 16013)) .saturating_add(T::DbWeight::get().reads(6)) } @@ -332,8 +332,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `212` // Estimated: `6152` - // Minimum execution time: 26_003_000 picoseconds. - Weight::from_parts(26_678_000, 0) + // Minimum execution time: 25_701_000 picoseconds. + Weight::from_parts(26_269_000, 0) .saturating_add(Weight::from_parts(0, 6152)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(3)) @@ -344,8 +344,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `206` // Estimated: `11096` - // Minimum execution time: 11_557_000 picoseconds. - Weight::from_parts(11_868_000, 0) + // Minimum execution time: 11_949_000 picoseconds. + Weight::from_parts(12_249_000, 0) .saturating_add(Weight::from_parts(0, 11096)) .saturating_add(T::DbWeight::get().reads(4)) } @@ -355,8 +355,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `170` // Estimated: `13535` - // Minimum execution time: 18_710_000 picoseconds. - Weight::from_parts(19_240_000, 0) + // Minimum execution time: 19_278_000 picoseconds. + Weight::from_parts(19_538_000, 0) .saturating_add(Weight::from_parts(0, 13535)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -379,8 +379,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `212` // Estimated: `13577` - // Minimum execution time: 34_393_000 picoseconds. - Weight::from_parts(35_138_000, 0) + // Minimum execution time: 35_098_000 picoseconds. + Weight::from_parts(35_871_000, 0) .saturating_add(Weight::from_parts(0, 13577)) .saturating_add(T::DbWeight::get().reads(11)) .saturating_add(T::DbWeight::get().writes(4)) @@ -393,8 +393,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `1588` - // Minimum execution time: 4_043_000 picoseconds. - Weight::from_parts(4_216_000, 0) + // Minimum execution time: 3_862_000 picoseconds. + Weight::from_parts(4_082_000, 0) .saturating_add(Weight::from_parts(0, 1588)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) @@ -405,8 +405,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `7740` // Estimated: `11205` - // Minimum execution time: 25_410_000 picoseconds. - Weight::from_parts(26_019_000, 0) + // Minimum execution time: 25_423_000 picoseconds. + Weight::from_parts(25_872_000, 0) .saturating_add(Weight::from_parts(0, 11205)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -417,8 +417,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `160` // Estimated: `3625` - // Minimum execution time: 38_850_000 picoseconds. - Weight::from_parts(39_593_000, 0) + // Minimum execution time: 37_148_000 picoseconds. + Weight::from_parts(37_709_000, 0) .saturating_add(Weight::from_parts(0, 3625)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) diff --git a/cumulus/parachains/runtimes/test-utils/src/lib.rs b/cumulus/parachains/runtimes/test-utils/src/lib.rs index e62daa16a125..3c84243306fb 100644 --- a/cumulus/parachains/runtimes/test-utils/src/lib.rs +++ b/cumulus/parachains/runtimes/test-utils/src/lib.rs @@ -425,12 +425,13 @@ impl< } // do teleport - >::teleport_assets( + >::limited_teleport_assets( origin, Box::new(dest.into()), Box::new(beneficiary.into()), Box::new((AssetId(asset), amount).into()), 0, + Unlimited, ) } } diff --git a/polkadot/runtime/westend/src/tests.rs b/polkadot/runtime/westend/src/tests.rs index bdd599d2b752..4acb81e963b2 100644 --- a/polkadot/runtime/westend/src/tests.rs +++ b/polkadot/runtime/westend/src/tests.rs @@ -54,11 +54,12 @@ fn sanity_check_teleport_assets_weight() { // Usually when XCM runs into an issue, it will return a weight of `Weight::MAX`, // so this test will certainly ensure that this problem does not occur. use frame_support::dispatch::GetDispatchInfo; - let weight = pallet_xcm::Call::::teleport_assets { + let weight = pallet_xcm::Call::::limited_teleport_assets { dest: Box::new(Here.into()), beneficiary: Box::new(Here.into()), assets: Box::new((Here, 200_000).into()), fee_asset_item: 0, + weight_limit: Unlimited, } .get_dispatch_info() .weight; diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 29b61988f73c..ef255068734a 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -940,13 +940,12 @@ pub mod pallet { } } - #[pallet::call] + #[pallet::call(weight(::WeightInfo))] impl Pallet { /// WARNING: DEPRECATED. `send` will be removed after June 2024. Use `send_blob` instead. #[allow(deprecated)] #[deprecated(note = "`send` will be removed after June 2024. Use `send_blob` instead.")] #[pallet::call_index(0)] - #[pallet::weight(T::WeightInfo::send())] pub fn send( origin: OriginFor, dest: Box, @@ -976,23 +975,10 @@ pub mod pallet { /// - `fee_asset_item`: The index into `assets` of the item which should be used to pay /// fees. #[pallet::call_index(1)] - #[pallet::weight({ - let maybe_assets: Result = (*assets.clone()).try_into(); - let maybe_dest: Result = (*dest.clone()).try_into(); - match (maybe_assets, maybe_dest) { - (Ok(assets), Ok(dest)) => { - use sp_std::vec; - let count = assets.len() as u32; - let mut message = Xcm(vec![ - WithdrawAsset(assets), - SetFeesMode { jit_withdraw: true }, - InitiateTeleport { assets: Wild(AllCounted(count)), dest, xcm: Xcm(vec![]) }, - ]); - T::Weigher::weight(&mut message).map_or(Weight::MAX, |w| T::WeightInfo::teleport_assets().saturating_add(w)) - } - _ => Weight::MAX, - } - })] + #[allow(deprecated)] + #[deprecated( + note = "This extrinsic uses `WeightLimit::Unlimited`, please migrate to `limited_teleport_assets` or `transfer_assets`" + )] pub fn teleport_assets( origin: OriginFor, dest: Box, @@ -1034,23 +1020,10 @@ pub mod pallet { /// - `fee_asset_item`: The index into `assets` of the item which should be used to pay /// fees. #[pallet::call_index(2)] - #[pallet::weight({ - let maybe_assets: Result = (*assets.clone()).try_into(); - let maybe_dest: Result = (*dest.clone()).try_into(); - match (maybe_assets, maybe_dest) { - (Ok(assets), Ok(dest)) => { - use sp_std::vec; - // heaviest version of locally executed XCM program: equivalent in weight to - // transfer assets to SA, reanchor them, extend XCM program, and send onward XCM - let mut message = Xcm(vec![ - SetFeesMode { jit_withdraw: true }, - TransferReserveAsset { assets, dest, xcm: Xcm(vec![]) } - ]); - T::Weigher::weight(&mut message).map_or(Weight::MAX, |w| T::WeightInfo::reserve_transfer_assets().saturating_add(w)) - } - _ => Weight::MAX, - } - })] + #[allow(deprecated)] + #[deprecated( + note = "This extrinsic uses `WeightLimit::Unlimited`, please migrate to `limited_reserve_transfer_assets` or `transfer_assets`" + )] pub fn reserve_transfer_assets( origin: OriginFor, dest: Box, @@ -1102,7 +1075,6 @@ pub mod pallet { /// - `location`: The destination that is being described. /// - `xcm_version`: The latest version of XCM that `location` supports. #[pallet::call_index(4)] - #[pallet::weight(T::WeightInfo::force_xcm_version())] pub fn force_xcm_version( origin: OriginFor, location: Box, @@ -1121,7 +1093,6 @@ pub mod pallet { /// - `origin`: Must be an origin specified by AdminOrigin. /// - `maybe_xcm_version`: The default XCM encoding version, or `None` to disable. #[pallet::call_index(5)] - #[pallet::weight(T::WeightInfo::force_default_xcm_version())] pub fn force_default_xcm_version( origin: OriginFor, maybe_xcm_version: Option, @@ -1136,7 +1107,6 @@ pub mod pallet { /// - `origin`: Must be an origin specified by AdminOrigin. /// - `location`: The location to which we should subscribe for XCM version notifications. #[pallet::call_index(6)] - #[pallet::weight(T::WeightInfo::force_subscribe_version_notify())] pub fn force_subscribe_version_notify( origin: OriginFor, location: Box, @@ -1160,7 +1130,6 @@ pub mod pallet { /// - `location`: The location to which we are currently subscribed for XCM version /// notifications which we no longer desire. #[pallet::call_index(7)] - #[pallet::weight(T::WeightInfo::force_unsubscribe_version_notify())] pub fn force_unsubscribe_version_notify( origin: OriginFor, location: Box, @@ -1193,7 +1162,7 @@ pub mod pallet { /// /// Fee payment on the destination side is made from the asset in the `assets` vector of /// index `fee_asset_item`, up to enough to pay for `weight_limit` of weight. If more weight - /// is needed than `weight_limit`, then the operation will fail and the assets send may be + /// is needed than `weight_limit`, then the operation will fail and the sent assets may be /// at risk. /// /// - `origin`: Must be capable of withdrawing the `assets` and executing XCM. @@ -1208,23 +1177,7 @@ pub mod pallet { /// fees. /// - `weight_limit`: The remote-side weight limit, if any, for the XCM fee purchase. #[pallet::call_index(8)] - #[pallet::weight({ - let maybe_assets: Result = (*assets.clone()).try_into(); - let maybe_dest: Result = (*dest.clone()).try_into(); - match (maybe_assets, maybe_dest) { - (Ok(assets), Ok(dest)) => { - use sp_std::vec; - // heaviest version of locally executed XCM program: equivalent in weight to - // transfer assets to SA, reanchor them, extend XCM program, and send onward XCM - let mut message = Xcm(vec![ - SetFeesMode { jit_withdraw: true }, - TransferReserveAsset { assets, dest, xcm: Xcm(vec![]) } - ]); - T::Weigher::weight(&mut message).map_or(Weight::MAX, |w| T::WeightInfo::reserve_transfer_assets().saturating_add(w)) - } - _ => Weight::MAX, - } - })] + #[pallet::weight(T::WeightInfo::reserve_transfer_assets())] pub fn limited_reserve_transfer_assets( origin: OriginFor, dest: Box, @@ -1247,7 +1200,7 @@ pub mod pallet { /// /// Fee payment on the destination side is made from the asset in the `assets` vector of /// index `fee_asset_item`, up to enough to pay for `weight_limit` of weight. If more weight - /// is needed than `weight_limit`, then the operation will fail and the assets send may be + /// is needed than `weight_limit`, then the operation will fail and the sent assets may be /// at risk. /// /// - `origin`: Must be capable of withdrawing the `assets` and executing XCM. @@ -1262,23 +1215,7 @@ pub mod pallet { /// fees. /// - `weight_limit`: The remote-side weight limit, if any, for the XCM fee purchase. #[pallet::call_index(9)] - #[pallet::weight({ - let maybe_assets: Result = (*assets.clone()).try_into(); - let maybe_dest: Result = (*dest.clone()).try_into(); - match (maybe_assets, maybe_dest) { - (Ok(assets), Ok(dest)) => { - use sp_std::vec; - let count = assets.len() as u32; - let mut message = Xcm(vec![ - WithdrawAsset(assets), - SetFeesMode { jit_withdraw: true }, - InitiateTeleport { assets: Wild(AllCounted(count)), dest, xcm: Xcm(vec![]) }, - ]); - T::Weigher::weight(&mut message).map_or(Weight::MAX, |w| T::WeightInfo::teleport_assets().saturating_add(w)) - } - _ => Weight::MAX, - } - })] + #[pallet::weight(T::WeightInfo::teleport_assets())] pub fn limited_teleport_assets( origin: OriginFor, dest: Box, @@ -1302,7 +1239,6 @@ pub mod pallet { /// - `origin`: Must be an origin specified by AdminOrigin. /// - `suspended`: `true` to suspend, `false` to resume. #[pallet::call_index(10)] - #[pallet::weight(T::WeightInfo::force_suspension())] pub fn force_suspension(origin: OriginFor, suspended: bool) -> DispatchResult { T::AdminOrigin::ensure_origin(origin)?; XcmExecutionSuspended::::set(suspended); @@ -1315,7 +1251,7 @@ pub mod pallet { /// Fee payment on the destination side is made from the asset in the `assets` vector of /// index `fee_asset_item` (hence referred to as `fees`), up to enough to pay for /// `weight_limit` of weight. If more weight is needed than `weight_limit`, then the - /// operation will fail and the assets sent may be at risk. + /// operation will fail and the sent assets may be at risk. /// /// `assets` (excluding `fees`) must have same reserve location or otherwise be teleportable /// to `dest`, no limitations imposed on `fees`. @@ -1343,26 +1279,6 @@ pub mod pallet { /// fees. /// - `weight_limit`: The remote-side weight limit, if any, for the XCM fee purchase. #[pallet::call_index(11)] - #[pallet::weight({ - let maybe_assets: Result = (*assets.clone()).try_into(); - let maybe_dest: Result = (*dest.clone()).try_into(); - match (maybe_assets, maybe_dest) { - (Ok(assets), Ok(dest)) => { - use sp_std::vec; - // heaviest version of locally executed XCM program: equivalent in weight to withdrawing fees, - // burning them, transferring rest of assets to SA, reanchoring them, extending XCM program, - // and sending onward XCM - let mut message = Xcm(vec![ - SetFeesMode { jit_withdraw: true }, - WithdrawAsset(assets.clone()), - BurnAsset(assets.clone()), - TransferReserveAsset { assets, dest, xcm: Xcm(vec![]) } - ]); - T::Weigher::weight(&mut message).map_or(Weight::MAX, |w| T::WeightInfo::transfer_assets().saturating_add(w)) - } - _ => Weight::MAX, - } - })] pub fn transfer_assets( origin: OriginFor, dest: Box, @@ -1452,22 +1368,6 @@ pub mod pallet { /// was the latest when they were trapped. /// - `beneficiary`: The location/account where the claimed assets will be deposited. #[pallet::call_index(12)] - #[pallet::weight({ - let assets_version = assets.identify_version(); - let maybe_assets: Result = (*assets.clone()).try_into(); - let maybe_beneficiary: Result = (*beneficiary.clone()).try_into(); - match (maybe_assets, maybe_beneficiary) { - (Ok(assets), Ok(beneficiary)) => { - let ticket: Location = GeneralIndex(assets_version as u128).into(); - let mut message = Xcm(vec![ - ClaimAsset { assets: assets.clone(), ticket }, - DepositAsset { assets: AllCounted(assets.len() as u32).into(), beneficiary }, - ]); - T::Weigher::weight(&mut message).map_or(Weight::MAX, |w| T::WeightInfo::claim_assets().saturating_add(w)) - } - _ => Weight::MAX - } - })] pub fn claim_assets( origin: OriginFor, assets: Box, @@ -1514,7 +1414,7 @@ pub mod pallet { /// /// The message is passed in encoded. It needs to be decodable as a [`VersionedXcm`]. #[pallet::call_index(13)] - #[pallet::weight(T::WeightInfo::execute_blob())] + #[pallet::weight(max_weight.saturating_add(T::WeightInfo::execute_blob()))] pub fn execute_blob( origin: OriginFor, encoded_message: BoundedVec, @@ -1535,7 +1435,6 @@ pub mod pallet { /// /// The message is passed in encoded. It needs to be decodable as a [`VersionedXcm`]. #[pallet::call_index(14)] - #[pallet::weight(T::WeightInfo::send_blob())] pub fn send_blob( origin: OriginFor, dest: Box, diff --git a/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs b/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs index 92d23cfd2817..7dc05c1cc70e 100644 --- a/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs +++ b/polkadot/xcm/pallet-xcm/src/tests/assets_transfer.rs @@ -31,13 +31,17 @@ use sp_runtime::{traits::AccountIdConversion, DispatchError, ModuleError}; use xcm::prelude::*; use xcm_executor::traits::ConvertLocation; -// Helper function to deduplicate testing different teleport types. -fn do_test_and_verify_teleport_assets( - origin_location: Location, - expected_beneficiary: Location, - call: Call, - expected_weight_limit: WeightLimit, -) { +/// Test `limited_teleport_assets` +/// +/// Asserts that the sender's balance is decreased as a result of execution of +/// local effects. +#[test] +fn limited_teleport_assets_works() { + let origin_location: Location = AccountId32 { network: None, id: ALICE.into() }.into(); + let expected_beneficiary: Location = AccountId32 { network: None, id: BOB.into() }.into(); + let weight_limit = WeightLimit::Limited(Weight::from_parts(5000, 5000)); + let expected_weight_limit = weight_limit.clone(); + let balances = vec![ (ALICE, INITIAL_BALANCE), (ParaId::from(OTHER_PARA_ID).into_account_truncating(), INITIAL_BALANCE), @@ -47,7 +51,14 @@ fn do_test_and_verify_teleport_assets( let weight = BaseXcmWeight::get() * 2; assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE); // call extrinsic - call(); + assert_ok!(XcmPallet::limited_teleport_assets( + RuntimeOrigin::signed(ALICE), + Box::new(RelayLocation::get().into()), + Box::new(expected_beneficiary.clone().into()), + Box::new((Here, SEND_AMOUNT).into()), + 0, + weight_limit, + )); assert_eq!(Balances::total_balance(&ALICE), INITIAL_BALANCE - SEND_AMOUNT); assert_eq!( sent_xcm(), @@ -88,57 +99,6 @@ fn do_test_and_verify_teleport_assets( }); } -/// Test `teleport_assets` -/// -/// Asserts that the sender's balance is decreased as a result of execution of -/// local effects. -#[test] -fn teleport_assets_works() { - let origin_location: Location = AccountId32 { network: None, id: ALICE.into() }.into(); - let beneficiary: Location = AccountId32 { network: None, id: BOB.into() }.into(); - do_test_and_verify_teleport_assets( - origin_location.clone(), - beneficiary.clone(), - || { - assert_ok!(XcmPallet::teleport_assets( - RuntimeOrigin::signed(ALICE), - Box::new(RelayLocation::get().into()), - Box::new(beneficiary.into()), - Box::new((Here, SEND_AMOUNT).into()), - 0, - )); - }, - Unlimited, - ); -} - -/// Test `limited_teleport_assets` -/// -/// Asserts that the sender's balance is decreased as a result of execution of -/// local effects. -#[test] -fn limited_teleport_assets_works() { - let origin_location: Location = AccountId32 { network: None, id: ALICE.into() }.into(); - let beneficiary: Location = AccountId32 { network: None, id: BOB.into() }.into(); - let weight_limit = WeightLimit::Limited(Weight::from_parts(5000, 5000)); - let expected_weight_limit = weight_limit.clone(); - do_test_and_verify_teleport_assets( - origin_location.clone(), - beneficiary.clone(), - || { - assert_ok!(XcmPallet::limited_teleport_assets( - RuntimeOrigin::signed(ALICE), - Box::new(RelayLocation::get().into()), - Box::new(beneficiary.into()), - Box::new((Here, SEND_AMOUNT).into()), - 0, - weight_limit, - )); - }, - expected_weight_limit, - ); -} - /// `limited_teleport_assets` should fail for filtered assets #[test] fn limited_teleport_filtered_assets_disallowed() { @@ -184,12 +144,13 @@ fn reserve_transfer_assets_with_paid_router_works() { let dest: Location = Junction::AccountId32 { network: None, id: user_account.clone().into() }.into(); assert_eq!(Balances::total_balance(&user_account), INITIAL_BALANCE); - assert_ok!(XcmPallet::reserve_transfer_assets( + assert_ok!(XcmPallet::limited_reserve_transfer_assets( RuntimeOrigin::signed(user_account.clone()), Box::new(Parachain(paid_para_id).into()), Box::new(dest.clone().into()), Box::new((Here, SEND_AMOUNT).into()), 0, + Unlimited, )); // XCM_FEES_NOT_WAIVED_USER_ACCOUNT spent amount diff --git a/polkadot/xcm/xcm-simulator/example/src/lib.rs b/polkadot/xcm/xcm-simulator/example/src/lib.rs index 13210179e910..56e204bf5718 100644 --- a/polkadot/xcm/xcm-simulator/example/src/lib.rs +++ b/polkadot/xcm/xcm-simulator/example/src/lib.rs @@ -250,12 +250,13 @@ mod tests { let withdraw_amount = 123; Relay::execute_with(|| { - assert_ok!(RelayChainPalletXcm::reserve_transfer_assets( + assert_ok!(RelayChainPalletXcm::limited_reserve_transfer_assets( relay_chain::RuntimeOrigin::signed(ALICE), Box::new(Parachain(1).into()), Box::new(AccountId32 { network: None, id: ALICE.into() }.into()), Box::new((Here, withdraw_amount).into()), 0, + Unlimited, )); assert_eq!( relay_chain::Balances::free_balance(&child_account_id(1)), diff --git a/prdoc/pr_3927.prdoc b/prdoc/pr_3927.prdoc new file mode 100644 index 000000000000..a568636d0bd0 --- /dev/null +++ b/prdoc/pr_3927.prdoc @@ -0,0 +1,13 @@ +title: "pallet-xcm: deprecate transfer extrinsics without weight limit" + +doc: + - audience: Runtime Dev + description: | + pallet-xcm's extrinsics `teleport_assets` and `reserve_transfer_assets` have been + marked as deprecated. Please change their usage to the `limited_teleport_assets` + and `limited_reserve_transfer_assets`, respectively; or use the generic/flexible + `transfer_assets` extrinsic. + +crates: +- name: pallet-xcm + bump: minor From 14603f2807892b9e9ec5a5ecb0f3941a2df327e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 2 Apr 2024 11:44:23 +0200 Subject: [PATCH 099/257] Fix parachain upgrade scheduling when done by the owner/root (#3341) When using `schedule_code_upgrade` to change the code of a parachain in the relay chain runtime, we had already fixed to not set the `GoAhead` signal. This was done to not brick any parachain after the upgrade, because they were seeing the signal without having any upgrade prepared. The remaining problem is that the parachain code is only upgraded after a parachain header was enacted, aka the parachain made some progress. However, this is quite complicated if the parachain is bricked (which is the most common scenario why to manually schedule a code upgrade). Thus, this pull request replaces `SetGoAhead` with `UpgradeStrategy` to signal to the logic kind of strategy want to use. The strategies are either `SetGoAheadSignal` or `ApplyAtExpectedBlock`. `SetGoAheadSignal` sets the go ahead signal as before and awaits a parachain block. `ApplyAtExpectedBlock` schedules the upgrade and applies it directly at the `expected_block` without waiting for the parachain to make any kind of progress. --- .../runtime/common/src/paras_registrar/mod.rs | 15 +- .../runtime/parachains/src/inclusion/mod.rs | 4 +- .../runtime/parachains/src/inclusion/tests.rs | 4 +- polkadot/runtime/parachains/src/lib.rs | 4 +- .../parachains/src/paras/benchmarking.rs | 2 +- .../src/paras/benchmarking/pvf_check.rs | 2 +- polkadot/runtime/parachains/src/paras/mod.rs | 226 ++++++++++++------ .../runtime/parachains/src/paras/tests.rs | 131 ++++------ prdoc/pr_3341.prdoc | 18 ++ 9 files changed, 237 insertions(+), 169 deletions(-) create mode 100644 prdoc/pr_3341.prdoc diff --git a/polkadot/runtime/common/src/paras_registrar/mod.rs b/polkadot/runtime/common/src/paras_registrar/mod.rs index 5b2098388d81..7abe23917e4c 100644 --- a/polkadot/runtime/common/src/paras_registrar/mod.rs +++ b/polkadot/runtime/common/src/paras_registrar/mod.rs @@ -29,7 +29,7 @@ use frame_system::{self, ensure_root, ensure_signed}; use primitives::{HeadData, Id as ParaId, ValidationCode, LOWEST_PUBLIC_ID, MIN_CODE_SIZE}; use runtime_parachains::{ configuration, ensure_parachain, - paras::{self, ParaGenesisArgs, SetGoAhead}, + paras::{self, ParaGenesisArgs, UpgradeStrategy}, Origin, ParaLifecycle, }; use sp_std::{prelude::*, result}; @@ -408,6 +408,13 @@ pub mod pallet { /// Schedule a parachain upgrade. /// + /// This will kick off a check of `new_code` by all validators. After the majority of the + /// validators have reported on the validity of the code, the code will either be enacted + /// or the upgrade will be rejected. If the code will be enacted, the current code of the + /// parachain will be overwritten directly. This means that any PoV will be checked by this + /// new code. The parachain itself will not be informed explictely that the validation code + /// has changed. + /// /// Can be called by Root, the parachain, or the parachain manager if the parachain is /// unlocked. #[pallet::call_index(7)] @@ -418,7 +425,11 @@ pub mod pallet { new_code: ValidationCode, ) -> DispatchResult { Self::ensure_root_para_or_owner(origin, para)?; - runtime_parachains::schedule_code_upgrade::(para, new_code, SetGoAhead::No)?; + runtime_parachains::schedule_code_upgrade::( + para, + new_code, + UpgradeStrategy::ApplyAtExpectedBlock, + )?; Ok(()) } diff --git a/polkadot/runtime/parachains/src/inclusion/mod.rs b/polkadot/runtime/parachains/src/inclusion/mod.rs index e77f8d15b40d..34afdec724a5 100644 --- a/polkadot/runtime/parachains/src/inclusion/mod.rs +++ b/polkadot/runtime/parachains/src/inclusion/mod.rs @@ -22,7 +22,7 @@ use crate::{ configuration::{self, HostConfiguration}, disputes, dmp, hrmp, - paras::{self, SetGoAhead}, + paras::{self, UpgradeStrategy}, scheduler, shared::{self, AllowedRelayParentsTracker}, util::make_persisted_validation_data_with_parent, @@ -839,7 +839,7 @@ impl Pallet { new_code, now, &config, - SetGoAhead::Yes, + UpgradeStrategy::SetGoAheadSignal, )); } diff --git a/polkadot/runtime/parachains/src/inclusion/tests.rs b/polkadot/runtime/parachains/src/inclusion/tests.rs index 5ab3a13324d2..97bf67ef934e 100644 --- a/polkadot/runtime/parachains/src/inclusion/tests.rs +++ b/polkadot/runtime/parachains/src/inclusion/tests.rs @@ -1590,7 +1590,7 @@ fn candidate_checks() { vec![9, 8, 7, 6, 5, 4, 3, 2, 1].into(), expected_at, &cfg, - SetGoAhead::Yes, + UpgradeStrategy::SetGoAheadSignal, ); } @@ -2857,7 +2857,7 @@ fn para_upgrade_delay_scheduled_from_inclusion() { let cause = &active_vote_state.causes()[0]; // Upgrade block is the block of inclusion, not candidate's parent. assert_matches!(cause, - paras::PvfCheckCause::Upgrade { id, included_at, set_go_ahead: SetGoAhead::Yes } + paras::PvfCheckCause::Upgrade { id, included_at, upgrade_strategy: UpgradeStrategy::SetGoAheadSignal } if id == &chain_a && included_at == &7 ); }); diff --git a/polkadot/runtime/parachains/src/lib.rs b/polkadot/runtime/parachains/src/lib.rs index b0dc27b72863..466bc7685ddf 100644 --- a/polkadot/runtime/parachains/src/lib.rs +++ b/polkadot/runtime/parachains/src/lib.rs @@ -54,7 +54,7 @@ mod mock; mod ump_tests; pub use origin::{ensure_parachain, Origin}; -pub use paras::{ParaLifecycle, SetGoAhead}; +pub use paras::{ParaLifecycle, UpgradeStrategy}; use primitives::{HeadData, Id as ParaId, ValidationCode}; use sp_runtime::{DispatchResult, FixedU128}; @@ -104,7 +104,7 @@ pub fn schedule_parachain_downgrade(id: ParaId) -> Result<(), pub fn schedule_code_upgrade( id: ParaId, new_code: ValidationCode, - set_go_ahead: SetGoAhead, + set_go_ahead: UpgradeStrategy, ) -> DispatchResult { paras::Pallet::::schedule_code_upgrade_external(id, new_code, set_go_ahead) } diff --git a/polkadot/runtime/parachains/src/paras/benchmarking.rs b/polkadot/runtime/parachains/src/paras/benchmarking.rs index 554f0c15af24..56e6ff153c15 100644 --- a/polkadot/runtime/parachains/src/paras/benchmarking.rs +++ b/polkadot/runtime/parachains/src/paras/benchmarking.rs @@ -129,7 +129,7 @@ benchmarks! { ValidationCode(vec![0]), expired, &config, - SetGoAhead::Yes, + UpgradeStrategy::SetGoAheadSignal, ); }: _(RawOrigin::Root, para_id, new_head) verify { diff --git a/polkadot/runtime/parachains/src/paras/benchmarking/pvf_check.rs b/polkadot/runtime/parachains/src/paras/benchmarking/pvf_check.rs index 53ccc35c477c..0bf5aa86c40f 100644 --- a/polkadot/runtime/parachains/src/paras/benchmarking/pvf_check.rs +++ b/polkadot/runtime/parachains/src/paras/benchmarking/pvf_check.rs @@ -177,7 +177,7 @@ where validation_code, /* relay_parent_number */ 1u32.into(), &configuration::Pallet::::config(), - SetGoAhead::Yes, + UpgradeStrategy::SetGoAheadSignal, ); } else { let r = Pallet::::schedule_para_initialize( diff --git a/polkadot/runtime/parachains/src/paras/mod.rs b/polkadot/runtime/parachains/src/paras/mod.rs index 017cd87f13b8..3eb66112fedf 100644 --- a/polkadot/runtime/parachains/src/paras/mod.rs +++ b/polkadot/runtime/parachains/src/paras/mod.rs @@ -386,16 +386,32 @@ pub(crate) enum PvfCheckCause { /// /// See https://github.com/paritytech/polkadot/issues/4601 for detailed explanation. included_at: BlockNumber, - /// Whether or not the given para should be sent the `GoAhead` signal. - set_go_ahead: SetGoAhead, + /// Whether or not the upgrade should be enacted directly. + /// + /// If set to `Yes` it means that no `GoAheadSignal` will be set and the parachain code + /// will also be overwritten directly. + upgrade_strategy: UpgradeStrategy, }, } -/// Should the `GoAhead` signal be set after a successful check of the new wasm binary? +/// The strategy on how to handle a validation code upgrade. +/// +/// When scheduling a parachain code upgrade the upgrade first is checked by all validators. The +/// validators ensure that the new validation code can be compiled and instantiated. After the +/// majority of the validators have reported their checking result the upgrade is either scheduled +/// or aborted. This strategy then comes into play around the relay chain block this upgrade was +/// scheduled in. #[derive(Debug, Copy, Clone, PartialEq, TypeInfo, Decode, Encode)] -pub enum SetGoAhead { - Yes, - No, +pub enum UpgradeStrategy { + /// Set the `GoAhead` signal to inform the parachain that it is time to upgrade. + /// + /// The upgrade will then be applied after the first parachain block was enacted that must have + /// observed the `GoAhead` signal. + SetGoAheadSignal, + /// Apply the upgrade directly at the expected relay chain block. + /// + /// This doesn't wait for the parachain to make any kind of progress. + ApplyAtExpectedBlock, } impl PvfCheckCause { @@ -758,7 +774,8 @@ pub mod pallet { pub(super) type PastCodePruning = StorageValue<_, Vec<(ParaId, BlockNumberFor)>, ValueQuery>; - /// The block number at which the planned code change is expected for a para. + /// The block number at which the planned code change is expected for a parachain. + /// /// The change will be applied after the first parablock for this ID included which executes /// in the context of a relay chain block with a number >= `expected_at`. #[pallet::storage] @@ -766,6 +783,18 @@ pub mod pallet { pub(super) type FutureCodeUpgrades = StorageMap<_, Twox64Concat, ParaId, BlockNumberFor>; + /// The list of upcoming future code upgrades. + /// + /// Each item is a pair of the parachain and the expected block at which the upgrade should be + /// applied. The upgrade will be applied at the given relay chain block. In contrast to + /// [`FutureCodeUpgrades`] this code upgrade will be applied regardless the parachain making any + /// progress or not. + /// + /// Ordered ascending by block number. + #[pallet::storage] + pub(super) type FutureCodeUpgradesAt = + StorageValue<_, Vec<(ParaId, BlockNumberFor)>, ValueQuery>; + /// The actual future code hash of a para. /// /// Corresponding code can be retrieved with [`CodeByHash`]. @@ -809,8 +838,10 @@ pub mod pallet { pub(super) type UpgradeCooldowns = StorageValue<_, Vec<(ParaId, BlockNumberFor)>, ValueQuery>; - /// The list of upcoming code upgrades. Each item is a pair of which para performs a code - /// upgrade and at which relay-chain block it is expected at. + /// The list of upcoming code upgrades. + /// + /// Each item is a pair of which para performs a code upgrade and at which relay-chain block it + /// is expected at. /// /// Ordered ascending by block number. #[pallet::storage] @@ -880,21 +911,9 @@ pub mod pallet { new_code: ValidationCode, ) -> DispatchResult { ensure_root(origin)?; - let maybe_prior_code_hash = CurrentCodeHash::::get(¶); let new_code_hash = new_code.hash(); Self::increase_code_ref(&new_code_hash, &new_code); - CurrentCodeHash::::insert(¶, new_code_hash); - - let now = frame_system::Pallet::::block_number(); - if let Some(prior_code_hash) = maybe_prior_code_hash { - Self::note_past_code(para, now, now, prior_code_hash); - } else { - log::error!( - target: LOG_TARGET, - "Pallet paras storage is inconsistent, prior code not found {:?}", - ¶ - ); - } + Self::set_current_code(para, new_code_hash, frame_system::Pallet::::block_number()); Self::deposit_event(Event::CurrentCodeUpdated(para)); Ok(()) } @@ -928,7 +947,7 @@ pub mod pallet { new_code, relay_parent_number, &config, - SetGoAhead::No, + UpgradeStrategy::ApplyAtExpectedBlock, ); Self::deposit_event(Event::CodeUpgradeScheduled(para)); Ok(()) @@ -1227,7 +1246,7 @@ impl Pallet { pub(crate) fn schedule_code_upgrade_external( id: ParaId, new_code: ValidationCode, - set_go_ahead: SetGoAhead, + upgrade_strategy: UpgradeStrategy, ) -> DispatchResult { // Check that we can schedule an upgrade at all. ensure!(Self::can_upgrade_validation_code(id), Error::::CannotUpgradeCode); @@ -1239,7 +1258,7 @@ impl Pallet { let current_block = frame_system::Pallet::::block_number(); // Schedule the upgrade with a delay just like if a parachain triggered the upgrade. let upgrade_block = current_block.saturating_add(config.validation_upgrade_delay); - Self::schedule_code_upgrade(id, new_code, upgrade_block, &config, set_go_ahead); + Self::schedule_code_upgrade(id, new_code, upgrade_block, &config, upgrade_strategy); Self::deposit_event(Event::CodeUpgradeScheduled(id)); Ok(()) } @@ -1252,8 +1271,9 @@ impl Pallet { /// Called by the initializer to initialize the paras pallet. pub(crate) fn initializer_initialize(now: BlockNumberFor) -> Weight { - let weight = Self::prune_old_code(now); - weight + Self::process_scheduled_upgrade_changes(now) + Self::prune_old_code(now) + + Self::process_scheduled_upgrade_changes(now) + + Self::process_future_code_upgrades_at(now) } /// Called by the initializer to finalize the paras pallet. @@ -1355,16 +1375,13 @@ impl Pallet { // NOTE both of those iterates over the list and the outgoing. We do not expect either // of these to be large. Thus should be fine. UpcomingUpgrades::::mutate(|upcoming_upgrades| { - *upcoming_upgrades = mem::take(upcoming_upgrades) - .into_iter() - .filter(|(para, _)| !outgoing.contains(para)) - .collect(); + upcoming_upgrades.retain(|(para, _)| !outgoing.contains(para)); }); UpgradeCooldowns::::mutate(|upgrade_cooldowns| { - *upgrade_cooldowns = mem::take(upgrade_cooldowns) - .into_iter() - .filter(|(para, _)| !outgoing.contains(para)) - .collect(); + upgrade_cooldowns.retain(|(para, _)| !outgoing.contains(para)); + }); + FutureCodeUpgradesAt::::mutate(|future_upgrades| { + future_upgrades.retain(|(para, _)| !outgoing.contains(para)); }); } @@ -1460,6 +1477,37 @@ impl Pallet { T::DbWeight::get().reads_writes(1 + pruning_tasks_done, 2 * pruning_tasks_done) } + /// Process the future code upgrades that should be applied directly. + /// + /// Upgrades that should not be applied directly are being processed in + /// [`Self::process_scheduled_upgrade_changes`]. + fn process_future_code_upgrades_at(now: BlockNumberFor) -> Weight { + // account weight for `FutureCodeUpgradeAt::mutate`. + let mut weight = T::DbWeight::get().reads_writes(1, 1); + FutureCodeUpgradesAt::::mutate( + |upcoming_upgrades: &mut Vec<(ParaId, BlockNumberFor)>| { + let num = upcoming_upgrades.iter().take_while(|&(_, at)| at <= &now).count(); + for (id, expected_at) in upcoming_upgrades.drain(..num) { + weight += T::DbWeight::get().reads_writes(1, 1); + + // Both should always be `Some` in this case, since a code upgrade is scheduled. + let new_code_hash = if let Some(new_code_hash) = FutureCodeHash::::take(&id) + { + new_code_hash + } else { + log::error!(target: LOG_TARGET, "Missing future code hash for {:?}", &id); + continue + }; + + weight += Self::set_current_code(id, new_code_hash, expected_at); + } + num + }, + ); + + weight + } + /// Process the timers related to upgrades. Specifically, the upgrade go ahead signals toggle /// and the upgrade cooldown restrictions. However, this function does not actually unset /// the upgrade restriction, that will happen in the `initializer_finalize` function. However, @@ -1580,14 +1628,14 @@ impl Pallet { PvfCheckCause::Onboarding(id) => { weight += Self::proceed_with_onboarding(*id, sessions_observed); }, - PvfCheckCause::Upgrade { id, included_at, set_go_ahead } => { + PvfCheckCause::Upgrade { id, included_at, upgrade_strategy } => { weight += Self::proceed_with_upgrade( *id, code_hash, now, *included_at, cfg, - *set_go_ahead, + *upgrade_strategy, ); }, } @@ -1621,38 +1669,50 @@ impl Pallet { now: BlockNumberFor, relay_parent_number: BlockNumberFor, cfg: &configuration::HostConfiguration>, - set_go_ahead: SetGoAhead, + upgrade_strategy: UpgradeStrategy, ) -> Weight { let mut weight = Weight::zero(); - // Compute the relay-chain block number starting at which the code upgrade is ready to be - // applied. + // Compute the relay-chain block number starting at which the code upgrade is ready to + // be applied. // - // The first parablock that has a relay-parent higher or at the same height of `expected_at` - // will trigger the code upgrade. The parablock that comes after that will be validated - // against the new validation code. + // The first parablock that has a relay-parent higher or at the same height of + // `expected_at` will trigger the code upgrade. The parablock that comes after that will + // be validated against the new validation code. // - // Here we are trying to choose the block number that will have `validation_upgrade_delay` - // blocks from the relay-parent of inclusion of the the block that scheduled code upgrade - // but no less than `minimum_validation_upgrade_delay`. We want this delay out of caution - // so that when the last vote for pre-checking comes the parachain will have some time until - // the upgrade finally takes place. + // Here we are trying to choose the block number that will have + // `validation_upgrade_delay` blocks from the relay-parent of inclusion of the the block + // that scheduled code upgrade but no less than `minimum_validation_upgrade_delay`. We + // want this delay out of caution so that when the last vote for pre-checking comes the + // parachain will have some time until the upgrade finally takes place. let expected_at = cmp::max( relay_parent_number + cfg.validation_upgrade_delay, now + cfg.minimum_validation_upgrade_delay, ); - weight += T::DbWeight::get().reads_writes(1, 4); - FutureCodeUpgrades::::insert(&id, expected_at); + match upgrade_strategy { + UpgradeStrategy::ApplyAtExpectedBlock => { + FutureCodeUpgradesAt::::mutate(|future_upgrades| { + let insert_idx = future_upgrades + .binary_search_by_key(&expected_at, |&(_, b)| b) + .unwrap_or_else(|idx| idx); + future_upgrades.insert(insert_idx, (id, expected_at)); + }); - // Only set an upcoming upgrade if `GoAhead` signal should be set for the respective para. - if set_go_ahead == SetGoAhead::Yes { - UpcomingUpgrades::::mutate(|upcoming_upgrades| { - let insert_idx = upcoming_upgrades - .binary_search_by_key(&expected_at, |&(_, b)| b) - .unwrap_or_else(|idx| idx); - upcoming_upgrades.insert(insert_idx, (id, expected_at)); - }); + weight += T::DbWeight::get().reads_writes(0, 2); + }, + UpgradeStrategy::SetGoAheadSignal => { + FutureCodeUpgrades::::insert(&id, expected_at); + + UpcomingUpgrades::::mutate(|upcoming_upgrades| { + let insert_idx = upcoming_upgrades + .binary_search_by_key(&expected_at, |&(_, b)| b) + .unwrap_or_else(|idx| idx); + upcoming_upgrades.insert(insert_idx, (id, expected_at)); + }); + + weight += T::DbWeight::get().reads_writes(1, 3); + }, } let expected_at = expected_at.saturated_into(); @@ -1892,7 +1952,7 @@ impl Pallet { new_code: ValidationCode, inclusion_block_number: BlockNumberFor, cfg: &configuration::HostConfiguration>, - set_go_ahead: SetGoAhead, + upgrade_strategy: UpgradeStrategy, ) -> Weight { let mut weight = T::DbWeight::get().reads(1); @@ -1949,7 +2009,7 @@ impl Pallet { }); weight += Self::kick_off_pvf_check( - PvfCheckCause::Upgrade { id, included_at: inclusion_block_number, set_go_ahead }, + PvfCheckCause::Upgrade { id, included_at: inclusion_block_number, upgrade_strategy }, code_hash, new_code, cfg, @@ -2061,24 +2121,10 @@ impl Pallet { log::error!(target: LOG_TARGET, "Missing future code hash for {:?}", &id); return T::DbWeight::get().reads_writes(3, 1 + 3) }; - let maybe_prior_code_hash = CurrentCodeHash::::get(&id); - CurrentCodeHash::::insert(&id, &new_code_hash); - let log = ConsensusLog::ParaUpgradeCode(id, new_code_hash); - >::deposit_log(log.into()); + let weight = Self::set_current_code(id, new_code_hash, expected_at); - // `now` is only used for registering pruning as part of `fn note_past_code` - let now = >::block_number(); - - let weight = if let Some(prior_code_hash) = maybe_prior_code_hash { - Self::note_past_code(id, expected_at, now, prior_code_hash) - } else { - log::error!(target: LOG_TARGET, "Missing prior code hash for para {:?}", &id); - Weight::zero() - }; - - // add 1 to writes due to heads update. - weight + T::DbWeight::get().reads_writes(3, 1 + 3) + weight + T::DbWeight::get().reads_writes(3, 3) } else { T::DbWeight::get().reads_writes(1, 1 + 0) } @@ -2094,6 +2140,34 @@ impl Pallet { weight.saturating_add(T::OnNewHead::on_new_head(id, &new_head)) } + /// Set the current code for the given parachain. + // `at` for para-triggered replacement is the block number of the relay-chain + // block in whose context the parablock was executed + // (i.e. number of `relay_parent` in the receipt) + pub(crate) fn set_current_code( + id: ParaId, + new_code_hash: ValidationCodeHash, + at: BlockNumberFor, + ) -> Weight { + let maybe_prior_code_hash = CurrentCodeHash::::get(&id); + CurrentCodeHash::::insert(&id, &new_code_hash); + + let log = ConsensusLog::ParaUpgradeCode(id, new_code_hash); + >::deposit_log(log.into()); + + // `now` is only used for registering pruning as part of `fn note_past_code` + let now = >::block_number(); + + let weight = if let Some(prior_code_hash) = maybe_prior_code_hash { + Self::note_past_code(id, at, now, prior_code_hash) + } else { + log::error!(target: LOG_TARGET, "Missing prior code hash for para {:?}", &id); + Weight::zero() + }; + + weight + T::DbWeight::get().writes(1) + } + /// Returns the list of PVFs (aka validation code) that require casting a vote by a validator in /// the active validator set. pub(crate) fn pvfs_require_precheck() -> Vec { diff --git a/polkadot/runtime/parachains/src/paras/tests.rs b/polkadot/runtime/parachains/src/paras/tests.rs index 39abd2367b72..ad75166271e3 100644 --- a/polkadot/runtime/parachains/src/paras/tests.rs +++ b/polkadot/runtime/parachains/src/paras/tests.rs @@ -451,7 +451,7 @@ fn code_upgrade_applied_after_delay() { new_code.clone(), 1, &Configuration::config(), - SetGoAhead::Yes, + UpgradeStrategy::SetGoAheadSignal, ); // Include votes for super-majority. submit_super_majority_pvf_votes(&new_code, EXPECTED_SESSION, true); @@ -521,7 +521,7 @@ fn code_upgrade_applied_after_delay() { } #[test] -fn code_upgrade_applied_without_setting_go_ahead_signal() { +fn upgrade_strategy_apply_at_expected_block_works() { let code_retention_period = 10; let validation_upgrade_delay = 5; let validation_upgrade_cooldown = 10; @@ -560,77 +560,42 @@ fn code_upgrade_applied_without_setting_go_ahead_signal() { run_to_block(2, Some(vec![1])); assert_eq!(Paras::current_code(¶_id), Some(original_code.clone())); - let (expected_at, next_possible_upgrade_at) = { - // this parablock is in the context of block 1. - let expected_at = 1 + validation_upgrade_delay; - let next_possible_upgrade_at = 1 + validation_upgrade_cooldown; - // `set_go_ahead` parameter set to `false` which prevents signaling the parachain - // with the `GoAhead` signal. - Paras::schedule_code_upgrade( - para_id, - new_code.clone(), - 1, - &Configuration::config(), - SetGoAhead::No, - ); - // Include votes for super-majority. - submit_super_majority_pvf_votes(&new_code, EXPECTED_SESSION, true); - - Paras::note_new_head(para_id, Default::default(), 1); - - assert!(Paras::past_code_meta(¶_id).most_recent_change().is_none()); - assert_eq!(FutureCodeUpgrades::::get(¶_id), Some(expected_at)); - assert_eq!(FutureCodeHash::::get(¶_id), Some(new_code.hash())); - assert_eq!(UpcomingUpgrades::::get(), vec![]); - assert_eq!(UpgradeCooldowns::::get(), vec![(para_id, next_possible_upgrade_at)]); - assert_eq!(Paras::current_code(¶_id), Some(original_code.clone())); - check_code_is_stored(&original_code); - check_code_is_stored(&new_code); - - (expected_at, next_possible_upgrade_at) - }; + // this parablock is in the context of block 1. + let expected_at = 1 + validation_upgrade_delay; + let next_possible_upgrade_at = 1 + validation_upgrade_cooldown; + // `set_go_ahead` parameter set to `false` which prevents signaling the parachain + // with the `GoAhead` signal. + Paras::schedule_code_upgrade( + para_id, + new_code.clone(), + 1, + &Configuration::config(), + UpgradeStrategy::ApplyAtExpectedBlock, + ); + // Include votes for super-majority. + submit_super_majority_pvf_votes(&new_code, EXPECTED_SESSION, true); + assert!(FutureCodeUpgradesAt::::get().iter().any(|(id, _)| *id == para_id)); + // Going to the expected block triggers the upgrade directly. run_to_block(expected_at, None); - // the candidate is in the context of the parent of `expected_at`, - // thus does not trigger the code upgrade. However, now the `UpgradeGoAheadSignal` - // should not be set. - { - Paras::note_new_head(para_id, Default::default(), expected_at - 1); - - assert!(Paras::past_code_meta(¶_id).most_recent_change().is_none()); - assert_eq!(FutureCodeUpgrades::::get(¶_id), Some(expected_at)); - assert_eq!(FutureCodeHash::::get(¶_id), Some(new_code.hash())); - assert!(UpgradeGoAheadSignal::::get(¶_id).is_none()); - assert_eq!(Paras::current_code(¶_id), Some(original_code.clone())); - check_code_is_stored(&original_code); - check_code_is_stored(&new_code); - } - - run_to_block(expected_at + 1, None); - - // the candidate is in the context of `expected_at`, and triggers - // the upgrade. - { - Paras::note_new_head(para_id, Default::default(), expected_at); + // Reporting a head doesn't change anything. + Paras::note_new_head(para_id, Default::default(), expected_at - 1); - assert_eq!(Paras::past_code_meta(¶_id).most_recent_change(), Some(expected_at)); - assert_eq!( - PastCodeHash::::get(&(para_id, expected_at)), - Some(original_code.hash()), - ); - assert!(FutureCodeUpgrades::::get(¶_id).is_none()); - assert!(FutureCodeHash::::get(¶_id).is_none()); - assert!(UpgradeGoAheadSignal::::get(¶_id).is_none()); - assert_eq!(Paras::current_code(¶_id), Some(new_code.clone())); - assert_eq!( - UpgradeRestrictionSignal::::get(¶_id), - Some(UpgradeRestriction::Present), - ); - assert_eq!(UpgradeCooldowns::::get(), vec![(para_id, next_possible_upgrade_at)]); - check_code_is_stored(&original_code); - check_code_is_stored(&new_code); - } + assert_eq!(Paras::past_code_meta(¶_id).most_recent_change(), Some(expected_at)); + assert_eq!(PastCodeHash::::get(&(para_id, expected_at)), Some(original_code.hash())); + assert!(FutureCodeUpgrades::::get(¶_id).is_none()); + assert!(FutureCodeUpgradesAt::::get().iter().all(|(id, _)| *id != para_id)); + assert!(FutureCodeHash::::get(¶_id).is_none()); + assert!(UpgradeGoAheadSignal::::get(¶_id).is_none()); + assert_eq!(Paras::current_code(¶_id), Some(new_code.clone())); + assert_eq!( + UpgradeRestrictionSignal::::get(¶_id), + Some(UpgradeRestriction::Present), + ); + assert_eq!(UpgradeCooldowns::::get(), vec![(para_id, next_possible_upgrade_at)]); + check_code_is_stored(&original_code); + check_code_is_stored(&new_code); run_to_block(next_possible_upgrade_at + 1, None); @@ -688,7 +653,7 @@ fn code_upgrade_applied_after_delay_even_when_late() { new_code.clone(), 1, &Configuration::config(), - SetGoAhead::Yes, + UpgradeStrategy::SetGoAheadSignal, ); // Include votes for super-majority. submit_super_majority_pvf_votes(&new_code, EXPECTED_SESSION, true); @@ -772,7 +737,7 @@ fn submit_code_change_when_not_allowed_is_err() { new_code.clone(), 1, &Configuration::config(), - SetGoAhead::Yes, + UpgradeStrategy::SetGoAheadSignal, ); // Include votes for super-majority. submit_super_majority_pvf_votes(&new_code, EXPECTED_SESSION, true); @@ -790,7 +755,7 @@ fn submit_code_change_when_not_allowed_is_err() { newer_code.clone(), 2, &Configuration::config(), - SetGoAhead::Yes, + UpgradeStrategy::SetGoAheadSignal, ); assert_eq!( FutureCodeUpgrades::::get(¶_id), @@ -854,7 +819,7 @@ fn upgrade_restriction_elapsed_doesnt_mean_can_upgrade() { new_code.clone(), 0, &Configuration::config(), - SetGoAhead::Yes, + UpgradeStrategy::SetGoAheadSignal, ); // Include votes for super-majority. submit_super_majority_pvf_votes(&new_code, EXPECTED_SESSION, true); @@ -879,7 +844,7 @@ fn upgrade_restriction_elapsed_doesnt_mean_can_upgrade() { newer_code.clone(), 30, &Configuration::config(), - SetGoAhead::Yes, + UpgradeStrategy::SetGoAheadSignal, ); assert_eq!(FutureCodeUpgrades::::get(¶_id), Some(0 + validation_upgrade_delay)); }); @@ -940,7 +905,7 @@ fn full_parachain_cleanup_storage() { new_code.clone(), 1, &Configuration::config(), - SetGoAhead::Yes, + UpgradeStrategy::SetGoAheadSignal, ); // Include votes for super-majority. submit_super_majority_pvf_votes(&new_code, EXPECTED_SESSION, true); @@ -1036,7 +1001,7 @@ fn cannot_offboard_ongoing_pvf_check() { new_code.clone(), RELAY_PARENT, &Configuration::config(), - SetGoAhead::Yes, + UpgradeStrategy::SetGoAheadSignal, ); assert!(!Paras::pvfs_require_precheck().is_empty()); @@ -1194,7 +1159,7 @@ fn code_hash_at_returns_up_to_end_of_code_retention_period() { new_code.clone(), 0, &Configuration::config(), - SetGoAhead::Yes, + UpgradeStrategy::SetGoAheadSignal, ); // Include votes for super-majority. submit_super_majority_pvf_votes(&new_code, EXPECTED_SESSION, true); @@ -1303,7 +1268,7 @@ fn pvf_check_coalescing_onboarding_and_upgrade() { validation_code.clone(), RELAY_PARENT, &Configuration::config(), - SetGoAhead::Yes, + UpgradeStrategy::SetGoAheadSignal, ); assert!(!Paras::pvfs_require_precheck().is_empty()); @@ -1413,7 +1378,7 @@ fn pvf_check_upgrade_reject() { new_code.clone(), RELAY_PARENT, &Configuration::config(), - SetGoAhead::Yes, + UpgradeStrategy::SetGoAheadSignal, ); check_code_is_stored(&new_code); @@ -1599,7 +1564,7 @@ fn include_pvf_check_statement_refunds_weight() { new_code.clone(), RELAY_PARENT, &Configuration::config(), - SetGoAhead::Yes, + UpgradeStrategy::SetGoAheadSignal, ); let mut stmts = IntoIterator::into_iter([0, 1, 2, 3]) @@ -1700,7 +1665,7 @@ fn poke_unused_validation_code_doesnt_remove_code_with_users() { validation_code.clone(), 1, &Configuration::config(), - SetGoAhead::Yes, + UpgradeStrategy::SetGoAheadSignal, ); Paras::note_new_head(para_id, HeadData::default(), 1); @@ -1771,7 +1736,7 @@ fn add_trusted_validation_code_insta_approval() { validation_code.clone(), 1, &Configuration::config(), - SetGoAhead::Yes, + UpgradeStrategy::SetGoAheadSignal, ); Paras::note_new_head(para_id, HeadData::default(), 1); @@ -1813,7 +1778,7 @@ fn add_trusted_validation_code_enacts_existing_pvf_vote() { validation_code.clone(), 1, &Configuration::config(), - SetGoAhead::Yes, + UpgradeStrategy::SetGoAheadSignal, ); Paras::note_new_head(para_id, HeadData::default(), 1); diff --git a/prdoc/pr_3341.prdoc b/prdoc/pr_3341.prdoc new file mode 100644 index 000000000000..de714fa5a1e5 --- /dev/null +++ b/prdoc/pr_3341.prdoc @@ -0,0 +1,18 @@ +title: "Fix `schedule_code_upgrade` when called by the owner/root" + +doc: + - audience: Runtime User + description: | + Fixes `schedule_code_upgrade` when being used by the owner/root. The call is used for + manually upgrading the validation code of a parachain on the relay chain. It was failing + before because the relay chain waited for the parachain to make progress. However, this + call is mostly used for when a parachain are bricked which means that they are not able + anymore to build any blocks. The fix is to schedule the validation code upgrade and then + to enact it at the scheduled block. The enacting happens now without requiring the parachain + to make any progress. + +crates: + - name: polkadot-runtime-common + bump: minor + - name: polkadot-runtime-parachains + bump: major From e43f54f10bc07999feae489c975d4a28258d3cdb Mon Sep 17 00:00:00 2001 From: Javier Viola <363911+pepoviola@users.noreply.github.com> Date: Tue, 2 Apr 2024 13:22:21 +0200 Subject: [PATCH 100/257] chore(zombienet): bump version (#3933) This version includes: - Internal metrics of zombienet (used to benchmark with v2). --- .gitlab/pipeline/zombienet.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitlab/pipeline/zombienet.yml b/.gitlab/pipeline/zombienet.yml index 82341eb709fe..52948e1eb719 100644 --- a/.gitlab/pipeline/zombienet.yml +++ b/.gitlab/pipeline/zombienet.yml @@ -1,7 +1,8 @@ .zombienet-refs: extends: .build-refs variables: - ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.98" + ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.99" + PUSHGATEWAY_URL: "http://zombienet-prometheus-pushgateway.managed-monitoring:9091/metrics/job/zombie-metrics" include: # substrate tests From ff1007e166e782584e6fa839f3d6776b104559e4 Mon Sep 17 00:00:00 2001 From: Serban Iorga Date: Tue, 2 Apr 2024 15:25:56 +0300 Subject: [PATCH 101/257] Update bridges subtree (#3938) Pulling the latest changes from `parity-bridges-common` --- Cargo.lock | 8 ++++---- bridges/README.md | 6 +++--- bridges/bin/runtime-common/Cargo.toml | 4 ++-- bridges/chains/chain-asset-hub-rococo/Cargo.toml | 5 +++-- bridges/chains/chain-asset-hub-westend/Cargo.toml | 5 +++-- bridges/chains/chain-bridge-hub-cumulus/Cargo.toml | 1 + bridges/chains/chain-bridge-hub-kusama/Cargo.toml | 1 + bridges/chains/chain-bridge-hub-polkadot/Cargo.toml | 1 + bridges/chains/chain-bridge-hub-rococo/Cargo.toml | 1 + bridges/chains/chain-bridge-hub-westend/Cargo.toml | 1 + bridges/chains/chain-kusama/Cargo.toml | 1 + bridges/chains/chain-polkadot-bulletin/Cargo.toml | 5 +++-- bridges/chains/chain-polkadot/Cargo.toml | 1 + bridges/chains/chain-rococo/Cargo.toml | 1 + bridges/chains/chain-westend/Cargo.toml | 1 + bridges/modules/grandpa/Cargo.toml | 5 +++-- bridges/modules/messages/Cargo.toml | 5 +++-- bridges/modules/parachains/Cargo.toml | 5 +++-- bridges/modules/relayers/Cargo.toml | 5 +++-- bridges/modules/xcm-bridge-hub-router/Cargo.toml | 5 +++-- bridges/modules/xcm-bridge-hub/Cargo.toml | 5 +++-- bridges/primitives/header-chain/Cargo.toml | 5 +++-- bridges/primitives/messages/Cargo.toml | 5 +++-- bridges/primitives/parachains/Cargo.toml | 5 +++-- bridges/primitives/polkadot-core/Cargo.toml | 5 +++-- bridges/primitives/relayers/Cargo.toml | 5 +++-- bridges/primitives/runtime/Cargo.toml | 5 +++-- bridges/primitives/test-utils/Cargo.toml | 3 ++- bridges/primitives/xcm-bridge-hub-router/Cargo.toml | 5 +++-- bridges/primitives/xcm-bridge-hub/Cargo.toml | 1 + 30 files changed, 69 insertions(+), 42 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fa07524cbf20..239e467923ac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17049,9 +17049,9 @@ dependencies = [ [[package]] name = "scale-info" -version = "2.11.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ef2175c2907e7c8bc0a9c3f86aeb5ec1f3b275300ad58a44d0c3ae379a5e52e" +checksum = "788745a868b0e751750388f4e6546eb921ef714a4317fa6954f7cde114eb2eb7" dependencies = [ "bitvec", "cfg-if", @@ -17063,9 +17063,9 @@ dependencies = [ [[package]] name = "scale-info-derive" -version = "2.11.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b8eb8fd61c5cdd3390d9b2132300a7e7618955b98b8416f118c1b4e144f" +checksum = "7dc2f4e8bc344b9fc3d5f74f72c2e55bfc38d28dc2ebc69c194a3df424e4d9ac" dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", diff --git a/bridges/README.md b/bridges/README.md index a2ce213d2541..8bfa39841f51 100644 --- a/bridges/README.md +++ b/bridges/README.md @@ -38,10 +38,10 @@ cargo test --all ``` Also you can build the repo with [Parity CI Docker -image](https://github.com/paritytech/scripts/tree/master/dockerfiles/bridges-ci): +image](https://github.com/paritytech/scripts/tree/master/dockerfiles/ci-unified): ```bash -docker pull paritytech/bridges-ci:production +docker pull paritytech/ci-unified:latest mkdir ~/cache chown 1000:1000 ~/cache #processes in the container runs as "nonroot" user with UID 1000 docker run --rm -it -w /shellhere/parity-bridges-common \ @@ -49,7 +49,7 @@ docker run --rm -it -w /shellhere/parity-bridges-common \ -v "$(pwd)":/shellhere/parity-bridges-common \ -e CARGO_HOME=/cache/cargo/ \ -e SCCACHE_DIR=/cache/sccache/ \ - -e CARGO_TARGET_DIR=/cache/target/ paritytech/bridges-ci:production cargo build --all + -e CARGO_TARGET_DIR=/cache/target/ paritytech/ci-unified:latest cargo build --all #artifacts can be found in ~/cache/target ``` diff --git a/bridges/bin/runtime-common/Cargo.toml b/bridges/bin/runtime-common/Cargo.toml index f00ba1c97345..67b91a16a302 100644 --- a/bridges/bin/runtime-common/Cargo.toml +++ b/bridges/bin/runtime-common/Cargo.toml @@ -11,10 +11,10 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } hash-db = { version = "0.16.0", default-features = false } log = { workspace = true } -scale-info = { version = "2.11.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } static_assertions = { version = "1.1", optional = true } # Bridge dependencies diff --git a/bridges/chains/chain-asset-hub-rococo/Cargo.toml b/bridges/chains/chain-asset-hub-rococo/Cargo.toml index 55dc384badd5..9a6419a5b405 100644 --- a/bridges/chains/chain-asset-hub-rococo/Cargo.toml +++ b/bridges/chains/chain-asset-hub-rococo/Cargo.toml @@ -5,13 +5,14 @@ version = "0.4.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } -scale-info = { version = "2.11.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Substrate Dependencies frame-support = { path = "../../../substrate/frame/support", default-features = false } diff --git a/bridges/chains/chain-asset-hub-westend/Cargo.toml b/bridges/chains/chain-asset-hub-westend/Cargo.toml index 1379b099a2a8..1c08ee28e417 100644 --- a/bridges/chains/chain-asset-hub-westend/Cargo.toml +++ b/bridges/chains/chain-asset-hub-westend/Cargo.toml @@ -5,13 +5,14 @@ version = "0.3.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } -scale-info = { version = "2.11.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Substrate Dependencies frame-support = { path = "../../../substrate/frame/support", default-features = false } diff --git a/bridges/chains/chain-bridge-hub-cumulus/Cargo.toml b/bridges/chains/chain-bridge-hub-cumulus/Cargo.toml index 5e14cb052b72..4b900002a4d8 100644 --- a/bridges/chains/chain-bridge-hub-cumulus/Cargo.toml +++ b/bridges/chains/chain-bridge-hub-cumulus/Cargo.toml @@ -5,6 +5,7 @@ version = "0.7.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true diff --git a/bridges/chains/chain-bridge-hub-kusama/Cargo.toml b/bridges/chains/chain-bridge-hub-kusama/Cargo.toml index 77bc8e54a9d1..ff6dd8849abe 100644 --- a/bridges/chains/chain-bridge-hub-kusama/Cargo.toml +++ b/bridges/chains/chain-bridge-hub-kusama/Cargo.toml @@ -5,6 +5,7 @@ version = "0.6.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true diff --git a/bridges/chains/chain-bridge-hub-polkadot/Cargo.toml b/bridges/chains/chain-bridge-hub-polkadot/Cargo.toml index 5d7a3bbcc1da..da8b8a82fa70 100644 --- a/bridges/chains/chain-bridge-hub-polkadot/Cargo.toml +++ b/bridges/chains/chain-bridge-hub-polkadot/Cargo.toml @@ -5,6 +5,7 @@ version = "0.6.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true diff --git a/bridges/chains/chain-bridge-hub-rococo/Cargo.toml b/bridges/chains/chain-bridge-hub-rococo/Cargo.toml index 3966ef72dcb0..f7672df012f2 100644 --- a/bridges/chains/chain-bridge-hub-rococo/Cargo.toml +++ b/bridges/chains/chain-bridge-hub-rococo/Cargo.toml @@ -5,6 +5,7 @@ version = "0.7.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true diff --git a/bridges/chains/chain-bridge-hub-westend/Cargo.toml b/bridges/chains/chain-bridge-hub-westend/Cargo.toml index d35eac8b3fef..ec74c4b947d6 100644 --- a/bridges/chains/chain-bridge-hub-westend/Cargo.toml +++ b/bridges/chains/chain-bridge-hub-westend/Cargo.toml @@ -5,6 +5,7 @@ version = "0.3.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true diff --git a/bridges/chains/chain-kusama/Cargo.toml b/bridges/chains/chain-kusama/Cargo.toml index 4ff4cb46976b..66061ff2793c 100644 --- a/bridges/chains/chain-kusama/Cargo.toml +++ b/bridges/chains/chain-kusama/Cargo.toml @@ -5,6 +5,7 @@ version = "0.5.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true diff --git a/bridges/chains/chain-polkadot-bulletin/Cargo.toml b/bridges/chains/chain-polkadot-bulletin/Cargo.toml index 37e060d897cd..2db16a00e924 100644 --- a/bridges/chains/chain-polkadot-bulletin/Cargo.toml +++ b/bridges/chains/chain-polkadot-bulletin/Cargo.toml @@ -5,13 +5,14 @@ version = "0.4.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive"] } -scale-info = { version = "2.11.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Bridge Dependencies diff --git a/bridges/chains/chain-polkadot/Cargo.toml b/bridges/chains/chain-polkadot/Cargo.toml index 0db6791f66e0..c700935f3083 100644 --- a/bridges/chains/chain-polkadot/Cargo.toml +++ b/bridges/chains/chain-polkadot/Cargo.toml @@ -5,6 +5,7 @@ version = "0.5.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true diff --git a/bridges/chains/chain-rococo/Cargo.toml b/bridges/chains/chain-rococo/Cargo.toml index 9c63f960ae49..5a5613bb376a 100644 --- a/bridges/chains/chain-rococo/Cargo.toml +++ b/bridges/chains/chain-rococo/Cargo.toml @@ -5,6 +5,7 @@ version = "0.6.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true diff --git a/bridges/chains/chain-westend/Cargo.toml b/bridges/chains/chain-westend/Cargo.toml index f5de9b95c82c..10b06d76507e 100644 --- a/bridges/chains/chain-westend/Cargo.toml +++ b/bridges/chains/chain-westend/Cargo.toml @@ -5,6 +5,7 @@ version = "0.3.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true diff --git a/bridges/modules/grandpa/Cargo.toml b/bridges/modules/grandpa/Cargo.toml index 25c6c4e03d55..0db1827211a0 100644 --- a/bridges/modules/grandpa/Cargo.toml +++ b/bridges/modules/grandpa/Cargo.toml @@ -5,6 +5,7 @@ description = "Module implementing GRANDPA on-chain light client used for bridgi authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true @@ -12,10 +13,10 @@ workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } finality-grandpa = { version = "0.16.2", default-features = false } log = { workspace = true } -scale-info = { version = "2.11.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Bridge Dependencies diff --git a/bridges/modules/messages/Cargo.toml b/bridges/modules/messages/Cargo.toml index 7d0e1b94959e..df5b92db7402 100644 --- a/bridges/modules/messages/Cargo.toml +++ b/bridges/modules/messages/Cargo.toml @@ -5,15 +5,16 @@ version = "0.7.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { workspace = true } num-traits = { version = "0.2", default-features = false } -scale-info = { version = "2.11.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Bridge dependencies diff --git a/bridges/modules/parachains/Cargo.toml b/bridges/modules/parachains/Cargo.toml index a9dd9beeb1f1..35213be0674a 100644 --- a/bridges/modules/parachains/Cargo.toml +++ b/bridges/modules/parachains/Cargo.toml @@ -5,14 +5,15 @@ description = "Module that allows bridged relay chains to exchange information o authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { workspace = true } -scale-info = { version = "2.11.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Bridge Dependencies diff --git a/bridges/modules/relayers/Cargo.toml b/bridges/modules/relayers/Cargo.toml index f3de72da7716..e2b7aca92249 100644 --- a/bridges/modules/relayers/Cargo.toml +++ b/bridges/modules/relayers/Cargo.toml @@ -5,14 +5,15 @@ version = "0.7.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { workspace = true } -scale-info = { version = "2.11.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Bridge dependencies diff --git a/bridges/modules/xcm-bridge-hub-router/Cargo.toml b/bridges/modules/xcm-bridge-hub-router/Cargo.toml index 98477f2df185..06f2a339bed9 100644 --- a/bridges/modules/xcm-bridge-hub-router/Cargo.toml +++ b/bridges/modules/xcm-bridge-hub-router/Cargo.toml @@ -5,14 +5,15 @@ version = "0.5.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { workspace = true } -scale-info = { version = "2.11.0", default-features = false, features = ["bit-vec", "derive", "serde"] } +scale-info = { version = "2.11.1", default-features = false, features = ["bit-vec", "derive", "serde"] } # Bridge dependencies diff --git a/bridges/modules/xcm-bridge-hub/Cargo.toml b/bridges/modules/xcm-bridge-hub/Cargo.toml index 68ac32281f3d..4483a3790900 100644 --- a/bridges/modules/xcm-bridge-hub/Cargo.toml +++ b/bridges/modules/xcm-bridge-hub/Cargo.toml @@ -5,14 +5,15 @@ version = "0.2.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { workspace = true } -scale-info = { version = "2.11.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Bridge Dependencies bp-messages = { path = "../../primitives/messages", default-features = false } diff --git a/bridges/primitives/header-chain/Cargo.toml b/bridges/primitives/header-chain/Cargo.toml index d96a02efba8a..f7a61a9ff32b 100644 --- a/bridges/primitives/header-chain/Cargo.toml +++ b/bridges/primitives/header-chain/Cargo.toml @@ -5,14 +5,15 @@ version = "0.7.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } finality-grandpa = { version = "0.16.2", default-features = false } -scale-info = { version = "2.11.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["alloc", "derive"], workspace = true } # Bridge dependencies diff --git a/bridges/primitives/messages/Cargo.toml b/bridges/primitives/messages/Cargo.toml index 9d742e3eded3..d41acfb9d328 100644 --- a/bridges/primitives/messages/Cargo.toml +++ b/bridges/primitives/messages/Cargo.toml @@ -5,13 +5,14 @@ version = "0.7.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["bit-vec", "derive"] } -scale-info = { version = "2.11.0", default-features = false, features = ["bit-vec", "derive"] } +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["bit-vec", "derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["bit-vec", "derive"] } serde = { features = ["alloc", "derive"], workspace = true } # Bridge dependencies diff --git a/bridges/primitives/parachains/Cargo.toml b/bridges/primitives/parachains/Cargo.toml index 3846c5635756..2e7000b86a5e 100644 --- a/bridges/primitives/parachains/Cargo.toml +++ b/bridges/primitives/parachains/Cargo.toml @@ -5,14 +5,15 @@ version = "0.7.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } impl-trait-for-tuples = "0.2" -scale-info = { version = "2.11.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Bridge dependencies diff --git a/bridges/primitives/polkadot-core/Cargo.toml b/bridges/primitives/polkadot-core/Cargo.toml index 5ab502569e43..53b1e574cb19 100644 --- a/bridges/primitives/polkadot-core/Cargo.toml +++ b/bridges/primitives/polkadot-core/Cargo.toml @@ -5,14 +5,15 @@ version = "0.7.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } parity-util-mem = { version = "0.12.0", optional = true } -scale-info = { version = "2.11.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { optional = true, features = ["derive"], workspace = true, default-features = true } # Bridge Dependencies diff --git a/bridges/primitives/relayers/Cargo.toml b/bridges/primitives/relayers/Cargo.toml index 71d0fbf2ec3a..1be7f1dc6ebd 100644 --- a/bridges/primitives/relayers/Cargo.toml +++ b/bridges/primitives/relayers/Cargo.toml @@ -5,13 +5,14 @@ version = "0.7.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["bit-vec", "derive"] } -scale-info = { version = "2.11.0", default-features = false, features = ["bit-vec", "derive"] } +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["bit-vec", "derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["bit-vec", "derive"] } # Bridge Dependencies diff --git a/bridges/primitives/runtime/Cargo.toml b/bridges/primitives/runtime/Cargo.toml index 2d454d264a13..cca9c21a608d 100644 --- a/bridges/primitives/runtime/Cargo.toml +++ b/bridges/primitives/runtime/Cargo.toml @@ -5,17 +5,18 @@ version = "0.7.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } hash-db = { version = "0.16.0", default-features = false } impl-trait-for-tuples = "0.2.2" log = { workspace = true } num-traits = { version = "0.2", default-features = false } -scale-info = { version = "2.11.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["alloc", "derive"], workspace = true } # Substrate Dependencies diff --git a/bridges/primitives/test-utils/Cargo.toml b/bridges/primitives/test-utils/Cargo.toml index d379e950b86e..d314c38683cd 100644 --- a/bridges/primitives/test-utils/Cargo.toml +++ b/bridges/primitives/test-utils/Cargo.toml @@ -5,6 +5,7 @@ description = "Utilities for testing substrate-based runtime bridge code" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true @@ -14,7 +15,7 @@ bp-header-chain = { path = "../header-chain", default-features = false } bp-parachains = { path = "../parachains", default-features = false } bp-polkadot-core = { path = "../polkadot-core", default-features = false } bp-runtime = { path = "../runtime", default-features = false } -codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } ed25519-dalek = { version = "2.1", default-features = false } finality-grandpa = { version = "0.16.2", default-features = false } sp-application-crypto = { path = "../../../substrate/primitives/application-crypto", default-features = false } diff --git a/bridges/primitives/xcm-bridge-hub-router/Cargo.toml b/bridges/primitives/xcm-bridge-hub-router/Cargo.toml index 734930f18c47..94eece16d579 100644 --- a/bridges/primitives/xcm-bridge-hub-router/Cargo.toml +++ b/bridges/primitives/xcm-bridge-hub-router/Cargo.toml @@ -5,13 +5,14 @@ version = "0.6.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true [dependencies] -codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["bit-vec", "derive"] } -scale-info = { version = "2.11.0", default-features = false, features = ["bit-vec", "derive"] } +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["bit-vec", "derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["bit-vec", "derive"] } # Substrate Dependencies sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } diff --git a/bridges/primitives/xcm-bridge-hub/Cargo.toml b/bridges/primitives/xcm-bridge-hub/Cargo.toml index ad49ec1e8315..27881bc99d1f 100644 --- a/bridges/primitives/xcm-bridge-hub/Cargo.toml +++ b/bridges/primitives/xcm-bridge-hub/Cargo.toml @@ -5,6 +5,7 @@ version = "0.2.0" authors.workspace = true edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +repository.workspace = true [lints] workspace = true From 3021cbcdded7277dd35f1210b26093630727dc71 Mon Sep 17 00:00:00 2001 From: Adrian Catangiu Date: Tue, 2 Apr 2024 15:28:48 +0300 Subject: [PATCH 102/257] beefy: error logs for validators with dummy keys (#3939) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This outputs: ``` 2024-04-02 14:36:02.135 ERROR tokio-runtime-worker beefy: 🥩 for session starting at block 21990151 no BEEFY authority key found in store, you must generate valid session keys (https://wiki.polkadot.network/docs/maintain-guides-how-to-validate-polkadot#generating-the-session-keys) ``` error log entry, once every session, for nodes running with `Role::Authority` that have no public BEEFY key in their keystore --------- Co-authored-by: Bastian Köcher --- polkadot/node/service/src/lib.rs | 25 +++--- substrate/bin/node/cli/src/service.rs | 1 + substrate/client/consensus/beefy/src/lib.rs | 18 ++++- substrate/client/consensus/beefy/src/tests.rs | 2 + .../client/consensus/beefy/src/worker.rs | 77 ++++--------------- 5 files changed, 50 insertions(+), 73 deletions(-) diff --git a/polkadot/node/service/src/lib.rs b/polkadot/node/service/src/lib.rs index 4f4ede537055..61076477f8e7 100644 --- a/polkadot/node/service/src/lib.rs +++ b/polkadot/node/service/src/lib.rs @@ -1233,6 +1233,7 @@ pub fn new_full( prometheus_registry: prometheus_registry.clone(), links: beefy_links, on_demand_justifications_handler: beefy_on_demand_justifications_handler, + is_authority: role.is_authority(), }; let gadget = beefy::start_beefy_gadget::<_, _, _, _, _, _, _>(beefy_params); @@ -1242,18 +1243,18 @@ pub fn new_full( task_manager .spawn_essential_handle() .spawn_blocking("beefy-gadget", None, gadget); - // When offchain indexing is enabled, MMR gadget should also run. - if is_offchain_indexing_enabled { - task_manager.spawn_essential_handle().spawn_blocking( - "mmr-gadget", - None, - MmrGadget::start( - client.clone(), - backend.clone(), - sp_mmr_primitives::INDEXING_PREFIX.to_vec(), - ), - ); - } + } + // When offchain indexing is enabled, MMR gadget should also run. + if is_offchain_indexing_enabled { + task_manager.spawn_essential_handle().spawn_blocking( + "mmr-gadget", + None, + MmrGadget::start( + client.clone(), + backend.clone(), + sp_mmr_primitives::INDEXING_PREFIX.to_vec(), + ), + ); } let config = grandpa::Config { diff --git a/substrate/bin/node/cli/src/service.rs b/substrate/bin/node/cli/src/service.rs index dddb261a71d1..d6e2a29d30b8 100644 --- a/substrate/bin/node/cli/src/service.rs +++ b/substrate/bin/node/cli/src/service.rs @@ -652,6 +652,7 @@ pub fn new_full_base( prometheus_registry: prometheus_registry.clone(), links: beefy_links, on_demand_justifications_handler: beefy_on_demand_justifications_handler, + is_authority: role.is_authority(), }; let beefy_gadget = beefy::start_beefy_gadget::<_, _, _, _, _, _, _>(beefy_params); diff --git a/substrate/client/consensus/beefy/src/lib.rs b/substrate/client/consensus/beefy/src/lib.rs index 323af1bc8305..714a0fb7c885 100644 --- a/substrate/client/consensus/beefy/src/lib.rs +++ b/substrate/client/consensus/beefy/src/lib.rs @@ -222,6 +222,8 @@ pub struct BeefyParams { pub links: BeefyVoterLinks, /// Handler for incoming BEEFY justifications requests from a remote peer. pub on_demand_justifications_handler: BeefyJustifsRequestHandler, + /// Whether running under "Authority" role. + pub is_authority: bool, } /// Helper object holding BEEFY worker communication/gossip components. /// @@ -270,6 +272,7 @@ where min_block_delta: u32, gossip_validator: Arc>, finality_notifications: &mut Fuse>, + is_authority: bool, ) -> Result { // Wait for BEEFY pallet to be active before starting voter. let (beefy_genesis, best_grandpa) = @@ -283,6 +286,7 @@ where runtime.clone(), &key_store, &metrics, + is_authority, ) .await?; // Update the gossip validator with the right starting round and set id. @@ -301,6 +305,7 @@ where comms: BeefyComms, links: BeefyVoterLinks, pending_justifications: BTreeMap, BeefyVersionedFinalityProof>, + is_authority: bool, ) -> BeefyWorker { BeefyWorker { backend: self.backend, @@ -313,6 +318,7 @@ where comms, links, pending_justifications, + is_authority, } } @@ -423,6 +429,7 @@ where runtime: Arc, key_store: &BeefyKeystore, metrics: &Option, + is_authority: bool, ) -> Result, Error> { // Initialize voter state from AUX DB if compatible. if let Some(mut state) = crate::aux_schema::load_persistent(backend.as_ref())? @@ -455,7 +462,13 @@ where "🥩 Handling missed BEEFY session after node restart: {:?}.", new_session_start ); - state.init_session_at(new_session_start, validator_set, key_store, metrics); + state.init_session_at( + new_session_start, + validator_set, + key_store, + metrics, + is_authority, + ); } return Ok(state) } @@ -491,6 +504,7 @@ pub async fn start_beefy_gadget( prometheus_registry, links, mut on_demand_justifications_handler, + is_authority, } = beefy_params; let BeefyNetworkParams { @@ -553,6 +567,7 @@ pub async fn start_beefy_gadget( min_block_delta, beefy_comms.gossip_validator.clone(), &mut finality_notifications, + is_authority, ).fuse() => { match builder_init_result { Ok(builder) => break builder, @@ -580,6 +595,7 @@ pub async fn start_beefy_gadget( beefy_comms, links.clone(), BTreeMap::new(), + is_authority, ); match futures::future::select( diff --git a/substrate/client/consensus/beefy/src/tests.rs b/substrate/client/consensus/beefy/src/tests.rs index d106c9dcd881..aecfec7b9ed1 100644 --- a/substrate/client/consensus/beefy/src/tests.rs +++ b/substrate/client/consensus/beefy/src/tests.rs @@ -379,6 +379,7 @@ async fn voter_init_setup( Arc::new(api.clone()), &key_store, &metrics, + true, ) .await } @@ -438,6 +439,7 @@ where min_block_delta, prometheus_registry: None, on_demand_justifications_handler: on_demand_justif_handler, + is_authority: true, }; let task = crate::start_beefy_gadget::<_, _, _, _, _, _, _>(beefy_params); diff --git a/substrate/client/consensus/beefy/src/worker.rs b/substrate/client/consensus/beefy/src/worker.rs index 7a47f286ef75..ac6b72d1ea40 100644 --- a/substrate/client/consensus/beefy/src/worker.rs +++ b/substrate/client/consensus/beefy/src/worker.rs @@ -33,7 +33,7 @@ use crate::{ }; use codec::{Codec, Decode, DecodeAll, Encode}; use futures::{stream::Fuse, FutureExt, StreamExt}; -use log::{debug, error, info, log_enabled, trace, warn}; +use log::{debug, error, info, trace, warn}; use sc_client_api::{Backend, FinalityNotification, FinalityNotifications, HeaderBackend}; use sc_utils::notification::NotificationReceiver; use sp_api::ProvideRuntimeApi; @@ -51,7 +51,7 @@ use sp_runtime::{ SaturatedConversion, }; use std::{ - collections::{BTreeMap, BTreeSet, VecDeque}, + collections::{BTreeMap, VecDeque}, fmt::Debug, sync::Arc, }; @@ -332,6 +332,7 @@ impl PersistedState { validator_set: ValidatorSet, key_store: &BeefyKeystore, metrics: &Option, + is_authority: bool, ) { debug!(target: LOG_TARGET, "🥩 New active validator set: {:?}", validator_set); @@ -348,11 +349,16 @@ impl PersistedState { } } - if log_enabled!(target: LOG_TARGET, log::Level::Debug) { - // verify the new validator set - only do it if we're also logging the warning - if verify_validator_set::(&new_session_start, &validator_set, key_store).is_err() { - metric_inc!(metrics, beefy_no_authority_found_in_store); - } + // verify we have some BEEFY key available in keystore when role is authority. + if is_authority && key_store.public_keys().map_or(false, |k| k.is_empty()) { + error!( + target: LOG_TARGET, + "🥩 for session starting at block {:?} no BEEFY authority key found in store, \ + you must generate valid session keys \ + (https://wiki.polkadot.network/docs/maintain-guides-how-to-validate-polkadot#generating-the-session-keys)", + new_session_start, + ); + metric_inc!(metrics, beefy_no_authority_found_in_store); } let id = validator_set.id(); @@ -390,6 +396,8 @@ pub(crate) struct BeefyWorker { pub persisted_state: PersistedState, /// BEEFY voter metrics pub metrics: Option, + /// Node runs under "Authority" role. + pub is_authority: bool, } impl BeefyWorker @@ -425,6 +433,7 @@ where validator_set, &self.key_store, &self.metrics, + self.is_authority, ); } @@ -1040,33 +1049,6 @@ where } } -/// Verify `active` validator set for `block` against the key store -/// -/// We want to make sure that we have _at least one_ key in our keystore that -/// is part of the validator set, that's because if there are no local keys -/// then we can't perform our job as a validator. -/// -/// Note that for a non-authority node there will be no keystore, and we will -/// return an error and don't check. The error can usually be ignored. -fn verify_validator_set( - block: &NumberFor, - active: &ValidatorSet, - key_store: &BeefyKeystore, -) -> Result<(), Error> { - let active: BTreeSet<&AuthorityId> = active.validators().iter().collect(); - - let public_keys = key_store.public_keys()?; - let store: BTreeSet<&AuthorityId> = public_keys.iter().collect(); - - if store.intersection(&active).count() == 0 { - let msg = "no authority public key found in store".to_string(); - debug!(target: LOG_TARGET, "🥩 for block {:?} {}", block, msg); - Err(Error::Keystore(msg)) - } else { - Ok(()) - } -} - #[cfg(test)] pub(crate) mod tests { use super::*; @@ -1208,6 +1190,7 @@ pub(crate) mod tests { comms, pending_justifications: BTreeMap::new(), persisted_state, + is_authority: true, } } @@ -1471,32 +1454,6 @@ pub(crate) mod tests { assert_eq!(extracted, Some(validator_set)); } - #[tokio::test] - async fn keystore_vs_validator_set() { - let keys = &[Keyring::Alice]; - let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); - let mut net = BeefyTestNet::new(1); - let mut worker = create_beefy_worker(net.peer(0), &keys[0], 1, validator_set.clone()); - - // keystore doesn't contain other keys than validators' - assert_eq!(verify_validator_set::(&1, &validator_set, &worker.key_store), Ok(())); - - // unknown `Bob` key - let keys = &[Keyring::Bob]; - let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); - let err_msg = "no authority public key found in store".to_string(); - let expected = Err(Error::Keystore(err_msg)); - assert_eq!(verify_validator_set::(&1, &validator_set, &worker.key_store), expected); - - // worker has no keystore - worker.key_store = None.into(); - let expected_err = Err(Error::Keystore("no Keystore".into())); - assert_eq!( - verify_validator_set::(&1, &validator_set, &worker.key_store), - expected_err - ); - } - #[tokio::test] async fn should_finalize_correctly() { let keys = [Keyring::Alice]; From a1e6f044737118eca827c452cd60f8fb9e8de42e Mon Sep 17 00:00:00 2001 From: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Date: Tue, 2 Apr 2024 16:12:34 +0300 Subject: [PATCH 103/257] chainHead: Allow methods to be called from within a single connection context and limit connections (#3481) This PR ensures that the chainHead RPC class can be called only from within the same connection context. The chainHead methods are now registered as raw methods. - https://github.com/paritytech/jsonrpsee/pull/1297 The concept of raw methods is introduced in jsonrpsee, which is an async method that exposes the connection ID: The raw method doesn't have the concept of a blocking method. Previously blocking methods are now spawning a blocking task to handle their blocking (ie DB) access. We spawn the same number of tasks as before, however we do that explicitly. Another approach would be implementing a RPC middleware that captures and decodes the method parameters: - https://github.com/paritytech/polkadot-sdk/pull/3343 However, that approach is prone to errors since the methods are hardcoded by name. Performace is affected by the double deserialization that needs to happen to extract the subscription ID we'd like to limit. Once from the middleware, and once from the methods itself. This PR paves the way to implement the chainHead connection limiter: - https://github.com/paritytech/polkadot-sdk/issues/1505 Registering tokens (subscription ID / operation ID) on the `RpcConnections` could be extended to return an error when the maximum number of operations is reached. While at it, have added an integration-test to ensure that chainHead methods can be called from within the same connection context. Before this is merged, a new JsonRPC release should be made to expose the `raw-methods`: - [x] Use jsonrpsee from crates io (blocked by: https://github.com/paritytech/jsonrpsee/pull/1297) Closes: https://github.com/paritytech/polkadot-sdk/issues/3207 cc @paritytech/subxt-team --------- Signed-off-by: Alexandru Vasile Co-authored-by: Niklas Adolfsson --- Cargo.lock | 34 +- substrate/client/rpc-spec-v2/Cargo.toml | 1 + .../client/rpc-spec-v2/src/chain_head/api.rs | 30 +- .../rpc-spec-v2/src/chain_head/chain_head.rs | 321 ++++++++++++------ .../src/chain_head/chain_head_follow.rs | 17 +- .../rpc-spec-v2/src/chain_head/error.rs | 7 + .../src/chain_head/subscription/inner.rs | 53 +++ .../src/chain_head/subscription/mod.rs | 132 ++++++- .../rpc-spec-v2/src/chain_head/tests.rs | 230 ++++++++++++- .../rpc-spec-v2/src/common/connections.rs | 262 ++++++++++++++ .../client/rpc-spec-v2/src/common/mod.rs | 1 + 11 files changed, 934 insertions(+), 154 deletions(-) create mode 100644 substrate/client/rpc-spec-v2/src/common/connections.rs diff --git a/Cargo.lock b/Cargo.lock index 239e467923ac..09114e9cc835 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6840,9 +6840,9 @@ checksum = "078e285eafdfb6c4b434e0d31e8cfcb5115b651496faca5749b88fafd4f23bfd" [[package]] name = "jsonrpsee" -version = "0.22.0" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a95f7cc23d5fab0cdeeaf6bad8c8f5e7a3aa7f0d211957ea78232b327ab27b0" +checksum = "87f3ae45a64cfc0882934f963be9431b2a165d667f53140358181f262aca0702" dependencies = [ "jsonrpsee-core", "jsonrpsee-http-client", @@ -6856,9 +6856,9 @@ dependencies = [ [[package]] name = "jsonrpsee-client-transport" -version = "0.22.0" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b1736cfa3845fd9f8f43751f2b8e0e83f7b6081e754502f7d63b6587692cc83" +checksum = "455fc882e56f58228df2aee36b88a1340eafd707c76af2fa68cf94b37d461131" dependencies = [ "futures-util", "http", @@ -6877,9 +6877,9 @@ dependencies = [ [[package]] name = "jsonrpsee-core" -version = "0.22.0" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82030d038658974732103e623ba2e0abec03bbbe175b39c0a2fafbada60c5868" +checksum = "b75568f4f9696e3a47426e1985b548e1a9fcb13372a5e320372acaf04aca30d1" dependencies = [ "anyhow", "async-lock 3.3.0", @@ -6903,9 +6903,9 @@ dependencies = [ [[package]] name = "jsonrpsee-http-client" -version = "0.22.0" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36a06ef0de060005fddf772d54597bb6a8b0413da47dcffd304b0306147b9678" +checksum = "9e7a95e346f55df84fb167b7e06470e196e7d5b9488a21d69c5d9732043ba7ba" dependencies = [ "async-trait", "hyper", @@ -6923,22 +6923,22 @@ dependencies = [ [[package]] name = "jsonrpsee-proc-macros" -version = "0.22.0" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69fc56131589f82e57805f7338b87023db4aafef813555708b159787e34ad6bc" +checksum = "30ca066e73dd70294aebc5c2675d8ffae43be944af027c857ce0d4c51785f014" dependencies = [ "heck 0.4.1", "proc-macro-crate 3.0.0", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.53", ] [[package]] name = "jsonrpsee-server" -version = "0.22.0" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d85be77fe5b2a94589e3164fb780017f7aff7d646b49278c0d0346af16975c8e" +checksum = "0e29c1bd1f9bba83c864977c73404e505f74f730fa0db89dd490ec174e36d7f0" dependencies = [ "futures-util", "http", @@ -6960,9 +6960,9 @@ dependencies = [ [[package]] name = "jsonrpsee-types" -version = "0.22.0" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a48fdc1202eafc51c63e00406575e59493284ace8b8b61aa16f3a6db5d64f1a" +checksum = "3467fd35feeee179f71ab294516bdf3a81139e7aeebdd860e46897c12e1a3368" dependencies = [ "anyhow", "beef", @@ -6973,9 +6973,9 @@ dependencies = [ [[package]] name = "jsonrpsee-ws-client" -version = "0.22.0" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5ce25d70a8e4d3cc574bbc3cad0137c326ad64b194793d5e7bbdd3fa4504181" +checksum = "68ca71e74983f624c0cb67828e480a981586074da8ad3a2f214c6a3f884edab9" dependencies = [ "http", "jsonrpsee-client-transport", diff --git a/substrate/client/rpc-spec-v2/Cargo.toml b/substrate/client/rpc-spec-v2/Cargo.toml index c62b3e789d38..937e5c6b626a 100644 --- a/substrate/client/rpc-spec-v2/Cargo.toml +++ b/substrate/client/rpc-spec-v2/Cargo.toml @@ -44,6 +44,7 @@ futures-util = { version = "0.3.30", default-features = false } rand = "0.8.5" [dev-dependencies] +jsonrpsee = { version = "0.22", features = ["server", "ws-client"] } serde_json = { workspace = true, default-features = true } tokio = { version = "1.22.0", features = ["macros"] } substrate-test-runtime-client = { path = "../../test-utils/runtime/client" } diff --git a/substrate/client/rpc-spec-v2/src/chain_head/api.rs b/substrate/client/rpc-spec-v2/src/chain_head/api.rs index 00000e1fb277..3851adac2644 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/api.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/api.rs @@ -27,7 +27,7 @@ use crate::{ common::events::StorageQuery, }; use jsonrpsee::{proc_macros::rpc, server::ResponsePayload}; -use sp_rpc::list::ListOrValue; +pub use sp_rpc::list::ListOrValue; #[rpc(client, server)] pub trait ChainHeadApi { @@ -54,8 +54,8 @@ pub trait ChainHeadApi { /// # Unstable /// /// This method is unstable and subject to change in the future. - #[method(name = "chainHead_unstable_body", blocking)] - fn chain_head_unstable_body( + #[method(name = "chainHead_unstable_body", raw_method)] + async fn chain_head_unstable_body( &self, follow_subscription: String, hash: Hash, @@ -73,8 +73,8 @@ pub trait ChainHeadApi { /// # Unstable /// /// This method is unstable and subject to change in the future. - #[method(name = "chainHead_unstable_header", blocking)] - fn chain_head_unstable_header( + #[method(name = "chainHead_unstable_header", raw_method)] + async fn chain_head_unstable_header( &self, follow_subscription: String, hash: Hash, @@ -85,8 +85,8 @@ pub trait ChainHeadApi { /// # Unstable /// /// This method is unstable and subject to change in the future. - #[method(name = "chainHead_unstable_storage", blocking)] - fn chain_head_unstable_storage( + #[method(name = "chainHead_unstable_storage", raw_method)] + async fn chain_head_unstable_storage( &self, follow_subscription: String, hash: Hash, @@ -99,8 +99,8 @@ pub trait ChainHeadApi { /// # Unstable /// /// This method is unstable and subject to change in the future. - #[method(name = "chainHead_unstable_call", blocking)] - fn chain_head_unstable_call( + #[method(name = "chainHead_unstable_call", raw_method)] + async fn chain_head_unstable_call( &self, follow_subscription: String, hash: Hash, @@ -118,8 +118,8 @@ pub trait ChainHeadApi { /// # Unstable /// /// This method is unstable and subject to change in the future. - #[method(name = "chainHead_unstable_unpin", blocking)] - fn chain_head_unstable_unpin( + #[method(name = "chainHead_unstable_unpin", raw_method)] + async fn chain_head_unstable_unpin( &self, follow_subscription: String, hash_or_hashes: ListOrValue, @@ -131,8 +131,8 @@ pub trait ChainHeadApi { /// # Unstable /// /// This method is unstable and subject to change in the future. - #[method(name = "chainHead_unstable_continue", blocking)] - fn chain_head_unstable_continue( + #[method(name = "chainHead_unstable_continue", raw_method)] + async fn chain_head_unstable_continue( &self, follow_subscription: String, operation_id: String, @@ -145,8 +145,8 @@ pub trait ChainHeadApi { /// # Unstable /// /// This method is unstable and subject to change in the future. - #[method(name = "chainHead_unstable_stopOperation", blocking)] - fn chain_head_unstable_stop_operation( + #[method(name = "chainHead_unstable_stopOperation", raw_method)] + async fn chain_head_unstable_stop_operation( &self, follow_subscription: String, operation_id: String, diff --git a/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs b/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs index 2bda22b45239..975abbca4b68 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs @@ -34,10 +34,10 @@ use crate::{ hex_string, SubscriptionTaskExecutor, }; use codec::Encode; -use futures::future::FutureExt; +use futures::{channel::oneshot, future::FutureExt}; use jsonrpsee::{ - core::async_trait, server::ResponsePayload, types::SubscriptionId, MethodResponseFuture, - PendingSubscriptionSink, SubscriptionSink, + core::async_trait, server::ResponsePayload, types::SubscriptionId, ConnectionDetails, + MethodResponseFuture, PendingSubscriptionSink, SubscriptionSink, }; use log::debug; use sc_client_api::{ @@ -65,6 +65,8 @@ pub struct ChainHeadConfig { /// The maximum number of items reported by the `chainHead_storage` before /// pagination is required. pub operation_max_storage_items: usize, + /// The maximum number of `chainHead_follow` subscriptions per connection. + pub max_follow_subscriptions_per_connection: usize, } /// Maximum pinned blocks across all connections. @@ -86,6 +88,9 @@ const MAX_ONGOING_OPERATIONS: usize = 16; /// before paginations is required. const MAX_STORAGE_ITER_ITEMS: usize = 5; +/// The maximum number of `chainHead_follow` subscriptions per connection. +const MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION: usize = 4; + impl Default for ChainHeadConfig { fn default() -> Self { ChainHeadConfig { @@ -93,6 +98,7 @@ impl Default for ChainHeadConfig { subscription_max_pinned_duration: MAX_PINNED_DURATION, subscription_max_ongoing_operations: MAX_ONGOING_OPERATIONS, operation_max_storage_items: MAX_STORAGE_ITER_ITEMS, + max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, } } } @@ -106,7 +112,7 @@ pub struct ChainHead, Block: BlockT, Client> { /// Executor to spawn subscriptions. executor: SubscriptionTaskExecutor, /// Keep track of the pinned blocks for each subscription. - subscriptions: Arc>, + subscriptions: SubscriptionManagement, /// The maximum number of items reported by the `chainHead_storage` before /// pagination is required. operation_max_storage_items: usize, @@ -126,12 +132,13 @@ impl, Block: BlockT, Client> ChainHead { client, backend: backend.clone(), executor, - subscriptions: Arc::new(SubscriptionManagement::new( + subscriptions: SubscriptionManagement::new( config.global_max_pinned_blocks, config.subscription_max_pinned_duration, config.subscription_max_ongoing_operations, + config.max_follow_subscriptions_per_connection, backend, - )), + ), operation_max_storage_items: config.operation_max_storage_items, _phantom: PhantomData, } @@ -182,12 +189,23 @@ where let client = self.client.clone(); let fut = async move { + // Ensure the current connection ID has enough space to accept a new subscription. + let connection_id = pending.connection_id(); + // The RAII `reserved_subscription` will clean up resources on drop: + // - free the reserved subscription for the connection ID. + // - remove the subscription ID from the subscription management. + let Some(mut reserved_subscription) = subscriptions.reserve_subscription(connection_id) + else { + pending.reject(ChainHeadRpcError::ReachedLimits).await; + return + }; + let Ok(sink) = pending.accept().await else { return }; let sub_id = read_subscription_id_as_string(&sink); - // Keep track of the subscription. - let Some(sub_data) = subscriptions.insert_subscription(sub_id.clone(), with_runtime) + let Some(sub_data) = + reserved_subscription.insert_subscription(sub_id.clone(), with_runtime) else { // Inserting the subscription can only fail if the JsonRPSee // generated a duplicate subscription ID. @@ -201,91 +219,117 @@ where let mut chain_head_follow = ChainHeadFollower::new( client, backend, - subscriptions.clone(), + subscriptions, with_runtime, sub_id.clone(), ); chain_head_follow.generate_events(sink, sub_data).await; - subscriptions.remove_subscription(&sub_id); debug!(target: LOG_TARGET, "[follow][id={:?}] Subscription removed", sub_id); }; self.executor.spawn("substrate-rpc-subscription", Some("rpc"), fut.boxed()); } - fn chain_head_unstable_body( + async fn chain_head_unstable_body( &self, + connection_details: ConnectionDetails, follow_subscription: String, hash: Block::Hash, ) -> ResponsePayload<'static, MethodResponse> { - let mut block_guard = match self.subscriptions.lock_block(&follow_subscription, hash, 1) { - Ok(block) => block, - Err(SubscriptionManagementError::SubscriptionAbsent) | - Err(SubscriptionManagementError::ExceededLimits) => - return ResponsePayload::success(MethodResponse::LimitReached), - Err(SubscriptionManagementError::BlockHashAbsent) => { - // Block is not part of the subscription. - return ResponsePayload::error(ChainHeadRpcError::InvalidBlock); - }, - Err(_) => return ResponsePayload::error(ChainHeadRpcError::InvalidBlock), - }; + if !self + .subscriptions + .contains_subscription(connection_details.id(), &follow_subscription) + { + // The spec says to return `LimitReached` if the follow subscription is invalid or + // stale. + return ResponsePayload::success(MethodResponse::LimitReached); + } - let operation_id = block_guard.operation().operation_id(); + let client = self.client.clone(); + let subscriptions = self.subscriptions.clone(); + let executor = self.executor.clone(); + + let result = spawn_blocking(&self.executor, async move { + let mut block_guard = match subscriptions.lock_block(&follow_subscription, hash, 1) { + Ok(block) => block, + Err(SubscriptionManagementError::SubscriptionAbsent) | + Err(SubscriptionManagementError::ExceededLimits) => + return ResponsePayload::success(MethodResponse::LimitReached), + Err(SubscriptionManagementError::BlockHashAbsent) => { + // Block is not part of the subscription. + return ResponsePayload::error(ChainHeadRpcError::InvalidBlock); + }, + Err(_) => return ResponsePayload::error(ChainHeadRpcError::InvalidBlock), + }; - let event = match self.client.block(hash) { - Ok(Some(signed_block)) => { - let extrinsics = signed_block - .block - .extrinsics() - .iter() - .map(|extrinsic| hex_string(&extrinsic.encode())) - .collect(); - FollowEvent::::OperationBodyDone(OperationBodyDone { + let operation_id = block_guard.operation().operation_id(); + + let event = match client.block(hash) { + Ok(Some(signed_block)) => { + let extrinsics = signed_block + .block + .extrinsics() + .iter() + .map(|extrinsic| hex_string(&extrinsic.encode())) + .collect(); + FollowEvent::::OperationBodyDone(OperationBodyDone { + operation_id: operation_id.clone(), + value: extrinsics, + }) + }, + Ok(None) => { + // The block's body was pruned. This subscription ID has become invalid. + debug!( + target: LOG_TARGET, + "[body][id={:?}] Stopping subscription because hash={:?} was pruned", + &follow_subscription, + hash + ); + subscriptions.remove_subscription(&follow_subscription); + return ResponsePayload::error(ChainHeadRpcError::InvalidBlock) + }, + Err(error) => FollowEvent::::OperationError(OperationError { operation_id: operation_id.clone(), - value: extrinsics, - }) - }, - Ok(None) => { - // The block's body was pruned. This subscription ID has become invalid. - debug!( - target: LOG_TARGET, - "[body][id={:?}] Stopping subscription because hash={:?} was pruned", - &follow_subscription, - hash - ); - self.subscriptions.remove_subscription(&follow_subscription); - return ResponsePayload::error(ChainHeadRpcError::InvalidBlock) - }, - Err(error) => FollowEvent::::OperationError(OperationError { - operation_id: operation_id.clone(), - error: error.to_string(), - }), - }; + error: error.to_string(), + }), + }; - let (rp, rp_fut) = method_started_response(operation_id, None); + let (rp, rp_fut) = method_started_response(operation_id, None); + let fut = async move { + // Wait for the server to send out the response and if it produces an error no event + // should be generated. + if rp_fut.await.is_err() { + return; + } - let fut = async move { - // Events should only by generated - // if the response was successfully propagated. - if rp_fut.await.is_err() { - return; - } - let _ = block_guard.response_sender().unbounded_send(event); - }; + let _ = block_guard.response_sender().unbounded_send(event); + }; + executor.spawn_blocking("substrate-rpc-subscription", Some("rpc"), fut.boxed()); - self.executor.spawn("substrate-rpc-subscription", Some("rpc"), fut.boxed()); + rp + }); - rp + result + .await + .unwrap_or_else(|_| ResponsePayload::success(MethodResponse::LimitReached)) } - fn chain_head_unstable_header( + async fn chain_head_unstable_header( &self, + connection_details: ConnectionDetails, follow_subscription: String, hash: Block::Hash, ) -> Result, ChainHeadRpcError> { - let _block_guard = match self.subscriptions.lock_block(&follow_subscription, hash, 1) { + if !self + .subscriptions + .contains_subscription(connection_details.id(), &follow_subscription) + { + return Ok(None); + } + + let block_guard = match self.subscriptions.lock_block(&follow_subscription, hash, 1) { Ok(block) => block, Err(SubscriptionManagementError::SubscriptionAbsent) | Err(SubscriptionManagementError::ExceededLimits) => return Ok(None), @@ -296,19 +340,35 @@ where Err(_) => return Err(ChainHeadRpcError::InvalidBlock.into()), }; - self.client - .header(hash) - .map(|opt_header| opt_header.map(|h| hex_string(&h.encode()))) - .map_err(|err| ChainHeadRpcError::InternalError(err.to_string())) + let client = self.client.clone(); + let result = spawn_blocking(&self.executor, async move { + let _block_guard = block_guard; + + client + .header(hash) + .map(|opt_header| opt_header.map(|h| hex_string(&h.encode()))) + .map_err(|err| ChainHeadRpcError::InternalError(err.to_string())) + }); + result.await.unwrap_or_else(|_| Ok(None)) } - fn chain_head_unstable_storage( + async fn chain_head_unstable_storage( &self, + connection_details: ConnectionDetails, follow_subscription: String, hash: Block::Hash, items: Vec>, child_trie: Option, ) -> ResponsePayload<'static, MethodResponse> { + if !self + .subscriptions + .contains_subscription(connection_details.id(), &follow_subscription) + { + // The spec says to return `LimitReached` if the follow subscription is invalid or + // stale. + return ResponsePayload::success(MethodResponse::LimitReached); + } + // Gain control over parameter parsing and returned error. let items = match items .into_iter() @@ -357,25 +417,25 @@ where let mut items = items; items.truncate(num_operations); - let (rp, rp_is_success) = method_started_response(operation_id, Some(discarded)); - + let (rp, rp_fut) = method_started_response(operation_id, Some(discarded)); let fut = async move { - // Events should only by generated - // if the response was successfully propagated. - if rp_is_success.await.is_err() { + // Wait for the server to send out the response and if it produces an error no event + // should be generated. + if rp_fut.await.is_err() { return; } + storage_client.generate_events(block_guard, hash, items, child_trie).await; }; - self.executor .spawn_blocking("substrate-rpc-subscription", Some("rpc"), fut.boxed()); rp } - fn chain_head_unstable_call( + async fn chain_head_unstable_call( &self, + connection_details: ConnectionDetails, follow_subscription: String, hash: Block::Hash, function: String, @@ -386,6 +446,15 @@ where Err(err) => return ResponsePayload::error(err), }; + if !self + .subscriptions + .contains_subscription(connection_details.id(), &follow_subscription) + { + // The spec says to return `LimitReached` if the follow subscription is invalid or + // stale. + return ResponsePayload::success(MethodResponse::LimitReached); + } + let mut block_guard = match self.subscriptions.lock_block(&follow_subscription, hash, 1) { Ok(block) => block, Err(SubscriptionManagementError::SubscriptionAbsent) | @@ -408,44 +477,53 @@ where } let operation_id = block_guard.operation().operation_id(); - let event = self - .client - .executor() - .call(hash, &function, &call_parameters, CallContext::Offchain) - .map(|result| { - FollowEvent::::OperationCallDone(OperationCallDone { - operation_id: operation_id.clone(), - output: hex_string(&result), - }) - }) - .unwrap_or_else(|error| { - FollowEvent::::OperationError(OperationError { - operation_id: operation_id.clone(), - error: error.to_string(), - }) - }); - - let (rp, rp_fut) = method_started_response(operation_id, None); + let client = self.client.clone(); + let (rp, rp_fut) = method_started_response(operation_id.clone(), None); let fut = async move { - // Events should only by generated - // if the response was successfully propagated. + // Wait for the server to send out the response and if it produces an error no event + // should be generated. if rp_fut.await.is_err() { - return; + return } + + let event = client + .executor() + .call(hash, &function, &call_parameters, CallContext::Offchain) + .map(|result| { + FollowEvent::::OperationCallDone(OperationCallDone { + operation_id: operation_id.clone(), + output: hex_string(&result), + }) + }) + .unwrap_or_else(|error| { + FollowEvent::::OperationError(OperationError { + operation_id: operation_id.clone(), + error: error.to_string(), + }) + }); + let _ = block_guard.response_sender().unbounded_send(event); }; - - self.executor.spawn("substrate-rpc-subscription", Some("rpc"), fut.boxed()); + self.executor + .spawn_blocking("substrate-rpc-subscription", Some("rpc"), fut.boxed()); rp } - fn chain_head_unstable_unpin( + async fn chain_head_unstable_unpin( &self, + connection_details: ConnectionDetails, follow_subscription: String, hash_or_hashes: ListOrValue, ) -> Result<(), ChainHeadRpcError> { + if !self + .subscriptions + .contains_subscription(connection_details.id(), &follow_subscription) + { + return Ok(()); + } + let result = match hash_or_hashes { ListOrValue::Value(hash) => self.subscriptions.unpin_blocks(&follow_subscription, [hash]), @@ -469,11 +547,19 @@ where } } - fn chain_head_unstable_continue( + async fn chain_head_unstable_continue( &self, + connection_details: ConnectionDetails, follow_subscription: String, operation_id: String, ) -> Result<(), ChainHeadRpcError> { + if !self + .subscriptions + .contains_subscription(connection_details.id(), &follow_subscription) + { + return Ok(()) + } + let Some(operation) = self.subscriptions.get_operation(&follow_subscription, &operation_id) else { return Ok(()) @@ -487,11 +573,19 @@ where } } - fn chain_head_unstable_stop_operation( + async fn chain_head_unstable_stop_operation( &self, + connection_details: ConnectionDetails, follow_subscription: String, operation_id: String, ) -> Result<(), ChainHeadRpcError> { + if !self + .subscriptions + .contains_subscription(connection_details.id(), &follow_subscription) + { + return Ok(()) + } + let Some(operation) = self.subscriptions.get_operation(&follow_subscription, &operation_id) else { return Ok(()) @@ -510,3 +604,26 @@ fn method_started_response( let rp = MethodResponse::Started(MethodResponseStarted { operation_id, discarded_items }); ResponsePayload::success(rp).notify_on_completion() } + +/// Spawn a blocking future on the provided executor and return the result on a oneshot channel. +/// +/// This is a wrapper to extract the result of a `executor.spawn_blocking` future. +fn spawn_blocking( + executor: &SubscriptionTaskExecutor, + fut: impl std::future::Future + Send + 'static, +) -> oneshot::Receiver +where + R: Send + 'static, +{ + let (tx, rx) = oneshot::channel(); + + let blocking_fut = async move { + let result = fut.await; + // Send the result back on the channel. + let _ = tx.send(result); + }; + + executor.spawn_blocking("substrate-rpc-subscription", Some("rpc"), blocking_fut.boxed()); + + rx +} diff --git a/substrate/client/rpc-spec-v2/src/chain_head/chain_head_follow.rs b/substrate/client/rpc-spec-v2/src/chain_head/chain_head_follow.rs index afa99f3aa164..90cc62a36fa9 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/chain_head_follow.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/chain_head_follow.rs @@ -60,7 +60,7 @@ pub struct ChainHeadFollower, Block: BlockT, Client> { /// Backend of the chain. backend: Arc, /// Subscriptions handle. - sub_handle: Arc>, + sub_handle: SubscriptionManagement, /// Subscription was started with the runtime updates flag. with_runtime: bool, /// Subscription ID. @@ -74,7 +74,7 @@ impl, Block: BlockT, Client> ChainHeadFollower, backend: Arc, - sub_handle: Arc>, + sub_handle: SubscriptionManagement, with_runtime: bool, sub_id: String, ) -> Self { @@ -546,7 +546,12 @@ where EventStream: Stream> + Unpin, { let mut stream_item = stream.next(); - let mut stop_event = rx_stop; + + // The stop event can be triggered by the chainHead logic when the pinned + // block guarantee cannot be hold. Or when the client is disconnected. + let connection_closed = sink.closed(); + tokio::pin!(connection_closed); + let mut stop_event = futures_util::future::select(rx_stop, connection_closed); while let Either::Left((Some(event), next_stop_event)) = futures_util::future::select(stream_item, stop_event).await @@ -594,8 +599,10 @@ where stop_event = next_stop_event; } - // If we got here either the substrate streams have closed - // or the `Stop` receiver was triggered. + // If we got here either: + // - the substrate streams have closed + // - the `Stop` receiver was triggered internally (cannot hold the pinned block guarantee) + // - the client disconnected. let msg = to_sub_message(&sink, &FollowEvent::::Stop); let _ = sink.send(msg).await; } diff --git a/substrate/client/rpc-spec-v2/src/chain_head/error.rs b/substrate/client/rpc-spec-v2/src/chain_head/error.rs index 8c50e445aa0c..35604db06600 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/error.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/error.rs @@ -23,6 +23,9 @@ use jsonrpsee::types::error::ErrorObject; /// ChainHead RPC errors. #[derive(Debug, thiserror::Error)] pub enum Error { + /// Maximum number of chainHead_follow has been reached. + #[error("Maximum number of chainHead_follow has been reached")] + ReachedLimits, /// The provided block hash is invalid. #[error("Invalid block hash")] InvalidBlock, @@ -46,6 +49,8 @@ pub enum Error { /// Errors for `chainHead` RPC module, as defined in /// . pub mod rpc_spec_v2 { + /// Maximum number of chainHead_follow has been reached. + pub const REACHED_LIMITS: i32 = -32800; /// The provided block hash is invalid. pub const INVALID_BLOCK_ERROR: i32 = -32801; /// The follow subscription was started with `withRuntime` set to `false`. @@ -70,6 +75,8 @@ impl From for ErrorObject<'static> { let msg = e.to_string(); match e { + Error::ReachedLimits => + ErrorObject::owned(rpc_spec_v2::REACHED_LIMITS, msg, None::<()>), Error::InvalidBlock => ErrorObject::owned(rpc_spec_v2::INVALID_BLOCK_ERROR, msg, None::<()>), Error::InvalidRuntimeCall(_) => diff --git a/substrate/client/rpc-spec-v2/src/chain_head/subscription/inner.rs b/substrate/client/rpc-spec-v2/src/chain_head/subscription/inner.rs index d2879679501f..1ebee3c80fc8 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/subscription/inner.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/subscription/inner.rs @@ -1455,4 +1455,57 @@ mod tests { let permit_three = ops.reserve_at_most(1).unwrap(); assert_eq!(permit_three.num_ops, 1); } + + #[test] + fn reserved_subscription_cleans_resources() { + let builder = TestClientBuilder::new(); + let backend = builder.backend(); + let subs = Arc::new(parking_lot::RwLock::new(SubscriptionsInner::new( + 10, + Duration::from_secs(10), + MAX_OPERATIONS_PER_SUB, + backend, + ))); + + // Maximum 2 subscriptions per connection. + let rpc_connections = crate::common::connections::RpcConnections::new(2); + + let subscription_management = + crate::chain_head::subscription::SubscriptionManagement::_from_inner( + subs.clone(), + rpc_connections.clone(), + ); + + let reserved_sub_first = subscription_management.reserve_subscription(1).unwrap(); + let mut reserved_sub_second = subscription_management.reserve_subscription(1).unwrap(); + // Subscriptions reserved but not yet populated. + assert_eq!(subs.read().subs.len(), 0); + + // Cannot reserve anymore. + assert!(subscription_management.reserve_subscription(1).is_none()); + // Drop the first subscription. + drop(reserved_sub_first); + // Space is freed-up for the rpc connections. + let mut reserved_sub_first = subscription_management.reserve_subscription(1).unwrap(); + + // Insert subscriptions. + let _sub_data_first = + reserved_sub_first.insert_subscription("sub1".to_string(), true).unwrap(); + let _sub_data_second = + reserved_sub_second.insert_subscription("sub2".to_string(), true).unwrap(); + // Check we have 2 subscriptions under management. + assert_eq!(subs.read().subs.len(), 2); + + // Drop first reserved subscription. + drop(reserved_sub_first); + // Check that the subscription is removed. + assert_eq!(subs.read().subs.len(), 1); + // Space is freed-up for the rpc connections. + let reserved_sub_first = subscription_management.reserve_subscription(1).unwrap(); + + // Drop all subscriptions. + drop(reserved_sub_first); + drop(reserved_sub_second); + assert_eq!(subs.read().subs.len(), 0); + } } diff --git a/substrate/client/rpc-spec-v2/src/chain_head/subscription/mod.rs b/substrate/client/rpc-spec-v2/src/chain_head/subscription/mod.rs index c830e662da2e..5b016af1aa49 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/subscription/mod.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/subscription/mod.rs @@ -16,6 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +use jsonrpsee::ConnectionId; use parking_lot::RwLock; use sc_client_api::Backend; use sp_runtime::traits::Block as BlockT; @@ -24,6 +25,11 @@ use std::{sync::Arc, time::Duration}; mod error; mod inner; +use crate::{ + chain_head::chain_head::LOG_TARGET, + common::connections::{RegisteredConnection, ReservedConnection, RpcConnections}, +}; + use self::inner::SubscriptionsInner; pub use self::inner::OperationState; @@ -34,7 +40,22 @@ pub use inner::{BlockGuard, InsertedSubscriptionData}; pub struct SubscriptionManagement> { /// Manage subscription by mapping the subscription ID /// to a set of block hashes. - inner: RwLock>, + inner: Arc>>, + + /// Ensures that chainHead methods can be called from a single connection context. + /// + /// For example, `chainHead_storage` cannot be called with a subscription ID that + /// was obtained from a different connection. + rpc_connections: RpcConnections, +} + +impl> Clone for SubscriptionManagement { + fn clone(&self) -> Self { + SubscriptionManagement { + inner: self.inner.clone(), + rpc_connections: self.rpc_connections.clone(), + } + } } impl> SubscriptionManagement { @@ -43,30 +64,55 @@ impl> SubscriptionManagement { global_max_pinned_blocks: usize, local_max_pin_duration: Duration, max_ongoing_operations: usize, + max_follow_subscriptions_per_connection: usize, backend: Arc, ) -> Self { SubscriptionManagement { - inner: RwLock::new(SubscriptionsInner::new( + inner: Arc::new(RwLock::new(SubscriptionsInner::new( global_max_pinned_blocks, local_max_pin_duration, max_ongoing_operations, backend, - )), + ))), + rpc_connections: RpcConnections::new(max_follow_subscriptions_per_connection), } } - /// Insert a new subscription ID. + /// Create a new instance from the inner state. /// - /// If the subscription was not previously inserted, returns the receiver that is - /// triggered upon the "Stop" event. Otherwise, if the subscription ID was already - /// inserted returns none. - pub fn insert_subscription( + /// # Note + /// + /// Used for testing. + #[cfg(test)] + pub(crate) fn _from_inner( + inner: Arc>>, + rpc_connections: RpcConnections, + ) -> Self { + SubscriptionManagement { inner, rpc_connections } + } + + /// Reserve space for a subscriptions. + /// + /// Fails if the connection ID is has reached the maximum number of active subscriptions. + pub fn reserve_subscription( &self, - sub_id: String, - runtime_updates: bool, - ) -> Option> { - let mut inner = self.inner.write(); - inner.insert_subscription(sub_id, runtime_updates) + connection_id: ConnectionId, + ) -> Option> { + let reserved_token = self.rpc_connections.reserve_space(connection_id)?; + + Some(ReservedSubscription { + state: ConnectionState::Reserved(reserved_token), + inner: self.inner.clone(), + }) + } + + /// Check if the given connection contains the given subscription. + pub fn contains_subscription( + &self, + connection_id: ConnectionId, + subscription_id: &str, + ) -> bool { + self.rpc_connections.contains_identifier(connection_id, subscription_id) } /// Remove the subscription ID with associated pinned blocks. @@ -136,3 +182,63 @@ impl> SubscriptionManagement { inner.get_operation(sub_id, operation_id) } } + +/// The state of the connection. +/// +/// The state starts in a [`ConnectionState::Reserved`] state and then transitions to +/// [`ConnectionState::Registered`] when the subscription is inserted. +enum ConnectionState { + Reserved(ReservedConnection), + Registered { _unregister_on_drop: RegisteredConnection, sub_id: String }, + Empty, +} + +/// RAII wrapper that removes the subscription from internal mappings and +/// gives back the reserved space for the connection. +pub struct ReservedSubscription> { + state: ConnectionState, + inner: Arc>>, +} + +impl> ReservedSubscription { + /// Insert a new subscription ID. + /// + /// If the subscription was not previously inserted, returns the receiver that is + /// triggered upon the "Stop" event. Otherwise, if the subscription ID was already + /// inserted returns none. + /// + /// # Note + /// + /// This method should be called only once. + pub fn insert_subscription( + &mut self, + sub_id: String, + runtime_updates: bool, + ) -> Option> { + match std::mem::replace(&mut self.state, ConnectionState::Empty) { + ConnectionState::Reserved(reserved) => { + let registered_token = reserved.register(sub_id.clone())?; + self.state = ConnectionState::Registered { + _unregister_on_drop: registered_token, + sub_id: sub_id.clone(), + }; + + let mut inner = self.inner.write(); + inner.insert_subscription(sub_id, runtime_updates) + }, + // Cannot insert multiple subscriptions into one single reserved space. + ConnectionState::Registered { .. } | ConnectionState::Empty => { + log::error!(target: LOG_TARGET, "Called insert_subscription on a connection that is not reserved"); + None + }, + } + } +} + +impl> Drop for ReservedSubscription { + fn drop(&mut self) { + if let ConnectionState::Registered { sub_id, .. } = &self.state { + self.inner.write().remove_subscription(sub_id); + } + } +} diff --git a/substrate/client/rpc-spec-v2/src/chain_head/tests.rs b/substrate/client/rpc-spec-v2/src/chain_head/tests.rs index 30152efb5b62..c3f10a201c58 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/tests.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/tests.rs @@ -17,7 +17,7 @@ // along with this program. If not, see . use crate::{ - chain_head::{event::MethodResponse, test_utils::ChainHeadMockClient}, + chain_head::{api::ChainHeadApiClient, event::MethodResponse, test_utils::ChainHeadMockClient}, common::events::{StorageQuery, StorageQueryType, StorageResultType}, hex_string, }; @@ -27,8 +27,12 @@ use assert_matches::assert_matches; use codec::{Decode, Encode}; use futures::Future; use jsonrpsee::{ - core::server::Subscription as RpcSubscription, rpc_params, MethodsError as Error, RpcModule, + core::{ + client::Subscription as RpcClientSubscription, server::Subscription as RpcSubscription, + }, + rpc_params, MethodsError as Error, RpcModule, }; + use sc_block_builder::BlockBuilderBuilder; use sc_client_api::ChildInfo; use sc_service::client::new_in_mem; @@ -59,6 +63,8 @@ const MAX_PINNED_BLOCKS: usize = 32; const MAX_PINNED_SECS: u64 = 60; const MAX_OPERATIONS: usize = 16; const MAX_PAGINATION_LIMIT: usize = 5; +const MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION: usize = 4; + const INVALID_HASH: [u8; 32] = [1; 32]; const KEY: &[u8] = b":mock"; const VALUE: &[u8] = b"hello world"; @@ -66,6 +72,35 @@ const CHILD_STORAGE_KEY: &[u8] = b"child"; const CHILD_VALUE: &[u8] = b"child value"; const DOES_NOT_PRODUCE_EVENTS_SECONDS: u64 = 10; +/// Start an RPC server with the chainHead module. +pub async fn run_server() -> std::net::SocketAddr { + let builder = TestClientBuilder::new(); + let backend = builder.backend(); + let client = Arc::new(builder.build()); + + let api = ChainHead::new( + client, + backend, + Arc::new(TaskExecutor::default()), + ChainHeadConfig { + global_max_pinned_blocks: MAX_PINNED_BLOCKS, + subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), + subscription_max_ongoing_operations: MAX_OPERATIONS, + operation_max_storage_items: MAX_PAGINATION_LIMIT, + max_follow_subscriptions_per_connection: 1, + }, + ) + .into_rpc(); + + let server = jsonrpsee::server::ServerBuilder::default().build("127.0.0.1:0").await.unwrap(); + + let addr = server.local_addr().unwrap(); + let handle = server.start(api); + + tokio::spawn(handle.stopped()); + addr +} + async fn get_next_event(sub: &mut RpcSubscription) -> T { let (event, _sub_id) = tokio::time::timeout(std::time::Duration::from_secs(60), sub.next()) .await @@ -113,6 +148,7 @@ async fn setup_api() -> ( subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) .into_rpc(); @@ -163,6 +199,7 @@ async fn follow_subscription_produces_blocks() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) .into_rpc(); @@ -231,6 +268,7 @@ async fn follow_with_runtime() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) .into_rpc(); @@ -543,6 +581,7 @@ async fn call_runtime_without_flag() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) .into_rpc(); @@ -1201,6 +1240,7 @@ async fn separate_operation_ids_for_subscriptions() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) .into_rpc(); @@ -1289,6 +1329,7 @@ async fn follow_generates_initial_blocks() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) .into_rpc(); @@ -1444,6 +1485,7 @@ async fn follow_exceeding_pinned_blocks() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) .into_rpc(); @@ -1520,6 +1562,7 @@ async fn follow_with_unpin() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) .into_rpc(); @@ -1631,6 +1674,7 @@ async fn unpin_duplicate_hashes() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) .into_rpc(); @@ -1733,6 +1777,7 @@ async fn follow_with_multiple_unpin_hashes() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) .into_rpc(); @@ -1886,6 +1931,7 @@ async fn follow_prune_best_block() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) .into_rpc(); @@ -2071,6 +2117,7 @@ async fn follow_forks_pruned_block() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) .into_rpc(); @@ -2230,6 +2277,7 @@ async fn follow_report_multiple_pruned_block() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) .into_rpc(); @@ -2475,6 +2523,7 @@ async fn pin_block_references() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) .into_rpc(); @@ -2612,6 +2661,7 @@ async fn follow_finalized_before_new_block() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) .into_rpc(); @@ -2726,6 +2776,7 @@ async fn ensure_operation_limits_works() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: 1, operation_max_storage_items: MAX_PAGINATION_LIMIT, + max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) .into_rpc(); @@ -2830,6 +2881,7 @@ async fn check_continue_operation() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: 1, + max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) .into_rpc(); @@ -3012,6 +3064,7 @@ async fn stop_storage_operation() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: 1, + max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) .into_rpc(); @@ -3297,3 +3350,176 @@ async fn storage_closest_merkle_value() { merkle_values_rhs.get(&hex_string(b":AAAA")).unwrap() ); } + +#[tokio::test] +async fn chain_head_single_connection_context() { + let server_addr = run_server().await; + let server_url = format!("ws://{}", server_addr); + let client = jsonrpsee::ws_client::WsClientBuilder::default() + .build(&server_url) + .await + .unwrap(); + // Calls cannot be made from a different connection context. + let second_client = jsonrpsee::ws_client::WsClientBuilder::default() + .build(&server_url) + .await + .unwrap(); + + let mut sub: RpcClientSubscription> = + ChainHeadApiClient::::chain_head_unstable_follow(&client, true) + .await + .unwrap(); + + let event = tokio::time::timeout(std::time::Duration::from_secs(60), sub.next()) + .await + .unwrap() + .unwrap() + .unwrap(); + let finalized_hash = match event { + FollowEvent::Initialized(init) => init.finalized_block_hashes.into_iter().last().unwrap(), + _ => panic!("Expected FollowEvent::Initialized"), + }; + + let first_sub_id = match sub.kind() { + jsonrpsee::core::client::SubscriptionKind::Subscription(id) => match id { + jsonrpsee::types::SubscriptionId::Num(num) => num.to_string(), + jsonrpsee::types::SubscriptionId::Str(s) => s.to_string(), + }, + _ => panic!("Unexpected subscription ID"), + }; + + // Trying to unpin from a different connection will have no effect. + let _response = ChainHeadApiClient::::chain_head_unstable_unpin( + &second_client, + first_sub_id.clone(), + crate::chain_head::api::ListOrValue::Value(finalized_hash.clone()), + ) + .await + .unwrap(); + + // Body can still be fetched from the first subscription. + let response: MethodResponse = ChainHeadApiClient::::chain_head_unstable_body( + &client, + first_sub_id.clone(), + finalized_hash.clone(), + ) + .await + .unwrap(); + assert_matches!(response, MethodResponse::Started(_started)); + + // Cannot make a call from a different connection context. + let response: MethodResponse = ChainHeadApiClient::::chain_head_unstable_body( + &second_client, + first_sub_id.clone(), + finalized_hash.clone(), + ) + .await + .unwrap(); + assert_matches!(response, MethodResponse::LimitReached); + + let response: Option = ChainHeadApiClient::::chain_head_unstable_header( + &client, + first_sub_id.clone(), + finalized_hash.clone(), + ) + .await + .unwrap(); + assert!(response.is_some()); + // Cannot make a call from a different connection context. + let response: Option = ChainHeadApiClient::::chain_head_unstable_header( + &second_client, + first_sub_id.clone(), + finalized_hash.clone(), + ) + .await + .unwrap(); + assert!(response.is_none()); + + let key = hex_string(&KEY); + let response: MethodResponse = ChainHeadApiClient::::chain_head_unstable_storage( + &client, + first_sub_id.clone(), + finalized_hash.clone(), + vec![StorageQuery { key: key.clone(), query_type: StorageQueryType::Hash }], + None, + ) + .await + .unwrap(); + assert_matches!(response, MethodResponse::Started(_started)); + // Cannot make a call from a different connection context. + let response: MethodResponse = ChainHeadApiClient::::chain_head_unstable_storage( + &second_client, + first_sub_id.clone(), + finalized_hash.clone(), + vec![StorageQuery { key: key.clone(), query_type: StorageQueryType::Hash }], + None, + ) + .await + .unwrap(); + assert_matches!(response, MethodResponse::LimitReached); + + let alice_id = AccountKeyring::Alice.to_account_id(); + // Hex encoded scale encoded bytes representing the call parameters. + let call_parameters = hex_string(&alice_id.encode()); + let response: MethodResponse = ChainHeadApiClient::::chain_head_unstable_call( + &client, + first_sub_id.clone(), + finalized_hash.clone(), + "AccountNonceApi_account_nonce".into(), + call_parameters.clone(), + ) + .await + .unwrap(); + assert_matches!(response, MethodResponse::Started(_started)); + // Cannot make a call from a different connection context. + let response: MethodResponse = ChainHeadApiClient::::chain_head_unstable_call( + &second_client, + first_sub_id.clone(), + finalized_hash.clone(), + "AccountNonceApi_account_nonce".into(), + call_parameters.clone(), + ) + .await + .unwrap(); + assert_matches!(response, MethodResponse::LimitReached); +} + +#[tokio::test] +async fn chain_head_limit_reached() { + let builder = TestClientBuilder::new(); + let backend = builder.backend(); + let client = Arc::new(builder.build()); + + // Maximum of 1 chainHead_follow subscription. + let api = ChainHead::new( + client.clone(), + backend, + Arc::new(TaskExecutor::default()), + ChainHeadConfig { + global_max_pinned_blocks: MAX_PINNED_BLOCKS, + subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), + subscription_max_ongoing_operations: MAX_OPERATIONS, + operation_max_storage_items: MAX_PAGINATION_LIMIT, + max_follow_subscriptions_per_connection: 1, + }, + ) + .into_rpc(); + + let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [true]).await.unwrap(); + // Initialized must always be reported first. + let _event: FollowEvent = get_next_event(&mut sub).await; + + let error = api.subscribe_unbounded("chainHead_unstable_follow", [true]).await.unwrap_err(); + assert!(error + .to_string() + .contains("Maximum number of chainHead_follow has been reached")); + + // After dropping the subscription, other subscriptions are allowed to be created. + drop(sub); + // Ensure the `chainHead_unfollow` is propagated to the server. + tokio::time::sleep(std::time::Duration::from_secs(5)).await; + + let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [true]).await.unwrap(); + // Initialized must always be reported first. + let _event: FollowEvent = get_next_event(&mut sub).await; +} diff --git a/substrate/client/rpc-spec-v2/src/common/connections.rs b/substrate/client/rpc-spec-v2/src/common/connections.rs new file mode 100644 index 000000000000..c16a80bf49db --- /dev/null +++ b/substrate/client/rpc-spec-v2/src/common/connections.rs @@ -0,0 +1,262 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use jsonrpsee::ConnectionId; +use parking_lot::Mutex; +use std::{ + collections::{HashMap, HashSet}, + sync::Arc, +}; + +/// Connection state which keeps track whether a connection exist and +/// the number of concurrent operations. +#[derive(Default, Clone)] +pub struct RpcConnections { + /// The number of identifiers that can be registered for each connection. + /// + /// # Example + /// + /// This is used to limit how many `chainHead_follow` subscriptions are active at one time. + capacity: usize, + /// Map the connecton ID to a set of identifiers. + data: Arc>>, +} + +#[derive(Default)] +struct ConnectionData { + /// The total number of identifiers for the given connection. + /// + /// An identifier for a connection might be: + /// - the subscription ID for chainHead_follow + /// - the operation ID for the transactionBroadcast API + /// - or simply how many times the transaction API has been called. + /// + /// # Note + /// + /// Because a pending subscription sink does not expose the future subscription ID, + /// we cannot register a subscription ID before the pending subscription is accepted. + /// This variable ensures that we have enough capacity to register an identifier, after + /// the subscription is accepted. Otherwise, a jsonrpc error object should be returned. + num_identifiers: usize, + /// Active registered identifiers for the given connection. + /// + /// # Note + /// + /// For chainHead, this represents the subscription ID. + /// For transactionBroadcast, this represents the operation ID. + /// For transaction, this is empty and the number of active calls is tracked by + /// [`Self::num_identifiers`]. + identifiers: HashSet, +} + +impl RpcConnections { + /// Constructs a new instance of [`RpcConnections`]. + pub fn new(capacity: usize) -> Self { + RpcConnections { capacity, data: Default::default() } + } + + /// Reserve space for a new connection identifier. + /// + /// If the number of active identifiers for the given connection exceeds the capacity, + /// returns None. + pub fn reserve_space(&self, connection_id: ConnectionId) -> Option { + let mut data = self.data.lock(); + + let entry = data.entry(connection_id).or_insert_with(ConnectionData::default); + if entry.num_identifiers >= self.capacity { + return None; + } + entry.num_identifiers = entry.num_identifiers.saturating_add(1); + + Some(ReservedConnection { connection_id, rpc_connections: Some(self.clone()) }) + } + + /// Gives back the reserved space before the connection identifier is registered. + /// + /// # Note + /// + /// This may happen if the pending subscription cannot be accepted (unlikely). + fn unreserve_space(&self, connection_id: ConnectionId) { + let mut data = self.data.lock(); + + let entry = data.entry(connection_id).or_insert_with(ConnectionData::default); + entry.num_identifiers = entry.num_identifiers.saturating_sub(1); + + if entry.num_identifiers == 0 { + data.remove(&connection_id); + } + } + + /// Register an identifier for the given connection. + /// + /// Users must call [`Self::reserve_space`] before calling this method to ensure enough + /// space is available. + /// + /// Returns true if the identifier was inserted successfully, false if the identifier was + /// already inserted or reached capacity. + fn register_identifier(&self, connection_id: ConnectionId, identifier: String) -> bool { + let mut data = self.data.lock(); + + let entry = data.entry(connection_id).or_insert_with(ConnectionData::default); + // Should be already checked `Self::reserve_space`. + if entry.identifiers.len() >= self.capacity { + return false; + } + + entry.identifiers.insert(identifier) + } + + /// Unregister an identifier for the given connection. + fn unregister_identifier(&self, connection_id: ConnectionId, identifier: &str) { + let mut data = self.data.lock(); + if let Some(connection_data) = data.get_mut(&connection_id) { + connection_data.identifiers.remove(identifier); + connection_data.num_identifiers = connection_data.num_identifiers.saturating_sub(1); + + if connection_data.num_identifiers == 0 { + data.remove(&connection_id); + } + } + } + + /// Check if the given connection contains the given identifier. + pub fn contains_identifier(&self, connection_id: ConnectionId, identifier: &str) -> bool { + let data = self.data.lock(); + data.get(&connection_id) + .map(|connection_data| connection_data.identifiers.contains(identifier)) + .unwrap_or(false) + } +} + +/// RAII wrapper that ensures the reserved space is given back if the object is +/// dropped before the identifier is registered. +pub struct ReservedConnection { + connection_id: ConnectionId, + rpc_connections: Option, +} + +impl ReservedConnection { + /// Register the identifier for the given connection. + pub fn register(mut self, identifier: String) -> Option { + let rpc_connections = self.rpc_connections.take()?; + + if rpc_connections.register_identifier(self.connection_id, identifier.clone()) { + Some(RegisteredConnection { + connection_id: self.connection_id, + identifier, + rpc_connections, + }) + } else { + None + } + } +} + +impl Drop for ReservedConnection { + fn drop(&mut self) { + if let Some(rpc_connections) = self.rpc_connections.take() { + rpc_connections.unreserve_space(self.connection_id); + } + } +} + +/// RAII wrapper that ensures the identifier is unregistered if the object is dropped. +pub struct RegisteredConnection { + connection_id: ConnectionId, + identifier: String, + rpc_connections: RpcConnections, +} + +impl Drop for RegisteredConnection { + fn drop(&mut self) { + self.rpc_connections.unregister_identifier(self.connection_id, &self.identifier); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn reserve_space() { + let rpc_connections = RpcConnections::new(2); + let reserved = rpc_connections.reserve_space(1); + assert!(reserved.is_some()); + assert_eq!(1, rpc_connections.data.lock().get(&1).unwrap().num_identifiers); + assert_eq!(rpc_connections.data.lock().len(), 1); + + let reserved = reserved.unwrap(); + let registered = reserved.register("identifier1".to_string()).unwrap(); + assert!(rpc_connections.contains_identifier(1, "identifier1")); + assert_eq!(1, rpc_connections.data.lock().get(&1).unwrap().num_identifiers); + drop(registered); + + // Data is dropped. + assert!(rpc_connections.data.lock().get(&1).is_none()); + assert!(rpc_connections.data.lock().is_empty()); + // Checks can still happen. + assert!(!rpc_connections.contains_identifier(1, "identifier1")); + } + + #[test] + fn reserve_space_capacity_reached() { + let rpc_connections = RpcConnections::new(2); + + // Reserve identifier for connection 1. + let reserved = rpc_connections.reserve_space(1); + assert!(reserved.is_some()); + assert_eq!(1, rpc_connections.data.lock().get(&1).unwrap().num_identifiers); + + // Add identifier for connection 1. + let reserved = reserved.unwrap(); + let registered = reserved.register("identifier1".to_string()).unwrap(); + assert!(rpc_connections.contains_identifier(1, "identifier1")); + assert_eq!(1, rpc_connections.data.lock().get(&1).unwrap().num_identifiers); + + // Reserve identifier for connection 1 again. + let reserved = rpc_connections.reserve_space(1); + assert!(reserved.is_some()); + assert_eq!(2, rpc_connections.data.lock().get(&1).unwrap().num_identifiers); + + // Add identifier for connection 1 again. + let reserved = reserved.unwrap(); + let registered_second = reserved.register("identifier2".to_string()).unwrap(); + assert!(rpc_connections.contains_identifier(1, "identifier2")); + assert_eq!(2, rpc_connections.data.lock().get(&1).unwrap().num_identifiers); + + // Cannot reserve more identifiers. + let reserved = rpc_connections.reserve_space(1); + assert!(reserved.is_none()); + + // Drop the first identifier. + drop(registered); + assert_eq!(1, rpc_connections.data.lock().get(&1).unwrap().num_identifiers); + assert!(rpc_connections.contains_identifier(1, "identifier2")); + assert!(!rpc_connections.contains_identifier(1, "identifier1")); + + // Can reserve again after clearing the space. + let reserved = rpc_connections.reserve_space(1); + assert!(reserved.is_some()); + assert_eq!(2, rpc_connections.data.lock().get(&1).unwrap().num_identifiers); + + // Ensure data is cleared. + drop(reserved); + drop(registered_second); + assert!(rpc_connections.data.lock().get(&1).is_none()); + } +} diff --git a/substrate/client/rpc-spec-v2/src/common/mod.rs b/substrate/client/rpc-spec-v2/src/common/mod.rs index ac1af8fce3c9..3167561d649a 100644 --- a/substrate/client/rpc-spec-v2/src/common/mod.rs +++ b/substrate/client/rpc-spec-v2/src/common/mod.rs @@ -13,5 +13,6 @@ //! Common types and functionality for the RPC-V2 spec. +pub mod connections; pub mod events; pub mod storage; From 8164280874c5aa55a96080511f6723529bda16d2 Mon Sep 17 00:00:00 2001 From: Serban Iorga Date: Tue, 2 Apr 2024 16:41:01 +0300 Subject: [PATCH 104/257] Align dependencies with `parity-bridges-common` (#3937) Working towards migrating the `parity-bridges-common` repo inside `polkadot-sdk`. This PR upgrades some dependencies in order to align them with the versions used in `parity-bridges-common` Related to https://github.com/paritytech/parity-bridges-common/issues/2538 --- Cargo.lock | 116 +++++++++++------- .../outbound-queue/merkle-tree/Cargo.toml | 2 +- .../snowbridge/runtime/test-common/Cargo.toml | 2 +- cumulus/client/collator/Cargo.toml | 4 +- cumulus/client/consensus/aura/Cargo.toml | 2 +- cumulus/client/consensus/common/Cargo.toml | 2 +- cumulus/client/consensus/proposer/Cargo.toml | 2 +- .../client/consensus/relay-chain/Cargo.toml | 2 +- cumulus/client/network/Cargo.toml | 2 +- cumulus/client/parachain-inherent/Cargo.toml | 4 +- cumulus/client/pov-recovery/Cargo.toml | 2 +- .../Cargo.toml | 2 +- .../client/relay-chain-interface/Cargo.toml | 2 +- .../relay-chain-minimal-node/Cargo.toml | 2 +- .../relay-chain-rpc-interface/Cargo.toml | 2 +- cumulus/pallets/aura-ext/Cargo.toml | 2 +- cumulus/pallets/collator-selection/Cargo.toml | 2 +- cumulus/pallets/dmp-queue/Cargo.toml | 2 +- cumulus/pallets/parachain-system/Cargo.toml | 2 +- cumulus/pallets/solo-to-para/Cargo.toml | 2 +- cumulus/pallets/xcm/Cargo.toml | 2 +- cumulus/pallets/xcmp-queue/Cargo.toml | 2 +- cumulus/parachains/common/Cargo.toml | 2 +- .../bridges/bridge-hub-rococo/Cargo.toml | 2 +- .../pallets/collective-content/Cargo.toml | 2 +- .../pallets/parachain-info/Cargo.toml | 2 +- cumulus/parachains/pallets/ping/Cargo.toml | 2 +- .../assets/asset-hub-rococo/Cargo.toml | 2 +- .../assets/asset-hub-westend/Cargo.toml | 2 +- .../runtimes/assets/common/Cargo.toml | 2 +- .../bridge-hubs/bridge-hub-rococo/Cargo.toml | 2 +- .../bridge-hubs/bridge-hub-westend/Cargo.toml | 2 +- .../runtimes/bridge-hubs/common/Cargo.toml | 2 +- .../collectives-westend/Cargo.toml | 2 +- .../contracts/contracts-rococo/Cargo.toml | 2 +- .../glutton/glutton-westend/Cargo.toml | 2 +- .../runtimes/starters/seedling/Cargo.toml | 2 +- .../runtimes/starters/shell/Cargo.toml | 2 +- .../runtimes/testing/penpal/Cargo.toml | 2 +- .../testing/rococo-parachain/Cargo.toml | 2 +- cumulus/polkadot-parachain/Cargo.toml | 2 +- cumulus/primitives/core/Cargo.toml | 2 +- .../primitives/parachain-inherent/Cargo.toml | 4 +- .../storage-weight-reclaim/Cargo.toml | 2 +- cumulus/test/runtime/Cargo.toml | 2 +- cumulus/test/service/Cargo.toml | 2 +- polkadot/Cargo.toml | 2 +- polkadot/cli/Cargo.toml | 2 +- polkadot/core-primitives/Cargo.toml | 2 +- polkadot/node/collation-generation/Cargo.toml | 2 +- polkadot/node/core/approval-voting/Cargo.toml | 6 +- polkadot/node/core/av-store/Cargo.toml | 4 +- polkadot/node/core/backing/Cargo.toml | 4 +- .../node/core/bitfield-signing/Cargo.toml | 2 +- .../node/core/candidate-validation/Cargo.toml | 6 +- polkadot/node/core/chain-api/Cargo.toml | 4 +- polkadot/node/core/chain-selection/Cargo.toml | 2 +- .../node/core/dispute-coordinator/Cargo.toml | 2 +- .../node/core/parachains-inherent/Cargo.toml | 4 +- .../core/prospective-parachains/Cargo.toml | 2 +- polkadot/node/core/provisioner/Cargo.toml | 2 +- polkadot/node/core/pvf-checker/Cargo.toml | 2 +- polkadot/node/core/pvf/Cargo.toml | 2 +- polkadot/node/core/pvf/common/Cargo.toml | 2 +- polkadot/node/core/runtime-api/Cargo.toml | 6 +- polkadot/node/jaeger/Cargo.toml | 2 +- polkadot/node/malus/Cargo.toml | 6 +- polkadot/node/metrics/Cargo.toml | 4 +- .../network/approval-distribution/Cargo.toml | 4 +- .../availability-distribution/Cargo.toml | 2 +- .../network/availability-recovery/Cargo.toml | 8 +- .../network/bitfield-distribution/Cargo.toml | 4 +- polkadot/node/network/bridge/Cargo.toml | 4 +- .../node/network/collator-protocol/Cargo.toml | 4 +- .../network/dispute-distribution/Cargo.toml | 4 +- .../node/network/gossip-support/Cargo.toml | 4 +- polkadot/node/network/protocol/Cargo.toml | 6 +- .../network/statement-distribution/Cargo.toml | 2 +- polkadot/node/overseer/Cargo.toml | 6 +- polkadot/node/primitives/Cargo.toml | 2 +- polkadot/node/service/Cargo.toml | 6 +- polkadot/node/subsystem-bench/Cargo.toml | 6 +- .../node/subsystem-test-helpers/Cargo.toml | 4 +- polkadot/node/subsystem-types/Cargo.toml | 4 +- polkadot/node/subsystem-util/Cargo.toml | 8 +- polkadot/node/test/client/Cargo.toml | 2 +- polkadot/node/test/service/Cargo.toml | 6 +- polkadot/parachain/Cargo.toml | 2 +- .../test-parachains/adder/collator/Cargo.toml | 2 +- .../undying/collator/Cargo.toml | 2 +- polkadot/primitives/Cargo.toml | 2 +- polkadot/runtime/common/Cargo.toml | 2 +- polkadot/runtime/parachains/Cargo.toml | 4 +- polkadot/runtime/rococo/Cargo.toml | 2 +- polkadot/runtime/test-runtime/Cargo.toml | 2 +- polkadot/runtime/westend/Cargo.toml | 2 +- polkadot/xcm/Cargo.toml | 2 +- polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml | 2 +- polkadot/xcm/pallet-xcm/Cargo.toml | 2 +- polkadot/xcm/xcm-builder/Cargo.toml | 2 +- polkadot/xcm/xcm-executor/Cargo.toml | 2 +- .../xcm-executor/integration-tests/Cargo.toml | 2 +- .../xcm-fee-payment-runtime-api/Cargo.toml | 2 +- polkadot/xcm/xcm-simulator/example/Cargo.toml | 2 +- polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml | 2 +- substrate/bin/node/bench/Cargo.toml | 2 +- substrate/bin/node/cli/Cargo.toml | 6 +- substrate/bin/node/runtime/Cargo.toml | 2 +- substrate/bin/node/testing/Cargo.toml | 2 +- substrate/client/api/Cargo.toml | 2 +- .../client/authority-discovery/Cargo.toml | 4 +- substrate/client/basic-authorship/Cargo.toml | 2 +- substrate/client/cli/Cargo.toml | 2 +- substrate/client/consensus/aura/Cargo.toml | 4 +- substrate/client/consensus/babe/Cargo.toml | 6 +- .../client/consensus/babe/rpc/Cargo.toml | 4 +- substrate/client/consensus/beefy/Cargo.toml | 6 +- .../client/consensus/beefy/rpc/Cargo.toml | 2 +- substrate/client/consensus/common/Cargo.toml | 4 +- substrate/client/consensus/grandpa/Cargo.toml | 6 +- .../client/consensus/grandpa/rpc/Cargo.toml | 2 +- .../client/consensus/manual-seal/Cargo.toml | 4 +- substrate/client/consensus/pow/Cargo.toml | 4 +- substrate/client/consensus/slots/Cargo.toml | 4 +- substrate/client/executor/Cargo.toml | 2 +- substrate/client/informant/Cargo.toml | 2 +- .../client/merkle-mountain-range/Cargo.toml | 4 +- substrate/client/mixnet/Cargo.toml | 2 +- substrate/client/network-gossip/Cargo.toml | 6 +- substrate/client/network/Cargo.toml | 4 +- substrate/client/network/bitswap/Cargo.toml | 2 +- substrate/client/network/common/Cargo.toml | 4 +- substrate/client/network/light/Cargo.toml | 2 +- substrate/client/network/statement/Cargo.toml | 2 +- substrate/client/network/sync/Cargo.toml | 4 +- substrate/client/network/test/Cargo.toml | 6 +- .../client/network/transactions/Cargo.toml | 2 +- substrate/client/offchain/Cargo.toml | 4 +- substrate/client/rpc-api/Cargo.toml | 2 +- substrate/client/rpc-servers/Cargo.toml | 2 +- substrate/client/rpc-spec-v2/Cargo.toml | 2 +- substrate/client/rpc/Cargo.toml | 8 +- substrate/client/service/Cargo.toml | 4 +- substrate/client/service/test/Cargo.toml | 2 +- substrate/client/statement-store/Cargo.toml | 2 +- substrate/client/sysinfo/Cargo.toml | 2 +- substrate/client/telemetry/Cargo.toml | 2 +- substrate/client/transaction-pool/Cargo.toml | 4 +- .../client/transaction-pool/api/Cargo.toml | 4 +- substrate/client/utils/Cargo.toml | 2 +- substrate/frame/Cargo.toml | 2 +- substrate/frame/alliance/Cargo.toml | 2 +- substrate/frame/asset-conversion/Cargo.toml | 2 +- substrate/frame/asset-rate/Cargo.toml | 2 +- substrate/frame/assets/Cargo.toml | 2 +- substrate/frame/atomic-swap/Cargo.toml | 2 +- substrate/frame/aura/Cargo.toml | 2 +- .../frame/authority-discovery/Cargo.toml | 2 +- substrate/frame/authorship/Cargo.toml | 2 +- substrate/frame/babe/Cargo.toml | 2 +- substrate/frame/bags-list/Cargo.toml | 2 +- substrate/frame/balances/Cargo.toml | 2 +- substrate/frame/beefy-mmr/Cargo.toml | 2 +- substrate/frame/beefy/Cargo.toml | 2 +- substrate/frame/benchmarking/Cargo.toml | 2 +- substrate/frame/benchmarking/pov/Cargo.toml | 2 +- substrate/frame/bounties/Cargo.toml | 2 +- substrate/frame/broker/Cargo.toml | 2 +- substrate/frame/child-bounties/Cargo.toml | 2 +- substrate/frame/collective/Cargo.toml | 2 +- substrate/frame/contracts/Cargo.toml | 4 +- .../frame/contracts/mock-network/Cargo.toml | 2 +- substrate/frame/contracts/uapi/Cargo.toml | 2 +- substrate/frame/conviction-voting/Cargo.toml | 2 +- substrate/frame/core-fellowship/Cargo.toml | 2 +- substrate/frame/democracy/Cargo.toml | 2 +- .../election-provider-multi-phase/Cargo.toml | 4 +- .../test-staking-e2e/Cargo.toml | 2 +- .../election-provider-support/Cargo.toml | 2 +- .../solution-type/Cargo.toml | 2 +- .../solution-type/fuzzer/Cargo.toml | 2 +- substrate/frame/elections-phragmen/Cargo.toml | 2 +- substrate/frame/examples/basic/Cargo.toml | 2 +- .../frame/examples/default-config/Cargo.toml | 2 +- substrate/frame/examples/dev-mode/Cargo.toml | 2 +- .../frame/examples/frame-crate/Cargo.toml | 2 +- .../frame/examples/kitchensink/Cargo.toml | 2 +- .../frame/examples/offchain-worker/Cargo.toml | 2 +- .../single-block-migrations/Cargo.toml | 2 +- substrate/frame/examples/split/Cargo.toml | 2 +- substrate/frame/examples/tasks/Cargo.toml | 2 +- substrate/frame/executive/Cargo.toml | 2 +- substrate/frame/fast-unstake/Cargo.toml | 2 +- substrate/frame/glutton/Cargo.toml | 2 +- substrate/frame/grandpa/Cargo.toml | 2 +- substrate/frame/identity/Cargo.toml | 2 +- substrate/frame/im-online/Cargo.toml | 2 +- substrate/frame/indices/Cargo.toml | 2 +- .../Cargo.toml | 2 +- substrate/frame/lottery/Cargo.toml | 2 +- substrate/frame/membership/Cargo.toml | 2 +- .../frame/merkle-mountain-range/Cargo.toml | 4 +- substrate/frame/message-queue/Cargo.toml | 2 +- substrate/frame/migrations/Cargo.toml | 2 +- substrate/frame/mixnet/Cargo.toml | 2 +- substrate/frame/multisig/Cargo.toml | 2 +- .../frame/nft-fractionalization/Cargo.toml | 2 +- substrate/frame/nfts/Cargo.toml | 2 +- substrate/frame/nis/Cargo.toml | 2 +- substrate/frame/node-authorization/Cargo.toml | 2 +- substrate/frame/nomination-pools/Cargo.toml | 2 +- .../nomination-pools/benchmarking/Cargo.toml | 2 +- .../test-transfer-stake/Cargo.toml | 2 +- substrate/frame/offences/Cargo.toml | 2 +- .../frame/offences/benchmarking/Cargo.toml | 2 +- substrate/frame/paged-list/Cargo.toml | 2 +- substrate/frame/parameters/Cargo.toml | 2 +- substrate/frame/preimage/Cargo.toml | 2 +- substrate/frame/proxy/Cargo.toml | 2 +- substrate/frame/ranked-collective/Cargo.toml | 2 +- substrate/frame/recovery/Cargo.toml | 2 +- substrate/frame/referenda/Cargo.toml | 2 +- substrate/frame/remark/Cargo.toml | 2 +- substrate/frame/root-offences/Cargo.toml | 2 +- substrate/frame/root-testing/Cargo.toml | 2 +- substrate/frame/safe-mode/Cargo.toml | 2 +- substrate/frame/salary/Cargo.toml | 2 +- substrate/frame/sassafras/Cargo.toml | 2 +- substrate/frame/scheduler/Cargo.toml | 2 +- substrate/frame/scored-pool/Cargo.toml | 2 +- substrate/frame/session/Cargo.toml | 2 +- .../frame/session/benchmarking/Cargo.toml | 2 +- substrate/frame/society/Cargo.toml | 2 +- substrate/frame/staking/Cargo.toml | 2 +- .../frame/state-trie-migration/Cargo.toml | 2 +- substrate/frame/statement/Cargo.toml | 2 +- substrate/frame/sudo/Cargo.toml | 2 +- substrate/frame/support/Cargo.toml | 2 +- substrate/frame/support/test/Cargo.toml | 2 +- .../support/test/compile_pass/Cargo.toml | 2 +- .../frame/support/test/pallet/Cargo.toml | 2 +- .../support/test/stg_frame_crate/Cargo.toml | 2 +- substrate/frame/system/Cargo.toml | 2 +- .../frame/system/benchmarking/Cargo.toml | 2 +- substrate/frame/timestamp/Cargo.toml | 2 +- substrate/frame/tips/Cargo.toml | 2 +- .../frame/transaction-payment/Cargo.toml | 2 +- .../asset-conversion-tx-payment/Cargo.toml | 2 +- .../asset-tx-payment/Cargo.toml | 2 +- .../frame/transaction-storage/Cargo.toml | 2 +- substrate/frame/treasury/Cargo.toml | 2 +- substrate/frame/tx-pause/Cargo.toml | 2 +- substrate/frame/uniques/Cargo.toml | 2 +- substrate/frame/utility/Cargo.toml | 2 +- substrate/frame/vesting/Cargo.toml | 2 +- substrate/frame/whitelist/Cargo.toml | 2 +- substrate/primitives/api/Cargo.toml | 2 +- substrate/primitives/api/test/Cargo.toml | 4 +- .../primitives/application-crypto/Cargo.toml | 2 +- substrate/primitives/arithmetic/Cargo.toml | 2 +- .../primitives/authority-discovery/Cargo.toml | 2 +- substrate/primitives/blockchain/Cargo.toml | 2 +- .../primitives/consensus/aura/Cargo.toml | 4 +- .../primitives/consensus/babe/Cargo.toml | 4 +- .../primitives/consensus/beefy/Cargo.toml | 4 +- .../primitives/consensus/common/Cargo.toml | 6 +- .../primitives/consensus/grandpa/Cargo.toml | 2 +- .../primitives/consensus/sassafras/Cargo.toml | 2 +- .../primitives/consensus/slots/Cargo.toml | 2 +- substrate/primitives/core/Cargo.toml | 2 +- substrate/primitives/inherents/Cargo.toml | 6 +- substrate/primitives/keyring/Cargo.toml | 2 +- .../merkle-mountain-range/Cargo.toml | 2 +- substrate/primitives/metadata-ir/Cargo.toml | 2 +- substrate/primitives/mixnet/Cargo.toml | 2 +- .../primitives/npos-elections/Cargo.toml | 2 +- substrate/primitives/runtime/Cargo.toml | 2 +- substrate/primitives/session/Cargo.toml | 2 +- substrate/primitives/staking/Cargo.toml | 2 +- .../primitives/statement-store/Cargo.toml | 2 +- .../primitives/test-primitives/Cargo.toml | 2 +- substrate/primitives/timestamp/Cargo.toml | 2 +- .../transaction-storage-proof/Cargo.toml | 4 +- substrate/primitives/trie/Cargo.toml | 2 +- substrate/primitives/version/Cargo.toml | 2 +- substrate/primitives/weights/Cargo.toml | 2 +- substrate/test-utils/Cargo.toml | 2 +- substrate/test-utils/client/Cargo.toml | 4 +- substrate/test-utils/runtime/Cargo.toml | 4 +- .../test-utils/runtime/client/Cargo.toml | 2 +- .../runtime/transaction-pool/Cargo.toml | 2 +- substrate/utils/binary-merkle-tree/Cargo.toml | 2 +- .../frame/remote-externalities/Cargo.toml | 2 +- substrate/utils/frame/rpc/client/Cargo.toml | 2 +- substrate/utils/frame/rpc/support/Cargo.toml | 4 +- substrate/utils/frame/rpc/system/Cargo.toml | 4 +- .../utils/frame/try-runtime/cli/Cargo.toml | 4 +- substrate/utils/wasm-builder/Cargo.toml | 2 +- templates/minimal/node/Cargo.toml | 2 +- templates/minimal/pallets/template/Cargo.toml | 2 +- .../parachain/pallets/template/Cargo.toml | 2 +- templates/parachain/runtime/Cargo.toml | 2 +- templates/solochain/node/Cargo.toml | 2 +- .../solochain/pallets/template/Cargo.toml | 2 +- templates/solochain/runtime/Cargo.toml | 2 +- 305 files changed, 466 insertions(+), 434 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 09114e9cc835..5125e46ca89a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -275,9 +275,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.2" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15c4c2c83f81532e5845a733998b6971faca23490340a418e9b72a3ec9de12ea" +checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" [[package]] name = "anstyle-parse" @@ -1239,9 +1239,9 @@ checksum = "ecc7ab41815b3c653ccd2978ec3255c81349336702dfdf62ee6f7069b12a3aae" [[package]] name = "async-trait" -version = "0.1.74" +version = "0.1.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" +checksum = "a507401cad91ec6a857ed5513a2073c82a9b9048762b885bb98655b306964681" dependencies = [ "proc-macro2", "quote", @@ -1393,7 +1393,7 @@ name = "binary-merkle-tree" version = "13.0.0" dependencies = [ "array-bytes 6.1.0", - "env_logger 0.9.3", + "env_logger 0.11.3", "hash-db", "log", "sp-core", @@ -4991,10 +4991,10 @@ dependencies = [ ] [[package]] -name = "env_logger" -version = "0.8.4" +name = "env_filter" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" +checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea" dependencies = [ "log", "regex", @@ -5002,15 +5002,12 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.9.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" +checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" dependencies = [ - "atty", - "humantime", "log", "regex", - "termcolor", ] [[package]] @@ -5026,6 +5023,19 @@ dependencies = [ "termcolor", ] +[[package]] +name = "env_logger" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "humantime", + "log", +] + [[package]] name = "environmental" version = "1.1.4" @@ -6758,7 +6768,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" dependencies = [ - "socket2 0.5.3", + "socket2 0.5.6", "widestring", "windows-sys 0.48.0", "winreg", @@ -9520,7 +9530,7 @@ dependencies = [ "array-bytes 6.1.0", "assert_matches", "bitflags 1.3.2", - "env_logger 0.9.3", + "env_logger 0.11.3", "environmental", "frame-benchmarking", "frame-support", @@ -9790,7 +9800,7 @@ dependencies = [ "sp-runtime", "sp-std 14.0.0", "sp-tracing 16.0.0", - "strum 0.24.1", + "strum 0.26.2", ] [[package]] @@ -10211,7 +10221,7 @@ name = "pallet-mmr" version = "27.0.0" dependencies = [ "array-bytes 6.1.0", - "env_logger 0.9.3", + "env_logger 0.11.3", "frame-benchmarking", "frame-support", "frame-system", @@ -12129,7 +12139,7 @@ version = "7.0.0" dependencies = [ "assert_matches", "bitvec", - "env_logger 0.9.3", + "env_logger 0.11.3", "futures", "futures-timer", "itertools 0.10.5", @@ -12159,7 +12169,7 @@ dependencies = [ "always-assert", "assert_matches", "bitvec", - "env_logger 0.9.3", + "env_logger 0.11.3", "futures", "futures-timer", "log", @@ -12215,7 +12225,7 @@ version = "7.0.0" dependencies = [ "assert_matches", "async-trait", - "env_logger 0.9.3", + "env_logger 0.11.3", "fatality", "futures", "futures-timer", @@ -12277,7 +12287,7 @@ version = "7.0.0" dependencies = [ "assert_matches", "bitvec", - "env_logger 0.9.3", + "env_logger 0.11.3", "fatality", "futures", "futures-timer", @@ -12449,7 +12459,7 @@ dependencies = [ "async-trait", "bitvec", "derive_more", - "env_logger 0.9.3", + "env_logger 0.11.3", "futures", "futures-timer", "itertools 0.10.5", @@ -12491,7 +12501,7 @@ version = "7.0.0" dependencies = [ "assert_matches", "bitvec", - "env_logger 0.9.3", + "env_logger 0.11.3", "futures", "futures-timer", "kvdb", @@ -12933,7 +12943,7 @@ dependencies = [ "rand_chacha 0.3.1", "sc-authority-discovery", "sc-network", - "strum 0.24.1", + "strum 0.26.2", "thiserror", "tracing-gum", ] @@ -13025,7 +13035,7 @@ dependencies = [ "assert_matches", "async-trait", "derive_more", - "env_logger 0.9.3", + "env_logger 0.11.3", "fatality", "futures", "futures-channel", @@ -13469,7 +13479,7 @@ dependencies = [ "assert_matches", "async-trait", "bitvec", - "env_logger 0.9.3", + "env_logger 0.11.3", "frame-benchmarking", "frame-benchmarking-cli", "frame-support", @@ -13645,7 +13655,7 @@ dependencies = [ "clap-num", "color-eyre", "colored", - "env_logger 0.9.3", + "env_logger 0.11.3", "futures", "futures-timer", "hex", @@ -16179,7 +16189,7 @@ dependencies = [ "array-bytes 6.1.0", "assert_matches", "criterion 0.4.0", - "env_logger 0.9.3", + "env_logger 0.11.3", "num_cpus", "parity-scale-codec", "parking_lot 0.12.1", @@ -16615,7 +16625,7 @@ name = "sc-rpc" version = "29.0.0" dependencies = [ "assert_matches", - "env_logger 0.9.3", + "env_logger 0.11.3", "futures", "jsonrpsee", "log", @@ -16857,7 +16867,7 @@ dependencies = [ name = "sc-statement-store" version = "10.0.0" dependencies = [ - "env_logger 0.9.3", + "env_logger 0.11.3", "log", "parity-db", "parking_lot 0.12.1", @@ -17940,7 +17950,7 @@ name = "snowbridge-outbound-queue-merkle-tree" version = "0.3.0" dependencies = [ "array-bytes 4.2.0", - "env_logger 0.9.3", + "env_logger 0.11.3", "hex", "hex-literal", "parity-scale-codec", @@ -18250,12 +18260,12 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.3" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877" +checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" dependencies = [ "libc", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -18586,7 +18596,7 @@ dependencies = [ "sp-keystore", "sp-mmr-primitives", "sp-runtime", - "strum 0.24.1", + "strum 0.26.2", "w3f-bls", ] @@ -18877,7 +18887,7 @@ version = "31.0.0" dependencies = [ "sp-core", "sp-runtime", - "strum 0.24.1", + "strum 0.26.2", ] [[package]] @@ -19763,6 +19773,15 @@ version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" +[[package]] +name = "strum" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29" +dependencies = [ + "strum_macros 0.26.2", +] + [[package]] name = "strum_macros" version = "0.24.3" @@ -19789,6 +19808,19 @@ dependencies = [ "syn 2.0.53", ] +[[package]] +name = "strum_macros" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.53", +] + [[package]] name = "subkey" version = "9.0.0" @@ -20054,7 +20086,7 @@ dependencies = [ "parity-wasm", "polkavm-linker", "sp-maybe-compressed-blob", - "strum 0.24.1", + "strum 0.26.2", "tempfile", "toml 0.8.8", "walkdir", @@ -20602,9 +20634,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.33.0" +version = "1.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f38200e3ef7995e5ef13baec2f432a6da0aa9ac495b2c0e8f3b7eec2c92d653" +checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" dependencies = [ "backtrace", "bytes", @@ -20614,16 +20646,16 @@ dependencies = [ "parking_lot 0.12.1", "pin-project-lite 0.2.12", "signal-hook-registry", - "socket2 0.5.3", + "socket2 0.5.6", "tokio-macros", "windows-sys 0.48.0", ] [[package]] name = "tokio-macros" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", diff --git a/bridges/snowbridge/pallets/outbound-queue/merkle-tree/Cargo.toml b/bridges/snowbridge/pallets/outbound-queue/merkle-tree/Cargo.toml index 0606e9de3305..5315d6b4adbc 100644 --- a/bridges/snowbridge/pallets/outbound-queue/merkle-tree/Cargo.toml +++ b/bridges/snowbridge/pallets/outbound-queue/merkle-tree/Cargo.toml @@ -23,7 +23,7 @@ sp-runtime = { path = "../../../../../substrate/primitives/runtime", default-fea [dev-dependencies] hex-literal = { version = "0.4.1" } -env_logger = "0.9" +env_logger = "0.11" hex = "0.4" array-bytes = "4.1" sp-crypto-hashing = { path = "../../../../../substrate/primitives/crypto/hashing" } diff --git a/bridges/snowbridge/runtime/test-common/Cargo.toml b/bridges/snowbridge/runtime/test-common/Cargo.toml index 4e8b311cb978..90b4f38e7214 100644 --- a/bridges/snowbridge/runtime/test-common/Cargo.toml +++ b/bridges/snowbridge/runtime/test-common/Cargo.toml @@ -14,7 +14,7 @@ workspace = true codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } hex-literal = { version = "0.4.1" } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { optional = true, features = ["derive"], workspace = true, default-features = true } smallvec = "1.11.0" diff --git a/cumulus/client/collator/Cargo.toml b/cumulus/client/collator/Cargo.toml index 0e911b9f3abf..42f7342d1a53 100644 --- a/cumulus/client/collator/Cargo.toml +++ b/cumulus/client/collator/Cargo.toml @@ -12,7 +12,7 @@ workspace = true [dependencies] parking_lot = "0.12.1" codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } -futures = "0.3.21" +futures = "0.3.30" tracing = "0.1.25" # Substrate @@ -34,7 +34,7 @@ cumulus-client-network = { path = "../network" } cumulus-primitives-core = { path = "../../primitives/core" } [dev-dependencies] -async-trait = "0.1.74" +async-trait = "0.1.79" # Substrate sp-maybe-compressed-blob = { path = "../../../substrate/primitives/maybe-compressed-blob" } diff --git a/cumulus/client/consensus/aura/Cargo.toml b/cumulus/client/consensus/aura/Cargo.toml index 58bb1dd5914b..70dd67cb9a00 100644 --- a/cumulus/client/consensus/aura/Cargo.toml +++ b/cumulus/client/consensus/aura/Cargo.toml @@ -10,7 +10,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" workspace = true [dependencies] -async-trait = "0.1.74" +async-trait = "0.1.79" codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } futures = "0.3.28" tracing = "0.1.37" diff --git a/cumulus/client/consensus/common/Cargo.toml b/cumulus/client/consensus/common/Cargo.toml index 5a014b10e35f..fb4a85ad1226 100644 --- a/cumulus/client/consensus/common/Cargo.toml +++ b/cumulus/client/consensus/common/Cargo.toml @@ -10,7 +10,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" workspace = true [dependencies] -async-trait = "0.1.74" +async-trait = "0.1.79" codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } dyn-clone = "1.0.16" futures = "0.3.28" diff --git a/cumulus/client/consensus/proposer/Cargo.toml b/cumulus/client/consensus/proposer/Cargo.toml index b37232bb4485..42ca4e06f8f4 100644 --- a/cumulus/client/consensus/proposer/Cargo.toml +++ b/cumulus/client/consensus/proposer/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] anyhow = "1.0" -async-trait = "0.1.74" +async-trait = "0.1.79" thiserror = { workspace = true } # Substrate diff --git a/cumulus/client/consensus/relay-chain/Cargo.toml b/cumulus/client/consensus/relay-chain/Cargo.toml index 3d06d6b89ef7..cb32b9804576 100644 --- a/cumulus/client/consensus/relay-chain/Cargo.toml +++ b/cumulus/client/consensus/relay-chain/Cargo.toml @@ -10,7 +10,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" workspace = true [dependencies] -async-trait = "0.1.74" +async-trait = "0.1.79" futures = "0.3.28" parking_lot = "0.12.1" tracing = "0.1.37" diff --git a/cumulus/client/network/Cargo.toml b/cumulus/client/network/Cargo.toml index 995ef606d270..1210975ef690 100644 --- a/cumulus/client/network/Cargo.toml +++ b/cumulus/client/network/Cargo.toml @@ -10,7 +10,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" workspace = true [dependencies] -async-trait = "0.1.74" +async-trait = "0.1.79" codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } futures = "0.3.28" futures-timer = "3.0.2" diff --git a/cumulus/client/parachain-inherent/Cargo.toml b/cumulus/client/parachain-inherent/Cargo.toml index e00f3ba26066..6e9adab1ffc9 100644 --- a/cumulus/client/parachain-inherent/Cargo.toml +++ b/cumulus/client/parachain-inherent/Cargo.toml @@ -7,9 +7,9 @@ description = "Inherent that needs to be present in every parachain block. Conta license = "Apache-2.0" [dependencies] -async-trait = "0.1.73" +async-trait = "0.1.79" codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } -scale-info = { version = "2.10.0", features = ["derive"] } +scale-info = { version = "2.11.1", features = ["derive"] } tracing = { version = "0.1.37" } # Substrate diff --git a/cumulus/client/pov-recovery/Cargo.toml b/cumulus/client/pov-recovery/Cargo.toml index 375a57a87c2a..571935620d6d 100644 --- a/cumulus/client/pov-recovery/Cargo.toml +++ b/cumulus/client/pov-recovery/Cargo.toml @@ -32,7 +32,7 @@ polkadot-primitives = { path = "../../../polkadot/primitives" } # Cumulus cumulus-primitives-core = { path = "../../primitives/core" } cumulus-relay-chain-interface = { path = "../relay-chain-interface" } -async-trait = "0.1.74" +async-trait = "0.1.79" [dev-dependencies] tokio = { version = "1.32.0", features = ["macros"] } diff --git a/cumulus/client/relay-chain-inprocess-interface/Cargo.toml b/cumulus/client/relay-chain-inprocess-interface/Cargo.toml index aa16230cd8af..7629b6c631a3 100644 --- a/cumulus/client/relay-chain-inprocess-interface/Cargo.toml +++ b/cumulus/client/relay-chain-inprocess-interface/Cargo.toml @@ -10,7 +10,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" workspace = true [dependencies] -async-trait = "0.1.74" +async-trait = "0.1.79" futures = "0.3.28" futures-timer = "3.0.2" diff --git a/cumulus/client/relay-chain-interface/Cargo.toml b/cumulus/client/relay-chain-interface/Cargo.toml index 6e652b892104..6df9847252fe 100644 --- a/cumulus/client/relay-chain-interface/Cargo.toml +++ b/cumulus/client/relay-chain-interface/Cargo.toml @@ -20,7 +20,7 @@ sp-state-machine = { path = "../../../substrate/primitives/state-machine" } sc-client-api = { path = "../../../substrate/client/api" } futures = "0.3.28" -async-trait = "0.1.74" +async-trait = "0.1.79" thiserror = { workspace = true } jsonrpsee-core = "0.22" parity-scale-codec = "3.6.4" diff --git a/cumulus/client/relay-chain-minimal-node/Cargo.toml b/cumulus/client/relay-chain-minimal-node/Cargo.toml index 98240c92adab..6860b42a5078 100644 --- a/cumulus/client/relay-chain-minimal-node/Cargo.toml +++ b/cumulus/client/relay-chain-minimal-node/Cargo.toml @@ -49,6 +49,6 @@ cumulus-primitives-core = { path = "../../primitives/core" } array-bytes = "6.1" tracing = "0.1.37" -async-trait = "0.1.74" +async-trait = "0.1.79" futures = "0.3.28" parking_lot = "0.12.1" diff --git a/cumulus/client/relay-chain-rpc-interface/Cargo.toml b/cumulus/client/relay-chain-rpc-interface/Cargo.toml index 801712b1ad15..149816772895 100644 --- a/cumulus/client/relay-chain-rpc-interface/Cargo.toml +++ b/cumulus/client/relay-chain-rpc-interface/Cargo.toml @@ -35,7 +35,7 @@ futures-timer = "3.0.2" parity-scale-codec = "3.6.4" jsonrpsee = { version = "0.22", features = ["ws-client"] } tracing = "0.1.37" -async-trait = "0.1.74" +async-trait = "0.1.79" url = "2.4.0" serde_json = { workspace = true, default-features = true } serde = { workspace = true, default-features = true } diff --git a/cumulus/pallets/aura-ext/Cargo.toml b/cumulus/pallets/aura-ext/Cargo.toml index ff30dce7b033..fe717596f9b3 100644 --- a/cumulus/pallets/aura-ext/Cargo.toml +++ b/cumulus/pallets/aura-ext/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Substrate frame-support = { path = "../../../substrate/frame/support", default-features = false } diff --git a/cumulus/pallets/collator-selection/Cargo.toml b/cumulus/pallets/collator-selection/Cargo.toml index 241a78466d61..c04d9e1403ec 100644 --- a/cumulus/pallets/collator-selection/Cargo.toml +++ b/cumulus/pallets/collator-selection/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] log = { workspace = true } codec = { default-features = false, features = ["derive"], package = "parity-scale-codec", version = "3.0.0" } rand = { version = "0.8.5", features = ["std_rng"], default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } sp-std = { path = "../../../substrate/primitives/std", default-features = false } sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } diff --git a/cumulus/pallets/dmp-queue/Cargo.toml b/cumulus/pallets/dmp-queue/Cargo.toml index 83ed994d0416..b2b24aeed72b 100644 --- a/cumulus/pallets/dmp-queue/Cargo.toml +++ b/cumulus/pallets/dmp-queue/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } frame-support = { path = "../../../substrate/frame/support", default-features = false } diff --git a/cumulus/pallets/parachain-system/Cargo.toml b/cumulus/pallets/parachain-system/Cargo.toml index 7e0442f0b585..a905df5b94a6 100644 --- a/cumulus/pallets/parachain-system/Cargo.toml +++ b/cumulus/pallets/parachain-system/Cargo.toml @@ -16,7 +16,7 @@ environmental = { version = "1.1.4", default-features = false } impl-trait-for-tuples = "0.2.1" log = { workspace = true } trie-db = { version = "0.28.0", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Substrate frame-benchmarking = { path = "../../../substrate/frame/benchmarking", default-features = false, optional = true } diff --git a/cumulus/pallets/solo-to-para/Cargo.toml b/cumulus/pallets/solo-to-para/Cargo.toml index f7dc5fe4de37..417038d7833c 100644 --- a/cumulus/pallets/solo-to-para/Cargo.toml +++ b/cumulus/pallets/solo-to-para/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Substrate frame-support = { path = "../../../substrate/frame/support", default-features = false } diff --git a/cumulus/pallets/xcm/Cargo.toml b/cumulus/pallets/xcm/Cargo.toml index 63cb14b16e76..9122e110fb92 100644 --- a/cumulus/pallets/xcm/Cargo.toml +++ b/cumulus/pallets/xcm/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } sp-std = { path = "../../../substrate/primitives/std", default-features = false } sp-io = { path = "../../../substrate/primitives/io", default-features = false } diff --git a/cumulus/pallets/xcmp-queue/Cargo.toml b/cumulus/pallets/xcmp-queue/Cargo.toml index 9078d5eda997..ab196c6d3ec6 100644 --- a/cumulus/pallets/xcmp-queue/Cargo.toml +++ b/cumulus/pallets/xcmp-queue/Cargo.toml @@ -12,7 +12,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"], default-features = false } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Substrate frame-support = { path = "../../../substrate/frame/support", default-features = false } diff --git a/cumulus/parachains/common/Cargo.toml b/cumulus/parachains/common/Cargo.toml index ebc9f822beb2..fa16205d0fd1 100644 --- a/cumulus/parachains/common/Cargo.toml +++ b/cumulus/parachains/common/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"], default-features = false } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Substrate frame-support = { path = "../../../substrate/frame/support", default-features = false } diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml index 18c39f895fac..010c252658c0 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml @@ -12,7 +12,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.4.0", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } hex-literal = "0.4.1" # Substrate diff --git a/cumulus/parachains/pallets/collective-content/Cargo.toml b/cumulus/parachains/pallets/collective-content/Cargo.toml index d4290dd2de24..b3fac47cb4ae 100644 --- a/cumulus/parachains/pallets/collective-content/Cargo.toml +++ b/cumulus/parachains/pallets/collective-content/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../../../../substrate/frame/benchmarking", default-features = false, optional = true } frame-support = { path = "../../../../substrate/frame/support", default-features = false } diff --git a/cumulus/parachains/pallets/parachain-info/Cargo.toml b/cumulus/parachains/pallets/parachain-info/Cargo.toml index 0e2f965e1cff..17981d238fd1 100644 --- a/cumulus/parachains/pallets/parachain-info/Cargo.toml +++ b/cumulus/parachains/pallets/parachain-info/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../../../../substrate/frame/support", default-features = false } frame-system = { path = "../../../../substrate/frame/system", default-features = false } diff --git a/cumulus/parachains/pallets/ping/Cargo.toml b/cumulus/parachains/pallets/ping/Cargo.toml index 1afd55eb0b92..15169b08b910 100644 --- a/cumulus/parachains/pallets/ping/Cargo.toml +++ b/cumulus/parachains/pallets/ping/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } sp-std = { path = "../../../../substrate/primitives/std", default-features = false } sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml index 53abb620022f..f5ea0937dec6 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml @@ -13,7 +13,7 @@ workspace = true codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } hex-literal = { version = "0.4.1" } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Substrate frame-benchmarking = { path = "../../../../../substrate/frame/benchmarking", default-features = false, optional = true } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml index 0f8a1182cd71..b792d64c03e0 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml @@ -13,7 +13,7 @@ workspace = true codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } hex-literal = { version = "0.4.1", optional = true } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Substrate frame-benchmarking = { path = "../../../../../substrate/frame/benchmarking", default-features = false, optional = true } diff --git a/cumulus/parachains/runtimes/assets/common/Cargo.toml b/cumulus/parachains/runtimes/assets/common/Cargo.toml index c9252375cfbf..12dfd9da1fff 100644 --- a/cumulus/parachains/runtimes/assets/common/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/common/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } log = { workspace = true } impl-trait-for-tuples = "0.2.2" diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml index 13b4b624eef2..1dd4f499b4dc 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml @@ -18,7 +18,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = ] } hex-literal = { version = "0.4.1" } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = [ +scale-info = { version = "2.11.1", default-features = false, features = [ "derive", ] } serde = { optional = true, features = ["derive"], workspace = true, default-features = true } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml index 0c46e6c2e14c..1501ed12e3ad 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml @@ -16,7 +16,7 @@ substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } hex-literal = { version = "0.4.1" } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { optional = true, features = ["derive"], workspace = true, default-features = true } # Substrate diff --git a/cumulus/parachains/runtimes/bridge-hubs/common/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/common/Cargo.toml index a4dcd19dc9e8..2ab6ee7995f2 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/common/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/common/Cargo.toml @@ -8,7 +8,7 @@ license = "Apache-2.0" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../../../../../substrate/frame/support", default-features = false } sp-std = { path = "../../../../../substrate/primitives/std", default-features = false } sp-core = { path = "../../../../../substrate/primitives/core", default-features = false } diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml b/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml index 4224b3971398..9c3acf6ad934 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml @@ -13,7 +13,7 @@ workspace = true codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } hex-literal = { version = "0.4.1" } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Substrate frame-benchmarking = { path = "../../../../../substrate/frame/benchmarking", default-features = false, optional = true } diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml index e4ac2016a726..a0aeb642df05 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml @@ -19,7 +19,7 @@ substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } hex-literal = { version = "0.4.1", optional = true } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Substrate sp-api = { path = "../../../../../substrate/primitives/api", default-features = false } diff --git a/cumulus/parachains/runtimes/glutton/glutton-westend/Cargo.toml b/cumulus/parachains/runtimes/glutton/glutton-westend/Cargo.toml index a357bf519e40..fe9cd25841bf 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/glutton/glutton-westend/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Substrate frame-benchmarking = { path = "../../../../../substrate/frame/benchmarking", default-features = false, optional = true } diff --git a/cumulus/parachains/runtimes/starters/seedling/Cargo.toml b/cumulus/parachains/runtimes/starters/seedling/Cargo.toml index 9f08fdf59437..eb702c9f2cdf 100644 --- a/cumulus/parachains/runtimes/starters/seedling/Cargo.toml +++ b/cumulus/parachains/runtimes/starters/seedling/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Substrate frame-executive = { path = "../../../../../substrate/frame/executive", default-features = false } diff --git a/cumulus/parachains/runtimes/starters/shell/Cargo.toml b/cumulus/parachains/runtimes/starters/shell/Cargo.toml index 2f82547afe9a..f66d04fec1fd 100644 --- a/cumulus/parachains/runtimes/starters/shell/Cargo.toml +++ b/cumulus/parachains/runtimes/starters/shell/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Substrate frame-executive = { path = "../../../../../substrate/frame/executive", default-features = false } diff --git a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml index c18f6571f416..028aa002a91e 100644 --- a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml +++ b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml @@ -21,7 +21,7 @@ substrate-wasm-builder = { path = "../../../../../substrate/utils/wasm-builder", codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } hex-literal = { version = "0.4.1", optional = true } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } smallvec = "1.11.0" # Substrate diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml b/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml index 790f38d94f50..df3aaa92c79e 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Substrate frame-benchmarking = { path = "../../../../../substrate/frame/benchmarking", default-features = false, optional = true } diff --git a/cumulus/polkadot-parachain/Cargo.toml b/cumulus/polkadot-parachain/Cargo.toml index 37b7be75ef91..280ece30fb68 100644 --- a/cumulus/polkadot-parachain/Cargo.toml +++ b/cumulus/polkadot-parachain/Cargo.toml @@ -15,7 +15,7 @@ name = "polkadot-parachain" path = "src/main.rs" [dependencies] -async-trait = "0.1.74" +async-trait = "0.1.79" clap = { version = "4.5.3", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.28" diff --git a/cumulus/primitives/core/Cargo.toml b/cumulus/primitives/core/Cargo.toml index 32c5054f359c..62c3f6751917 100644 --- a/cumulus/primitives/core/Cargo.toml +++ b/cumulus/primitives/core/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Substrate sp-api = { path = "../../../substrate/primitives/api", default-features = false } diff --git a/cumulus/primitives/parachain-inherent/Cargo.toml b/cumulus/primitives/parachain-inherent/Cargo.toml index f434305a0ce0..fcf4c93bc2f0 100644 --- a/cumulus/primitives/parachain-inherent/Cargo.toml +++ b/cumulus/primitives/parachain-inherent/Cargo.toml @@ -10,9 +10,9 @@ license = "Apache-2.0" workspace = true [dependencies] -async-trait = { version = "0.1.74", optional = true } +async-trait = { version = "0.1.79", optional = true } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Substrate sp-core = { path = "../../../substrate/primitives/core", default-features = false } diff --git a/cumulus/primitives/storage-weight-reclaim/Cargo.toml b/cumulus/primitives/storage-weight-reclaim/Cargo.toml index 54eec3ffb5e3..6dbf7904bf79 100644 --- a/cumulus/primitives/storage-weight-reclaim/Cargo.toml +++ b/cumulus/primitives/storage-weight-reclaim/Cargo.toml @@ -12,7 +12,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../../../substrate/frame/support", default-features = false } frame-system = { path = "../../../substrate/frame/system", default-features = false } diff --git a/cumulus/test/runtime/Cargo.toml b/cumulus/test/runtime/Cargo.toml index 449a8b819bc0..b430b118fa1f 100644 --- a/cumulus/test/runtime/Cargo.toml +++ b/cumulus/test/runtime/Cargo.toml @@ -10,7 +10,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # Substrate frame-executive = { path = "../../../substrate/frame/executive", default-features = false } diff --git a/cumulus/test/service/Cargo.toml b/cumulus/test/service/Cargo.toml index 113e0aca68a8..040fb479f6e8 100644 --- a/cumulus/test/service/Cargo.toml +++ b/cumulus/test/service/Cargo.toml @@ -13,7 +13,7 @@ name = "test-parachain" path = "src/main.rs" [dependencies] -async-trait = "0.1.74" +async-trait = "0.1.79" clap = { version = "4.5.3", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0" } criterion = { version = "0.5.1", features = ["async_tokio"] } diff --git a/polkadot/Cargo.toml b/polkadot/Cargo.toml index 883568b23f74..659edcb041c3 100644 --- a/polkadot/Cargo.toml +++ b/polkadot/Cargo.toml @@ -45,7 +45,7 @@ tikv-jemallocator = { version = "0.5.0", features = ["unprefixed_malloc_on_suppo assert_cmd = "2.0.4" nix = { version = "0.26.1", features = ["signal"] } tempfile = "3.2.0" -tokio = "1.24.2" +tokio = "1.37" substrate-rpc-client = { path = "../substrate/utils/frame/rpc/client" } polkadot-core-primitives = { path = "core-primitives" } diff --git a/polkadot/cli/Cargo.toml b/polkadot/cli/Cargo.toml index f57efa7ba436..b0c22c5a97fe 100644 --- a/polkadot/cli/Cargo.toml +++ b/polkadot/cli/Cargo.toml @@ -22,7 +22,7 @@ cfg-if = "1.0" clap = { version = "4.5.3", features = ["derive"], optional = true } log = { workspace = true, default-features = true } thiserror = { workspace = true } -futures = "0.3.21" +futures = "0.3.30" pyro = { package = "pyroscope", version = "0.5.3", optional = true } pyroscope_pprofrs = { version = "0.2", optional = true } diff --git a/polkadot/core-primitives/Cargo.toml b/polkadot/core-primitives/Cargo.toml index d3aef89cb74d..8dfa0b87328b 100644 --- a/polkadot/core-primitives/Cargo.toml +++ b/polkadot/core-primitives/Cargo.toml @@ -13,7 +13,7 @@ workspace = true sp-core = { path = "../../substrate/primitives/core", default-features = false } sp-std = { path = "../../substrate/primitives/std", default-features = false } sp-runtime = { path = "../../substrate/primitives/runtime", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } [features] diff --git a/polkadot/node/collation-generation/Cargo.toml b/polkadot/node/collation-generation/Cargo.toml index f72af87c15ed..ebc53a9e01bb 100644 --- a/polkadot/node/collation-generation/Cargo.toml +++ b/polkadot/node/collation-generation/Cargo.toml @@ -10,7 +10,7 @@ description = "Collator-side subsystem that handles incoming candidate submissio workspace = true [dependencies] -futures = "0.3.21" +futures = "0.3.30" gum = { package = "tracing-gum", path = "../gum" } polkadot-erasure-coding = { path = "../../erasure-coding" } polkadot-node-primitives = { path = "../primitives" } diff --git a/polkadot/node/core/approval-voting/Cargo.toml b/polkadot/node/core/approval-voting/Cargo.toml index 2a5b6198b9a8..ced7706c40a2 100644 --- a/polkadot/node/core/approval-voting/Cargo.toml +++ b/polkadot/node/core/approval-voting/Cargo.toml @@ -10,7 +10,7 @@ description = "Approval Voting Subsystem of the Polkadot node" workspace = true [dependencies] -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.2" parity-scale-codec = { version = "3.6.1", default-features = false, features = ["bit-vec", "derive"] } gum = { package = "tracing-gum", path = "../../gum" } @@ -41,7 +41,7 @@ rand_chacha = { version = "0.3.1" } rand = "0.8.5" [dev-dependencies] -async-trait = "0.1.74" +async-trait = "0.1.79" parking_lot = "0.12.1" sp-keyring = { path = "../../../../substrate/primitives/keyring" } sp-keystore = { path = "../../../../substrate/primitives/keystore" } @@ -52,4 +52,4 @@ assert_matches = "1.4.0" kvdb-memorydb = "0.13.0" test-helpers = { package = "polkadot-primitives-test-helpers", path = "../../../primitives/test-helpers" } log = { workspace = true, default-features = true } -env_logger = "0.9.0" +env_logger = "0.11" diff --git a/polkadot/node/core/av-store/Cargo.toml b/polkadot/node/core/av-store/Cargo.toml index 05212da74798..bc9b979228a1 100644 --- a/polkadot/node/core/av-store/Cargo.toml +++ b/polkadot/node/core/av-store/Cargo.toml @@ -10,7 +10,7 @@ license.workspace = true workspace = true [dependencies] -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.2" kvdb = "0.13.0" thiserror = { workspace = true } @@ -29,7 +29,7 @@ polkadot-node-jaeger = { path = "../../jaeger" } [dev-dependencies] log = { workspace = true, default-features = true } -env_logger = "0.9.0" +env_logger = "0.11" assert_matches = "1.4.0" kvdb-memorydb = "0.13.0" diff --git a/polkadot/node/core/backing/Cargo.toml b/polkadot/node/core/backing/Cargo.toml index d0c1f9aa4832..26fa54470fbd 100644 --- a/polkadot/node/core/backing/Cargo.toml +++ b/polkadot/node/core/backing/Cargo.toml @@ -10,7 +10,7 @@ description = "The Candidate Backing Subsystem. Tracks parachain candidates that workspace = true [dependencies] -futures = "0.3.21" +futures = "0.3.30" sp-keystore = { path = "../../../../substrate/primitives/keystore" } polkadot-primitives = { path = "../../../primitives" } polkadot-node-primitives = { path = "../../primitives" } @@ -30,7 +30,7 @@ sp-application-crypto = { path = "../../../../substrate/primitives/application-c sp-keyring = { path = "../../../../substrate/primitives/keyring" } sc-keystore = { path = "../../../../substrate/client/keystore" } sp-tracing = { path = "../../../../substrate/primitives/tracing" } -futures = { version = "0.3.21", features = ["thread-pool"] } +futures = { version = "0.3.30", features = ["thread-pool"] } assert_matches = "1.4.0" rstest = "0.18.2" polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } diff --git a/polkadot/node/core/bitfield-signing/Cargo.toml b/polkadot/node/core/bitfield-signing/Cargo.toml index 6ecfffd7249b..0663e0f1b699 100644 --- a/polkadot/node/core/bitfield-signing/Cargo.toml +++ b/polkadot/node/core/bitfield-signing/Cargo.toml @@ -10,7 +10,7 @@ description = "Bitfield signing subsystem for the Polkadot node" workspace = true [dependencies] -futures = "0.3.21" +futures = "0.3.30" gum = { package = "tracing-gum", path = "../../gum" } polkadot-primitives = { path = "../../../primitives" } polkadot-node-subsystem = { path = "../../subsystem" } diff --git a/polkadot/node/core/candidate-validation/Cargo.toml b/polkadot/node/core/candidate-validation/Cargo.toml index 15fc8c940d33..0cf4707aad29 100644 --- a/polkadot/node/core/candidate-validation/Cargo.toml +++ b/polkadot/node/core/candidate-validation/Cargo.toml @@ -10,8 +10,8 @@ license.workspace = true workspace = true [dependencies] -async-trait = "0.1.74" -futures = "0.3.21" +async-trait = "0.1.79" +futures = "0.3.30" futures-timer = "3.0.2" gum = { package = "tracing-gum", path = "../../gum" } @@ -31,7 +31,7 @@ polkadot-node-core-pvf = { path = "../pvf" } [dev-dependencies] sp-keyring = { path = "../../../../substrate/primitives/keyring" } -futures = { version = "0.3.21", features = ["thread-pool"] } +futures = { version = "0.3.30", features = ["thread-pool"] } assert_matches = "1.4.0" polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } sp-core = { path = "../../../../substrate/primitives/core" } diff --git a/polkadot/node/core/chain-api/Cargo.toml b/polkadot/node/core/chain-api/Cargo.toml index 9aa017ecba3d..f4d02d3f47b2 100644 --- a/polkadot/node/core/chain-api/Cargo.toml +++ b/polkadot/node/core/chain-api/Cargo.toml @@ -10,7 +10,7 @@ description = "The Chain API subsystem provides access to chain related utility workspace = true [dependencies] -futures = "0.3.21" +futures = "0.3.30" gum = { package = "tracing-gum", path = "../../gum" } polkadot-node-metrics = { path = "../../metrics" } polkadot-node-subsystem = { path = "../../subsystem" } @@ -19,7 +19,7 @@ sc-client-api = { path = "../../../../substrate/client/api" } sc-consensus-babe = { path = "../../../../substrate/client/consensus/babe" } [dev-dependencies] -futures = { version = "0.3.21", features = ["thread-pool"] } +futures = { version = "0.3.30", features = ["thread-pool"] } maplit = "1.0.2" parity-scale-codec = "3.6.1" polkadot-node-primitives = { path = "../../primitives" } diff --git a/polkadot/node/core/chain-selection/Cargo.toml b/polkadot/node/core/chain-selection/Cargo.toml index 96fd42785cdd..318f27a43086 100644 --- a/polkadot/node/core/chain-selection/Cargo.toml +++ b/polkadot/node/core/chain-selection/Cargo.toml @@ -10,7 +10,7 @@ license.workspace = true workspace = true [dependencies] -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3" gum = { package = "tracing-gum", path = "../../gum" } polkadot-primitives = { path = "../../../primitives" } diff --git a/polkadot/node/core/dispute-coordinator/Cargo.toml b/polkadot/node/core/dispute-coordinator/Cargo.toml index 1fff0a771706..cd3238449bea 100644 --- a/polkadot/node/core/dispute-coordinator/Cargo.toml +++ b/polkadot/node/core/dispute-coordinator/Cargo.toml @@ -10,7 +10,7 @@ license.workspace = true workspace = true [dependencies] -futures = "0.3.21" +futures = "0.3.30" gum = { package = "tracing-gum", path = "../../gum" } parity-scale-codec = "3.6.1" kvdb = "0.13.0" diff --git a/polkadot/node/core/parachains-inherent/Cargo.toml b/polkadot/node/core/parachains-inherent/Cargo.toml index 24da4dc1e316..4f6090f90e95 100644 --- a/polkadot/node/core/parachains-inherent/Cargo.toml +++ b/polkadot/node/core/parachains-inherent/Cargo.toml @@ -10,11 +10,11 @@ description = "Parachains inherent data provider for Polkadot node" workspace = true [dependencies] -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.2" gum = { package = "tracing-gum", path = "../../gum" } thiserror = { workspace = true } -async-trait = "0.1.74" +async-trait = "0.1.79" polkadot-node-subsystem = { path = "../../subsystem" } polkadot-overseer = { path = "../../overseer" } polkadot-primitives = { path = "../../../primitives" } diff --git a/polkadot/node/core/prospective-parachains/Cargo.toml b/polkadot/node/core/prospective-parachains/Cargo.toml index f66a66e859ec..ab3cef99e54f 100644 --- a/polkadot/node/core/prospective-parachains/Cargo.toml +++ b/polkadot/node/core/prospective-parachains/Cargo.toml @@ -10,7 +10,7 @@ description = "The Prospective Parachains subsystem. Tracks and handles prospect workspace = true [dependencies] -futures = "0.3.19" +futures = "0.3.30" gum = { package = "tracing-gum", path = "../../gum" } parity-scale-codec = "3.6.4" thiserror = { workspace = true } diff --git a/polkadot/node/core/provisioner/Cargo.toml b/polkadot/node/core/provisioner/Cargo.toml index 2a09e2b5b2cc..ec1a4abb3ece 100644 --- a/polkadot/node/core/provisioner/Cargo.toml +++ b/polkadot/node/core/provisioner/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } -futures = "0.3.21" +futures = "0.3.30" gum = { package = "tracing-gum", path = "../../gum" } thiserror = { workspace = true } polkadot-primitives = { path = "../../../primitives" } diff --git a/polkadot/node/core/pvf-checker/Cargo.toml b/polkadot/node/core/pvf-checker/Cargo.toml index f4f954e316c0..91b12b868097 100644 --- a/polkadot/node/core/pvf-checker/Cargo.toml +++ b/polkadot/node/core/pvf-checker/Cargo.toml @@ -10,7 +10,7 @@ license.workspace = true workspace = true [dependencies] -futures = "0.3.21" +futures = "0.3.30" thiserror = { workspace = true } gum = { package = "tracing-gum", path = "../../gum" } diff --git a/polkadot/node/core/pvf/Cargo.toml b/polkadot/node/core/pvf/Cargo.toml index 6ad36a39be60..a0233d6b7517 100644 --- a/polkadot/node/core/pvf/Cargo.toml +++ b/polkadot/node/core/pvf/Cargo.toml @@ -14,7 +14,7 @@ always-assert = "0.1" array-bytes = "6.1" blake3 = "1.5" cfg-if = "1.0" -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.2" gum = { package = "tracing-gum", path = "../../gum" } is_executable = "1.0.1" diff --git a/polkadot/node/core/pvf/common/Cargo.toml b/polkadot/node/core/pvf/common/Cargo.toml index 56bad9792fa0..f3eb9d919aae 100644 --- a/polkadot/node/core/pvf/common/Cargo.toml +++ b/polkadot/node/core/pvf/common/Cargo.toml @@ -12,7 +12,7 @@ workspace = true [dependencies] cfg-if = "1.0" cpu-time = "1.0.0" -futures = "0.3.21" +futures = "0.3.30" gum = { package = "tracing-gum", path = "../../../gum" } libc = "0.2.152" thiserror = { workspace = true } diff --git a/polkadot/node/core/runtime-api/Cargo.toml b/polkadot/node/core/runtime-api/Cargo.toml index 2de3a6ee325a..91f5c35b2794 100644 --- a/polkadot/node/core/runtime-api/Cargo.toml +++ b/polkadot/node/core/runtime-api/Cargo.toml @@ -10,7 +10,7 @@ license.workspace = true workspace = true [dependencies] -futures = "0.3.21" +futures = "0.3.30" gum = { package = "tracing-gum", path = "../../gum" } schnellru = "0.2.1" @@ -25,8 +25,8 @@ polkadot-node-subsystem-types = { path = "../../subsystem-types" } sp-api = { path = "../../../../substrate/primitives/api" } sp-core = { path = "../../../../substrate/primitives/core" } sp-keyring = { path = "../../../../substrate/primitives/keyring" } -async-trait = "0.1.74" -futures = { version = "0.3.21", features = ["thread-pool"] } +async-trait = "0.1.79" +futures = { version = "0.3.30", features = ["thread-pool"] } polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } polkadot-node-primitives = { path = "../../primitives" } test-helpers = { package = "polkadot-primitives-test-helpers", path = "../../../primitives/test-helpers" } diff --git a/polkadot/node/jaeger/Cargo.toml b/polkadot/node/jaeger/Cargo.toml index 23ab8f842108..6fa3d41eddb1 100644 --- a/polkadot/node/jaeger/Cargo.toml +++ b/polkadot/node/jaeger/Cargo.toml @@ -18,6 +18,6 @@ polkadot-node-primitives = { path = "../primitives" } sc-network = { path = "../../../substrate/client/network" } sp-core = { path = "../../../substrate/primitives/core" } thiserror = { workspace = true } -tokio = "1.24.2" +tokio = "1.37" log = { workspace = true, default-features = true } parity-scale-codec = { version = "3.6.1", default-features = false } diff --git a/polkadot/node/malus/Cargo.toml b/polkadot/node/malus/Cargo.toml index b3eb856f08ef..2f63c2f0938d 100644 --- a/polkadot/node/malus/Cargo.toml +++ b/polkadot/node/malus/Cargo.toml @@ -40,11 +40,11 @@ polkadot-node-primitives = { path = "../primitives" } polkadot-primitives = { path = "../../primitives" } color-eyre = { version = "0.6.1", default-features = false } assert_matches = "1.5" -async-trait = "0.1.74" +async-trait = "0.1.79" sp-keystore = { path = "../../../substrate/primitives/keystore" } sp-core = { path = "../../../substrate/primitives/core" } clap = { version = "4.5.3", features = ["derive"] } -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.2" gum = { package = "tracing-gum", path = "../gum" } erasure = { package = "polkadot-erasure-coding", path = "../../erasure-coding" } @@ -58,7 +58,7 @@ polkadot-node-core-pvf-prepare-worker = { path = "../core/pvf/prepare-worker" } [dev-dependencies] polkadot-node-subsystem-test-helpers = { path = "../subsystem-test-helpers" } sp-core = { path = "../../../substrate/primitives/core" } -futures = { version = "0.3.21", features = ["thread-pool"] } +futures = { version = "0.3.30", features = ["thread-pool"] } [build-dependencies] substrate-build-script-utils = { path = "../../../substrate/utils/build-script-utils" } diff --git a/polkadot/node/metrics/Cargo.toml b/polkadot/node/metrics/Cargo.toml index c567278f70ea..fbf0abf829e1 100644 --- a/polkadot/node/metrics/Cargo.toml +++ b/polkadot/node/metrics/Cargo.toml @@ -10,7 +10,7 @@ license.workspace = true workspace = true [dependencies] -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.2" gum = { package = "tracing-gum", path = "../gum" } @@ -30,7 +30,7 @@ log = { workspace = true, default-features = true } assert_cmd = "2.0.4" tempfile = "3.2.0" hyper = { version = "0.14.20", default-features = false, features = ["http1", "tcp"] } -tokio = "1.24.2" +tokio = "1.37" polkadot-test-service = { path = "../test/service", features = ["runtime-metrics"] } substrate-test-utils = { path = "../../../substrate/test-utils" } sc-service = { path = "../../../substrate/client/service" } diff --git a/polkadot/node/network/approval-distribution/Cargo.toml b/polkadot/node/network/approval-distribution/Cargo.toml index 2bc09c5f42ac..4c04ad83f84f 100644 --- a/polkadot/node/network/approval-distribution/Cargo.toml +++ b/polkadot/node/network/approval-distribution/Cargo.toml @@ -20,7 +20,7 @@ polkadot-node-jaeger = { path = "../../jaeger" } rand = "0.8" itertools = "0.10.5" -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.2" gum = { package = "tracing-gum", path = "../../gum" } bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } @@ -37,5 +37,5 @@ schnorrkel = { version = "0.11.4", default-features = false } # rand_core should match schnorrkel rand_core = "0.6.2" rand_chacha = "0.3.1" -env_logger = "0.9.0" +env_logger = "0.11" log = { workspace = true, default-features = true } diff --git a/polkadot/node/network/availability-distribution/Cargo.toml b/polkadot/node/network/availability-distribution/Cargo.toml index ac606bd377f7..b5636203f166 100644 --- a/polkadot/node/network/availability-distribution/Cargo.toml +++ b/polkadot/node/network/availability-distribution/Cargo.toml @@ -10,7 +10,7 @@ license.workspace = true workspace = true [dependencies] -futures = "0.3.21" +futures = "0.3.30" gum = { package = "tracing-gum", path = "../../gum" } parity-scale-codec = { version = "3.6.1", features = ["std"] } polkadot-primitives = { path = "../../../primitives" } diff --git a/polkadot/node/network/availability-recovery/Cargo.toml b/polkadot/node/network/availability-recovery/Cargo.toml index 23c4148fa858..dd0e0c432345 100644 --- a/polkadot/node/network/availability-recovery/Cargo.toml +++ b/polkadot/node/network/availability-recovery/Cargo.toml @@ -10,13 +10,13 @@ license.workspace = true workspace = true [dependencies] -futures = "0.3.21" -tokio = "1.24.2" +futures = "0.3.30" +tokio = "1.37" schnellru = "0.2.1" rand = "0.8.5" fatality = "0.0.6" thiserror = { workspace = true } -async-trait = "0.1.74" +async-trait = "0.1.79" gum = { package = "tracing-gum", path = "../../gum" } polkadot-erasure-coding = { path = "../../../erasure-coding" } @@ -30,7 +30,7 @@ sc-network = { path = "../../../../substrate/client/network" } [dev-dependencies] assert_matches = "1.4.0" -env_logger = "0.9.0" +env_logger = "0.11" futures-timer = "3.0.2" log = { workspace = true, default-features = true } diff --git a/polkadot/node/network/bitfield-distribution/Cargo.toml b/polkadot/node/network/bitfield-distribution/Cargo.toml index 0ddb5f643b89..6b5b784b7fd8 100644 --- a/polkadot/node/network/bitfield-distribution/Cargo.toml +++ b/polkadot/node/network/bitfield-distribution/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] always-assert = "0.1" -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.2" gum = { package = "tracing-gum", path = "../../gum" } polkadot-primitives = { path = "../../../primitives" } @@ -30,6 +30,6 @@ sp-keystore = { path = "../../../../substrate/primitives/keystore" } sp-keyring = { path = "../../../../substrate/primitives/keyring" } maplit = "1.0.2" log = { workspace = true, default-features = true } -env_logger = "0.9.0" +env_logger = "0.11" assert_matches = "1.4.0" rand_chacha = "0.3.1" diff --git a/polkadot/node/network/bridge/Cargo.toml b/polkadot/node/network/bridge/Cargo.toml index 2e889fc30eb9..9c2423e7e581 100644 --- a/polkadot/node/network/bridge/Cargo.toml +++ b/polkadot/node/network/bridge/Cargo.toml @@ -11,8 +11,8 @@ workspace = true [dependencies] always-assert = "0.1" -async-trait = "0.1.74" -futures = "0.3.21" +async-trait = "0.1.79" +futures = "0.3.30" gum = { package = "tracing-gum", path = "../../gum" } polkadot-primitives = { path = "../../../primitives" } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } diff --git a/polkadot/node/network/collator-protocol/Cargo.toml b/polkadot/node/network/collator-protocol/Cargo.toml index cfd88df958ce..2c7135742f56 100644 --- a/polkadot/node/network/collator-protocol/Cargo.toml +++ b/polkadot/node/network/collator-protocol/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] bitvec = { version = "1.0.1", default-features = false, features = ["alloc"] } -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3" gum = { package = "tracing-gum", path = "../../gum" } @@ -30,7 +30,7 @@ tokio-util = "0.7.1" [dev-dependencies] log = { workspace = true, default-features = true } -env_logger = "0.9.0" +env_logger = "0.11" assert_matches = "1.4.0" sp-core = { path = "../../../../substrate/primitives/core", features = ["std"] } diff --git a/polkadot/node/network/dispute-distribution/Cargo.toml b/polkadot/node/network/dispute-distribution/Cargo.toml index 14d59d04f2bf..ff9c302c7314 100644 --- a/polkadot/node/network/dispute-distribution/Cargo.toml +++ b/polkadot/node/network/dispute-distribution/Cargo.toml @@ -10,7 +10,7 @@ license.workspace = true workspace = true [dependencies] -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.2" gum = { package = "tracing-gum", path = "../../gum" } derive_more = "0.99.17" @@ -31,7 +31,7 @@ indexmap = "2.0.0" [dev-dependencies] async-channel = "1.8.0" -async-trait = "0.1.74" +async-trait = "0.1.79" polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } sp-keyring = { path = "../../../../substrate/primitives/keyring" } sp-tracing = { path = "../../../../substrate/primitives/tracing" } diff --git a/polkadot/node/network/gossip-support/Cargo.toml b/polkadot/node/network/gossip-support/Cargo.toml index 8d0edc206d72..2d6f2f954c66 100644 --- a/polkadot/node/network/gossip-support/Cargo.toml +++ b/polkadot/node/network/gossip-support/Cargo.toml @@ -22,7 +22,7 @@ polkadot-node-subsystem = { path = "../../subsystem" } polkadot-node-subsystem-util = { path = "../../subsystem-util" } polkadot-primitives = { path = "../../../primitives" } -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.2" rand = { version = "0.8.5", default-features = false } rand_chacha = { version = "0.3.1", default-features = false } @@ -37,7 +37,7 @@ sp-authority-discovery = { path = "../../../../substrate/primitives/authority-di polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" } assert_matches = "1.4.0" -async-trait = "0.1.74" +async-trait = "0.1.79" parking_lot = "0.12.1" lazy_static = "1.4.0" quickcheck = "1.0.3" diff --git a/polkadot/node/network/protocol/Cargo.toml b/polkadot/node/network/protocol/Cargo.toml index 7efa0b8ca820..81936364897f 100644 --- a/polkadot/node/network/protocol/Cargo.toml +++ b/polkadot/node/network/protocol/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] async-channel = "1.8.0" -async-trait = "0.1.74" +async-trait = "0.1.79" hex = "0.4.3" polkadot-primitives = { path = "../../../primitives" } polkadot-node-primitives = { path = "../../primitives" } @@ -19,8 +19,8 @@ polkadot-node-jaeger = { path = "../../jaeger" } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } sc-network = { path = "../../../../substrate/client/network" } sc-authority-discovery = { path = "../../../../substrate/client/authority-discovery" } -strum = { version = "0.24", features = ["derive"] } -futures = "0.3.21" +strum = { version = "0.26.2", features = ["derive"] } +futures = "0.3.30" thiserror = { workspace = true } fatality = "0.0.6" rand = "0.8" diff --git a/polkadot/node/network/statement-distribution/Cargo.toml b/polkadot/node/network/statement-distribution/Cargo.toml index 01f7d818c1c5..d8ae031cbf36 100644 --- a/polkadot/node/network/statement-distribution/Cargo.toml +++ b/polkadot/node/network/statement-distribution/Cargo.toml @@ -10,7 +10,7 @@ license.workspace = true workspace = true [dependencies] -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.2" gum = { package = "tracing-gum", path = "../../gum" } polkadot-primitives = { path = "../../../primitives" } diff --git a/polkadot/node/overseer/Cargo.toml b/polkadot/node/overseer/Cargo.toml index f91ec80d9440..ef79cfe2f702 100644 --- a/polkadot/node/overseer/Cargo.toml +++ b/polkadot/node/overseer/Cargo.toml @@ -12,7 +12,7 @@ workspace = true [dependencies] client = { package = "sc-client-api", path = "../../../substrate/client/api" } sp-api = { path = "../../../substrate/primitives/api" } -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.2" parking_lot = "0.12.1" polkadot-node-network-protocol = { path = "../network/protocol" } @@ -23,13 +23,13 @@ polkadot-primitives = { path = "../../primitives" } orchestra = { version = "0.3.5", default-features = false, features = ["futures_channel"] } gum = { package = "tracing-gum", path = "../gum" } sp-core = { path = "../../../substrate/primitives/core" } -async-trait = "0.1.74" +async-trait = "0.1.79" tikv-jemalloc-ctl = { version = "0.5.0", optional = true } [dev-dependencies] metered = { package = "prioritized-metered-channel", version = "0.6.1", default-features = false, features = ["futures_channel"] } sp-core = { path = "../../../substrate/primitives/core" } -futures = { version = "0.3.21", features = ["thread-pool"] } +futures = { version = "0.3.30", features = ["thread-pool"] } femme = "2.2.1" assert_matches = "1.4.0" test-helpers = { package = "polkadot-primitives-test-helpers", path = "../../primitives/test-helpers" } diff --git a/polkadot/node/primitives/Cargo.toml b/polkadot/node/primitives/Cargo.toml index b4541bcc346c..a4bbd824e671 100644 --- a/polkadot/node/primitives/Cargo.toml +++ b/polkadot/node/primitives/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] bounded-vec = "0.7" -futures = "0.3.21" +futures = "0.3.30" polkadot-primitives = { path = "../../primitives" } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } sp-core = { path = "../../../substrate/primitives/core" } diff --git a/polkadot/node/service/Cargo.toml b/polkadot/node/service/Cargo.toml index 932f3e679f41..9688ab556473 100644 --- a/polkadot/node/service/Cargo.toml +++ b/polkadot/node/service/Cargo.toml @@ -77,8 +77,8 @@ frame-benchmarking-cli = { path = "../../../substrate/utils/frame/benchmarking-c frame-benchmarking = { path = "../../../substrate/frame/benchmarking" } # External Crates -async-trait = "0.1.74" -futures = "0.3.21" +async-trait = "0.1.79" +futures = "0.3.30" hex-literal = "0.4.1" is_executable = "1.0.1" gum = { package = "tracing-gum", path = "../gum" } @@ -148,7 +148,7 @@ xcm-fee-payment-runtime-api = { path = "../../xcm/xcm-fee-payment-runtime-api" } polkadot-test-client = { path = "../test/client" } polkadot-node-subsystem-test-helpers = { path = "../subsystem-test-helpers" } test-helpers = { package = "polkadot-primitives-test-helpers", path = "../../primitives/test-helpers" } -env_logger = "0.9.0" +env_logger = "0.11" assert_matches = "1.5.0" serial_test = "2.0.0" tempfile = "3.2" diff --git a/polkadot/node/subsystem-bench/Cargo.toml b/polkadot/node/subsystem-bench/Cargo.toml index b494f05180d1..37224d110e88 100644 --- a/polkadot/node/subsystem-bench/Cargo.toml +++ b/polkadot/node/subsystem-bench/Cargo.toml @@ -35,12 +35,12 @@ color-eyre = { version = "0.6.1", default-features = false } polkadot-overseer = { path = "../overseer" } colored = "2.0.4" assert_matches = "1.5" -async-trait = "0.1.57" +async-trait = "0.1.79" sp-keystore = { path = "../../../substrate/primitives/keystore" } sc-keystore = { path = "../../../substrate/client/keystore" } sp-core = { path = "../../../substrate/primitives/core" } clap = { version = "4.5.3", features = ["derive"] } -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.2" bincode = "1.3.3" sha1 = "0.10.6" @@ -48,7 +48,7 @@ hex = "0.4.3" gum = { package = "tracing-gum", path = "../gum" } polkadot-erasure-coding = { package = "polkadot-erasure-coding", path = "../../erasure-coding" } log = { workspace = true, default-features = true } -env_logger = "0.9.0" +env_logger = "0.11" rand = "0.8.5" # `rand` only supports uniform distribution, we need normal distribution for latency. rand_distr = "0.4.3" diff --git a/polkadot/node/subsystem-test-helpers/Cargo.toml b/polkadot/node/subsystem-test-helpers/Cargo.toml index c71f030568d9..57678e8e8d4a 100644 --- a/polkadot/node/subsystem-test-helpers/Cargo.toml +++ b/polkadot/node/subsystem-test-helpers/Cargo.toml @@ -11,8 +11,8 @@ license.workspace = true workspace = true [dependencies] -async-trait = "0.1.74" -futures = "0.3.21" +async-trait = "0.1.79" +futures = "0.3.30" parking_lot = "0.12.1" polkadot-node-subsystem = { path = "../subsystem" } polkadot-erasure-coding = { path = "../../erasure-coding" } diff --git a/polkadot/node/subsystem-types/Cargo.toml b/polkadot/node/subsystem-types/Cargo.toml index 54c8f7e2ade7..101907763877 100644 --- a/polkadot/node/subsystem-types/Cargo.toml +++ b/polkadot/node/subsystem-types/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] derive_more = "0.99.17" -futures = "0.3.21" +futures = "0.3.30" polkadot-primitives = { path = "../../primitives" } polkadot-node-primitives = { path = "../primitives" } polkadot-node-network-protocol = { path = "../network/protocol" } @@ -29,5 +29,5 @@ sc-transaction-pool-api = { path = "../../../substrate/client/transaction-pool/a smallvec = "1.8.0" substrate-prometheus-endpoint = { path = "../../../substrate/utils/prometheus" } thiserror = { workspace = true } -async-trait = "0.1.74" +async-trait = "0.1.79" bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } diff --git a/polkadot/node/subsystem-util/Cargo.toml b/polkadot/node/subsystem-util/Cargo.toml index a668f8de76a0..79a6a75e4cdf 100644 --- a/polkadot/node/subsystem-util/Cargo.toml +++ b/polkadot/node/subsystem-util/Cargo.toml @@ -10,8 +10,8 @@ license.workspace = true workspace = true [dependencies] -async-trait = "0.1.74" -futures = "0.3.21" +async-trait = "0.1.79" +futures = "0.3.30" futures-channel = "0.3.23" itertools = "0.10" parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } @@ -44,8 +44,8 @@ parity-db = { version = "0.4.12" } [dev-dependencies] assert_matches = "1.4.0" -env_logger = "0.9.0" -futures = { version = "0.3.21", features = ["thread-pool"] } +env_logger = "0.11" +futures = { version = "0.3.30", features = ["thread-pool"] } log = { workspace = true, default-features = true } polkadot-node-subsystem-test-helpers = { path = "../subsystem-test-helpers" } lazy_static = "1.4.0" diff --git a/polkadot/node/test/client/Cargo.toml b/polkadot/node/test/client/Cargo.toml index 36748c3b455b..7db00404eb8e 100644 --- a/polkadot/node/test/client/Cargo.toml +++ b/polkadot/node/test/client/Cargo.toml @@ -38,7 +38,7 @@ frame-benchmarking = { path = "../../../../substrate/frame/benchmarking" } [dev-dependencies] sp-keyring = { path = "../../../../substrate/primitives/keyring" } -futures = "0.3.21" +futures = "0.3.30" [features] runtime-benchmarks = [ diff --git a/polkadot/node/test/service/Cargo.toml b/polkadot/node/test/service/Cargo.toml index e7892abcd87b..48a206f23c66 100644 --- a/polkadot/node/test/service/Cargo.toml +++ b/polkadot/node/test/service/Cargo.toml @@ -10,13 +10,13 @@ license.workspace = true workspace = true [dependencies] -futures = "0.3.21" +futures = "0.3.30" hex = "0.4.3" gum = { package = "tracing-gum", path = "../../gum" } rand = "0.8.5" serde_json = { workspace = true, default-features = true } tempfile = "3.2.0" -tokio = "1.24.2" +tokio = "1.37" # Polkadot dependencies polkadot-overseer = { path = "../../overseer" } @@ -63,7 +63,7 @@ substrate-test-client = { path = "../../../../substrate/test-utils/client" } [dev-dependencies] pallet-balances = { path = "../../../../substrate/frame/balances", default-features = false } substrate-test-utils = { path = "../../../../substrate/test-utils" } -tokio = { version = "1.24.2", features = ["macros"] } +tokio = { version = "1.37", features = ["macros"] } [features] runtime-metrics = ["polkadot-test-runtime/runtime-metrics"] diff --git a/polkadot/parachain/Cargo.toml b/polkadot/parachain/Cargo.toml index d8c3cea7ad8b..15eea2addc89 100644 --- a/polkadot/parachain/Cargo.toml +++ b/polkadot/parachain/Cargo.toml @@ -14,7 +14,7 @@ workspace = true # this crate for WASM. This is critical to avoid forcing all parachain WASM into implementing # various unnecessary Substrate-specific endpoints. parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive", "serde"] } sp-std = { path = "../../substrate/primitives/std", default-features = false } sp-runtime = { path = "../../substrate/primitives/runtime", default-features = false, features = ["serde"] } sp-core = { path = "../../substrate/primitives/core", default-features = false, features = ["serde"] } diff --git a/polkadot/parachain/test-parachains/adder/collator/Cargo.toml b/polkadot/parachain/test-parachains/adder/collator/Cargo.toml index 30bce806f9ff..5a2b54057414 100644 --- a/polkadot/parachain/test-parachains/adder/collator/Cargo.toml +++ b/polkadot/parachain/test-parachains/adder/collator/Cargo.toml @@ -17,7 +17,7 @@ path = "src/main.rs" [dependencies] parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } clap = { version = "4.5.3", features = ["derive"] } -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.2" log = { workspace = true, default-features = true } diff --git a/polkadot/parachain/test-parachains/undying/collator/Cargo.toml b/polkadot/parachain/test-parachains/undying/collator/Cargo.toml index bede10a7673b..cacf7304f90a 100644 --- a/polkadot/parachain/test-parachains/undying/collator/Cargo.toml +++ b/polkadot/parachain/test-parachains/undying/collator/Cargo.toml @@ -17,7 +17,7 @@ path = "src/main.rs" [dependencies] parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } clap = { version = "4.5.3", features = ["derive"] } -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.2" log = { workspace = true, default-features = true } diff --git a/polkadot/primitives/Cargo.toml b/polkadot/primitives/Cargo.toml index e63fb621c788..004fa62acf34 100644 --- a/polkadot/primitives/Cargo.toml +++ b/polkadot/primitives/Cargo.toml @@ -13,7 +13,7 @@ workspace = true bitvec = { version = "1.0.0", default-features = false, features = ["alloc", "serde"] } hex-literal = "0.4.1" parity-scale-codec = { version = "3.6.1", default-features = false, features = ["bit-vec", "derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["bit-vec", "derive", "serde"] } +scale-info = { version = "2.11.1", default-features = false, features = ["bit-vec", "derive", "serde"] } log = { workspace = true, default-features = false } serde = { features = ["alloc", "derive"], workspace = true } diff --git a/polkadot/runtime/common/Cargo.toml b/polkadot/runtime/common/Cargo.toml index eae5d4fb2ef9..4219a7e7b0dc 100644 --- a/polkadot/runtime/common/Cargo.toml +++ b/polkadot/runtime/common/Cargo.toml @@ -15,7 +15,7 @@ bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } log = { workspace = true } rustc-hex = { version = "2.1.0", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["alloc"], workspace = true } serde_derive = { workspace = true } static_assertions = "1.1.0" diff --git a/polkadot/runtime/parachains/Cargo.toml b/polkadot/runtime/parachains/Cargo.toml index 6e693b83ae13..dff8549f29f3 100644 --- a/polkadot/runtime/parachains/Cargo.toml +++ b/polkadot/runtime/parachains/Cargo.toml @@ -15,7 +15,7 @@ bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } log = { workspace = true } rustc-hex = { version = "2.1.0", default-features = false } -scale-info = { version = "2.11.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["alloc", "derive"], workspace = true } derive_more = "0.99.17" bitflags = "1.3.2" @@ -59,7 +59,7 @@ polkadot-runtime-metrics = { path = "../metrics", default-features = false } polkadot-core-primitives = { path = "../../core-primitives", default-features = false } [dev-dependencies] -futures = "0.3.21" +futures = "0.3.30" hex-literal = "0.4.1" keyring = { package = "sp-keyring", path = "../../../substrate/primitives/keyring" } frame-support-test = { path = "../../../substrate/frame/support/test" } diff --git a/polkadot/runtime/rococo/Cargo.toml b/polkadot/runtime/rococo/Cargo.toml index ff178b17070e..19cc984e5829 100644 --- a/polkadot/runtime/rococo/Cargo.toml +++ b/polkadot/runtime/rococo/Cargo.toml @@ -12,7 +12,7 @@ workspace = true [dependencies] parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } log = { workspace = true } serde = { workspace = true } serde_derive = { optional = true, workspace = true } diff --git a/polkadot/runtime/test-runtime/Cargo.toml b/polkadot/runtime/test-runtime/Cargo.toml index 9753a4093045..35fb684597e7 100644 --- a/polkadot/runtime/test-runtime/Cargo.toml +++ b/polkadot/runtime/test-runtime/Cargo.toml @@ -15,7 +15,7 @@ bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } log = { workspace = true } rustc-hex = { version = "2.1.0", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { workspace = true } serde_derive = { optional = true, workspace = true } smallvec = "1.8.0" diff --git a/polkadot/runtime/westend/Cargo.toml b/polkadot/runtime/westend/Cargo.toml index a265901c5e9b..be60d62e43f7 100644 --- a/polkadot/runtime/westend/Cargo.toml +++ b/polkadot/runtime/westend/Cargo.toml @@ -13,7 +13,7 @@ workspace = true [dependencies] bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } log = { workspace = true } rustc-hex = { version = "2.1.0", default-features = false } serde = { workspace = true } diff --git a/polkadot/xcm/Cargo.toml b/polkadot/xcm/Cargo.toml index f9ccfb9833a6..b214342d2f48 100644 --- a/polkadot/xcm/Cargo.toml +++ b/polkadot/xcm/Cargo.toml @@ -16,7 +16,7 @@ derivative = { version = "2.2.0", default-features = false, features = ["use_cor impl-trait-for-tuples = "0.2.2" log = { workspace = true } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive", "serde"] } sp-weights = { path = "../../substrate/primitives/weights", default-features = false, features = ["serde"] } serde = { features = ["alloc", "derive", "rc"], workspace = true } schemars = { version = "0.8.13", default-features = true, optional = true } diff --git a/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml b/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml index 80f2d1deedf7..8c71426a6fae 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml +++ b/polkadot/xcm/pallet-xcm-benchmarks/Cargo.toml @@ -14,7 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../../../substrate/frame/support", default-features = false } frame-system = { path = "../../../substrate/frame/system", default-features = false } sp-runtime = { path = "../../../substrate/primitives/runtime", default-features = false } diff --git a/polkadot/xcm/pallet-xcm/Cargo.toml b/polkadot/xcm/pallet-xcm/Cargo.toml index 08307c34f8a9..460597e6649a 100644 --- a/polkadot/xcm/pallet-xcm/Cargo.toml +++ b/polkadot/xcm/pallet-xcm/Cargo.toml @@ -12,7 +12,7 @@ workspace = true [dependencies] bounded-collections = { version = "0.2.0", default-features = false } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { optional = true, features = ["derive"], workspace = true, default-features = true } log = { workspace = true } diff --git a/polkadot/xcm/xcm-builder/Cargo.toml b/polkadot/xcm/xcm-builder/Cargo.toml index 10726b0f5119..997ca99fb12c 100644 --- a/polkadot/xcm/xcm-builder/Cargo.toml +++ b/polkadot/xcm/xcm-builder/Cargo.toml @@ -12,7 +12,7 @@ workspace = true [dependencies] impl-trait-for-tuples = "0.2.1" parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } xcm = { package = "staging-xcm", path = "..", default-features = false } xcm-executor = { package = "staging-xcm-executor", path = "../xcm-executor", default-features = false } sp-std = { path = "../../../substrate/primitives/std", default-features = false } diff --git a/polkadot/xcm/xcm-executor/Cargo.toml b/polkadot/xcm/xcm-executor/Cargo.toml index 71bd58073db6..aebc768bb906 100644 --- a/polkadot/xcm/xcm-executor/Cargo.toml +++ b/polkadot/xcm/xcm-executor/Cargo.toml @@ -13,7 +13,7 @@ workspace = true impl-trait-for-tuples = "0.2.2" environmental = { version = "1.1.4", default-features = false } parity-scale-codec = { version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.5.0", default-features = false, features = ["derive", "serde"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive", "serde"] } xcm = { package = "staging-xcm", path = "..", default-features = false } sp-std = { path = "../../../substrate/primitives/std", default-features = false } sp-io = { path = "../../../substrate/primitives/io", default-features = false } diff --git a/polkadot/xcm/xcm-executor/integration-tests/Cargo.toml b/polkadot/xcm/xcm-executor/integration-tests/Cargo.toml index 1e572e6210a2..9c9c53f0ee1b 100644 --- a/polkadot/xcm/xcm-executor/integration-tests/Cargo.toml +++ b/polkadot/xcm/xcm-executor/integration-tests/Cargo.toml @@ -14,7 +14,7 @@ workspace = true codec = { package = "parity-scale-codec", version = "3.6.1" } frame-support = { path = "../../../../substrate/frame/support", default-features = false } frame-system = { path = "../../../../substrate/frame/system" } -futures = "0.3.21" +futures = "0.3.30" pallet-transaction-payment = { path = "../../../../substrate/frame/transaction-payment" } pallet-xcm = { path = "../../pallet-xcm" } polkadot-test-client = { path = "../../../node/test/client" } diff --git a/polkadot/xcm/xcm-fee-payment-runtime-api/Cargo.toml b/polkadot/xcm/xcm-fee-payment-runtime-api/Cargo.toml index 682642d13c3a..30c7c0bac14f 100644 --- a/polkadot/xcm/xcm-fee-payment-runtime-api/Cargo.toml +++ b/polkadot/xcm/xcm-fee-payment-runtime-api/Cargo.toml @@ -16,7 +16,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = ] } sp-api = { path = "../../../substrate/primitives/api", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = [ +scale-info = { version = "2.11.1", default-features = false, features = [ "derive", "serde", ] } diff --git a/polkadot/xcm/xcm-simulator/example/Cargo.toml b/polkadot/xcm/xcm-simulator/example/Cargo.toml index af471df60aba..0e13a10a1410 100644 --- a/polkadot/xcm/xcm-simulator/example/Cargo.toml +++ b/polkadot/xcm/xcm-simulator/example/Cargo.toml @@ -11,7 +11,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } -scale-info = { version = "2.10.0", features = ["derive"] } +scale-info = { version = "2.11.1", features = ["derive"] } log = { workspace = true } frame-system = { path = "../../../../substrate/frame/system" } diff --git a/polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml b/polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml index 30644dc0e0a5..ca794a07bfb0 100644 --- a/polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml +++ b/polkadot/xcm/xcm-simulator/fuzzer/Cargo.toml @@ -14,7 +14,7 @@ workspace = true codec = { package = "parity-scale-codec", version = "3.6.1" } honggfuzz = "0.5.55" arbitrary = "1.3.2" -scale-info = { version = "2.10.0", features = ["derive"] } +scale-info = { version = "2.11.1", features = ["derive"] } frame-system = { path = "../../../../substrate/frame/system" } frame-support = { path = "../../../../substrate/frame/support" } diff --git a/substrate/bin/node/bench/Cargo.toml b/substrate/bin/node/bench/Cargo.toml index d5de1dbe6c44..49485fe2a1b9 100644 --- a/substrate/bin/node/bench/Cargo.toml +++ b/substrate/bin/node/bench/Cargo.toml @@ -44,4 +44,4 @@ lazy_static = "1.4.0" parity-db = "0.4.12" sc-transaction-pool = { path = "../../../client/transaction-pool" } sc-transaction-pool-api = { path = "../../../client/transaction-pool/api" } -futures = { version = "0.3.21", features = ["thread-pool"] } +futures = { version = "0.3.30", features = ["thread-pool"] } diff --git a/substrate/bin/node/cli/Cargo.toml b/substrate/bin/node/cli/Cargo.toml index 8bddbbe04828..6346063b9d27 100644 --- a/substrate/bin/node/cli/Cargo.toml +++ b/substrate/bin/node/cli/Cargo.toml @@ -45,7 +45,7 @@ clap = { version = "4.5.3", features = ["derive"], optional = true } codec = { package = "parity-scale-codec", version = "3.6.1" } serde = { features = ["derive"], workspace = true, default-features = true } jsonrpsee = { version = "0.22", features = ["server"] } -futures = "0.3.21" +futures = "0.3.30" log = { workspace = true, default-features = true } rand = "0.8" @@ -129,7 +129,7 @@ sc-block-builder = { path = "../../../client/block-builder" } sp-tracing = { path = "../../../primitives/tracing" } sp-blockchain = { path = "../../../primitives/blockchain" } sp-crypto-hashing = { path = "../../../primitives/crypto/hashing" } -futures = "0.3.21" +futures = "0.3.30" tempfile = "3.1.0" assert_cmd = "2.0.2" nix = { version = "0.26.1", features = ["signal"] } @@ -160,7 +160,7 @@ sp-externalities = { path = "../../../primitives/externalities" } sp-keyring = { path = "../../../primitives/keyring" } sp-runtime = { path = "../../../primitives/runtime" } serde_json = { workspace = true, default-features = true } -scale-info = { version = "2.10.0", features = ["derive", "serde"] } +scale-info = { version = "2.11.1", features = ["derive", "serde"] } sp-trie = { path = "../../../primitives/trie" } sp-state-machine = { path = "../../../primitives/state-machine" } diff --git a/substrate/bin/node/runtime/Cargo.toml b/substrate/bin/node/runtime/Cargo.toml index 4d342ceb460a..8f68b1d3e2f0 100644 --- a/substrate/bin/node/runtime/Cargo.toml +++ b/substrate/bin/node/runtime/Cargo.toml @@ -23,7 +23,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "derive", "max-encoded-len", ] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive", "serde"] } static_assertions = "1.1.0" log = { workspace = true } serde_json = { features = ["alloc", "arbitrary_precision"], workspace = true } diff --git a/substrate/bin/node/testing/Cargo.toml b/substrate/bin/node/testing/Cargo.toml index 31f8689d46ca..fa3f90193ba5 100644 --- a/substrate/bin/node/testing/Cargo.toml +++ b/substrate/bin/node/testing/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } fs_extra = "1" -futures = "0.3.21" +futures = "0.3.30" log = { workspace = true, default-features = true } tempfile = "3.1.0" frame-system = { path = "../../../frame/system" } diff --git a/substrate/client/api/Cargo.toml b/substrate/client/api/Cargo.toml index cd7b613e277f..fb650c5b532f 100644 --- a/substrate/client/api/Cargo.toml +++ b/substrate/client/api/Cargo.toml @@ -21,7 +21,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "derive", ] } fnv = "1.0.6" -futures = "0.3.21" +futures = "0.3.30" log = { workspace = true, default-features = true } parking_lot = "0.12.1" prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus" } diff --git a/substrate/client/authority-discovery/Cargo.toml b/substrate/client/authority-discovery/Cargo.toml index 26580064b3c4..dbd9ba0131a6 100644 --- a/substrate/client/authority-discovery/Cargo.toml +++ b/substrate/client/authority-discovery/Cargo.toml @@ -21,7 +21,7 @@ prost-build = "0.11" [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.1" ip_network = "0.4.1" libp2p = { version = "0.51.4", features = ["ed25519", "kad"] } @@ -43,7 +43,7 @@ sp-blockchain = { path = "../../primitives/blockchain" } sp-core = { path = "../../primitives/core" } sp-keystore = { path = "../../primitives/keystore" } sp-runtime = { path = "../../primitives/runtime" } -async-trait = "0.1.74" +async-trait = "0.1.79" multihash-codetable = { version = "0.1.1", features = [ "digest", "serde", diff --git a/substrate/client/basic-authorship/Cargo.toml b/substrate/client/basic-authorship/Cargo.toml index 51a06464d0d6..4890b66c9b2f 100644 --- a/substrate/client/basic-authorship/Cargo.toml +++ b/substrate/client/basic-authorship/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.1" log = { workspace = true, default-features = true } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus" } diff --git a/substrate/client/cli/Cargo.toml b/substrate/client/cli/Cargo.toml index 47b29555e660..805d3ee117f4 100644 --- a/substrate/client/cli/Cargo.toml +++ b/substrate/client/cli/Cargo.toml @@ -20,7 +20,7 @@ array-bytes = "6.1" chrono = "0.4.31" clap = { version = "4.5.3", features = ["derive", "string", "wrap_help"] } fdlimit = "0.3.0" -futures = "0.3.21" +futures = "0.3.30" itertools = "0.10.3" libp2p-identity = { version = "0.1.3", features = ["ed25519", "peerid"] } log = { workspace = true, default-features = true } diff --git a/substrate/client/consensus/aura/Cargo.toml b/substrate/client/consensus/aura/Cargo.toml index 213f75974da0..64e2d16cd913 100644 --- a/substrate/client/consensus/aura/Cargo.toml +++ b/substrate/client/consensus/aura/Cargo.toml @@ -16,9 +16,9 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -async-trait = "0.1.74" +async-trait = "0.1.79" codec = { package = "parity-scale-codec", version = "3.6.1" } -futures = "0.3.21" +futures = "0.3.30" log = { workspace = true, default-features = true } thiserror = { workspace = true } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus" } diff --git a/substrate/client/consensus/babe/Cargo.toml b/substrate/client/consensus/babe/Cargo.toml index c98fb7112b7c..b001e3d117aa 100644 --- a/substrate/client/consensus/babe/Cargo.toml +++ b/substrate/client/consensus/babe/Cargo.toml @@ -17,9 +17,9 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -async-trait = "0.1.74" +async-trait = "0.1.79" codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } -futures = "0.3.21" +futures = "0.3.30" log = { workspace = true, default-features = true } num-bigint = "0.4.3" num-rational = "0.4.1" @@ -54,4 +54,4 @@ sc-network-test = { path = "../../network/test" } sp-timestamp = { path = "../../../primitives/timestamp" } sp-tracing = { path = "../../../primitives/tracing" } substrate-test-runtime-client = { path = "../../../test-utils/runtime/client" } -tokio = "1.22.0" +tokio = "1.37" diff --git a/substrate/client/consensus/babe/rpc/Cargo.toml b/substrate/client/consensus/babe/rpc/Cargo.toml index 043b566673e7..b2661bbde27e 100644 --- a/substrate/client/consensus/babe/rpc/Cargo.toml +++ b/substrate/client/consensus/babe/rpc/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] jsonrpsee = { version = "0.22", features = ["client-core", "macros", "server"] } -futures = "0.3.21" +futures = "0.3.30" serde = { features = ["derive"], workspace = true, default-features = true } thiserror = { workspace = true } sc-consensus-babe = { path = ".." } @@ -34,7 +34,7 @@ sp-runtime = { path = "../../../../primitives/runtime" } [dev-dependencies] serde_json = { workspace = true, default-features = true } -tokio = "1.22.0" +tokio = "1.37" sc-consensus = { path = "../../common" } sc-keystore = { path = "../../../keystore" } sc-transaction-pool-api = { path = "../../../transaction-pool/api" } diff --git a/substrate/client/consensus/beefy/Cargo.toml b/substrate/client/consensus/beefy/Cargo.toml index 8552a4900223..c1d57baa394a 100644 --- a/substrate/client/consensus/beefy/Cargo.toml +++ b/substrate/client/consensus/beefy/Cargo.toml @@ -14,10 +14,10 @@ workspace = true [dependencies] array-bytes = "6.1" async-channel = "1.8.0" -async-trait = "0.1.74" +async-trait = "0.1.79" codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } fnv = "1.0.6" -futures = "0.3" +futures = "0.3.30" log = { workspace = true, default-features = true } parking_lot = "0.12.1" thiserror = { workspace = true } @@ -40,7 +40,7 @@ sp-crypto-hashing = { path = "../../../primitives/crypto/hashing" } sp-keystore = { path = "../../../primitives/keystore" } sp-mmr-primitives = { path = "../../../primitives/merkle-mountain-range" } sp-runtime = { path = "../../../primitives/runtime" } -tokio = "1.22.0" +tokio = "1.37" [dev-dependencies] diff --git a/substrate/client/consensus/beefy/rpc/Cargo.toml b/substrate/client/consensus/beefy/rpc/Cargo.toml index bb2ae4a08966..e46fc4f4410a 100644 --- a/substrate/client/consensus/beefy/rpc/Cargo.toml +++ b/substrate/client/consensus/beefy/rpc/Cargo.toml @@ -13,7 +13,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } -futures = "0.3.21" +futures = "0.3.30" jsonrpsee = { version = "0.22", features = ["client-core", "macros", "server"] } log = { workspace = true, default-features = true } parking_lot = "0.12.1" diff --git a/substrate/client/consensus/common/Cargo.toml b/substrate/client/consensus/common/Cargo.toml index f691e84717d1..b2738a1d12d9 100644 --- a/substrate/client/consensus/common/Cargo.toml +++ b/substrate/client/consensus/common/Cargo.toml @@ -16,8 +16,8 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -async-trait = "0.1.74" -futures = { version = "0.3.21", features = ["thread-pool"] } +async-trait = "0.1.79" +futures = { version = "0.3.30", features = ["thread-pool"] } futures-timer = "3.0.1" libp2p-identity = { version = "0.1.3", features = ["ed25519", "peerid"] } log = { workspace = true, default-features = true } diff --git a/substrate/client/consensus/grandpa/Cargo.toml b/substrate/client/consensus/grandpa/Cargo.toml index 1ab953525220..797b4ea35b29 100644 --- a/substrate/client/consensus/grandpa/Cargo.toml +++ b/substrate/client/consensus/grandpa/Cargo.toml @@ -19,10 +19,10 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] ahash = "0.8.2" array-bytes = "6.1" -async-trait = "0.1.74" +async-trait = "0.1.79" dyn-clone = "1.0" finality-grandpa = { version = "0.16.2", features = ["derive-codec"] } -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.1" log = { workspace = true, default-features = true } parity-scale-codec = { version = "3.6.1", features = ["derive"] } @@ -58,7 +58,7 @@ sp-runtime = { path = "../../../primitives/runtime" } assert_matches = "1.3.0" finality-grandpa = { version = "0.16.2", features = ["derive-codec", "test-helpers"] } serde = { workspace = true, default-features = true } -tokio = "1.22.0" +tokio = "1.37" sc-network = { path = "../../network" } sc-network-test = { path = "../../network/test" } sp-keyring = { path = "../../../primitives/keyring" } diff --git a/substrate/client/consensus/grandpa/rpc/Cargo.toml b/substrate/client/consensus/grandpa/rpc/Cargo.toml index f7e87415448e..0789a429ac41 100644 --- a/substrate/client/consensus/grandpa/rpc/Cargo.toml +++ b/substrate/client/consensus/grandpa/rpc/Cargo.toml @@ -14,7 +14,7 @@ workspace = true [dependencies] finality-grandpa = { version = "0.16.2", features = ["derive-codec"] } -futures = "0.3.16" +futures = "0.3.30" jsonrpsee = { version = "0.22", features = ["client-core", "macros", "server"] } log = { workspace = true, default-features = true } parity-scale-codec = { version = "3.6.1", features = ["derive"] } diff --git a/substrate/client/consensus/manual-seal/Cargo.toml b/substrate/client/consensus/manual-seal/Cargo.toml index ac32fed72289..1422d46105b2 100644 --- a/substrate/client/consensus/manual-seal/Cargo.toml +++ b/substrate/client/consensus/manual-seal/Cargo.toml @@ -18,9 +18,9 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] jsonrpsee = { version = "0.22", features = ["client-core", "macros", "server"] } assert_matches = "1.3.0" -async-trait = "0.1.74" +async-trait = "0.1.79" codec = { package = "parity-scale-codec", version = "3.6.1" } -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.1" log = { workspace = true, default-features = true } serde = { features = ["derive"], workspace = true, default-features = true } diff --git a/substrate/client/consensus/pow/Cargo.toml b/substrate/client/consensus/pow/Cargo.toml index 0791514035b4..ecfa29aa194d 100644 --- a/substrate/client/consensus/pow/Cargo.toml +++ b/substrate/client/consensus/pow/Cargo.toml @@ -16,9 +16,9 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -async-trait = "0.1.74" +async-trait = "0.1.79" codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.1" log = { workspace = true, default-features = true } parking_lot = "0.12.1" diff --git a/substrate/client/consensus/slots/Cargo.toml b/substrate/client/consensus/slots/Cargo.toml index 75f8b29a2fd7..4ac6ce907137 100644 --- a/substrate/client/consensus/slots/Cargo.toml +++ b/substrate/client/consensus/slots/Cargo.toml @@ -17,9 +17,9 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -async-trait = "0.1.74" +async-trait = "0.1.79" codec = { package = "parity-scale-codec", version = "3.6.1" } -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.1" log = { workspace = true, default-features = true } sc-client-api = { path = "../../api" } diff --git a/substrate/client/executor/Cargo.toml b/substrate/client/executor/Cargo.toml index 7fad7e3a2a0e..cb0befe98710 100644 --- a/substrate/client/executor/Cargo.toml +++ b/substrate/client/executor/Cargo.toml @@ -51,7 +51,7 @@ tracing-subscriber = "0.2.19" paste = "1.0" regex = "1.6.0" criterion = "0.4.0" -env_logger = "0.9" +env_logger = "0.11" num_cpus = "1.13.1" tempfile = "3.3.0" diff --git a/substrate/client/informant/Cargo.toml b/substrate/client/informant/Cargo.toml index bd15e94ebafa..191ef5f19f8d 100644 --- a/substrate/client/informant/Cargo.toml +++ b/substrate/client/informant/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] ansi_term = "0.12.1" -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.1" log = { workspace = true, default-features = true } sc-client-api = { path = "../api" } diff --git a/substrate/client/merkle-mountain-range/Cargo.toml b/substrate/client/merkle-mountain-range/Cargo.toml index 60232bccb0e0..46b7a1011c46 100644 --- a/substrate/client/merkle-mountain-range/Cargo.toml +++ b/substrate/client/merkle-mountain-range/Cargo.toml @@ -15,7 +15,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } -futures = "0.3" +futures = "0.3.30" log = { workspace = true, default-features = true } sp-api = { path = "../../primitives/api" } sp-blockchain = { path = "../../primitives/blockchain" } @@ -32,4 +32,4 @@ parking_lot = "0.12.1" sc-block-builder = { path = "../block-builder" } sp-tracing = { path = "../../primitives/tracing" } substrate-test-runtime-client = { path = "../../test-utils/runtime/client" } -tokio = "1.17.0" +tokio = "1.37" diff --git a/substrate/client/mixnet/Cargo.toml b/substrate/client/mixnet/Cargo.toml index 736184f4668c..3beeae9f9b14 100644 --- a/substrate/client/mixnet/Cargo.toml +++ b/substrate/client/mixnet/Cargo.toml @@ -21,7 +21,7 @@ arrayvec = "0.7.2" blake2 = "0.10.4" bytes = "1" codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -futures = "0.3.25" +futures = "0.3.30" futures-timer = "3.0.2" libp2p-identity = { version = "0.1.3", features = ["peerid"] } log = { workspace = true, default-features = true } diff --git a/substrate/client/network-gossip/Cargo.toml b/substrate/client/network-gossip/Cargo.toml index a14761c0d6e8..346e6bd6a5c6 100644 --- a/substrate/client/network-gossip/Cargo.toml +++ b/substrate/client/network-gossip/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] ahash = "0.8.2" -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.1" libp2p = "0.51.4" log = { workspace = true, default-features = true } @@ -31,8 +31,8 @@ sc-network-sync = { path = "../network/sync" } sp-runtime = { path = "../../primitives/runtime" } [dev-dependencies] -tokio = "1.22.0" -async-trait = "0.1.74" +tokio = "1.37" +async-trait = "0.1.79" codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } quickcheck = { version = "1.0.3", default-features = false } substrate-test-runtime-client = { path = "../../test-utils/runtime/client" } diff --git a/substrate/client/network/Cargo.toml b/substrate/client/network/Cargo.toml index c6f17647166c..a891336d2417 100644 --- a/substrate/client/network/Cargo.toml +++ b/substrate/client/network/Cargo.toml @@ -19,13 +19,13 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] array-bytes = "6.1" async-channel = "1.8.0" -async-trait = "0.1" +async-trait = "0.1.79" asynchronous-codec = "0.6" bytes = "1" codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } either = "1.5.3" fnv = "1.0.6" -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.2" ip_network = "0.4.1" libp2p = { version = "0.51.4", features = ["dns", "identify", "kad", "macros", "mdns", "noise", "ping", "request-response", "tcp", "tokio", "websocket", "yamux"] } diff --git a/substrate/client/network/bitswap/Cargo.toml b/substrate/client/network/bitswap/Cargo.toml index 7ef3ea212427..587e2e70867b 100644 --- a/substrate/client/network/bitswap/Cargo.toml +++ b/substrate/client/network/bitswap/Cargo.toml @@ -21,7 +21,7 @@ prost-build = "0.11" [dependencies] async-channel = "1.8.0" cid = "0.9.0" -futures = "0.3.21" +futures = "0.3.30" libp2p-identity = { version = "0.1.3", features = ["peerid"] } log = { workspace = true, default-features = true } prost = "0.12" diff --git a/substrate/client/network/common/Cargo.toml b/substrate/client/network/common/Cargo.toml index 7a6d904b74b1..f9248b0bb51c 100644 --- a/substrate/client/network/common/Cargo.toml +++ b/substrate/client/network/common/Cargo.toml @@ -19,12 +19,12 @@ targets = ["x86_64-unknown-linux-gnu"] prost-build = "0.11" [dependencies] -async-trait = "0.1.74" +async-trait = "0.1.79" bitflags = "1.3.2" codec = { package = "parity-scale-codec", version = "3.6.1", features = [ "derive", ] } -futures = "0.3.21" +futures = "0.3.30" libp2p-identity = { version = "0.1.3", features = ["peerid"] } sc-consensus = { path = "../../consensus/common" } sp-consensus = { path = "../../../primitives/consensus/common" } diff --git a/substrate/client/network/light/Cargo.toml b/substrate/client/network/light/Cargo.toml index c757f727fb71..2628fd07d3e4 100644 --- a/substrate/client/network/light/Cargo.toml +++ b/substrate/client/network/light/Cargo.toml @@ -24,7 +24,7 @@ array-bytes = "6.1" codec = { package = "parity-scale-codec", version = "3.6.1", features = [ "derive", ] } -futures = "0.3.21" +futures = "0.3.30" libp2p-identity = { version = "0.1.3", features = ["peerid"] } log = { workspace = true, default-features = true } prost = "0.12" diff --git a/substrate/client/network/statement/Cargo.toml b/substrate/client/network/statement/Cargo.toml index b6efee5d9d36..635cfc5d0d5e 100644 --- a/substrate/client/network/statement/Cargo.toml +++ b/substrate/client/network/statement/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] array-bytes = "6.1" async-channel = "1.8.0" codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } -futures = "0.3.21" +futures = "0.3.30" libp2p = "0.51.4" log = { workspace = true, default-features = true } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus" } diff --git a/substrate/client/network/sync/Cargo.toml b/substrate/client/network/sync/Cargo.toml index 32ba3b6356c0..6b46d67a3cae 100644 --- a/substrate/client/network/sync/Cargo.toml +++ b/substrate/client/network/sync/Cargo.toml @@ -21,9 +21,9 @@ prost-build = "0.11" [dependencies] array-bytes = "6.1" async-channel = "1.8.0" -async-trait = "0.1.74" +async-trait = "0.1.79" codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.2" libp2p = "0.51.4" log = { workspace = true, default-features = true } diff --git a/substrate/client/network/test/Cargo.toml b/substrate/client/network/test/Cargo.toml index 4f57287a39cc..56fc89e1b2b9 100644 --- a/substrate/client/network/test/Cargo.toml +++ b/substrate/client/network/test/Cargo.toml @@ -16,9 +16,9 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -tokio = "1.22.0" -async-trait = "0.1.74" -futures = "0.3.21" +tokio = "1.37" +async-trait = "0.1.79" +futures = "0.3.30" futures-timer = "3.0.1" libp2p = "0.51.4" log = { workspace = true, default-features = true } diff --git a/substrate/client/network/transactions/Cargo.toml b/substrate/client/network/transactions/Cargo.toml index 01c8ac8814d6..0ab7386ef21f 100644 --- a/substrate/client/network/transactions/Cargo.toml +++ b/substrate/client/network/transactions/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] array-bytes = "6.1" codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } -futures = "0.3.21" +futures = "0.3.30" libp2p = "0.51.4" log = { workspace = true, default-features = true } prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../../utils/prometheus" } diff --git a/substrate/client/offchain/Cargo.toml b/substrate/client/offchain/Cargo.toml index caa4bb03f40c..a3a3cfaa8fca 100644 --- a/substrate/client/offchain/Cargo.toml +++ b/substrate/client/offchain/Cargo.toml @@ -20,7 +20,7 @@ array-bytes = "6.1" bytes = "1.1" codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } fnv = "1.0.6" -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.2" hyper = { version = "0.14.16", features = ["http2", "stream"] } hyper-rustls = { version = "0.24.0", features = ["http2"] } @@ -46,7 +46,7 @@ log = { workspace = true, default-features = true } [dev-dependencies] lazy_static = "1.4.0" -tokio = "1.22.0" +tokio = "1.37" sc-block-builder = { path = "../block-builder" } sc-client-db = { path = "../db", default-features = true } sc-transaction-pool = { path = "../transaction-pool" } diff --git a/substrate/client/rpc-api/Cargo.toml b/substrate/client/rpc-api/Cargo.toml index 1b7af6a4a52f..169714d22453 100644 --- a/substrate/client/rpc-api/Cargo.toml +++ b/substrate/client/rpc-api/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["derive"], workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } thiserror = { workspace = true } diff --git a/substrate/client/rpc-servers/Cargo.toml b/substrate/client/rpc-servers/Cargo.toml index 3adc81c57d59..bc21b5b1582f 100644 --- a/substrate/client/rpc-servers/Cargo.toml +++ b/substrate/client/rpc-servers/Cargo.toml @@ -25,5 +25,5 @@ tower-http = { version = "0.4.0", features = ["cors"] } tower = { version = "0.4.13", features = ["util"] } http = "0.2.8" hyper = "0.14.27" -futures = "0.3.29" +futures = "0.3.30" governor = "0.6.0" diff --git a/substrate/client/rpc-spec-v2/Cargo.toml b/substrate/client/rpc-spec-v2/Cargo.toml index 937e5c6b626a..e2612d914542 100644 --- a/substrate/client/rpc-spec-v2/Cargo.toml +++ b/substrate/client/rpc-spec-v2/Cargo.toml @@ -34,7 +34,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1" } thiserror = { workspace = true } serde = { workspace = true, default-features = true } hex = "0.4" -futures = "0.3.21" +futures = "0.3.30" parking_lot = "0.12.1" tokio-stream = { version = "0.1.14", features = ["sync"] } tokio = { version = "1.22.0", features = ["sync"] } diff --git a/substrate/client/rpc/Cargo.toml b/substrate/client/rpc/Cargo.toml index f65e6c9a59ec..dff34215b025 100644 --- a/substrate/client/rpc/Cargo.toml +++ b/substrate/client/rpc/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } -futures = "0.3.21" +futures = "0.3.30" jsonrpsee = { version = "0.22", features = ["server"] } log = { workspace = true, default-features = true } parking_lot = "0.12.1" @@ -40,10 +40,10 @@ sp-runtime = { path = "../../primitives/runtime" } sp-session = { path = "../../primitives/session" } sp-version = { path = "../../primitives/version" } sp-statement-store = { path = "../../primitives/statement-store" } -tokio = "1.22.0" +tokio = "1.37" [dev-dependencies] -env_logger = "0.9" +env_logger = "0.11" assert_matches = "1.3.0" sc-block-builder = { path = "../block-builder" } sc-network = { path = "../network" } @@ -51,7 +51,7 @@ sc-network-common = { path = "../network/common" } sc-transaction-pool = { path = "../transaction-pool" } sp-consensus = { path = "../../primitives/consensus/common" } sp-crypto-hashing = { path = "../../primitives/crypto/hashing" } -tokio = "1.22.0" +tokio = "1.37" sp-io = { path = "../../primitives/io" } substrate-test-runtime-client = { path = "../../test-utils/runtime/client" } pretty_assertions = "1.2.1" diff --git a/substrate/client/service/Cargo.toml b/substrate/client/service/Cargo.toml index bbf67d1fbd0a..b81f2e2f55ab 100644 --- a/substrate/client/service/Cargo.toml +++ b/substrate/client/service/Cargo.toml @@ -30,7 +30,7 @@ runtime-benchmarks = [ [dependencies] jsonrpsee = { version = "0.22", features = ["server"] } thiserror = { workspace = true } -futures = "0.3.21" +futures = "0.3.30" rand = "0.8.5" parking_lot = "0.12.1" log = { workspace = true, default-features = true } @@ -79,7 +79,7 @@ sc-tracing = { path = "../tracing" } sc-sysinfo = { path = "../sysinfo" } tracing = "0.1.29" tracing-futures = { version = "0.2.4" } -async-trait = "0.1.74" +async-trait = "0.1.79" tokio = { version = "1.22.0", features = ["parking_lot", "rt-multi-thread", "time"] } tempfile = "3.1.0" directories = "5.0.1" diff --git a/substrate/client/service/test/Cargo.toml b/substrate/client/service/test/Cargo.toml index ee7e60f60117..2de984689bad 100644 --- a/substrate/client/service/test/Cargo.toml +++ b/substrate/client/service/test/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] async-channel = "1.8.0" array-bytes = "6.1" fdlimit = "0.3.0" -futures = "0.3.21" +futures = "0.3.30" log = { workspace = true, default-features = true } parity-scale-codec = "3.6.1" parking_lot = "0.12.1" diff --git a/substrate/client/statement-store/Cargo.toml b/substrate/client/statement-store/Cargo.toml index 676f6cb36f67..8ca6d11dbe0d 100644 --- a/substrate/client/statement-store/Cargo.toml +++ b/substrate/client/statement-store/Cargo.toml @@ -31,4 +31,4 @@ sc-keystore = { path = "../keystore" } [dev-dependencies] tempfile = "3.1.0" -env_logger = "0.9" +env_logger = "0.11" diff --git a/substrate/client/sysinfo/Cargo.toml b/substrate/client/sysinfo/Cargo.toml index ba58452ffb58..32b7755c64b5 100644 --- a/substrate/client/sysinfo/Cargo.toml +++ b/substrate/client/sysinfo/Cargo.toml @@ -17,7 +17,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -futures = "0.3.19" +futures = "0.3.30" libc = "0.2" log = { workspace = true, default-features = true } rand = "0.8.5" diff --git a/substrate/client/telemetry/Cargo.toml b/substrate/client/telemetry/Cargo.toml index 8ab00202f0ba..9a29a33a591f 100644 --- a/substrate/client/telemetry/Cargo.toml +++ b/substrate/client/telemetry/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] chrono = "0.4.31" -futures = "0.3.21" +futures = "0.3.30" libp2p = { version = "0.51.4", features = ["dns", "tcp", "tokio", "wasm-ext", "websocket"] } log = { workspace = true, default-features = true } parking_lot = "0.12.1" diff --git a/substrate/client/transaction-pool/Cargo.toml b/substrate/client/transaction-pool/Cargo.toml index 2ca37afd61b8..e2a0b87eaabb 100644 --- a/substrate/client/transaction-pool/Cargo.toml +++ b/substrate/client/transaction-pool/Cargo.toml @@ -16,9 +16,9 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -async-trait = "0.1.74" +async-trait = "0.1.79" codec = { package = "parity-scale-codec", version = "3.6.1" } -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.2" linked-hash-map = "0.5.4" log = { workspace = true, default-features = true } diff --git a/substrate/client/transaction-pool/api/Cargo.toml b/substrate/client/transaction-pool/api/Cargo.toml index d52e4783fabc..1bb72ef55442 100644 --- a/substrate/client/transaction-pool/api/Cargo.toml +++ b/substrate/client/transaction-pool/api/Cargo.toml @@ -12,9 +12,9 @@ description = "Transaction pool client facing API." workspace = true [dependencies] -async-trait = "0.1.74" +async-trait = "0.1.79" codec = { package = "parity-scale-codec", version = "3.6.1" } -futures = "0.3.21" +futures = "0.3.30" log = { workspace = true, default-features = true } serde = { features = ["derive"], workspace = true, default-features = true } thiserror = { workspace = true } diff --git a/substrate/client/utils/Cargo.toml b/substrate/client/utils/Cargo.toml index 7f604219bc09..a101f4b3f3ad 100644 --- a/substrate/client/utils/Cargo.toml +++ b/substrate/client/utils/Cargo.toml @@ -14,7 +14,7 @@ workspace = true [dependencies] async-channel = "1.8.0" -futures = "0.3.21" +futures = "0.3.30" futures-timer = "3.0.2" lazy_static = "1.4.0" log = { workspace = true, default-features = true } diff --git a/substrate/frame/Cargo.toml b/substrate/frame/Cargo.toml index ab394592071d..27001ee5afd9 100644 --- a/substrate/frame/Cargo.toml +++ b/substrate/frame/Cargo.toml @@ -22,7 +22,7 @@ targets = ["x86_64-unknown-linux-gnu"] parity-scale-codec = { version = "3.2.2", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.6.0", default-features = false, features = [ +scale-info = { version = "2.11.1", default-features = false, features = [ "derive", ] } diff --git a/substrate/frame/alliance/Cargo.toml b/substrate/frame/alliance/Cargo.toml index bc873ad69c80..af1fcb296f67 100644 --- a/substrate/frame/alliance/Cargo.toml +++ b/substrate/frame/alliance/Cargo.toml @@ -20,7 +20,7 @@ array-bytes = { version = "6.1", optional = true } log = { workspace = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } sp-std = { path = "../../primitives/std", default-features = false } sp-core = { path = "../../primitives/core", default-features = false } diff --git a/substrate/frame/asset-conversion/Cargo.toml b/substrate/frame/asset-conversion/Cargo.toml index 1f2db14dac2d..1a8e8eea4849 100644 --- a/substrate/frame/asset-conversion/Cargo.toml +++ b/substrate/frame/asset-conversion/Cargo.toml @@ -20,7 +20,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } sp-api = { path = "../../primitives/api", default-features = false } sp-core = { path = "../../primitives/core", default-features = false } sp-io = { path = "../../primitives/io", default-features = false } diff --git a/substrate/frame/asset-rate/Cargo.toml b/substrate/frame/asset-rate/Cargo.toml index 6e7bbf29fc43..cd502148a8d8 100644 --- a/substrate/frame/asset-rate/Cargo.toml +++ b/substrate/frame/asset-rate/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/assets/Cargo.toml b/substrate/frame/assets/Cargo.toml index 2efc96348cb5..3b95750c14c8 100644 --- a/substrate/frame/assets/Cargo.toml +++ b/substrate/frame/assets/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } sp-std = { path = "../../primitives/std", default-features = false } # Needed for various traits. In our case, `OnFinalize`. sp-runtime = { path = "../../primitives/runtime", default-features = false } diff --git a/substrate/frame/atomic-swap/Cargo.toml b/substrate/frame/atomic-swap/Cargo.toml index 0283af1d1b06..c641071df902 100644 --- a/substrate/frame/atomic-swap/Cargo.toml +++ b/substrate/frame/atomic-swap/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } sp-core = { path = "../../primitives/core", default-features = false } diff --git a/substrate/frame/aura/Cargo.toml b/substrate/frame/aura/Cargo.toml index de698487efa7..97349107f1f4 100644 --- a/substrate/frame/aura/Cargo.toml +++ b/substrate/frame/aura/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } pallet-timestamp = { path = "../timestamp", default-features = false } diff --git a/substrate/frame/authority-discovery/Cargo.toml b/substrate/frame/authority-discovery/Cargo.toml index 0922007e57e8..a7aba711a568 100644 --- a/substrate/frame/authority-discovery/Cargo.toml +++ b/substrate/frame/authority-discovery/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } pallet-session = { path = "../session", default-features = false, features = [ diff --git a/substrate/frame/authorship/Cargo.toml b/substrate/frame/authorship/Cargo.toml index 4b318f12519e..2bfd59a48e10 100644 --- a/substrate/frame/authorship/Cargo.toml +++ b/substrate/frame/authorship/Cargo.toml @@ -20,7 +20,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "derive", ] } impl-trait-for-tuples = "0.2.2" -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } sp-runtime = { path = "../../primitives/runtime", default-features = false } diff --git a/substrate/frame/babe/Cargo.toml b/substrate/frame/babe/Cargo.toml index fc7385efa1f1..9f6ef2bc05ea 100644 --- a/substrate/frame/babe/Cargo.toml +++ b/substrate/frame/babe/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive", "serde"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/bags-list/Cargo.toml b/substrate/frame/bags-list/Cargo.toml index 49d28482c329..5deb504d0a4f 100644 --- a/substrate/frame/bags-list/Cargo.toml +++ b/substrate/frame/bags-list/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.10.0", default-features = false, features = [ +scale-info = { version = "2.11.1", default-features = false, features = [ "derive", ] } diff --git a/substrate/frame/balances/Cargo.toml b/substrate/frame/balances/Cargo.toml index b27a5bb24787..28eabdaf5062 100644 --- a/substrate/frame/balances/Cargo.toml +++ b/substrate/frame/balances/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/beefy-mmr/Cargo.toml b/substrate/frame/beefy-mmr/Cargo.toml index 177077317731..8fcb8e1d559b 100644 --- a/substrate/frame/beefy-mmr/Cargo.toml +++ b/substrate/frame/beefy-mmr/Cargo.toml @@ -15,7 +15,7 @@ workspace = true array-bytes = { version = "6.1", optional = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { optional = true, workspace = true, default-features = true } binary-merkle-tree = { path = "../../utils/binary-merkle-tree", default-features = false } frame-support = { path = "../support", default-features = false } diff --git a/substrate/frame/beefy/Cargo.toml b/substrate/frame/beefy/Cargo.toml index e38eaa6fb078..f181f4d41cdc 100644 --- a/substrate/frame/beefy/Cargo.toml +++ b/substrate/frame/beefy/Cargo.toml @@ -14,7 +14,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive", "serde"] } serde = { optional = true, workspace = true, default-features = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/benchmarking/Cargo.toml b/substrate/frame/benchmarking/Cargo.toml index bf42aae979cd..8210e8cfa626 100644 --- a/substrate/frame/benchmarking/Cargo.toml +++ b/substrate/frame/benchmarking/Cargo.toml @@ -20,7 +20,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = linregress = { version = "0.5.1", optional = true } log = { workspace = true } paste = "1.0" -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { optional = true, workspace = true, default-features = true } frame-support = { path = "../support", default-features = false } frame-support-procedural = { path = "../support/procedural", default-features = false } diff --git a/substrate/frame/benchmarking/pov/Cargo.toml b/substrate/frame/benchmarking/pov/Cargo.toml index ce5daeb5b7b4..5d3aaa789048 100644 --- a/substrate/frame/benchmarking/pov/Cargo.toml +++ b/substrate/frame/benchmarking/pov/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "..", default-features = false } frame-support = { path = "../../support", default-features = false } frame-system = { path = "../../system", default-features = false } diff --git a/substrate/frame/bounties/Cargo.toml b/substrate/frame/bounties/Cargo.toml index 191a38d20b2f..3307e47e9818 100644 --- a/substrate/frame/bounties/Cargo.toml +++ b/substrate/frame/bounties/Cargo.toml @@ -20,7 +20,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "derive", ] } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/broker/Cargo.toml b/substrate/frame/broker/Cargo.toml index 31f9a6b63178..3b6bd2019cc1 100644 --- a/substrate/frame/broker/Cargo.toml +++ b/substrate/frame/broker/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } bitvec = { version = "1.0.0", default-features = false } sp-std = { path = "../../primitives/std", default-features = false } sp-arithmetic = { path = "../../primitives/arithmetic", default-features = false } diff --git a/substrate/frame/child-bounties/Cargo.toml b/substrate/frame/child-bounties/Cargo.toml index 589ca95a7516..14a5e25e13da 100644 --- a/substrate/frame/child-bounties/Cargo.toml +++ b/substrate/frame/child-bounties/Cargo.toml @@ -20,7 +20,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "derive", ] } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/collective/Cargo.toml b/substrate/frame/collective/Cargo.toml index e19e1496e7b5..850390409abc 100644 --- a/substrate/frame/collective/Cargo.toml +++ b/substrate/frame/collective/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/contracts/Cargo.toml b/substrate/frame/contracts/Cargo.toml index 2aa37a2bf213..d963ac261d19 100644 --- a/substrate/frame/contracts/Cargo.toml +++ b/substrate/frame/contracts/Cargo.toml @@ -24,7 +24,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "derive", "max-encoded-len", ] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } log = { workspace = true } serde = { optional = true, features = ["derive"], workspace = true, default-features = true } smallvec = { version = "1", default-features = false, features = [ @@ -58,7 +58,7 @@ xcm-builder = { package = "staging-xcm-builder", path = "../../../polkadot/xcm/x [dev-dependencies] array-bytes = "6.1" assert_matches = "1" -env_logger = "0.9" +env_logger = "0.11" pretty_assertions = "1" wat = "1" pallet-contracts-fixtures = { path = "./fixtures" } diff --git a/substrate/frame/contracts/mock-network/Cargo.toml b/substrate/frame/contracts/mock-network/Cargo.toml index 0c4cd1356f4d..387c3ca39d04 100644 --- a/substrate/frame/contracts/mock-network/Cargo.toml +++ b/substrate/frame/contracts/mock-network/Cargo.toml @@ -30,7 +30,7 @@ pallet-xcm = { path = "../../../../polkadot/xcm/pallet-xcm", default-features = polkadot-parachain-primitives = { path = "../../../../polkadot/parachain" } polkadot-primitives = { path = "../../../../polkadot/primitives" } polkadot-runtime-parachains = { path = "../../../../polkadot/runtime/parachains" } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } sp-api = { path = "../../../primitives/api", default-features = false } sp-core = { path = "../../../primitives/core", default-features = false } sp-io = { path = "../../../primitives/io", default-features = false } diff --git a/substrate/frame/contracts/uapi/Cargo.toml b/substrate/frame/contracts/uapi/Cargo.toml index 12bb6b8fc2c0..d9a5ee14f054 100644 --- a/substrate/frame/contracts/uapi/Cargo.toml +++ b/substrate/frame/contracts/uapi/Cargo.toml @@ -14,7 +14,7 @@ workspace = true [dependencies] paste = { version = "1.0", default-features = false } bitflags = "1.0" -scale-info = { version = "2.10.0", default-features = false, features = ["derive"], optional = true } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"], optional = true } scale = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ "derive", "max-encoded-len", diff --git a/substrate/frame/conviction-voting/Cargo.toml b/substrate/frame/conviction-voting/Cargo.toml index ff5af995026f..ffb5122ed7f9 100644 --- a/substrate/frame/conviction-voting/Cargo.toml +++ b/substrate/frame/conviction-voting/Cargo.toml @@ -21,7 +21,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "derive", "max-encoded-len", ] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["derive"], optional = true, workspace = true, default-features = true } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } diff --git a/substrate/frame/core-fellowship/Cargo.toml b/substrate/frame/core-fellowship/Cargo.toml index 3e678d327446..b4258281b701 100644 --- a/substrate/frame/core-fellowship/Cargo.toml +++ b/substrate/frame/core-fellowship/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/democracy/Cargo.toml b/substrate/frame/democracy/Cargo.toml index 9a55cda5340c..edd2d742b506 100644 --- a/substrate/frame/democracy/Cargo.toml +++ b/substrate/frame/democracy/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["derive"], optional = true, workspace = true, default-features = true } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } diff --git a/substrate/frame/election-provider-multi-phase/Cargo.toml b/substrate/frame/election-provider-multi-phase/Cargo.toml index eadce8c1ff84..2074b51f50f4 100644 --- a/substrate/frame/election-provider-multi-phase/Cargo.toml +++ b/substrate/frame/election-provider-multi-phase/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.10.0", default-features = false, features = [ +scale-info = { version = "2.11.1", default-features = false, features = [ "derive", ] } log = { workspace = true } @@ -38,7 +38,7 @@ frame-election-provider-support = { path = "../election-provider-support", defau frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } pallet-election-provider-support-benchmarking = { path = "../election-provider-support/benchmarking", default-features = false, optional = true } rand = { version = "0.8.5", default-features = false, features = ["alloc", "small_rng"], optional = true } -strum = { version = "0.24.1", default-features = false, features = ["derive"], optional = true } +strum = { version = "0.26.2", default-features = false, features = ["derive"], optional = true } [dev-dependencies] parking_lot = "0.12.1" diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml b/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml index e6384450a6fd..25c280921f8c 100644 --- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml +++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dev-dependencies] parking_lot = "0.12.1" codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } -scale-info = { version = "2.10.0", features = ["derive"] } +scale-info = { version = "2.11.1", features = ["derive"] } log = { workspace = true } sp-runtime = { path = "../../../primitives/runtime" } diff --git a/substrate/frame/election-provider-support/Cargo.toml b/substrate/frame/election-provider-support/Cargo.toml index b182b831ea0d..0d9748ee34e5 100644 --- a/substrate/frame/election-provider-support/Cargo.toml +++ b/substrate/frame/election-provider-support/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-election-provider-solution-type = { path = "solution-type" } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/election-provider-support/solution-type/Cargo.toml b/substrate/frame/election-provider-support/solution-type/Cargo.toml index 1bf1165229a7..09c6a492dd0d 100644 --- a/substrate/frame/election-provider-support/solution-type/Cargo.toml +++ b/substrate/frame/election-provider-support/solution-type/Cargo.toml @@ -25,7 +25,7 @@ proc-macro-crate = "3.0.0" [dev-dependencies] parity-scale-codec = "3.6.1" -scale-info = "2.10.0" +scale-info = "2.11.1" sp-arithmetic = { path = "../../../primitives/arithmetic" } # used by generate_solution_type: frame-election-provider-support = { path = ".." } diff --git a/substrate/frame/election-provider-support/solution-type/fuzzer/Cargo.toml b/substrate/frame/election-provider-support/solution-type/fuzzer/Cargo.toml index a27f0f7d4dd4..1fb9e2387ed8 100644 --- a/substrate/frame/election-provider-support/solution-type/fuzzer/Cargo.toml +++ b/substrate/frame/election-provider-support/solution-type/fuzzer/Cargo.toml @@ -21,7 +21,7 @@ honggfuzz = "0.5" rand = { version = "0.8", features = ["small_rng", "std"] } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-election-provider-solution-type = { path = ".." } frame-election-provider-support = { path = "../.." } sp-arithmetic = { path = "../../../../primitives/arithmetic" } diff --git a/substrate/frame/elections-phragmen/Cargo.toml b/substrate/frame/elections-phragmen/Cargo.toml index 4dc4a3454aa0..81dc48476a06 100644 --- a/substrate/frame/elections-phragmen/Cargo.toml +++ b/substrate/frame/elections-phragmen/Cargo.toml @@ -20,7 +20,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "derive", ] } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/examples/basic/Cargo.toml b/substrate/frame/examples/basic/Cargo.toml index e4ab5112201d..43b37c6beba2 100644 --- a/substrate/frame/examples/basic/Cargo.toml +++ b/substrate/frame/examples/basic/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../../benchmarking", default-features = false, optional = true } frame-support = { path = "../../support", default-features = false } frame-system = { path = "../../system", default-features = false } diff --git a/substrate/frame/examples/default-config/Cargo.toml b/substrate/frame/examples/default-config/Cargo.toml index e40845a425a2..2aa062ee6c1a 100644 --- a/substrate/frame/examples/default-config/Cargo.toml +++ b/substrate/frame/examples/default-config/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../../support", default-features = false } frame-system = { path = "../../system", default-features = false } diff --git a/substrate/frame/examples/dev-mode/Cargo.toml b/substrate/frame/examples/dev-mode/Cargo.toml index a9c4e3f3b1fc..71b97796ecdd 100644 --- a/substrate/frame/examples/dev-mode/Cargo.toml +++ b/substrate/frame/examples/dev-mode/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../../support", default-features = false } frame-system = { path = "../../system", default-features = false } pallet-balances = { path = "../../balances", default-features = false } diff --git a/substrate/frame/examples/frame-crate/Cargo.toml b/substrate/frame/examples/frame-crate/Cargo.toml index 93a46ba7b249..76bfd65282a9 100644 --- a/substrate/frame/examples/frame-crate/Cargo.toml +++ b/substrate/frame/examples/frame-crate/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame = { path = "../..", default-features = false, features = ["experimental", "runtime"] } diff --git a/substrate/frame/examples/kitchensink/Cargo.toml b/substrate/frame/examples/kitchensink/Cargo.toml index 37384107530e..d8311897c6e1 100644 --- a/substrate/frame/examples/kitchensink/Cargo.toml +++ b/substrate/frame/examples/kitchensink/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../../support", default-features = false, features = ["experimental"] } frame-system = { path = "../../system", default-features = false } diff --git a/substrate/frame/examples/offchain-worker/Cargo.toml b/substrate/frame/examples/offchain-worker/Cargo.toml index fc5151ff292b..468af0345cae 100644 --- a/substrate/frame/examples/offchain-worker/Cargo.toml +++ b/substrate/frame/examples/offchain-worker/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } lite-json = { version = "0.2.0", default-features = false } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../../support", default-features = false } frame-system = { path = "../../system", default-features = false } sp-core = { path = "../../../primitives/core", default-features = false } diff --git a/substrate/frame/examples/single-block-migrations/Cargo.toml b/substrate/frame/examples/single-block-migrations/Cargo.toml index 1020cc9e2bb9..b1d560a85f3f 100644 --- a/substrate/frame/examples/single-block-migrations/Cargo.toml +++ b/substrate/frame/examples/single-block-migrations/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] docify = "0.2.8" log = { version = "0.4.21", default-features = false } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../../support", default-features = false } frame-executive = { path = "../../executive", default-features = false } frame-system = { path = "../../system", default-features = false } diff --git a/substrate/frame/examples/split/Cargo.toml b/substrate/frame/examples/split/Cargo.toml index 230dc980b1a6..1ef3521e0606 100644 --- a/substrate/frame/examples/split/Cargo.toml +++ b/substrate/frame/examples/split/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../../support", default-features = false } frame-system = { path = "../../system", default-features = false } diff --git a/substrate/frame/examples/tasks/Cargo.toml b/substrate/frame/examples/tasks/Cargo.toml index 4d14bf313d7b..3f59d57ea0f2 100644 --- a/substrate/frame/examples/tasks/Cargo.toml +++ b/substrate/frame/examples/tasks/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../../support", default-features = false } frame-system = { path = "../../system", default-features = false } diff --git a/substrate/frame/executive/Cargo.toml b/substrate/frame/executive/Cargo.toml index 63285e4cb493..95de7c3f3d1f 100644 --- a/substrate/frame/executive/Cargo.toml +++ b/substrate/frame/executive/Cargo.toml @@ -21,7 +21,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "derive", ] } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } frame-try-runtime = { path = "../try-runtime", default-features = false, optional = true } diff --git a/substrate/frame/fast-unstake/Cargo.toml b/substrate/frame/fast-unstake/Cargo.toml index fb425dc310d4..f05f22f76416 100644 --- a/substrate/frame/fast-unstake/Cargo.toml +++ b/substrate/frame/fast-unstake/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/glutton/Cargo.toml b/substrate/frame/glutton/Cargo.toml index 7de18080b879..5ce010f1c262 100644 --- a/substrate/frame/glutton/Cargo.toml +++ b/substrate/frame/glutton/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] blake2 = { version = "0.10.4", default-features = false } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } log = { workspace = true } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } diff --git a/substrate/frame/grandpa/Cargo.toml b/substrate/frame/grandpa/Cargo.toml index db540564fbe7..f4dd92129f38 100644 --- a/substrate/frame/grandpa/Cargo.toml +++ b/substrate/frame/grandpa/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive", "serde"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/identity/Cargo.toml b/substrate/frame/identity/Cargo.toml index 912444bf6036..8c0052004ae3 100644 --- a/substrate/frame/identity/Cargo.toml +++ b/substrate/frame/identity/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } enumflags2 = { version = "0.7.7" } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/im-online/Cargo.toml b/substrate/frame/im-online/Cargo.toml index 038cbbcd678c..46b416f0f9a8 100644 --- a/substrate/frame/im-online/Cargo.toml +++ b/substrate/frame/im-online/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive", "serde"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/indices/Cargo.toml b/substrate/frame/indices/Cargo.toml index f810ea36a707..7b14bf358f1e 100644 --- a/substrate/frame/indices/Cargo.toml +++ b/substrate/frame/indices/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/insecure-randomness-collective-flip/Cargo.toml b/substrate/frame/insecure-randomness-collective-flip/Cargo.toml index f26bfa95bfd0..f4d65d9e560a 100644 --- a/substrate/frame/insecure-randomness-collective-flip/Cargo.toml +++ b/substrate/frame/insecure-randomness-collective-flip/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } safe-mix = { version = "1.0", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } sp-runtime = { path = "../../primitives/runtime", default-features = false } diff --git a/substrate/frame/lottery/Cargo.toml b/substrate/frame/lottery/Cargo.toml index 3930ff32fc91..5f79704445f9 100644 --- a/substrate/frame/lottery/Cargo.toml +++ b/substrate/frame/lottery/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/membership/Cargo.toml b/substrate/frame/membership/Cargo.toml index 642146702927..6f67db0ae709 100644 --- a/substrate/frame/membership/Cargo.toml +++ b/substrate/frame/membership/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive", "serde"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/merkle-mountain-range/Cargo.toml b/substrate/frame/merkle-mountain-range/Cargo.toml index d623e25cec26..6dc919e16505 100644 --- a/substrate/frame/merkle-mountain-range/Cargo.toml +++ b/substrate/frame/merkle-mountain-range/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } @@ -29,7 +29,7 @@ sp-std = { path = "../../primitives/std", default-features = false } [dev-dependencies] array-bytes = "6.1" -env_logger = "0.9" +env_logger = "0.11" itertools = "0.10.3" [features] diff --git a/substrate/frame/message-queue/Cargo.toml b/substrate/frame/message-queue/Cargo.toml index 8d9da7df39ea..f263c41831be 100644 --- a/substrate/frame/message-queue/Cargo.toml +++ b/substrate/frame/message-queue/Cargo.toml @@ -13,7 +13,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { optional = true, features = ["derive"], workspace = true, default-features = true } log = { workspace = true } environmental = { version = "1.1.4", default-features = false } diff --git a/substrate/frame/migrations/Cargo.toml b/substrate/frame/migrations/Cargo.toml index 0a91d2f94c4c..4726ac5c521e 100644 --- a/substrate/frame/migrations/Cargo.toml +++ b/substrate/frame/migrations/Cargo.toml @@ -15,7 +15,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = docify = "0.2.8" impl-trait-for-tuples = "0.2.2" log = "0.4.21" -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { default-features = false, optional = true, path = "../benchmarking" } frame-support = { default-features = false, path = "../support" } diff --git a/substrate/frame/mixnet/Cargo.toml b/substrate/frame/mixnet/Cargo.toml index d1bb01dde1a4..6a4ef5c29ac8 100644 --- a/substrate/frame/mixnet/Cargo.toml +++ b/substrate/frame/mixnet/Cargo.toml @@ -21,7 +21,7 @@ frame-benchmarking = { default-features = false, optional = true, path = "../ben frame-support = { default-features = false, path = "../support" } frame-system = { default-features = false, path = "../system" } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["derive"], workspace = true } sp-application-crypto = { default-features = false, path = "../../primitives/application-crypto" } sp-arithmetic = { default-features = false, path = "../../primitives/arithmetic" } diff --git a/substrate/frame/multisig/Cargo.toml b/substrate/frame/multisig/Cargo.toml index 1d2a79bdc52f..2437acbc2e23 100644 --- a/substrate/frame/multisig/Cargo.toml +++ b/substrate/frame/multisig/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/nft-fractionalization/Cargo.toml b/substrate/frame/nft-fractionalization/Cargo.toml index 8002b7e1165f..b5a929468f7d 100644 --- a/substrate/frame/nft-fractionalization/Cargo.toml +++ b/substrate/frame/nft-fractionalization/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/nfts/Cargo.toml b/substrate/frame/nfts/Cargo.toml index 69e9ea170b14..4f818ea3e08c 100644 --- a/substrate/frame/nfts/Cargo.toml +++ b/substrate/frame/nfts/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } enumflags2 = { version = "0.7.7" } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/nis/Cargo.toml b/substrate/frame/nis/Cargo.toml index 025daa07b0c5..d0ba74a92731 100644 --- a/substrate/frame/nis/Cargo.toml +++ b/substrate/frame/nis/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/node-authorization/Cargo.toml b/substrate/frame/node-authorization/Cargo.toml index a39b0ec4eff8..63376163cdcb 100644 --- a/substrate/frame/node-authorization/Cargo.toml +++ b/substrate/frame/node-authorization/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } sp-core = { path = "../../primitives/core", default-features = false } diff --git a/substrate/frame/nomination-pools/Cargo.toml b/substrate/frame/nomination-pools/Cargo.toml index 9830f31d5fa9..55e9ef6fbd33 100644 --- a/substrate/frame/nomination-pools/Cargo.toml +++ b/substrate/frame/nomination-pools/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.10.0", default-features = false, features = [ +scale-info = { version = "2.11.1", default-features = false, features = [ "derive", ] } diff --git a/substrate/frame/nomination-pools/benchmarking/Cargo.toml b/substrate/frame/nomination-pools/benchmarking/Cargo.toml index 8123e1c6f566..3924b6f08143 100644 --- a/substrate/frame/nomination-pools/benchmarking/Cargo.toml +++ b/substrate/frame/nomination-pools/benchmarking/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] # parity codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } # FRAME frame-benchmarking = { path = "../../benchmarking", default-features = false } diff --git a/substrate/frame/nomination-pools/test-transfer-stake/Cargo.toml b/substrate/frame/nomination-pools/test-transfer-stake/Cargo.toml index 52d0cefb0def..9d1f92ef3eef 100644 --- a/substrate/frame/nomination-pools/test-transfer-stake/Cargo.toml +++ b/substrate/frame/nomination-pools/test-transfer-stake/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dev-dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } -scale-info = { version = "2.10.0", features = ["derive"] } +scale-info = { version = "2.11.1", features = ["derive"] } sp-runtime = { path = "../../../primitives/runtime" } sp-io = { path = "../../../primitives/io" } diff --git a/substrate/frame/offences/Cargo.toml b/substrate/frame/offences/Cargo.toml index b3ef4671ce56..f8efc88bafc1 100644 --- a/substrate/frame/offences/Cargo.toml +++ b/substrate/frame/offences/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { optional = true, workspace = true, default-features = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/offences/benchmarking/Cargo.toml b/substrate/frame/offences/benchmarking/Cargo.toml index 8dcce84d257e..07905a1e0aa4 100644 --- a/substrate/frame/offences/benchmarking/Cargo.toml +++ b/substrate/frame/offences/benchmarking/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../../benchmarking", default-features = false } frame-election-provider-support = { path = "../../election-provider-support", default-features = false } frame-support = { path = "../../support", default-features = false } diff --git a/substrate/frame/paged-list/Cargo.toml b/substrate/frame/paged-list/Cargo.toml index bbe8e33d484d..26f3d7e48ced 100644 --- a/substrate/frame/paged-list/Cargo.toml +++ b/substrate/frame/paged-list/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } docify = "0.2.8" -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } diff --git a/substrate/frame/parameters/Cargo.toml b/substrate/frame/parameters/Cargo.toml index ab93be14e6c3..2527bdf3a71f 100644 --- a/substrate/frame/parameters/Cargo.toml +++ b/substrate/frame/parameters/Cargo.toml @@ -9,7 +9,7 @@ edition.workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["max-encoded-len"] } -scale-info = { version = "2.1.2", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } paste = { version = "1.0.14", default-features = false } serde = { features = ["derive"], optional = true, workspace = true, default-features = true } docify = "0.2.8" diff --git a/substrate/frame/preimage/Cargo.toml b/substrate/frame/preimage/Cargo.toml index 10a15f97bd5a..d67fc7bead04 100644 --- a/substrate/frame/preimage/Cargo.toml +++ b/substrate/frame/preimage/Cargo.toml @@ -13,7 +13,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/proxy/Cargo.toml b/substrate/frame/proxy/Cargo.toml index 17930079afd2..0a3b39e471d4 100644 --- a/substrate/frame/proxy/Cargo.toml +++ b/substrate/frame/proxy/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["max-encoded-len"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/ranked-collective/Cargo.toml b/substrate/frame/ranked-collective/Cargo.toml index 54e84c0b5588..0a6595807750 100644 --- a/substrate/frame/ranked-collective/Cargo.toml +++ b/substrate/frame/ranked-collective/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/recovery/Cargo.toml b/substrate/frame/recovery/Cargo.toml index 421c79951373..43608de37fc3 100644 --- a/substrate/frame/recovery/Cargo.toml +++ b/substrate/frame/recovery/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/referenda/Cargo.toml b/substrate/frame/referenda/Cargo.toml index 2dfb25a2fd3a..f4e0171443aa 100644 --- a/substrate/frame/referenda/Cargo.toml +++ b/substrate/frame/referenda/Cargo.toml @@ -20,7 +20,7 @@ assert_matches = { version = "1.5", optional = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["derive"], optional = true, workspace = true, default-features = true } sp-arithmetic = { path = "../../primitives/arithmetic", default-features = false } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } diff --git a/substrate/frame/remark/Cargo.toml b/substrate/frame/remark/Cargo.toml index 45710f0539e2..e746b0382aea 100644 --- a/substrate/frame/remark/Cargo.toml +++ b/substrate/frame/remark/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { optional = true, workspace = true, default-features = true } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } diff --git a/substrate/frame/root-offences/Cargo.toml b/substrate/frame/root-offences/Cargo.toml index 80b330950681..ad3dcf1f90ea 100644 --- a/substrate/frame/root-offences/Cargo.toml +++ b/substrate/frame/root-offences/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } pallet-session = { path = "../session", default-features = false, features = ["historical"] } pallet-staking = { path = "../staking", default-features = false } diff --git a/substrate/frame/root-testing/Cargo.toml b/substrate/frame/root-testing/Cargo.toml index 51b72665b81a..bf14516ee322 100644 --- a/substrate/frame/root-testing/Cargo.toml +++ b/substrate/frame/root-testing/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } sp-core = { path = "../../primitives/core", default-features = false } diff --git a/substrate/frame/safe-mode/Cargo.toml b/substrate/frame/safe-mode/Cargo.toml index 6ddeff263c1a..b6b7e5a67e48 100644 --- a/substrate/frame/safe-mode/Cargo.toml +++ b/substrate/frame/safe-mode/Cargo.toml @@ -20,7 +20,7 @@ docify = "0.2.8" frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } sp-arithmetic = { path = "../../primitives/arithmetic", default-features = false } sp-runtime = { path = "../../primitives/runtime", default-features = false } sp-std = { path = "../../primitives/std", default-features = false } diff --git a/substrate/frame/salary/Cargo.toml b/substrate/frame/salary/Cargo.toml index ba57fd46eebb..8c77edcb173a 100644 --- a/substrate/frame/salary/Cargo.toml +++ b/substrate/frame/salary/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/sassafras/Cargo.toml b/substrate/frame/sassafras/Cargo.toml index 325a39bf5979..09977142efc8 100644 --- a/substrate/frame/sassafras/Cargo.toml +++ b/substrate/frame/sassafras/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] scale-codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/scheduler/Cargo.toml b/substrate/frame/scheduler/Cargo.toml index a3e684a20836..40a717364470 100644 --- a/substrate/frame/scheduler/Cargo.toml +++ b/substrate/frame/scheduler/Cargo.toml @@ -15,7 +15,7 @@ workspace = true [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/scored-pool/Cargo.toml b/substrate/frame/scored-pool/Cargo.toml index ae6ade5189d0..92b70e01b9ab 100644 --- a/substrate/frame/scored-pool/Cargo.toml +++ b/substrate/frame/scored-pool/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } sp-io = { path = "../../primitives/io", default-features = false } diff --git a/substrate/frame/session/Cargo.toml b/substrate/frame/session/Cargo.toml index de041307f702..86814f8276e7 100644 --- a/substrate/frame/session/Cargo.toml +++ b/substrate/frame/session/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } impl-trait-for-tuples = "0.2.2" log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive", "serde"] } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } pallet-timestamp = { path = "../timestamp", default-features = false } diff --git a/substrate/frame/session/benchmarking/Cargo.toml b/substrate/frame/session/benchmarking/Cargo.toml index 291fda3c4c7a..a00fbd8f6fdf 100644 --- a/substrate/frame/session/benchmarking/Cargo.toml +++ b/substrate/frame/session/benchmarking/Cargo.toml @@ -29,7 +29,7 @@ sp-std = { path = "../../../primitives/std", default-features = false } [dev-dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", features = ["derive"] } -scale-info = "2.10.0" +scale-info = "2.11.1" frame-election-provider-support = { path = "../../election-provider-support" } pallet-balances = { path = "../../balances" } pallet-staking-reward-curve = { path = "../../staking/reward-curve" } diff --git a/substrate/frame/society/Cargo.toml b/substrate/frame/society/Cargo.toml index 3dab082b3954..3d99ddba392b 100644 --- a/substrate/frame/society/Cargo.toml +++ b/substrate/frame/society/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] log = { workspace = true } rand_chacha = { version = "0.2", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } sp-std = { path = "../../primitives/std", default-features = false } diff --git a/substrate/frame/staking/Cargo.toml b/substrate/frame/staking/Cargo.toml index 15c4bf9e290e..4fd0cedbae63 100644 --- a/substrate/frame/staking/Cargo.toml +++ b/substrate/frame/staking/Cargo.toml @@ -20,7 +20,7 @@ serde = { features = ["alloc", "derive"], workspace = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive", "serde"] } sp-io = { path = "../../primitives/io", default-features = false } sp-runtime = { path = "../../primitives/runtime", default-features = false, features = ["serde"] } sp-staking = { path = "../../primitives/staking", default-features = false, features = ["serde"] } diff --git a/substrate/frame/state-trie-migration/Cargo.toml b/substrate/frame/state-trie-migration/Cargo.toml index e837956613ed..613308c308e1 100644 --- a/substrate/frame/state-trie-migration/Cargo.toml +++ b/substrate/frame/state-trie-migration/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { optional = true, workspace = true, default-features = true } thousands = { version = "0.2.0", optional = true } zstd = { version = "0.12.4", default-features = false, optional = true } diff --git a/substrate/frame/statement/Cargo.toml b/substrate/frame/statement/Cargo.toml index 6827dbda962b..92bc32191ab8 100644 --- a/substrate/frame/statement/Cargo.toml +++ b/substrate/frame/statement/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } sp-statement-store = { path = "../../primitives/statement-store", default-features = false } diff --git a/substrate/frame/sudo/Cargo.toml b/substrate/frame/sudo/Cargo.toml index a60324847f1a..805f46a77f2e 100644 --- a/substrate/frame/sudo/Cargo.toml +++ b/substrate/frame/sudo/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } sp-io = { path = "../../primitives/io", default-features = false } diff --git a/substrate/frame/support/Cargo.toml b/substrate/frame/support/Cargo.toml index 3a61cfa6fac6..ecdd93826327 100644 --- a/substrate/frame/support/Cargo.toml +++ b/substrate/frame/support/Cargo.toml @@ -22,7 +22,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "derive", "max-encoded-len", ] } -scale-info = { version = "2.10.0", default-features = false, features = [ +scale-info = { version = "2.11.1", default-features = false, features = [ "derive", ] } frame-metadata = { version = "16.0.0", default-features = false, features = [ diff --git a/substrate/frame/support/test/Cargo.toml b/substrate/frame/support/test/Cargo.toml index 2f12cc00ed9e..88124e0a43b9 100644 --- a/substrate/frame/support/test/Cargo.toml +++ b/substrate/frame/support/test/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] static_assertions = "1.1.0" serde = { features = ["derive"], workspace = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-metadata = { version = "16.0.0", default-features = false, features = ["current"] } sp-api = { path = "../../../primitives/api", default-features = false } sp-arithmetic = { path = "../../../primitives/arithmetic", default-features = false } diff --git a/substrate/frame/support/test/compile_pass/Cargo.toml b/substrate/frame/support/test/compile_pass/Cargo.toml index 0617aa105a21..3f52b4664b18 100644 --- a/substrate/frame/support/test/compile_pass/Cargo.toml +++ b/substrate/frame/support/test/compile_pass/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } renamed-frame-support = { package = "frame-support", path = "../..", default-features = false } renamed-frame-system = { package = "frame-system", path = "../../../system", default-features = false } sp-core = { path = "../../../../primitives/core", default-features = false } diff --git a/substrate/frame/support/test/pallet/Cargo.toml b/substrate/frame/support/test/pallet/Cargo.toml index ca889faef876..7a20c3f27306 100644 --- a/substrate/frame/support/test/pallet/Cargo.toml +++ b/substrate/frame/support/test/pallet/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["derive"], workspace = true } frame-support = { path = "../..", default-features = false } frame-system = { path = "../../../system", default-features = false } diff --git a/substrate/frame/support/test/stg_frame_crate/Cargo.toml b/substrate/frame/support/test/stg_frame_crate/Cargo.toml index 632ea4e794f6..295b2a1a5247 100644 --- a/substrate/frame/support/test/stg_frame_crate/Cargo.toml +++ b/substrate/frame/support/test/stg_frame_crate/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } frame = { path = "../../..", default-features = false, features = ["experimental", "runtime"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } [features] default = ["std"] diff --git a/substrate/frame/system/Cargo.toml b/substrate/frame/system/Cargo.toml index d094c6bf9849..16b3b946e221 100644 --- a/substrate/frame/system/Cargo.toml +++ b/substrate/frame/system/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] cfg-if = "1.0" codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive", "serde"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive", "serde"] } serde = { features = ["alloc", "derive"], workspace = true } frame-support = { path = "../support", default-features = false } sp-core = { path = "../../primitives/core", default-features = false, features = ["serde"] } diff --git a/substrate/frame/system/benchmarking/Cargo.toml b/substrate/frame/system/benchmarking/Cargo.toml index 80fdff756c02..473a6bb132d7 100644 --- a/substrate/frame/system/benchmarking/Cargo.toml +++ b/substrate/frame/system/benchmarking/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../../benchmarking", default-features = false } frame-support = { path = "../../support", default-features = false } frame-system = { path = "..", default-features = false } diff --git a/substrate/frame/timestamp/Cargo.toml b/substrate/frame/timestamp/Cargo.toml index d8ba45a2ad28..da49b29c89b7 100644 --- a/substrate/frame/timestamp/Cargo.toml +++ b/substrate/frame/timestamp/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/tips/Cargo.toml b/substrate/frame/tips/Cargo.toml index 7339cf0a8cce..a2acf0638ffb 100644 --- a/substrate/frame/tips/Cargo.toml +++ b/substrate/frame/tips/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["derive"], optional = true, workspace = true, default-features = true } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } diff --git a/substrate/frame/transaction-payment/Cargo.toml b/substrate/frame/transaction-payment/Cargo.toml index 275e1c01f927..24e5a714f0fe 100644 --- a/substrate/frame/transaction-payment/Cargo.toml +++ b/substrate/frame/transaction-payment/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { optional = true, workspace = true, default-features = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/transaction-payment/asset-conversion-tx-payment/Cargo.toml b/substrate/frame/transaction-payment/asset-conversion-tx-payment/Cargo.toml index 7640cc815e56..fef9afdee05f 100644 --- a/substrate/frame/transaction-payment/asset-conversion-tx-payment/Cargo.toml +++ b/substrate/frame/transaction-payment/asset-conversion-tx-payment/Cargo.toml @@ -24,7 +24,7 @@ frame-system = { path = "../../system", default-features = false } pallet-asset-conversion = { path = "../../asset-conversion", default-features = false } pallet-transaction-payment = { path = "..", default-features = false } codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } [dev-dependencies] sp-core = { path = "../../../primitives/core", default-features = false } diff --git a/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml b/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml index 1da3237df081..fc4f1aecc15e 100644 --- a/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml +++ b/substrate/frame/transaction-payment/asset-tx-payment/Cargo.toml @@ -29,7 +29,7 @@ frame-benchmarking = { path = "../../benchmarking", default-features = false, op # Other dependencies codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { optional = true, workspace = true, default-features = true } [dev-dependencies] diff --git a/substrate/frame/transaction-storage/Cargo.toml b/substrate/frame/transaction-storage/Cargo.toml index 1386d9b5a569..31741cf32d83 100644 --- a/substrate/frame/transaction-storage/Cargo.toml +++ b/substrate/frame/transaction-storage/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] array-bytes = { version = "6.1", optional = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { optional = true, workspace = true, default-features = true } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } diff --git a/substrate/frame/treasury/Cargo.toml b/substrate/frame/treasury/Cargo.toml index 16bb4e92520b..34037338a52b 100644 --- a/substrate/frame/treasury/Cargo.toml +++ b/substrate/frame/treasury/Cargo.toml @@ -22,7 +22,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = ] } docify = "0.2.8" impl-trait-for-tuples = "0.2.2" -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["derive"], optional = true, workspace = true, default-features = true } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } diff --git a/substrate/frame/tx-pause/Cargo.toml b/substrate/frame/tx-pause/Cargo.toml index a5916c048f46..5f028179037d 100644 --- a/substrate/frame/tx-pause/Cargo.toml +++ b/substrate/frame/tx-pause/Cargo.toml @@ -20,7 +20,7 @@ docify = "0.2.8" frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } sp-runtime = { path = "../../primitives/runtime", default-features = false } sp-std = { path = "../../primitives/std", default-features = false } pallet-balances = { path = "../balances", default-features = false, optional = true } diff --git a/substrate/frame/uniques/Cargo.toml b/substrate/frame/uniques/Cargo.toml index 4e5f21b3d8df..ee6af191d33f 100644 --- a/substrate/frame/uniques/Cargo.toml +++ b/substrate/frame/uniques/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/utility/Cargo.toml b/substrate/frame/utility/Cargo.toml index ce5cd0fa61f2..2ad575ed51ff 100644 --- a/substrate/frame/utility/Cargo.toml +++ b/substrate/frame/utility/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/vesting/Cargo.toml b/substrate/frame/vesting/Cargo.toml index 96938b95a2ad..e71731e39778 100644 --- a/substrate/frame/vesting/Cargo.toml +++ b/substrate/frame/vesting/Cargo.toml @@ -20,7 +20,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = "derive", ] } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/frame/whitelist/Cargo.toml b/substrate/frame/whitelist/Cargo.toml index 1a867f8075d1..5c28fe29142c 100644 --- a/substrate/frame/whitelist/Cargo.toml +++ b/substrate/frame/whitelist/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } diff --git a/substrate/primitives/api/Cargo.toml b/substrate/primitives/api/Cargo.toml index f4b1d13c5203..544ba72141eb 100644 --- a/substrate/primitives/api/Cargo.toml +++ b/substrate/primitives/api/Cargo.toml @@ -28,7 +28,7 @@ sp-state-machine = { path = "../state-machine", default-features = false, option sp-trie = { path = "../trie", default-features = false, optional = true } hash-db = { version = "0.16.0", optional = true } thiserror = { optional = true, workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = [ +scale-info = { version = "2.11.1", default-features = false, features = [ "derive", ] } sp-metadata-ir = { path = "../metadata-ir", default-features = false, optional = true } diff --git a/substrate/primitives/api/test/Cargo.toml b/substrate/primitives/api/test/Cargo.toml index 3a90553bbf00..52a4bd7bda30 100644 --- a/substrate/primitives/api/test/Cargo.toml +++ b/substrate/primitives/api/test/Cargo.toml @@ -26,11 +26,11 @@ codec = { package = "parity-scale-codec", version = "3.6.1" } sp-state-machine = { path = "../../state-machine" } trybuild = "1.0.88" rustversion = "1.0.6" -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } [dev-dependencies] criterion = "0.4.0" -futures = "0.3.21" +futures = "0.3.30" log = { workspace = true, default-features = true } sp-core = { path = "../../core" } static_assertions = "1.1.0" diff --git a/substrate/primitives/application-crypto/Cargo.toml b/substrate/primitives/application-crypto/Cargo.toml index 6f90a2b6262e..20e2be4d1552 100644 --- a/substrate/primitives/application-crypto/Cargo.toml +++ b/substrate/primitives/application-crypto/Cargo.toml @@ -20,7 +20,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] sp-core = { path = "../core", default-features = false } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { optional = true, features = ["alloc", "derive"], workspace = true } sp-std = { path = "../std", default-features = false } sp-io = { path = "../io", default-features = false } diff --git a/substrate/primitives/arithmetic/Cargo.toml b/substrate/primitives/arithmetic/Cargo.toml index 45f48d77a311..16eae43c73fa 100644 --- a/substrate/primitives/arithmetic/Cargo.toml +++ b/substrate/primitives/arithmetic/Cargo.toml @@ -23,7 +23,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features = ] } integer-sqrt = "0.1.2" num-traits = { version = "0.2.17", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["alloc", "derive"], optional = true, workspace = true } static_assertions = "1.1.0" sp-std = { path = "../std", default-features = false } diff --git a/substrate/primitives/authority-discovery/Cargo.toml b/substrate/primitives/authority-discovery/Cargo.toml index 8ee8bb94ed97..88d93f400596 100644 --- a/substrate/primitives/authority-discovery/Cargo.toml +++ b/substrate/primitives/authority-discovery/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } sp-api = { path = "../api", default-features = false } sp-application-crypto = { path = "../application-crypto", default-features = false } sp-runtime = { path = "../runtime", default-features = false } diff --git a/substrate/primitives/blockchain/Cargo.toml b/substrate/primitives/blockchain/Cargo.toml index 9d13d627eebc..e716b61bfeb1 100644 --- a/substrate/primitives/blockchain/Cargo.toml +++ b/substrate/primitives/blockchain/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -futures = "0.3.21" +futures = "0.3.30" log = { workspace = true, default-features = true } parking_lot = "0.12.1" schnellru = "0.2.1" diff --git a/substrate/primitives/consensus/aura/Cargo.toml b/substrate/primitives/consensus/aura/Cargo.toml index 0cedc59ea8fb..b689c84f158c 100644 --- a/substrate/primitives/consensus/aura/Cargo.toml +++ b/substrate/primitives/consensus/aura/Cargo.toml @@ -16,9 +16,9 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -async-trait = { version = "0.1.74", optional = true } +async-trait = { version = "0.1.79", optional = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } sp-api = { path = "../../api", default-features = false } sp-application-crypto = { path = "../../application-crypto", default-features = false } sp-consensus-slots = { path = "../slots", default-features = false } diff --git a/substrate/primitives/consensus/babe/Cargo.toml b/substrate/primitives/consensus/babe/Cargo.toml index 724b9fd3e289..2420f48b1f4a 100644 --- a/substrate/primitives/consensus/babe/Cargo.toml +++ b/substrate/primitives/consensus/babe/Cargo.toml @@ -16,9 +16,9 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -async-trait = { version = "0.1.74", optional = true } +async-trait = { version = "0.1.79", optional = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["alloc", "derive"], optional = true, workspace = true } sp-api = { path = "../../api", default-features = false } sp-application-crypto = { path = "../../application-crypto", default-features = false } diff --git a/substrate/primitives/consensus/beefy/Cargo.toml b/substrate/primitives/consensus/beefy/Cargo.toml index fbcc6e0c1048..a16d943b9146 100644 --- a/substrate/primitives/consensus/beefy/Cargo.toml +++ b/substrate/primitives/consensus/beefy/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { optional = true, features = ["alloc", "derive"], workspace = true } sp-api = { path = "../../api", default-features = false } sp-application-crypto = { path = "../../application-crypto", default-features = false } @@ -26,7 +26,7 @@ sp-io = { path = "../../io", default-features = false } sp-mmr-primitives = { path = "../../merkle-mountain-range", default-features = false } sp-runtime = { path = "../../runtime", default-features = false } sp-keystore = { path = "../../keystore", default-features = false } -strum = { version = "0.24.1", features = ["derive"], default-features = false } +strum = { version = "0.26.2", features = ["derive"], default-features = false } lazy_static = { version = "1.4.0", optional = true } [dev-dependencies] diff --git a/substrate/primitives/consensus/common/Cargo.toml b/substrate/primitives/consensus/common/Cargo.toml index 048e31b0265f..90aeadd5055e 100644 --- a/substrate/primitives/consensus/common/Cargo.toml +++ b/substrate/primitives/consensus/common/Cargo.toml @@ -17,8 +17,8 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -async-trait = "0.1.74" -futures = { version = "0.3.21", features = ["thread-pool"] } +async-trait = "0.1.79" +futures = { version = "0.3.30", features = ["thread-pool"] } log = { workspace = true, default-features = true } thiserror = { workspace = true } sp-core = { path = "../../core" } @@ -27,7 +27,7 @@ sp-runtime = { path = "../../runtime" } sp-state-machine = { path = "../../state-machine" } [dev-dependencies] -futures = "0.3.21" +futures = "0.3.30" sp-test-primitives = { path = "../../test-primitives" } [features] diff --git a/substrate/primitives/consensus/grandpa/Cargo.toml b/substrate/primitives/consensus/grandpa/Cargo.toml index 1f2da55c5a16..6c228383d003 100644 --- a/substrate/primitives/consensus/grandpa/Cargo.toml +++ b/substrate/primitives/consensus/grandpa/Cargo.toml @@ -20,7 +20,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } grandpa = { package = "finality-grandpa", version = "0.16.2", default-features = false, features = ["derive-codec"] } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["alloc", "derive"], optional = true, workspace = true } sp-api = { path = "../../api", default-features = false } sp-application-crypto = { path = "../../application-crypto", default-features = false } diff --git a/substrate/primitives/consensus/sassafras/Cargo.toml b/substrate/primitives/consensus/sassafras/Cargo.toml index 085709d4c8b5..07304ed9b240 100644 --- a/substrate/primitives/consensus/sassafras/Cargo.toml +++ b/substrate/primitives/consensus/sassafras/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] scale-codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["derive"], optional = true, workspace = true } sp-api = { path = "../../api", default-features = false } sp-application-crypto = { path = "../../application-crypto", default-features = false, features = ["bandersnatch-experimental"] } diff --git a/substrate/primitives/consensus/slots/Cargo.toml b/substrate/primitives/consensus/slots/Cargo.toml index 94c02dba203d..a8b129006179 100644 --- a/substrate/primitives/consensus/slots/Cargo.toml +++ b/substrate/primitives/consensus/slots/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["alloc", "derive"], optional = true, workspace = true } sp-timestamp = { path = "../../timestamp", default-features = false } diff --git a/substrate/primitives/core/Cargo.toml b/substrate/primitives/core/Cargo.toml index 908f2498de53..833b2af95cd1 100644 --- a/substrate/primitives/core/Cargo.toml +++ b/substrate/primitives/core/Cargo.toml @@ -38,7 +38,7 @@ sp-std = { path = "../std", default-features = false } sp-debug-derive = { path = "../debug-derive", default-features = false } sp-storage = { path = "../storage", default-features = false } sp-externalities = { path = "../externalities", optional = true } -futures = { version = "0.3.21", optional = true } +futures = { version = "0.3.30", optional = true } dyn-clonable = { version = "0.9.0", optional = true } thiserror = { optional = true, workspace = true } tracing = { version = "0.1.29", optional = true } diff --git a/substrate/primitives/inherents/Cargo.toml b/substrate/primitives/inherents/Cargo.toml index 6463c423fe7b..c08ac459de53 100644 --- a/substrate/primitives/inherents/Cargo.toml +++ b/substrate/primitives/inherents/Cargo.toml @@ -17,15 +17,15 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -async-trait = { version = "0.1.74", optional = true } +async-trait = { version = "0.1.79", optional = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } impl-trait-for-tuples = "0.2.2" thiserror = { optional = true, workspace = true } sp-runtime = { path = "../runtime", default-features = false, optional = true } [dev-dependencies] -futures = "0.3.21" +futures = "0.3.30" [features] default = ["std"] diff --git a/substrate/primitives/keyring/Cargo.toml b/substrate/primitives/keyring/Cargo.toml index 940fe90916d2..7471e9cf8ffa 100644 --- a/substrate/primitives/keyring/Cargo.toml +++ b/substrate/primitives/keyring/Cargo.toml @@ -17,7 +17,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -strum = { version = "0.24.1", features = ["derive"], default-features = false } +strum = { version = "0.26.2", features = ["derive"], default-features = false } sp-core = { path = "../core", default-features = false } sp-runtime = { path = "../runtime", default-features = false } diff --git a/substrate/primitives/merkle-mountain-range/Cargo.toml b/substrate/primitives/merkle-mountain-range/Cargo.toml index 9c07f699b37a..891f893a0c96 100644 --- a/substrate/primitives/merkle-mountain-range/Cargo.toml +++ b/substrate/primitives/merkle-mountain-range/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } log = { workspace = true } mmr-lib = { package = "ckb-merkle-mountain-range", version = "0.5.2", default-features = false } serde = { features = ["alloc", "derive"], optional = true, workspace = true } diff --git a/substrate/primitives/metadata-ir/Cargo.toml b/substrate/primitives/metadata-ir/Cargo.toml index 31c839b5c485..ca8408d0ad97 100644 --- a/substrate/primitives/metadata-ir/Cargo.toml +++ b/substrate/primitives/metadata-ir/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } frame-metadata = { version = "16.0.0", default-features = false, features = ["current"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } [features] default = ["std"] diff --git a/substrate/primitives/mixnet/Cargo.toml b/substrate/primitives/mixnet/Cargo.toml index 8ba7f36da43c..07840ca63cb2 100644 --- a/substrate/primitives/mixnet/Cargo.toml +++ b/substrate/primitives/mixnet/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } sp-api = { default-features = false, path = "../api" } sp-application-crypto = { default-features = false, path = "../application-crypto" } diff --git a/substrate/primitives/npos-elections/Cargo.toml b/substrate/primitives/npos-elections/Cargo.toml index b0b9890c0619..afa59af64d6d 100644 --- a/substrate/primitives/npos-elections/Cargo.toml +++ b/substrate/primitives/npos-elections/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["alloc", "derive"], optional = true, workspace = true } sp-arithmetic = { path = "../arithmetic", default-features = false } sp-core = { path = "../core", default-features = false } diff --git a/substrate/primitives/runtime/Cargo.toml b/substrate/primitives/runtime/Cargo.toml index 3128ebce8f7a..fb5fd60fbbfd 100644 --- a/substrate/primitives/runtime/Cargo.toml +++ b/substrate/primitives/runtime/Cargo.toml @@ -24,7 +24,7 @@ impl-trait-for-tuples = "0.2.2" log = { workspace = true } paste = "1.0" rand = { version = "0.8.5", optional = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["alloc", "derive"], optional = true, workspace = true } sp-application-crypto = { path = "../application-crypto", default-features = false } sp-arithmetic = { path = "../arithmetic", default-features = false } diff --git a/substrate/primitives/session/Cargo.toml b/substrate/primitives/session/Cargo.toml index 784228c42e9b..cdee4fb03e12 100644 --- a/substrate/primitives/session/Cargo.toml +++ b/substrate/primitives/session/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } sp-api = { path = "../api", default-features = false } sp-core = { path = "../core", default-features = false } sp-runtime = { path = "../runtime", optional = true } diff --git a/substrate/primitives/staking/Cargo.toml b/substrate/primitives/staking/Cargo.toml index 6304551b8e60..e380abb6a8c0 100644 --- a/substrate/primitives/staking/Cargo.toml +++ b/substrate/primitives/staking/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] serde = { features = ["alloc", "derive"], optional = true, workspace = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } impl-trait-for-tuples = "0.2.2" sp-core = { path = "../core", default-features = false } diff --git a/substrate/primitives/statement-store/Cargo.toml b/substrate/primitives/statement-store/Cargo.toml index 000fcd987040..b36bff69a007 100644 --- a/substrate/primitives/statement-store/Cargo.toml +++ b/substrate/primitives/statement-store/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } sp-core = { path = "../core", default-features = false } sp-crypto-hashing = { path = "../crypto/hashing", default-features = false } sp-runtime = { path = "../runtime", default-features = false } diff --git a/substrate/primitives/test-primitives/Cargo.toml b/substrate/primitives/test-primitives/Cargo.toml index 1b51c5f59190..051355543156 100644 --- a/substrate/primitives/test-primitives/Cargo.toml +++ b/substrate/primitives/test-primitives/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["derive"], optional = true, workspace = true } sp-application-crypto = { path = "../application-crypto", default-features = false } sp-core = { path = "../core", default-features = false } diff --git a/substrate/primitives/timestamp/Cargo.toml b/substrate/primitives/timestamp/Cargo.toml index 11afb1755908..5a1d4fcc985c 100644 --- a/substrate/primitives/timestamp/Cargo.toml +++ b/substrate/primitives/timestamp/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -async-trait = { version = "0.1.74", optional = true } +async-trait = { version = "0.1.79", optional = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } thiserror = { optional = true, workspace = true } sp-inherents = { path = "../inherents", default-features = false } diff --git a/substrate/primitives/transaction-storage-proof/Cargo.toml b/substrate/primitives/transaction-storage-proof/Cargo.toml index fbd0a4752fca..137a232fce73 100644 --- a/substrate/primitives/transaction-storage-proof/Cargo.toml +++ b/substrate/primitives/transaction-storage-proof/Cargo.toml @@ -16,9 +16,9 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -async-trait = { version = "0.1.74", optional = true } +async-trait = { version = "0.1.79", optional = true } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } sp-core = { path = "../core", optional = true } sp-inherents = { path = "../inherents", default-features = false } sp-runtime = { path = "../runtime", default-features = false } diff --git a/substrate/primitives/trie/Cargo.toml b/substrate/primitives/trie/Cargo.toml index dd7ab080e5f4..28c496d7a8e0 100644 --- a/substrate/primitives/trie/Cargo.toml +++ b/substrate/primitives/trie/Cargo.toml @@ -29,7 +29,7 @@ memory-db = { version = "0.32.0", default-features = false } nohash-hasher = { version = "0.2.0", optional = true } parking_lot = { version = "0.12.1", optional = true } rand = { version = "0.8", optional = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } thiserror = { optional = true, workspace = true } tracing = { version = "0.1.29", optional = true } trie-db = { version = "0.28.0", default-features = false } diff --git a/substrate/primitives/version/Cargo.toml b/substrate/primitives/version/Cargo.toml index a94e2322430b..d686b0c75512 100644 --- a/substrate/primitives/version/Cargo.toml +++ b/substrate/primitives/version/Cargo.toml @@ -20,7 +20,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } impl-serde = { version = "0.4.0", default-features = false, optional = true } parity-wasm = { version = "0.45", optional = true } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { features = ["alloc", "derive"], optional = true, workspace = true } thiserror = { optional = true, workspace = true } sp-crypto-hashing-proc-macro = { path = "../crypto/hashing/proc-macro" } diff --git a/substrate/primitives/weights/Cargo.toml b/substrate/primitives/weights/Cargo.toml index d3118defb58d..e73d4a702b42 100644 --- a/substrate/primitives/weights/Cargo.toml +++ b/substrate/primitives/weights/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] bounded-collections = { version = "0.2.0", default-features = false } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } serde = { optional = true, features = ["alloc", "derive"], workspace = true } smallvec = "1.11.0" sp-arithmetic = { path = "../arithmetic", default-features = false } diff --git a/substrate/test-utils/Cargo.toml b/substrate/test-utils/Cargo.toml index af8b01cdef08..56b1c038199a 100644 --- a/substrate/test-utils/Cargo.toml +++ b/substrate/test-utils/Cargo.toml @@ -16,7 +16,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -futures = "0.3.16" +futures = "0.3.30" tokio = { version = "1.22.0", features = ["macros", "time"] } [dev-dependencies] diff --git a/substrate/test-utils/client/Cargo.toml b/substrate/test-utils/client/Cargo.toml index 349b04d32d7b..4e4e65314fc3 100644 --- a/substrate/test-utils/client/Cargo.toml +++ b/substrate/test-utils/client/Cargo.toml @@ -17,9 +17,9 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] array-bytes = "6.1" -async-trait = "0.1.74" +async-trait = "0.1.79" codec = { package = "parity-scale-codec", version = "3.6.1" } -futures = "0.3.21" +futures = "0.3.30" serde = { workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } sc-client-api = { path = "../../client/api" } diff --git a/substrate/test-utils/runtime/Cargo.toml b/substrate/test-utils/runtime/Cargo.toml index f49503da8ca5..ffbd59f39ad2 100644 --- a/substrate/test-utils/runtime/Cargo.toml +++ b/substrate/test-utils/runtime/Cargo.toml @@ -22,7 +22,7 @@ sp-consensus-babe = { path = "../../primitives/consensus/babe", default-features sp-genesis-builder = { path = "../../primitives/genesis-builder", default-features = false } sp-block-builder = { path = "../../primitives/block-builder", default-features = false } codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } sp-inherents = { path = "../../primitives/inherents", default-features = false } sp-keyring = { path = "../../primitives/keyring", default-features = false } sp-offchain = { path = "../../primitives/offchain", default-features = false } @@ -53,7 +53,7 @@ array-bytes = { version = "6.1", optional = true } log = { workspace = true } [dev-dependencies] -futures = "0.3.21" +futures = "0.3.30" sc-block-builder = { path = "../../client/block-builder" } sc-chain-spec = { path = "../../client/chain-spec" } sc-executor = { path = "../../client/executor" } diff --git a/substrate/test-utils/runtime/client/Cargo.toml b/substrate/test-utils/runtime/client/Cargo.toml index cbb964f67852..5ca24fea33ed 100644 --- a/substrate/test-utils/runtime/client/Cargo.toml +++ b/substrate/test-utils/runtime/client/Cargo.toml @@ -15,7 +15,7 @@ workspace = true targets = ["x86_64-unknown-linux-gnu"] [dependencies] -futures = "0.3.21" +futures = "0.3.30" sc-block-builder = { path = "../../../client/block-builder" } sc-client-api = { path = "../../../client/api" } sc-consensus = { path = "../../../client/consensus/common" } diff --git a/substrate/test-utils/runtime/transaction-pool/Cargo.toml b/substrate/test-utils/runtime/transaction-pool/Cargo.toml index 33e56e8e55e7..9b52706c7399 100644 --- a/substrate/test-utils/runtime/transaction-pool/Cargo.toml +++ b/substrate/test-utils/runtime/transaction-pool/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } -futures = "0.3.21" +futures = "0.3.30" parking_lot = "0.12.1" thiserror = { workspace = true } sc-transaction-pool = { path = "../../../client/transaction-pool" } diff --git a/substrate/utils/binary-merkle-tree/Cargo.toml b/substrate/utils/binary-merkle-tree/Cargo.toml index 6ba515afee17..a89006d94dc1 100644 --- a/substrate/utils/binary-merkle-tree/Cargo.toml +++ b/substrate/utils/binary-merkle-tree/Cargo.toml @@ -18,7 +18,7 @@ hash-db = { version = "0.16.0", default-features = false } [dev-dependencies] array-bytes = "6.1" -env_logger = "0.9" +env_logger = "0.11" sp-core = { path = "../../primitives/core" } sp-runtime = { path = "../../primitives/runtime" } diff --git a/substrate/utils/frame/remote-externalities/Cargo.toml b/substrate/utils/frame/remote-externalities/Cargo.toml index 61e0a861ee0e..82b019154832 100644 --- a/substrate/utils/frame/remote-externalities/Cargo.toml +++ b/substrate/utils/frame/remote-externalities/Cargo.toml @@ -26,7 +26,7 @@ sp-io = { path = "../../../primitives/io" } sp-runtime = { path = "../../../primitives/runtime" } tokio = { version = "1.22.0", features = ["macros", "rt-multi-thread"] } substrate-rpc-client = { path = "../rpc/client" } -futures = "0.3" +futures = "0.3.30" indicatif = "0.17.7" spinners = "4.1.0" tokio-retry = "0.3.0" diff --git a/substrate/utils/frame/rpc/client/Cargo.toml b/substrate/utils/frame/rpc/client/Cargo.toml index b51e3f44f4e6..501bb95b2579 100644 --- a/substrate/utils/frame/rpc/client/Cargo.toml +++ b/substrate/utils/frame/rpc/client/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] jsonrpsee = { version = "0.22", features = ["ws-client"] } sc-rpc-api = { path = "../../../../client/rpc-api" } -async-trait = "0.1.74" +async-trait = "0.1.79" serde = { workspace = true, default-features = true } sp-runtime = { path = "../../../../primitives/runtime" } log = { workspace = true, default-features = true } diff --git a/substrate/utils/frame/rpc/support/Cargo.toml b/substrate/utils/frame/rpc/support/Cargo.toml index 2e4bb6a10578..84db06da7b0d 100644 --- a/substrate/utils/frame/rpc/support/Cargo.toml +++ b/substrate/utils/frame/rpc/support/Cargo.toml @@ -23,9 +23,9 @@ sc-rpc-api = { path = "../../../../client/rpc-api" } sp-storage = { path = "../../../../primitives/storage" } [dev-dependencies] -scale-info = "2.10.0" +scale-info = "2.11.1" jsonrpsee = { version = "0.22", features = ["jsonrpsee-types", "ws-client"] } -tokio = "1.22.0" +tokio = "1.37" sp-core = { path = "../../../../primitives/core" } sp-runtime = { path = "../../../../primitives/runtime" } frame-system = { path = "../../../../frame/system" } diff --git a/substrate/utils/frame/rpc/system/Cargo.toml b/substrate/utils/frame/rpc/system/Cargo.toml index f9a84a01af82..9e571bef9d04 100644 --- a/substrate/utils/frame/rpc/system/Cargo.toml +++ b/substrate/utils/frame/rpc/system/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1" } jsonrpsee = { version = "0.22", features = ["client-core", "macros", "server"] } -futures = "0.3.21" +futures = "0.3.30" log = { workspace = true, default-features = true } frame-system-rpc-runtime-api = { path = "../../../../frame/system/rpc/runtime-api" } sc-rpc-api = { path = "../../../../client/rpc-api" } @@ -31,7 +31,7 @@ sp-runtime = { path = "../../../../primitives/runtime" } [dev-dependencies] sc-transaction-pool = { path = "../../../../client/transaction-pool" } -tokio = "1.22.0" +tokio = "1.37" assert_matches = "1.3.0" sp-tracing = { path = "../../../../primitives/tracing" } substrate-test-runtime-client = { path = "../../../../test-utils/runtime/client" } diff --git a/substrate/utils/frame/try-runtime/cli/Cargo.toml b/substrate/utils/frame/try-runtime/cli/Cargo.toml index 3ff57745a2db..618cb645475d 100644 --- a/substrate/utils/frame/try-runtime/cli/Cargo.toml +++ b/substrate/utils/frame/try-runtime/cli/Cargo.toml @@ -37,7 +37,7 @@ sp-weights = { path = "../../../../primitives/weights" } frame-try-runtime = { path = "../../../../frame/try-runtime", optional = true } substrate-rpc-client = { path = "../../rpc/client" } -async-trait = "0.1.74" +async-trait = "0.1.79" clap = { version = "4.5.3", features = ["derive"] } hex = { version = "0.4.3", default-features = false } log = { workspace = true, default-features = true } @@ -52,7 +52,7 @@ node-primitives = { path = "../../../../bin/node/primitives" } regex = "1.7.3" substrate-cli-test-utils = { path = "../../../../test-utils/cli" } tempfile = "3.1.0" -tokio = "1.27.0" +tokio = "1.37" [features] try-runtime = [ diff --git a/substrate/utils/wasm-builder/Cargo.toml b/substrate/utils/wasm-builder/Cargo.toml index 7abd1a202848..bac323e2e6a0 100644 --- a/substrate/utils/wasm-builder/Cargo.toml +++ b/substrate/utils/wasm-builder/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] build-helper = "0.1.1" cargo_metadata = "0.15.4" console = "0.15.8" -strum = { version = "0.24.1", features = ["derive"] } +strum = { version = "0.26.2", features = ["derive"] } tempfile = "3.1.0" toml = "0.8.8" walkdir = "2.4.0" diff --git a/templates/minimal/node/Cargo.toml b/templates/minimal/node/Cargo.toml index 41d9708ea607..0668304e5028 100644 --- a/templates/minimal/node/Cargo.toml +++ b/templates/minimal/node/Cargo.toml @@ -18,7 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] clap = { version = "4.5.3", features = ["derive"] } -futures = { version = "0.3.21", features = ["thread-pool"] } +futures = { version = "0.3.30", features = ["thread-pool"] } futures-timer = "3.0.1" jsonrpsee = { version = "0.22", features = ["server"] } serde_json = { workspace = true, default-features = true } diff --git a/templates/minimal/pallets/template/Cargo.toml b/templates/minimal/pallets/template/Cargo.toml index 9982e5ea53bc..a85391f29421 100644 --- a/templates/minimal/pallets/template/Cargo.toml +++ b/templates/minimal/pallets/template/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive", ], default-features = false } -scale-info = { version = "2.10.0", default-features = false, features = [ +scale-info = { version = "2.11.1", default-features = false, features = [ "derive", ] } frame = { path = "../../../../substrate/frame", default-features = false, features = [ diff --git a/templates/parachain/pallets/template/Cargo.toml b/templates/parachain/pallets/template/Cargo.toml index 89eb9d517163..199da2f12d2c 100644 --- a/templates/parachain/pallets/template/Cargo.toml +++ b/templates/parachain/pallets/template/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.10.0", default-features = false, features = [ +scale-info = { version = "2.11.1", default-features = false, features = [ "derive", ] } diff --git a/templates/parachain/runtime/Cargo.toml b/templates/parachain/runtime/Cargo.toml index 41a510c5ed35..0d985796a11e 100644 --- a/templates/parachain/runtime/Cargo.toml +++ b/templates/parachain/runtime/Cargo.toml @@ -24,7 +24,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = ] } hex-literal = { version = "0.4.1", optional = true } log = { workspace = true } -scale-info = { version = "2.10.0", default-features = false, features = [ +scale-info = { version = "2.11.1", default-features = false, features = [ "derive", ] } smallvec = "1.11.0" diff --git a/templates/solochain/node/Cargo.toml b/templates/solochain/node/Cargo.toml index a0bb5c27ed3b..1ddd1cb3a7b4 100644 --- a/templates/solochain/node/Cargo.toml +++ b/templates/solochain/node/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] clap = { version = "4.5.3", features = ["derive"] } -futures = { version = "0.3.21", features = ["thread-pool"] } +futures = { version = "0.3.30", features = ["thread-pool"] } serde_json = { workspace = true, default-features = true } jsonrpsee = { version = "0.22", features = ["server"] } diff --git a/templates/solochain/pallets/template/Cargo.toml b/templates/solochain/pallets/template/Cargo.toml index bd2347151989..24519f1d22e0 100644 --- a/templates/solochain/pallets/template/Cargo.toml +++ b/templates/solochain/pallets/template/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.10.0", default-features = false, features = [ +scale-info = { version = "2.11.1", default-features = false, features = [ "derive", ] } diff --git a/templates/solochain/runtime/Cargo.toml b/templates/solochain/runtime/Cargo.toml index 90dd823eb645..7a81f192043f 100644 --- a/templates/solochain/runtime/Cargo.toml +++ b/templates/solochain/runtime/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.10.0", default-features = false, features = [ +scale-info = { version = "2.11.1", default-features = false, features = [ "derive", "serde", ] } From b659b7dd494b50e0dbeb3e2ba1a792d90bf44b25 Mon Sep 17 00:00:00 2001 From: Dastan <88332432+dastansam@users.noreply.github.com> Date: Tue, 2 Apr 2024 15:43:09 +0200 Subject: [PATCH 105/257] migrations: prevent accidentally using unversioned migrations instead of `VersionedMigration` (#3835) closes #1324 #### Problem Currently, it is possible to accidentally use inner unversioned migration instead of `VersionedMigration` since both implement `OnRuntimeUpgrade`. #### Solution With this change, we make it clear that value of `Inner` is not intended to be used directly. It is achieved by bounding `Inner` to new trait `UncheckedOnRuntimeUpgrade`, which has the same interface (except `unchecked_` prefix) as `OnRuntimeUpgrade`. #### `try-runtime` functions Since developers can implement `try-runtime` for `Inner` value in `VersionedMigration` and have custom logic for it, I added the same `try-runtime` functions to `UncheckedOnRuntimeUpgrade`. I looked for a ways to not duplicate functions, but couldn't find anything that doesn't significantly change the codebase. So I would appreciate If you have any suggestions to improve this cc @liamaharon @xlc polkadot address: 16FqwPZ8GRC5U5D4Fu7W33nA55ZXzXGWHwmbnE1eT6pxuqcT --------- Co-authored-by: Liam Aharon --- cumulus/pallets/xcmp-queue/src/migration.rs | 9 +- .../common/src/assigned_slots/migration.rs | 5 +- .../common/src/paras_registrar/migration.rs | 4 +- .../src/assigner_on_demand/migration.rs | 8 +- .../src/configuration/migration/v10.rs | 10 +- .../src/configuration/migration/v11.rs | 8 +- .../src/configuration/migration/v12.rs | 4 +- .../parachains/src/inclusion/migration.rs | 10 +- .../parachains/src/scheduler/migration.rs | 9 +- polkadot/xcm/pallet-xcm/src/migration.rs | 4 +- prdoc/pr_3835.prdoc | 54 +++++ .../single-block-migrations/src/lib.rs | 24 +-- .../src/migrations/v1.rs | 196 ++++++++---------- substrate/frame/grandpa/src/migrations/v5.rs | 15 +- substrate/frame/identity/src/migration.rs | 6 +- .../frame/nomination-pools/src/migration.rs | 8 +- substrate/frame/society/src/migrations.rs | 4 +- substrate/frame/support/src/migrations.rs | 22 +- substrate/frame/support/src/traits.rs | 2 +- substrate/frame/support/src/traits/hooks.rs | 28 ++- .../support/test/tests/versioned_migration.rs | 8 +- substrate/frame/uniques/src/migration.rs | 8 +- 22 files changed, 257 insertions(+), 189 deletions(-) create mode 100644 prdoc/pr_3835.prdoc diff --git a/cumulus/pallets/xcmp-queue/src/migration.rs b/cumulus/pallets/xcmp-queue/src/migration.rs index c7fa61a3e3f0..1702cd70bc2f 100644 --- a/cumulus/pallets/xcmp-queue/src/migration.rs +++ b/cumulus/pallets/xcmp-queue/src/migration.rs @@ -20,7 +20,7 @@ use crate::{Config, OverweightIndex, Pallet, QueueConfig, QueueConfigData, DEFAU use cumulus_primitives_core::XcmpMessageFormat; use frame_support::{ pallet_prelude::*, - traits::{EnqueueMessage, OnRuntimeUpgrade, StorageVersion}, + traits::{EnqueueMessage, StorageVersion, UncheckedOnRuntimeUpgrade}, weights::{constants::WEIGHT_REF_TIME_PER_MILLIS, Weight}, }; @@ -96,7 +96,7 @@ pub mod v2 { /// 2D weights). pub struct UncheckedMigrationToV2(PhantomData); - impl OnRuntimeUpgrade for UncheckedMigrationToV2 { + impl UncheckedOnRuntimeUpgrade for UncheckedMigrationToV2 { #[allow(deprecated)] fn on_runtime_upgrade() -> Weight { let translate = |pre: v1::QueueConfigData| -> v2::QueueConfigData { @@ -187,7 +187,7 @@ pub mod v3 { /// Migrates the pallet storage to v3. pub struct UncheckedMigrationToV3(PhantomData); - impl OnRuntimeUpgrade for UncheckedMigrationToV3 { + impl UncheckedOnRuntimeUpgrade for UncheckedMigrationToV3 { fn on_runtime_upgrade() -> Weight { #[frame_support::storage_alias] type Overweight = @@ -266,7 +266,7 @@ pub mod v4 { /// thresholds to at least the default values. pub struct UncheckedMigrationToV4(PhantomData); - impl OnRuntimeUpgrade for UncheckedMigrationToV4 { + impl UncheckedOnRuntimeUpgrade for UncheckedMigrationToV4 { fn on_runtime_upgrade() -> Weight { let translate = |pre: v2::QueueConfigData| -> QueueConfigData { let pre_default = v2::QueueConfigData::default(); @@ -315,6 +315,7 @@ pub mod v4 { mod tests { use super::*; use crate::mock::{new_test_ext, Test}; + use frame_support::traits::OnRuntimeUpgrade; #[test] #[allow(deprecated)] diff --git a/polkadot/runtime/common/src/assigned_slots/migration.rs b/polkadot/runtime/common/src/assigned_slots/migration.rs index def6bad692a2..7e582dfa5963 100644 --- a/polkadot/runtime/common/src/assigned_slots/migration.rs +++ b/polkadot/runtime/common/src/assigned_slots/migration.rs @@ -15,7 +15,7 @@ // along with Polkadot. If not, see . use super::{Config, MaxPermanentSlots, MaxTemporarySlots, Pallet, LOG_TARGET}; -use frame_support::traits::{Get, GetStorageVersion, OnRuntimeUpgrade}; +use frame_support::traits::{Get, GetStorageVersion, UncheckedOnRuntimeUpgrade}; #[cfg(feature = "try-runtime")] use frame_support::ensure; @@ -23,10 +23,9 @@ use frame_support::ensure; use sp_std::vec::Vec; pub mod v1 { - use super::*; pub struct VersionUncheckedMigrateToV1(sp_std::marker::PhantomData); - impl OnRuntimeUpgrade for VersionUncheckedMigrateToV1 { + impl UncheckedOnRuntimeUpgrade for VersionUncheckedMigrateToV1 { #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { let on_chain_version = Pallet::::on_chain_storage_version(); diff --git a/polkadot/runtime/common/src/paras_registrar/migration.rs b/polkadot/runtime/common/src/paras_registrar/migration.rs index f977674a1e4e..18bb6bbfb559 100644 --- a/polkadot/runtime/common/src/paras_registrar/migration.rs +++ b/polkadot/runtime/common/src/paras_registrar/migration.rs @@ -15,7 +15,7 @@ // along with Polkadot. If not, see . use super::*; -use frame_support::traits::{Contains, OnRuntimeUpgrade}; +use frame_support::traits::{Contains, UncheckedOnRuntimeUpgrade}; #[derive(Encode, Decode)] pub struct ParaInfoV1 { @@ -27,7 +27,7 @@ pub struct ParaInfoV1 { pub struct VersionUncheckedMigrateToV1( sp_std::marker::PhantomData<(T, UnlockParaIds)>, ); -impl> OnRuntimeUpgrade +impl> UncheckedOnRuntimeUpgrade for VersionUncheckedMigrateToV1 { fn on_runtime_upgrade() -> Weight { diff --git a/polkadot/runtime/parachains/src/assigner_on_demand/migration.rs b/polkadot/runtime/parachains/src/assigner_on_demand/migration.rs index 5071653377d4..8589ddc292bd 100644 --- a/polkadot/runtime/parachains/src/assigner_on_demand/migration.rs +++ b/polkadot/runtime/parachains/src/assigner_on_demand/migration.rs @@ -18,7 +18,7 @@ use super::*; use frame_support::{ migrations::VersionedMigration, pallet_prelude::ValueQuery, storage_alias, - traits::OnRuntimeUpgrade, weights::Weight, + traits::UncheckedOnRuntimeUpgrade, weights::Weight, }; mod v0 { @@ -51,7 +51,7 @@ mod v1 { /// Migration to V1 pub struct UncheckedMigrateToV1(sp_std::marker::PhantomData); - impl OnRuntimeUpgrade for UncheckedMigrateToV1 { + impl UncheckedOnRuntimeUpgrade for UncheckedMigrateToV1 { fn on_runtime_upgrade() -> Weight { let mut weight: Weight = Weight::zero(); @@ -141,7 +141,7 @@ pub type MigrateV0ToV1 = VersionedMigration< #[cfg(test)] mod tests { - use super::{v0, v1, OnRuntimeUpgrade, Weight}; + use super::{v0, v1, UncheckedOnRuntimeUpgrade, Weight}; use crate::mock::{new_test_ext, MockGenesisConfig, OnDemandAssigner, Test}; use primitives::Id as ParaId; @@ -163,7 +163,7 @@ mod tests { // For tests, db weight is zero. assert_eq!( - as OnRuntimeUpgrade>::on_runtime_upgrade(), + as UncheckedOnRuntimeUpgrade>::on_runtime_upgrade(), Weight::zero() ); diff --git a/polkadot/runtime/parachains/src/configuration/migration/v10.rs b/polkadot/runtime/parachains/src/configuration/migration/v10.rs index 3c8d6084ace7..fa72c357d7da 100644 --- a/polkadot/runtime/parachains/src/configuration/migration/v10.rs +++ b/polkadot/runtime/parachains/src/configuration/migration/v10.rs @@ -17,7 +17,11 @@ //! A module that is responsible for migration of storage. use crate::configuration::{Config, Pallet}; -use frame_support::{pallet_prelude::*, traits::Defensive, weights::Weight}; +use frame_support::{ + pallet_prelude::*, + traits::{Defensive, UncheckedOnRuntimeUpgrade}, + weights::Weight, +}; use frame_system::pallet_prelude::BlockNumberFor; use primitives::{ AsyncBackingParams, Balance, ExecutorParams, NodeFeatures, SessionIndex, @@ -26,8 +30,6 @@ use primitives::{ use sp_runtime::Perbill; use sp_std::vec::Vec; -use frame_support::traits::OnRuntimeUpgrade; - use super::v9::V9HostConfiguration; // All configuration of the runtime with respect to paras. #[derive(Clone, Encode, PartialEq, Decode, Debug)] @@ -163,7 +165,7 @@ mod v10 { } pub struct VersionUncheckedMigrateToV10(sp_std::marker::PhantomData); -impl OnRuntimeUpgrade for VersionUncheckedMigrateToV10 { +impl UncheckedOnRuntimeUpgrade for VersionUncheckedMigrateToV10 { #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { log::trace!(target: crate::configuration::LOG_TARGET, "Running pre_upgrade() for HostConfiguration MigrateToV10"); diff --git a/polkadot/runtime/parachains/src/configuration/migration/v11.rs b/polkadot/runtime/parachains/src/configuration/migration/v11.rs index 7ed9d0868855..65656e8d7c06 100644 --- a/polkadot/runtime/parachains/src/configuration/migration/v11.rs +++ b/polkadot/runtime/parachains/src/configuration/migration/v11.rs @@ -18,7 +18,10 @@ use crate::configuration::{self, Config, Pallet}; use frame_support::{ - migrations::VersionedMigration, pallet_prelude::*, traits::Defensive, weights::Weight, + migrations::VersionedMigration, + pallet_prelude::*, + traits::{Defensive, UncheckedOnRuntimeUpgrade}, + weights::Weight, }; use frame_system::pallet_prelude::BlockNumberFor; use primitives::{ @@ -27,7 +30,6 @@ use primitives::{ }; use sp_std::vec::Vec; -use frame_support::traits::OnRuntimeUpgrade; use polkadot_core_primitives::Balance; use sp_arithmetic::Perbill; @@ -176,7 +178,7 @@ pub type MigrateToV11 = VersionedMigration< >; pub struct UncheckedMigrateToV11(sp_std::marker::PhantomData); -impl OnRuntimeUpgrade for UncheckedMigrateToV11 { +impl UncheckedOnRuntimeUpgrade for UncheckedMigrateToV11 { #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { log::trace!(target: crate::configuration::LOG_TARGET, "Running pre_upgrade() for HostConfiguration MigrateToV11"); diff --git a/polkadot/runtime/parachains/src/configuration/migration/v12.rs b/polkadot/runtime/parachains/src/configuration/migration/v12.rs index 4295a79893e8..69bacc83d044 100644 --- a/polkadot/runtime/parachains/src/configuration/migration/v12.rs +++ b/polkadot/runtime/parachains/src/configuration/migration/v12.rs @@ -20,7 +20,7 @@ use crate::configuration::{self, migration::v11::V11HostConfiguration, Config, P use frame_support::{ migrations::VersionedMigration, pallet_prelude::*, - traits::{Defensive, OnRuntimeUpgrade}, + traits::{Defensive, UncheckedOnRuntimeUpgrade}, }; use frame_system::pallet_prelude::BlockNumberFor; use primitives::vstaging::SchedulerParams; @@ -70,7 +70,7 @@ pub type MigrateToV12 = VersionedMigration< pub struct UncheckedMigrateToV12(sp_std::marker::PhantomData); -impl OnRuntimeUpgrade for UncheckedMigrateToV12 { +impl UncheckedOnRuntimeUpgrade for UncheckedMigrateToV12 { #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { log::trace!(target: crate::configuration::LOG_TARGET, "Running pre_upgrade() for HostConfiguration MigrateToV12"); diff --git a/polkadot/runtime/parachains/src/inclusion/migration.rs b/polkadot/runtime/parachains/src/inclusion/migration.rs index 1e63b209f4e7..5f35680ee694 100644 --- a/polkadot/runtime/parachains/src/inclusion/migration.rs +++ b/polkadot/runtime/parachains/src/inclusion/migration.rs @@ -73,7 +73,7 @@ mod v1 { CandidatePendingAvailability as V1CandidatePendingAvailability, Config, Pallet, PendingAvailability as V1PendingAvailability, }; - use frame_support::{traits::OnRuntimeUpgrade, weights::Weight}; + use frame_support::{traits::UncheckedOnRuntimeUpgrade, weights::Weight}; use sp_core::Get; use sp_std::{collections::vec_deque::VecDeque, vec::Vec}; @@ -87,7 +87,7 @@ mod v1 { pub struct VersionUncheckedMigrateToV1(sp_std::marker::PhantomData); - impl OnRuntimeUpgrade for VersionUncheckedMigrateToV1 { + impl UncheckedOnRuntimeUpgrade for VersionUncheckedMigrateToV1 { #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { log::trace!(target: crate::inclusion::LOG_TARGET, "Running pre_upgrade() for inclusion MigrateToV1"); @@ -216,7 +216,7 @@ mod tests { }, mock::{new_test_ext, MockGenesisConfig, Test}, }; - use frame_support::traits::OnRuntimeUpgrade; + use frame_support::traits::UncheckedOnRuntimeUpgrade; use primitives::{AvailabilityBitfield, Id as ParaId}; use test_helpers::{dummy_candidate_commitments, dummy_candidate_descriptor, dummy_hash}; @@ -225,7 +225,7 @@ mod tests { new_test_ext(MockGenesisConfig::default()).execute_with(|| { // No data to migrate. assert_eq!( - as OnRuntimeUpgrade>::on_runtime_upgrade(), + as UncheckedOnRuntimeUpgrade>::on_runtime_upgrade(), Weight::zero() ); assert!(V1PendingAvailability::::iter().next().is_none()); @@ -299,7 +299,7 @@ mod tests { // For tests, db weight is zero. assert_eq!( - as OnRuntimeUpgrade>::on_runtime_upgrade(), + as UncheckedOnRuntimeUpgrade>::on_runtime_upgrade(), Weight::zero() ); diff --git a/polkadot/runtime/parachains/src/scheduler/migration.rs b/polkadot/runtime/parachains/src/scheduler/migration.rs index c47fbab046fe..b030940fb41d 100644 --- a/polkadot/runtime/parachains/src/scheduler/migration.rs +++ b/polkadot/runtime/parachains/src/scheduler/migration.rs @@ -19,7 +19,7 @@ use super::*; use frame_support::{ migrations::VersionedMigration, pallet_prelude::ValueQuery, storage_alias, - traits::OnRuntimeUpgrade, weights::Weight, + traits::UncheckedOnRuntimeUpgrade, weights::Weight, }; /// Old/legacy assignment representation (v0). @@ -105,7 +105,8 @@ mod v0 { // - Assignments only consist of `ParaId`, `Assignment` is a concrete type (Same as V0Assignment). mod v1 { use frame_support::{ - pallet_prelude::ValueQuery, storage_alias, traits::OnRuntimeUpgrade, weights::Weight, + pallet_prelude::ValueQuery, storage_alias, traits::UncheckedOnRuntimeUpgrade, + weights::Weight, }; use frame_system::pallet_prelude::BlockNumberFor; @@ -164,7 +165,7 @@ mod v1 { /// Migration to V1 pub struct UncheckedMigrateToV1(sp_std::marker::PhantomData); - impl OnRuntimeUpgrade for UncheckedMigrateToV1 { + impl UncheckedOnRuntimeUpgrade for UncheckedMigrateToV1 { fn on_runtime_upgrade() -> Weight { let mut weight: Weight = Weight::zero(); @@ -302,7 +303,7 @@ mod v2 { /// Migration to V2 pub struct UncheckedMigrateToV2(sp_std::marker::PhantomData); - impl OnRuntimeUpgrade for UncheckedMigrateToV2 { + impl UncheckedOnRuntimeUpgrade for UncheckedMigrateToV2 { fn on_runtime_upgrade() -> Weight { let mut weight: Weight = Weight::zero(); diff --git a/polkadot/xcm/pallet-xcm/src/migration.rs b/polkadot/xcm/pallet-xcm/src/migration.rs index 018436aa3c93..b157e6b5c3d5 100644 --- a/polkadot/xcm/pallet-xcm/src/migration.rs +++ b/polkadot/xcm/pallet-xcm/src/migration.rs @@ -19,7 +19,7 @@ use crate::{ }; use frame_support::{ pallet_prelude::*, - traits::{OnRuntimeUpgrade, StorageVersion}, + traits::{OnRuntimeUpgrade, StorageVersion, UncheckedOnRuntimeUpgrade}, weights::Weight, }; @@ -35,7 +35,7 @@ pub mod v1 { /// /// Use experimental [`MigrateToV1`] instead. pub struct VersionUncheckedMigrateToV1(sp_std::marker::PhantomData); - impl OnRuntimeUpgrade for VersionUncheckedMigrateToV1 { + impl UncheckedOnRuntimeUpgrade for VersionUncheckedMigrateToV1 { fn on_runtime_upgrade() -> Weight { let mut weight = T::DbWeight::get().reads(1); diff --git a/prdoc/pr_3835.prdoc b/prdoc/pr_3835.prdoc new file mode 100644 index 000000000000..d2f49f8fc116 --- /dev/null +++ b/prdoc/pr_3835.prdoc @@ -0,0 +1,54 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: "migrations: prevent accidentally using inner unversioned migration instead of `VersionedMigration`" + +doc: + - audience: Runtime Dev + description: | + Currently, it is possible to accidentally use inner unversioned migration instead of `VersionedMigration` + since both implement `OnRuntimeUpgrade`. With this change, we make it clear that `Inner` is not intended + to be used directly. It is achieved by bounding `Inner` to new trait `UncheckedOnRuntimeUpgrade`, which + has the same interface as `OnRuntimeUpgrade`, but can not be used directly for runtime upgrade migrations. + + This change will break all existing migrations passed to `VersionedMigration`. Developers should simply change + those migrations to implement `UncheckedOnRuntimeUpgrade` instead of `OnRuntimeUpgrade`. + + Example: + + ``` + --- a/path/to/migration.rs + +++ b/path/to/migration.rs + @@ -1,7 +1,7 @@ + -impl OnRuntimeUpgrade for MigrateVNToVM { + +impl UncheckedOnRuntimeUpgrade for MigrateVNToVM { + fn on_runtime_upgrade() -> Weight { + // Migration logic here + // Adjust the migration logic if necessary to align with the expectations + // of new `UncheckedOnRuntimeUpgrade` trait. + 0 + } + } + ``` + +crates: + - name: "pallet-example-single-block-migrations" + bump: "major" + - name: "pallet-xcm" + bump: "major" + - name: "pallet-grandpa" + bump: "major" + - name: "pallet-identity" + bump: "major" + - name: "pallet-nomination-pools" + bump: "major" + - name: "pallet-society" + bump: "major" + - name: "frame-support" + bump: "major" + - name: "pallet-uniques" + bump: "major" + - name: "polkadot-runtime-parachains" + bump: "major" + - name: "polkadot-runtime-common" + bump: "major" diff --git a/substrate/frame/examples/single-block-migrations/src/lib.rs b/substrate/frame/examples/single-block-migrations/src/lib.rs index b36d52622678..411537aa8c65 100644 --- a/substrate/frame/examples/single-block-migrations/src/lib.rs +++ b/substrate/frame/examples/single-block-migrations/src/lib.rs @@ -89,7 +89,7 @@ //! //! See the migration source code for detailed comments. //! -//! To keep the migration logic organised, it is split across additional modules: +//! Here's a brief overview of modules and types defined in `v1.rs`: //! //! ### `mod v0` //! @@ -98,28 +98,29 @@ //! //! This allows reading the old v0 value from storage during the migration. //! -//! ### `mod version_unchecked` +//! ### `InnerMigrateV0ToV1` //! //! Here we define our raw migration logic, -//! `version_unchecked::MigrateV0ToV1` which implements the [`OnRuntimeUpgrade`] trait. +//! `InnerMigrateV0ToV1` which implements the [`UncheckedOnRuntimeUpgrade`] trait. //! -//! Importantly, it is kept in a private module so that it cannot be accidentally used in a runtime. +//! #### Why [`UncheckedOnRuntimeUpgrade`]? //! -//! Private modules cannot be referenced in docs, so please read the code directly. +//! Otherwise, we would have two implementations of [`OnRuntimeUpgrade`] which could be confusing, +//! and may lead to accidentally using the wrong one. //! //! #### Standalone Struct or Pallet Hook? //! //! Note that the storage migration logic is attached to a standalone struct implementing -//! [`OnRuntimeUpgrade`], rather than implementing the +//! [`UncheckedOnRuntimeUpgrade`], rather than implementing the //! [`Hooks::on_runtime_upgrade`](frame_support::traits::Hooks::on_runtime_upgrade) hook directly on //! the pallet. The pallet hook is better suited for special types of logic that need to execute on //! every runtime upgrade, but not so much for one-off storage migrations. //! -//! ### `pub mod versioned` +//! ### `MigrateV0ToV1` //! -//! Here, `version_unchecked::MigrateV0ToV1` is wrapped in a +//! Here, `InnerMigrateV0ToV1` is wrapped in a //! [`VersionedMigration`] to define -//! [`versioned::MigrateV0ToV1`](crate::migrations::v1::versioned::MigrateV0ToV1), which may be used +//! [`MigrateV0ToV1`](crate::migrations::v1::MigrateV0ToV1), which may be used //! in runtimes. //! //! Using [`VersionedMigration`] ensures that @@ -128,8 +129,6 @@ //! - Reads and writes from checking and setting the on-chain storage version are accounted for in //! the final [`Weight`](frame_support::weights::Weight) //! -//! This is the only public module exported from `v1`. -//! //! ### `mod test` //! //! Here basic unit tests are defined for the migration. @@ -142,7 +141,8 @@ //! [`VersionedMigration`]: frame_support::migrations::VersionedMigration //! [`GetStorageVersion`]: frame_support::traits::GetStorageVersion //! [`OnRuntimeUpgrade`]: frame_support::traits::OnRuntimeUpgrade -//! [`MigrateV0ToV1`]: crate::migrations::v1::versioned::MigrationV0ToV1 +//! [`UncheckedOnRuntimeUpgrade`]: frame_support::traits::UncheckedOnRuntimeUpgrade +//! [`MigrateV0ToV1`]: crate::migrations::v1::MigrateV0ToV1 // We make sure this pallet uses `no_std` for compiling to Wasm. #![cfg_attr(not(feature = "std"), no_std)] diff --git a/substrate/frame/examples/single-block-migrations/src/migrations/v1.rs b/substrate/frame/examples/single-block-migrations/src/migrations/v1.rs index b46640a32020..18ef4e72cc4f 100644 --- a/substrate/frame/examples/single-block-migrations/src/migrations/v1.rs +++ b/substrate/frame/examples/single-block-migrations/src/migrations/v1.rs @@ -17,7 +17,7 @@ use frame_support::{ storage_alias, - traits::{Get, OnRuntimeUpgrade}, + traits::{Get, UncheckedOnRuntimeUpgrade}, }; #[cfg(feature = "try-runtime")] @@ -34,118 +34,92 @@ mod v0 { pub type Value = StorageValue, u32>; } -/// Private module containing *version unchecked* migration logic. +/// Implements [`UncheckedOnRuntimeUpgrade`], migrating the state of this pallet from V0 to V1. /// -/// Should only be used by the [`VersionedMigration`](frame_support::migrations::VersionedMigration) -/// type in this module to create something to export. +/// In V0 of the template [`crate::Value`] is just a `u32`. In V1, it has been upgraded to +/// contain the struct [`crate::CurrentAndPreviousValue`]. /// -/// The unversioned migration should be kept private so the unversioned migration cannot -/// accidentally be used in any runtimes. -/// -/// For more about this pattern of keeping items private, see -/// - -/// - -mod version_unchecked { - use super::*; +/// In this migration, update the on-chain storage for the pallet to reflect the new storage +/// layout. +pub struct InnerMigrateV0ToV1(sp_std::marker::PhantomData); + +impl UncheckedOnRuntimeUpgrade for InnerMigrateV0ToV1 { + /// Return the existing [`crate::Value`] so we can check that it was correctly set in + /// `InnerMigrateV0ToV1::post_upgrade`. + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { + use codec::Encode; + + // Access the old value using the `storage_alias` type + let old_value = v0::Value::::get(); + // Return it as an encoded `Vec` + Ok(old_value.encode()) + } - /// Implements [`OnRuntimeUpgrade`], migrating the state of this pallet from V0 to V1. - /// - /// In V0 of the template [`crate::Value`] is just a `u32`. In V1, it has been upgraded to - /// contain the struct [`crate::CurrentAndPreviousValue`]. + /// Migrate the storage from V0 to V1. /// - /// In this migration, update the on-chain storage for the pallet to reflect the new storage - /// layout. - pub struct MigrateV0ToV1(sp_std::marker::PhantomData); - - impl OnRuntimeUpgrade for MigrateV0ToV1 { - /// Return the existing [`crate::Value`] so we can check that it was correctly set in - /// `version_unchecked::MigrateV0ToV1::post_upgrade`. - #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { - use codec::Encode; - - // Access the old value using the `storage_alias` type - let old_value = v0::Value::::get(); - // Return it as an encoded `Vec` - Ok(old_value.encode()) - } - - /// Migrate the storage from V0 to V1. - /// - /// - If the value doesn't exist, there is nothing to do. - /// - If the value exists, it is read and then written back to storage inside a - /// [`crate::CurrentAndPreviousValue`]. - fn on_runtime_upgrade() -> frame_support::weights::Weight { - // Read the old value from storage - if let Some(old_value) = v0::Value::::take() { - // Write the new value to storage - let new = crate::CurrentAndPreviousValue { current: old_value, previous: None }; - crate::Value::::put(new); - // One read for the old value, one write for the new value - T::DbWeight::get().reads_writes(1, 1) - } else { - // One read for trying to access the old value - T::DbWeight::get().reads(1) - } + /// - If the value doesn't exist, there is nothing to do. + /// - If the value exists, it is read and then written back to storage inside a + /// [`crate::CurrentAndPreviousValue`]. + fn on_runtime_upgrade() -> frame_support::weights::Weight { + // Read the old value from storage + if let Some(old_value) = v0::Value::::take() { + // Write the new value to storage + let new = crate::CurrentAndPreviousValue { current: old_value, previous: None }; + crate::Value::::put(new); + // One read for the old value, one write for the new value + T::DbWeight::get().reads_writes(1, 1) + } else { + // One read for trying to access the old value + T::DbWeight::get().reads(1) } + } - /// Verifies the storage was migrated correctly. - /// - /// - If there was no old value, the new value should not be set. - /// - If there was an old value, the new value should be a - /// [`crate::CurrentAndPreviousValue`]. - #[cfg(feature = "try-runtime")] - fn post_upgrade(state: Vec) -> Result<(), sp_runtime::TryRuntimeError> { - use codec::Decode; - use frame_support::ensure; - - let maybe_old_value = Option::::decode(&mut &state[..]).map_err(|_| { - sp_runtime::TryRuntimeError::Other("Failed to decode old value from storage") - })?; - - match maybe_old_value { - Some(old_value) => { - let expected_new_value = - crate::CurrentAndPreviousValue { current: old_value, previous: None }; - let actual_new_value = crate::Value::::get(); - - ensure!(actual_new_value.is_some(), "New value not set"); - ensure!( - actual_new_value == Some(expected_new_value), - "New value not set correctly" - ); - }, - None => { - ensure!(crate::Value::::get().is_none(), "New value unexpectedly set"); - }, - }; - Ok(()) - } + /// Verifies the storage was migrated correctly. + /// + /// - If there was no old value, the new value should not be set. + /// - If there was an old value, the new value should be a [`crate::CurrentAndPreviousValue`]. + #[cfg(feature = "try-runtime")] + fn post_upgrade(state: Vec) -> Result<(), sp_runtime::TryRuntimeError> { + use codec::Decode; + use frame_support::ensure; + + let maybe_old_value = Option::::decode(&mut &state[..]).map_err(|_| { + sp_runtime::TryRuntimeError::Other("Failed to decode old value from storage") + })?; + + match maybe_old_value { + Some(old_value) => { + let expected_new_value = + crate::CurrentAndPreviousValue { current: old_value, previous: None }; + let actual_new_value = crate::Value::::get(); + + ensure!(actual_new_value.is_some(), "New value not set"); + ensure!( + actual_new_value == Some(expected_new_value), + "New value not set correctly" + ); + }, + None => { + ensure!(crate::Value::::get().is_none(), "New value unexpectedly set"); + }, + }; + Ok(()) } } -/// Public module containing *version checked* migration logic. -/// -/// This is the only module that should be exported from this module. -/// -/// See [`VersionedMigration`](frame_support::migrations::VersionedMigration) docs for more about -/// how it works. -pub mod versioned { - use super::*; - - /// `version_unchecked::MigrateV0ToV1` wrapped in a - /// [`VersionedMigration`](frame_support::migrations::VersionedMigration), which ensures that: - /// - The migration only runs once when the on-chain storage version is 0 - /// - The on-chain storage version is updated to `1` after the migration executes - /// - Reads/Writes from checking/settings the on-chain storage version are accounted for - pub type MigrateV0ToV1 = frame_support::migrations::VersionedMigration< - 0, // The migration will only execute when the on-chain storage version is 0 - 1, // The on-chain storage version will be set to 1 after the migration is complete - version_unchecked::MigrateV0ToV1, - crate::pallet::Pallet, - ::DbWeight, - >; -} +/// [`UncheckedOnRuntimeUpgrade`] implementation [`InnerMigrateV0ToV1`] wrapped in a +/// [`VersionedMigration`](frame_support::migrations::VersionedMigration), which ensures that: +/// - The migration only runs once when the on-chain storage version is 0 +/// - The on-chain storage version is updated to `1` after the migration executes +/// - Reads/Writes from checking/settings the on-chain storage version are accounted for +pub type MigrateV0ToV1 = frame_support::migrations::VersionedMigration< + 0, // The migration will only execute when the on-chain storage version is 0 + 1, // The on-chain storage version will be set to 1 after the migration is complete + InnerMigrateV0ToV1, + crate::pallet::Pallet, + ::DbWeight, +>; /// Tests for our migration. /// @@ -155,10 +129,10 @@ pub mod versioned { /// 3. The storage is in the expected state after the migration #[cfg(any(all(feature = "try-runtime", test), doc))] mod test { + use self::InnerMigrateV0ToV1; use super::*; use crate::mock::{new_test_ext, MockRuntime}; use frame_support::assert_ok; - use version_unchecked::MigrateV0ToV1; #[test] fn handles_no_existing_value() { @@ -168,16 +142,16 @@ mod test { assert!(v0::Value::::get().is_none()); // Get the pre_upgrade bytes - let bytes = match MigrateV0ToV1::::pre_upgrade() { + let bytes = match InnerMigrateV0ToV1::::pre_upgrade() { Ok(bytes) => bytes, Err(e) => panic!("pre_upgrade failed: {:?}", e), }; // Execute the migration - let weight = MigrateV0ToV1::::on_runtime_upgrade(); + let weight = InnerMigrateV0ToV1::::on_runtime_upgrade(); // Verify post_upgrade succeeds - assert_ok!(MigrateV0ToV1::::post_upgrade(bytes)); + assert_ok!(InnerMigrateV0ToV1::::post_upgrade(bytes)); // The weight should be just 1 read for trying to access the old value. assert_eq!(weight, ::DbWeight::get().reads(1)); @@ -195,16 +169,16 @@ mod test { v0::Value::::put(initial_value); // Get the pre_upgrade bytes - let bytes = match MigrateV0ToV1::::pre_upgrade() { + let bytes = match InnerMigrateV0ToV1::::pre_upgrade() { Ok(bytes) => bytes, Err(e) => panic!("pre_upgrade failed: {:?}", e), }; // Execute the migration - let weight = MigrateV0ToV1::::on_runtime_upgrade(); + let weight = InnerMigrateV0ToV1::::on_runtime_upgrade(); // Verify post_upgrade succeeds - assert_ok!(MigrateV0ToV1::::post_upgrade(bytes)); + assert_ok!(InnerMigrateV0ToV1::::post_upgrade(bytes)); // The weight used should be 1 read for the old value, and 1 write for the new // value. diff --git a/substrate/frame/grandpa/src/migrations/v5.rs b/substrate/frame/grandpa/src/migrations/v5.rs index 24cfc34104b5..a0865a3f2bf9 100644 --- a/substrate/frame/grandpa/src/migrations/v5.rs +++ b/substrate/frame/grandpa/src/migrations/v5.rs @@ -20,7 +20,7 @@ use codec::Decode; use frame_support::{ migrations::VersionedMigration, storage, - traits::{Get, OnRuntimeUpgrade}, + traits::{Get, UncheckedOnRuntimeUpgrade}, weights::Weight, }; use sp_consensus_grandpa::AuthorityList; @@ -36,9 +36,9 @@ fn load_authority_list() -> AuthorityList { } /// Actual implementation of [`MigrateV4ToV5`]. -pub struct MigrateImpl(PhantomData); +pub struct UncheckedMigrateImpl(PhantomData); -impl OnRuntimeUpgrade for MigrateImpl { +impl UncheckedOnRuntimeUpgrade for UncheckedMigrateImpl { #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { use codec::Encode; @@ -92,5 +92,10 @@ impl OnRuntimeUpgrade for MigrateImpl { /// Migrate the storage from V4 to V5. /// /// Switches from `GRANDPA_AUTHORITIES_KEY` to a normal FRAME storage item. -pub type MigrateV4ToV5 = - VersionedMigration<4, 5, MigrateImpl, Pallet, ::DbWeight>; +pub type MigrateV4ToV5 = VersionedMigration< + 4, + 5, + UncheckedMigrateImpl, + Pallet, + ::DbWeight, +>; diff --git a/substrate/frame/identity/src/migration.rs b/substrate/frame/identity/src/migration.rs index 88ac08d1bf56..8725bfd39df1 100644 --- a/substrate/frame/identity/src/migration.rs +++ b/substrate/frame/identity/src/migration.rs @@ -16,7 +16,9 @@ //! Storage migrations for the Identity pallet. use super::*; -use frame_support::{migrations::VersionedMigration, pallet_prelude::*, traits::OnRuntimeUpgrade}; +use frame_support::{ + migrations::VersionedMigration, pallet_prelude::*, traits::UncheckedOnRuntimeUpgrade, +}; #[cfg(feature = "try-runtime")] use codec::{Decode, Encode}; @@ -66,7 +68,7 @@ pub mod v1 { /// prevent stalling a parachain by accumulating too much weight in the migration. To have an /// unlimited migration (e.g. in a chain without PoV limits), set this to `u64::MAX`. pub struct VersionUncheckedMigrateV0ToV1(PhantomData); - impl OnRuntimeUpgrade for VersionUncheckedMigrateV0ToV1 { + impl UncheckedOnRuntimeUpgrade for VersionUncheckedMigrateV0ToV1 { #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, TryRuntimeError> { let identities = v0::IdentityOf::::iter().count(); diff --git a/substrate/frame/nomination-pools/src/migration.rs b/substrate/frame/nomination-pools/src/migration.rs index d19e46c49d0b..781aed63d132 100644 --- a/substrate/frame/nomination-pools/src/migration.rs +++ b/substrate/frame/nomination-pools/src/migration.rs @@ -17,7 +17,7 @@ use super::*; use crate::log; -use frame_support::traits::OnRuntimeUpgrade; +use frame_support::traits::{OnRuntimeUpgrade, UncheckedOnRuntimeUpgrade}; use sp_std::{collections::btree_map::BTreeMap, vec::Vec}; #[cfg(feature = "try-runtime")] @@ -203,7 +203,7 @@ pub mod v8 { } pub struct VersionUncheckedMigrateV7ToV8(sp_std::marker::PhantomData); - impl OnRuntimeUpgrade for VersionUncheckedMigrateV7ToV8 { + impl UncheckedOnRuntimeUpgrade for VersionUncheckedMigrateV7ToV8 { #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, TryRuntimeError> { Ok(Vec::new()) @@ -282,7 +282,7 @@ pub(crate) mod v7 { CountedStorageMap, Twox64Concat, PoolId, V7BondedPoolInner>; pub struct VersionUncheckedMigrateV6ToV7(sp_std::marker::PhantomData); - impl OnRuntimeUpgrade for VersionUncheckedMigrateV6ToV7 { + impl UncheckedOnRuntimeUpgrade for VersionUncheckedMigrateV6ToV7 { fn on_runtime_upgrade() -> Weight { let migrated = BondedPools::::count(); // The TVL should be the sum of all the funds that are actively staked and in the @@ -353,7 +353,7 @@ mod v6 { }) } } - impl OnRuntimeUpgrade for MigrateToV6 { + impl UncheckedOnRuntimeUpgrade for MigrateToV6 { fn on_runtime_upgrade() -> Weight { let mut success = 0u64; let mut fail = 0u64; diff --git a/substrate/frame/society/src/migrations.rs b/substrate/frame/society/src/migrations.rs index 8fd87b1163a4..7ded1f84f582 100644 --- a/substrate/frame/society/src/migrations.rs +++ b/substrate/frame/society/src/migrations.rs @@ -19,7 +19,7 @@ use super::*; use codec::{Decode, Encode}; -use frame_support::traits::{Defensive, DefensiveOption, Instance, OnRuntimeUpgrade}; +use frame_support::traits::{Defensive, DefensiveOption, Instance, UncheckedOnRuntimeUpgrade}; #[cfg(feature = "try-runtime")] use sp_runtime::TryRuntimeError; @@ -36,7 +36,7 @@ impl< T: Config, I: Instance + 'static, PastPayouts: Get::AccountId, BalanceOf)>>, - > OnRuntimeUpgrade for VersionUncheckedMigrateToV2 + > UncheckedOnRuntimeUpgrade for VersionUncheckedMigrateToV2 { #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, TryRuntimeError> { diff --git a/substrate/frame/support/src/migrations.rs b/substrate/frame/support/src/migrations.rs index 2ceab44cb16b..b8cbcd690481 100644 --- a/substrate/frame/support/src/migrations.rs +++ b/substrate/frame/support/src/migrations.rs @@ -41,19 +41,19 @@ use sp_std::{marker::PhantomData, vec::Vec}; /// It takes 5 type parameters: /// - `From`: The version being upgraded from. /// - `To`: The version being upgraded to. -/// - `Inner`: An implementation of `OnRuntimeUpgrade`. +/// - `Inner`: An implementation of `UncheckedOnRuntimeUpgrade`. /// - `Pallet`: The Pallet being upgraded. /// - `Weight`: The runtime's RuntimeDbWeight implementation. /// /// When a [`VersionedMigration`] `on_runtime_upgrade`, `pre_upgrade`, or `post_upgrade` method is /// called, the on-chain version of the pallet is compared to `From`. If they match, the `Inner` -/// equivalent is called and the pallets on-chain version is set to `To` after the migration. -/// Otherwise, a warning is logged notifying the developer that the upgrade was a noop and should -/// probably be removed. +/// `UncheckedOnRuntimeUpgrade` is called and the pallets on-chain version is set to `To` +/// after the migration. Otherwise, a warning is logged notifying the developer that the upgrade was +/// a noop and should probably be removed. /// -/// It is STRONGLY RECOMMENDED to write the unversioned migration logic in a private module and -/// only export the versioned migration logic to prevent accidentally using the unversioned -/// migration in any runtimes. +/// By not bounding `Inner` with `OnRuntimeUpgrade`, we prevent developers from +/// accidentally using the unchecked version of the migration in a runtime upgrade instead of +/// [`VersionedMigration`]. /// /// ### Examples /// ```ignore @@ -71,9 +71,9 @@ use sp_std::{marker::PhantomData, vec::Vec}; /// /// - https://internals.rust-lang.org/t/lang-team-minutes-private-in-public-rules/4504/40 /// mod version_unchecked { /// use super::*; -/// pub struct MigrateV5ToV6(sp_std::marker::PhantomData); -/// impl OnRuntimeUpgrade for VersionUncheckedMigrateV5ToV6 { -/// // OnRuntimeUpgrade implementation... +/// pub struct VersionUncheckedMigrateV5ToV6(sp_std::marker::PhantomData); +/// impl UncheckedOnRuntimeUpgrade for VersionUncheckedMigrateV5ToV6 { +/// // `UncheckedOnRuntimeUpgrade` implementation... /// } /// } /// @@ -116,7 +116,7 @@ pub enum VersionedPostUpgradeData { impl< const FROM: u16, const TO: u16, - Inner: crate::traits::OnRuntimeUpgrade, + Inner: crate::traits::UncheckedOnRuntimeUpgrade, Pallet: GetStorageVersion + PalletInfoAccess, DbWeight: Get, > crate::traits::OnRuntimeUpgrade for VersionedMigration diff --git a/substrate/frame/support/src/traits.rs b/substrate/frame/support/src/traits.rs index 24e7e1c8a65c..66777cef7b8e 100644 --- a/substrate/frame/support/src/traits.rs +++ b/substrate/frame/support/src/traits.rs @@ -87,7 +87,7 @@ pub use hooks::GenesisBuild; pub use hooks::{ BeforeAllRuntimeMigrations, BuildGenesisConfig, Hooks, IntegrityTest, OnFinalize, OnGenesis, OnIdle, OnInitialize, OnPoll, OnRuntimeUpgrade, OnTimestampSet, PostInherents, - PostTransactions, PreInherents, + PostTransactions, PreInherents, UncheckedOnRuntimeUpgrade, }; pub mod schedule; diff --git a/substrate/frame/support/src/traits/hooks.rs b/substrate/frame/support/src/traits/hooks.rs index d83e27047458..ccccc5063286 100644 --- a/substrate/frame/support/src/traits/hooks.rs +++ b/substrate/frame/support/src/traits/hooks.rs @@ -227,6 +227,30 @@ pub trait OnRuntimeUpgrade { } } +/// This trait is intended for use within `VersionedMigration` to execute storage migrations without +/// automatic version checks. Implementations should ensure migration logic is safe and idempotent. +pub trait UncheckedOnRuntimeUpgrade { + /// Called within `VersionedMigration` to execute the actual migration. It is also + /// expected that no version checks are performed within this function. + /// + /// See also [`Hooks::on_runtime_upgrade`]. + fn on_runtime_upgrade() -> Weight { + Weight::zero() + } + + /// See [`Hooks::pre_upgrade`]. + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, TryRuntimeError> { + Ok(Vec::new()) + } + + /// See [`Hooks::post_upgrade`]. + #[cfg(feature = "try-runtime")] + fn post_upgrade(_state: Vec) -> Result<(), TryRuntimeError> { + Ok(()) + } +} + #[cfg_attr(all(not(feature = "tuples-96"), not(feature = "tuples-128")), impl_for_tuples(64))] #[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))] #[cfg_attr(feature = "tuples-128", impl_for_tuples(128))] @@ -459,7 +483,9 @@ pub trait Hooks { /// ## Implementation Note: Standalone Migrations /// /// Additional migrations can be created by directly implementing [`OnRuntimeUpgrade`] on - /// structs and passing them to `Executive`. + /// structs and passing them to `Executive`. Or alternatively, by implementing + /// [`UncheckedOnRuntimeUpgrade`], passing it to [`crate::migrations::VersionedMigration`], + /// which already implements [`OnRuntimeUpgrade`]. /// /// ## Implementation Note: Pallet Versioning /// diff --git a/substrate/frame/support/test/tests/versioned_migration.rs b/substrate/frame/support/test/tests/versioned_migration.rs index 3fdfb902129e..e7d146940cb9 100644 --- a/substrate/frame/support/test/tests/versioned_migration.rs +++ b/substrate/frame/support/test/tests/versioned_migration.rs @@ -23,7 +23,7 @@ use frame_support::{ construct_runtime, derive_impl, migrations::VersionedMigration, parameter_types, - traits::{GetStorageVersion, OnRuntimeUpgrade, StorageVersion}, + traits::{GetStorageVersion, OnRuntimeUpgrade, StorageVersion, UncheckedOnRuntimeUpgrade}, weights::constants::RocksDbWeight, }; use frame_system::Config; @@ -103,9 +103,11 @@ parameter_types! { static PostUpgradeCalledWith: Vec = Vec::new(); } -/// Implement `OnRuntimeUpgrade` for `SomeUnversionedMigration`. +/// Implement `UncheckedOnRuntimeUpgrade` for `SomeUnversionedMigration`. /// It sets SomeStorage to S, and returns a weight derived from UpgradeReads and UpgradeWrites. -impl OnRuntimeUpgrade for SomeUnversionedMigration { +impl UncheckedOnRuntimeUpgrade + for SomeUnversionedMigration +{ fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { PreUpgradeCalled::set(true); Ok(PreUpgradeReturnBytes::get().to_vec()) diff --git a/substrate/frame/uniques/src/migration.rs b/substrate/frame/uniques/src/migration.rs index ba0855a6bb65..90d44e7790d6 100644 --- a/substrate/frame/uniques/src/migration.rs +++ b/substrate/frame/uniques/src/migration.rs @@ -18,15 +18,15 @@ //! Various pieces of common functionality. use super::*; use core::marker::PhantomData; -use frame_support::traits::{Get, OnRuntimeUpgrade}; +use frame_support::traits::{Get, UncheckedOnRuntimeUpgrade}; mod v1 { use super::*; /// Actual implementation of the storage migration. - pub struct MigrateToV1Impl(PhantomData<(T, I)>); + pub struct UncheckedMigrateToV1Impl(PhantomData<(T, I)>); - impl, I: 'static> OnRuntimeUpgrade for MigrateToV1Impl { + impl, I: 'static> UncheckedOnRuntimeUpgrade for UncheckedMigrateToV1Impl { fn on_runtime_upgrade() -> frame_support::weights::Weight { let mut count = 0; for (collection, detail) in Collection::::iter() { @@ -49,7 +49,7 @@ mod v1 { pub type MigrateV0ToV1 = frame_support::migrations::VersionedMigration< 0, 1, - v1::MigrateToV1Impl, + v1::UncheckedMigrateToV1Impl, Pallet, ::DbWeight, >; From 0a986104cb4e03d5422d89ded714529a5f11cac6 Mon Sep 17 00:00:00 2001 From: Clara van Staden Date: Tue, 2 Apr 2024 15:53:05 +0200 Subject: [PATCH 106/257] Snowbridge: Synchronize from Snowfork repository (#3761) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR includes the following 2 improvements: ## Ethereum Client Author: @yrong ### Original Upstream PRs - https://github.com/Snowfork/polkadot-sdk/pull/123 - https://github.com/Snowfork/polkadot-sdk/pull/125 ### Description The Ethereum client syncs beacon headers as they are finalized, and imports every execution header. When a message is received, it is verified against the import execution header. This is unnecessary, since the execution header can be sent with the message as proof. The recent Deneb Ethereum upgrade made it easier to locate the relevant beacon header from an execution header, and so this improvement was made possible. This resolves a concern @svyatonik had in our initial Rococo PR: https://github.com/paritytech/polkadot-sdk/pull/2522#discussion_r1431270691 ## Inbound Queue Author: @yrong ### Original Upstream PR - https://github.com/Snowfork/polkadot-sdk/pull/118 ### Description When the AH sovereign account (who pays relayer rewards) is depleted, the inbound message will not fail. The relayer just will not receive rewards. Both these changes were done by @yrong, many thanks. ❤️ --------- Co-authored-by: claravanstaden Co-authored-by: Ron Co-authored-by: Vincent Geddes Co-authored-by: Svyatoslav Nikolsky --- .../ethereum-client/fixtures/src/lib.rs | 272 ++++++---- .../ethereum-client/src/benchmarking/mod.rs | 18 - .../pallets/ethereum-client/src/impls.rs | 138 +++-- .../pallets/ethereum-client/src/lib.rs | 237 +-------- .../pallets/ethereum-client/src/mock.rs | 61 +-- .../pallets/ethereum-client/src/tests.rs | 474 +++++------------- .../pallets/ethereum-client/src/types.rs | 12 +- .../pallets/ethereum-client/src/weights.rs | 7 - .../fixtures/execution-header-update.json | 54 -- .../tests/fixtures/execution-proof.json | 54 ++ .../fixtures/finalized-header-update.json | 48 +- .../tests/fixtures/inbound-message.json | 94 +++- .../tests/fixtures/initial-checkpoint.json | 30 +- .../tests/fixtures/sync-committee-update.json | 42 +- .../pallets/inbound-queue/fixtures/src/lib.rs | 11 - .../fixtures/src/register_token.rs | 84 +++- .../register_token_with_insufficient_fee.rs | 42 -- .../inbound-queue/fixtures/src/send_token.rs | 82 ++- .../fixtures/src/send_token_to_penpal.rs | 86 +++- .../inbound-queue/src/benchmarking/mod.rs | 4 +- .../pallets/inbound-queue/src/lib.rs | 25 +- .../pallets/inbound-queue/src/mock.rs | 45 +- .../pallets/inbound-queue/src/test.rs | 83 ++- .../snowbridge/primitives/beacon/src/lib.rs | 8 +- .../snowbridge/primitives/beacon/src/types.rs | 100 ++-- .../primitives/beacon/src/updates.rs | 47 +- .../snowbridge/primitives/core/src/inbound.rs | 18 +- .../snowbridge/runtime/test-common/src/lib.rs | 22 - .../snowbridge/scripts/contribute-upstream.sh | 6 + .../bridge-hub-rococo/src/tests/snowbridge.rs | 148 +++--- .../assets/asset-hub-rococo/src/xcm_config.rs | 4 +- .../bridge-hubs/bridge-hub-rococo/src/lib.rs | 13 +- .../snowbridge_pallet_ethereum_client.rs | 22 - .../snowbridge_pallet_inbound_queue.rs | 14 +- prdoc/pr_3761.prdoc | 25 + 35 files changed, 1123 insertions(+), 1307 deletions(-) delete mode 100755 bridges/snowbridge/pallets/ethereum-client/tests/fixtures/execution-header-update.json create mode 100755 bridges/snowbridge/pallets/ethereum-client/tests/fixtures/execution-proof.json delete mode 100644 bridges/snowbridge/pallets/inbound-queue/fixtures/src/register_token_with_insufficient_fee.rs create mode 100644 prdoc/pr_3761.prdoc diff --git a/bridges/snowbridge/pallets/ethereum-client/fixtures/src/lib.rs b/bridges/snowbridge/pallets/ethereum-client/fixtures/src/lib.rs index facaffb8149c..37fe45ba60b0 100644 --- a/bridges/snowbridge/pallets/ethereum-client/fixtures/src/lib.rs +++ b/bridges/snowbridge/pallets/ethereum-client/fixtures/src/lib.rs @@ -6,9 +6,10 @@ use hex_literal::hex; use snowbridge_beacon_primitives::{ - types::deneb, updates::AncestryProof, BeaconHeader, ExecutionHeaderUpdate, - NextSyncCommitteeUpdate, SyncAggregate, SyncCommittee, VersionedExecutionPayloadHeader, + types::deneb, AncestryProof, BeaconHeader, ExecutionProof, NextSyncCommitteeUpdate, + SyncAggregate, SyncCommittee, VersionedExecutionPayloadHeader, }; +use snowbridge_core::inbound::{InboundQueueFixture, Log, Message, Proof}; use sp_core::U256; use sp_std::{boxed::Box, vec}; @@ -20,11 +21,11 @@ type Update = snowbridge_beacon_primitives::Update; pub fn make_checkpoint() -> Box { Box::new(CheckpointUpdate { header: BeaconHeader { - slot: 2496, - proposer_index: 2, - parent_root: hex!("c99e49787106733eeebab4d93eb326e1f2214575c9d928f0c4ab0da0776f1622").into(), - state_root: hex!("fbf8a08c86ef36bd173e37e733da4a78aa8e85fee99a990e858dd12a59087fde").into(), - body_root: hex!("a2a8ad06901447b2807a9059580a4c40d8a941f325b1343c69f7c7c6c90e4ab0").into(), + slot: 864, + proposer_index: 4, + parent_root: hex!("614e7672f991ac268cd841055973f55e1e42228831a211adef207bb7329be614").into(), + state_root: hex!("5fa8dfca3d760e4242ab46d529144627aa85348a19173b6e081172c701197a4a").into(), + body_root: hex!("0f34c083b1803666bb1ac5e73fa71582731a2cf37d279ff0a3b0cad5a2ff371e").into(), }, current_sync_committee: SyncCommittee { pubkeys: [ @@ -544,20 +545,20 @@ pub fn make_checkpoint() -> Box { aggregate_pubkey: hex!("8fbd66eeec2ff69ef0b836f04b1d67d88bcd4dfd495061964ad757c77abe822a39fa1cd8ed0d4d9bc9276cea73fd745c").into(), }, current_sync_committee_branch: vec![ - hex!("3ade38d498a062b50880a9409e1ca3a7fd4315d91eeb3bb83e56ac6bfe8d6a59").into(), - hex!("93880225bf99a0c5ec22b266ff829837754e9c5edf37a68c05b8f803fd82fa45").into(), - hex!("4c60656ec9a95fcf11030ad309c716b5b15beb7f60a0bcfc7c9d4eff505472ff").into(), - hex!("22d1645fceb4bf9a695043dda19a53e784ec70df6a6b1bd66ea30eba1cca5f2f").into(), - hex!("a8fc6cad84ceefc633ec56c2d031d525e1cb4b51c70eb252919fce5bba9a1fde").into(), + hex!("3ade38d498a062b50880a9409e1ca3a7fd4315d91eeb3bb83e56ac6bfe8d6a59").into(), + hex!("a9e90f89e7f90fd5d79a6bbcaf40ba5cfc05ab1b561ac51c84867c32248d5b1e").into(), + hex!("bd1a76b03e02402bb24a627de1980a80ab17691980271f597b844b89b497ef75").into(), + hex!("07bbcd27c7cad089023db046eda17e8209842b7d97add8b873519e84fe6480e7").into(), + hex!("94c11eeee4cb6192bf40810f23486d8c75dfbc2b6f28d988d6f74435ede243b0").into(), ], validators_root: hex!("270d43e74ce340de4bca2b1936beca0f4f5408d9e78aec4850920baf659d5b69").into(), - block_roots_root: hex!("d160b7687041891b73e54b06fc4e04f82d0fa8fdd76705895e216c6b24709dfe").into(), + block_roots_root: hex!("b9aab9c388c4e4fcd899b71f62c498fc73406e38e8eb14aa440e9affa06f2a10").into(), block_roots_branch: vec![ - hex!("105290e42d98ab6a0ada6e55453cede36c672abf645eeb986b88d7487616e135").into(), - hex!("9da41f274bcdf6122335443d9ce94d07163b48dba3e2f9499ff56f4e48b48b99").into(), - hex!("ecea7e1d3152d8130e83afdfe34b4de4ba2b69a33c9471991096daf454de9cf5").into(), - hex!("b2bf1758e50b2bfff29169fbc70fdb884b2b05bb615dbc53567574da6f4f1ae2").into(), - hex!("cd87069daf70975779126d6af833b7d636c75ca4d5e750ebcad0e76408a5e5bf").into(), + hex!("733422bd810895dab74cbbe07c69dd440cbb51f573181ad4dddac30fcdd0f41f").into(), + hex!("9b9eca73ab01d14549c325ba1b4610bb20bf1f8ec2dbd649f9d8cc7f3cea75fa").into(), + hex!("bcc666ad0ad9f9725cbd682bc95589d35b1b53b2a615f1e6e8dd5e086336becf").into(), + hex!("3069b547a08f703a1715016e926cbd64e71f93f64fb68d98d8c8f1ab745c46e5").into(), + hex!("c2de7e1097239404e17b263cfa0473533cc41e903cb03440d633bc5c27314cb4").into(), ], }) } @@ -567,13 +568,13 @@ pub fn make_sync_committee_update() -> Box { attested_header: BeaconHeader { slot: 129, proposer_index: 5, - parent_root: hex!("e32b6c18f029e755b0273dc1c4fa2bc4979794c8286ad40276c1b8a8e36049d8").into(), - state_root: hex!("5ec9dacf25a5f09f20be0c59246b3d8dcfe64bd085b4bac5cec180690339801e").into(), - body_root: hex!("4080cf2412d6ff77fc3164ad6155423a7112f207f173145ec16371a93f481f87").into(), + parent_root: hex!("c2def03fe44a2802130ca1a6d8406e4ccf4f344fec7075d4d84431cd4a8b0904").into(), + state_root: hex!("fa62cde6666add7353d7aedcb61ebe3c6c84b5361e34f814825b1250affb5be4").into(), + body_root: hex!("0f9c69f243fe7b5fa5860396c66c720a9e8b1e526e7914188930497cc4a9134c").into(), }, sync_aggregate: SyncAggregate{ sync_committee_bits: hex!("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), - sync_committee_signature: hex!("a761c3333fbb3d36bc8f65454f898da38001499dcd37494cf3d86940a995399ae649216ba4c985af154f83f72c8b1856079b7636a7a8d7d3f7602df2cbf699edb72b65253e82de4d9cc4db7377eafb22f799129f63f094a21c00675bdd5cc243").into(), + sync_committee_signature: hex!("810cfde2afea3e276256c09bdf1cd321c33dcadeefddcfd24f488e6f756d917cfda90b5b437b3a4b4ef880985afa28a40cf565ec0a82877ddee36adc01d55d9d4a911ae3e22556e4c2636f1c707366fba019fb49450440fcd263d0b054b04bf0").into(), }, signature_slot: 130, next_sync_committee_update: Some(NextSyncCommitteeUpdate { @@ -1096,34 +1097,34 @@ pub fn make_sync_committee_update() -> Box { }, next_sync_committee_branch: vec![ hex!("3ade38d498a062b50880a9409e1ca3a7fd4315d91eeb3bb83e56ac6bfe8d6a59").into(), - hex!("fd1e5ff5d4a15081efe3ff17857b1f95984c9a271b1c41c2f81f43e60c2cc541").into(), - hex!("e1c97f93bb7352d395d1ff8ee29881572cb7eb5d71634783701171dcd30cd93d").into(), - hex!("77fa2170ddbd89b15dae02f2e6cf9f76c8e00d1c4217320acffbe01576d0da61").into(), - hex!("e97288e0627219087a024078d69445f34f0583a6350a7c3c40c39fd1fa6f8d68").into(), + hex!("43276bee17fc9fba3f4866e902f0e5b5b308d79db91154bb8bf819973837a7d9").into(), + hex!("5572348e13ce59446ca0ea7cfeed07579da05f121920a76559e19bda94dd81cd").into(), + hex!("2d58adca9f3c742530de037f1933d6de1920ea4b68581613d4bc32b71547f221").into(), + hex!("7072b3c6577cd5a89b3234968f316f54630bb97eafbdb59e5b61637a9640255f").into(), ], }), finalized_header: BeaconHeader{ slot: 64, proposer_index: 4, - parent_root: hex!("0f7bc2353778c14c7f6dba0fc5fe6eec87228b0d3a5447b61dce67b4d9338de3").into(), - state_root: hex!("feb990de653ce494c0a263f820eaf05a9300dbdc30cb6065ede602827bfccde4").into(), - body_root: hex!("f5235cd8c24f2695fc5b7989926305c10ad8cf5a87d62a739f675f5543df2ec1").into(), + parent_root: hex!("a876486aaad7ddb897f369fd22d0a9903cd61d00c9e0dfe7998dd68d1008c678").into(), + state_root: hex!("818e21c3388575f8ccc9ff17ec79d5a57915bcd31bccf47770f65a18e068416b").into(), + body_root: hex!("1d1f73b864b3bb7e11ff91b56ca1381e0f9ca8122b2c542db88243604c763019").into(), }, finality_branch: vec![ hex!("0200000000000000000000000000000000000000000000000000000000000000").into(), hex!("10c726fac935bf9657cc7476d3cfa7bedec5983dcfb59e8a7df6d0a619e108d7").into(), hex!("98e9116c6bb7f20de18800dc63e73e689d06d6a47d35b5e2b32cf093d475840d").into(), - hex!("e1c97f93bb7352d395d1ff8ee29881572cb7eb5d71634783701171dcd30cd93d").into(), - hex!("77fa2170ddbd89b15dae02f2e6cf9f76c8e00d1c4217320acffbe01576d0da61").into(), - hex!("e97288e0627219087a024078d69445f34f0583a6350a7c3c40c39fd1fa6f8d68").into(), + hex!("5572348e13ce59446ca0ea7cfeed07579da05f121920a76559e19bda94dd81cd").into(), + hex!("2d58adca9f3c742530de037f1933d6de1920ea4b68581613d4bc32b71547f221").into(), + hex!("7072b3c6577cd5a89b3234968f316f54630bb97eafbdb59e5b61637a9640255f").into(), ], - block_roots_root: hex!("6fcdfd1c3fb1bdd421fe59dddfff3855b5ed5e30373887991a0059d019ad12bc").into(), + block_roots_root: hex!("715b08694bef183a6d94b3113d16a7129f89fc3edec85a7e0eaf6ef9153552ef").into(), block_roots_branch: vec![ - hex!("94b59531f172bc24f914bc0c10104ccb158676850f8cc3b47b6ddb7f096ebdd7").into(), - hex!("22470ed9155a938587d44d5fa19217c0f939d8862e504e67cd8cb4d1b960795e").into(), - hex!("feec3ef1a68f93849e71e84f90b99602cccc31868137b6887ca8244a4b979e8e").into(), + hex!("4028c72c71b6ce80ea7d18b2c9471f4e4fa39746261a9921e832a4a2f9bdf7bb").into(), + hex!("75f98062661785d3290b7bd998b64446582baa49210733fd4603e1a97cd45a44").into(), + hex!("6fb757f44052f30c464810f01b0132adfa1a5446d8715b41e9af88eee1ee3e65").into(), hex!("5340ad5877c72dca689ca04bc8fedb78d67a4801d99887937edd8ccd29f87e82").into(), - hex!("f5ff4b0c6190005015889879568f5f0d9c40134c7ec4ffdda47950dcd92395ad").into(), + hex!("f2b3cb56753939a728ccad399a434ca490f018f2f331529ec0d8b2d59c509271").into(), ], }) } @@ -1131,95 +1132,180 @@ pub fn make_sync_committee_update() -> Box { pub fn make_finalized_header_update() -> Box { Box::new(Update { attested_header: BeaconHeader { - slot: 2566, - proposer_index: 6, - parent_root: hex!("6eb9f13a2c496318ce1ab3087bbd872f5c9519a1a7ca8231a2453e3cb523af00").into(), - state_root: hex!("c8cb12766113dff7e46d2917267bf33d0626d99dd47715fcdbc5c65fad3c04b4").into(), - body_root: hex!("d8cfd0d7bc9bc3724417a1655bb0a67c0765ca36197320f4d834150b52ef1420").into(), + slot: 933, + proposer_index: 1, + parent_root: hex!("f5fc63e2780ca302b97aea73fc95d74d702b5afe9a772c2b68f695026337b620").into(), + state_root: hex!("d856d11636bc4d866e78be9e747b222b0977556a367ab42e4085277301438050").into(), + body_root: hex!("5689091ab4eb76c2e876271add4924e1c66ce987c300c24aac2ad8c703e9a33f").into(), }, sync_aggregate: SyncAggregate{ sync_committee_bits: hex!("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), - sync_committee_signature: hex!("9296f9a0387f2cac47008e22ad7c3cd3d49d35384c13e6aa1eacca7dca7c3d2ca81515e50eb3396b9550ed20ef7d8fa2049a186598feb2c00e93728045fcff917733d1827481b8fc95f3913e27fc70112c2490496eb57bb7181f02c3f9fd471f").into(), + sync_committee_signature: hex!("93a3d482fe2a2f7fd2b634169752a8fddf1dc28b23a020b398be8526faf37a74ca0f6db1bed78a9c7256c09a6115235e108e0e8a7ce09287317b0856c4b77dfa5adba6cf4c3ebea5bfa4cd2fcde80fd0a532f2defe65d530201d5d2258796559").into(), }, - signature_slot: 2567, + signature_slot: 934, next_sync_committee_update: None, finalized_header: BeaconHeader { - slot: 2496, - proposer_index: 2, - parent_root: hex!("c99e49787106733eeebab4d93eb326e1f2214575c9d928f0c4ab0da0776f1622").into(), - state_root: hex!("fbf8a08c86ef36bd173e37e733da4a78aa8e85fee99a990e858dd12a59087fde").into(), - body_root: hex!("a2a8ad06901447b2807a9059580a4c40d8a941f325b1343c69f7c7c6c90e4ab0").into(), + slot: 864, + proposer_index: 4, + parent_root: hex!("614e7672f991ac268cd841055973f55e1e42228831a211adef207bb7329be614").into(), + state_root: hex!("5fa8dfca3d760e4242ab46d529144627aa85348a19173b6e081172c701197a4a").into(), + body_root: hex!("0f34c083b1803666bb1ac5e73fa71582731a2cf37d279ff0a3b0cad5a2ff371e").into(), }, finality_branch: vec![ - hex!("4e00000000000000000000000000000000000000000000000000000000000000").into(), + hex!("1b00000000000000000000000000000000000000000000000000000000000000").into(), hex!("10c726fac935bf9657cc7476d3cfa7bedec5983dcfb59e8a7df6d0a619e108d7").into(), hex!("98e9116c6bb7f20de18800dc63e73e689d06d6a47d35b5e2b32cf093d475840d").into(), - hex!("958b8e43347f6df6fa5eb3d62d06a862381a6585aa40640dd1c0de11f1cf89c1").into(), - hex!("f107dce04faa86a28fc5d4a618be9cb8d4fc3c23d6c42c3624f3ff4bf6586a03").into(), - hex!("a501cdc02e86969ac3e4d0c5a36f4f049efaa1ab8cb6693f51d130eb52a80f30").into(), + hex!("f12d9aededc72724e417b518fe6f847684f26f81616243dedf8c551cc7d504f5").into(), + hex!("89a85d0907ab3fd6e00ae385f61d456c6191646404ae7b8d23d0e60440cf4d00").into(), + hex!("9fc943b6020eb61d780d78bcc6f6102a81d2c868d58f36e61c6e286a2dc4d8c2").into(), ], - block_roots_root: hex!("d160b7687041891b73e54b06fc4e04f82d0fa8fdd76705895e216c6b24709dfe").into(), + block_roots_root: hex!("b9aab9c388c4e4fcd899b71f62c498fc73406e38e8eb14aa440e9affa06f2a10").into(), block_roots_branch: vec![ - hex!("105290e42d98ab6a0ada6e55453cede36c672abf645eeb986b88d7487616e135").into(), - hex!("9da41f274bcdf6122335443d9ce94d07163b48dba3e2f9499ff56f4e48b48b99").into(), - hex!("ecea7e1d3152d8130e83afdfe34b4de4ba2b69a33c9471991096daf454de9cf5").into(), - hex!("b2bf1758e50b2bfff29169fbc70fdb884b2b05bb615dbc53567574da6f4f1ae2").into(), - hex!("cd87069daf70975779126d6af833b7d636c75ca4d5e750ebcad0e76408a5e5bf").into(), + hex!("733422bd810895dab74cbbe07c69dd440cbb51f573181ad4dddac30fcdd0f41f").into(), + hex!("9b9eca73ab01d14549c325ba1b4610bb20bf1f8ec2dbd649f9d8cc7f3cea75fa").into(), + hex!("bcc666ad0ad9f9725cbd682bc95589d35b1b53b2a615f1e6e8dd5e086336becf").into(), + hex!("3069b547a08f703a1715016e926cbd64e71f93f64fb68d98d8c8f1ab745c46e5").into(), + hex!("c2de7e1097239404e17b263cfa0473533cc41e903cb03440d633bc5c27314cb4").into(), ] }) } -pub fn make_execution_header_update() -> Box { - Box::new(ExecutionHeaderUpdate { +pub fn make_execution_proof() -> Box { + Box::new(ExecutionProof { header: BeaconHeader { - slot: 215, - proposer_index: 2, - parent_root: hex!("97518f531a252bb6ca547b21aca9da767943ec99211d3b15c804e34c3a523f45").into(), - state_root: hex!("b088b5a3a8c90d6dc919a695cd7bb0267c6f983ea2e675c559ceb8f46cb90b67").into(), - body_root: hex!("0ba23c8224fdd01531d5ad51486353bd524a0b4c20bca704e26d3210616f829b").into(), + slot: 393, + proposer_index: 4, + parent_root: hex!("6545b47a614a1dd4cad042a0cdbbf5be347e8ffcdc02c6c64540d5153acebeef").into(), + state_root: hex!("b62ac34a8cb82497be9542fe2114410c9f6021855b766015406101a1f3d86434").into(), + body_root: hex!("04005fe231e11a5b7b1580cb73b177ae8b338bedd745497e6bb7122126a806db").into(), }, ancestry_proof: Some(AncestryProof { header_branch: vec![ - hex!("97518f531a252bb6ca547b21aca9da767943ec99211d3b15c804e34c3a523f45").into(), - hex!("5ce0db996bd499c2b4f7a93263d5aafd052f420efb617cce6fdd54e25516aa45").into(), - hex!("84f0e373b66011ce774c7061440c0a50a51cce2b4b335395eee3e563d605597f").into(), - hex!("48f9ccc5f9594142c18c3b5c39a99f0549329c6ab3ba06c9a50030eadca87770").into(), - hex!("f89d6e311e05bc75a6f63ce118bccce254551f1a88d54c3b4f773f81f946bd99").into(), - hex!("2edd6d893c22636675147c07dfcdb541a146e87c3f15b51c388be4868246dc9b").into(), - hex!("d76b7de5f856e3208a91a42c9c398a7f4fab35e667bf916346050ae742514a2d").into(), - hex!("83a2e233e76385953ca41de4c3afe60471a61f0cc1b3846b4a0670e3e563b747").into(), - hex!("e783a5a109c2ad74e4eb53e8f6b11b31266a92a9e16c1fd5873109c5d41b282c").into(), - hex!("d4ea1ef3869ee6a0fd0b19d7d70027d144eecd4f1d32cbf47632a0a9069164b9").into(), - hex!("f8179564b58eb93a850d35e4156a04db651106442ad891c3e85155c1762792f1").into(), - hex!("4cbb1edb48cf1e32fb30db60aaaeaf6190ffe4d0c8dbc96cec307daecb78be12").into(), + hex!("6545b47a614a1dd4cad042a0cdbbf5be347e8ffcdc02c6c64540d5153acebeef").into(), + hex!("fa84cc88ca53a72181599ff4eb07d8b444bce023fe2347c3b4f51004c43439d3").into(), + hex!("cadc8ae211c6f2221c9138e829249adf902419c78eb4727a150baa4d9a02cc9d").into(), + hex!("33a89962df08a35c52bd7e1d887cd71fa7803e68787d05c714036f6edf75947c").into(), + hex!("2c9760fce5c2829ef3f25595a703c21eb22d0186ce223295556ed5da663a82cf").into(), + hex!("e1aa87654db79c8a0ecd6c89726bb662fcb1684badaef5cd5256f479e3c622e1").into(), + hex!("aa70d5f314e4a1fbb9c362f3db79b21bf68b328887248651fbd29fc501d0ca97").into(), + hex!("160b6c235b3a1ed4ef5f80b03ee1c76f7bf3f591c92fca9d8663e9221b9f9f0f").into(), + hex!("f68d7dcd6a07a18e9de7b5d2aa1980eb962e11d7dcb584c96e81a7635c8d2535").into(), + hex!("1d5f912dfd6697110dd1ecb5cb8e77952eef57d85deb373572572df62bb157fc").into(), + hex!("ffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b").into(), + hex!("6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220").into(), hex!("b7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f").into(), ], - finalized_block_root: hex!("890a7f23b9ed2160901654be9efc575d6830ca860e2a97866ae3423fb7bd7231").into(), + finalized_block_root: hex!("751414cd97c0624f922b3e80285e9f776b08fa22fd5f87391f2ed7ef571a8d46").into(), }), execution_header: VersionedExecutionPayloadHeader::Deneb(deneb::ExecutionPayloadHeader { - parent_hash: hex!("d82ec63f5c5e6ba61d62f09c188f158e6449b94bdcc31941e68639eec3c4cf7a").into(), + parent_hash: hex!("8092290aa21b7751576440f77edd02a94058429ce50e63a92d620951fb25eda2").into(), fee_recipient: hex!("0000000000000000000000000000000000000000").into(), - state_root: hex!("8b65545fe5f3216b47b6339b9c91ca2b7f1032a970b04246d9e9fb4460ee34c3").into(), - receipts_root: hex!("7b1f61b9714c080ef0be014e01657a15f45f0304b477beebc7ca5596c8033095").into(), - logs_bloom: hex!("00000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000080000000000000000000000000000004000000000080000000000000000000000000000000000010100000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000040004000000000000002000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000200000000000010").into(), - prev_randao: hex!("6d9e2a012d82b1b6cb0a2c1c1ed24cc16dbb56e6e39ae545371e0666ab057862").into(), - block_number: 215, - gas_limit: 64842908, - gas_used: 119301, - timestamp: 1705859527, - extra_data: hex!("d983010d0a846765746888676f312e32312e358664617277696e").into(), + state_root: hex!("96a83e9ddf745346fafcb0b03d57314623df669ed543c110662b21302a0fae8b").into(), + receipts_root: hex!("dccdfceea05036f7b61dcdabadc937945d31e68a8d3dfd4dc85684457988c284").into(), + logs_bloom: hex!("00000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000080000000400000000000000000000004000000000080000000000000000000000000000000000010100000000000000000000000000000000020000000000000000000000000000000000080000000000000000000000000000040004000000000000002002002000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000200000200000010").into(), + prev_randao: hex!("62e309d4f5119d1f5c783abc20fc1a549efbab546d8d0b25ff1cfd58be524e67").into(), + block_number: 393, + gas_limit: 54492273, + gas_used: 199644, + timestamp: 1710552813, + extra_data: hex!("d983010d0b846765746888676f312e32312e368664617277696e").into(), base_fee_per_gas: U256::from(7u64), - block_hash: hex!("48498dbfbcfae53a7f4c289ee00747aceea925f6260c50ead5a33e1c55c40f98").into(), - transactions_root: hex!("5ebc1347fe3df0611d4f66b19bd8e1c6f4eaed0371d850f14c83b1c77ea234e6").into(), + block_hash: hex!("6a9810efb9581d30c1a5c9074f27c68ea779a8c1ae31c213241df16225f4e131").into(), + transactions_root: hex!("2cfa6ed7327e8807c7973516c5c32a68ef2459e586e8067e113d081c3bd8c07d").into(), withdrawals_root: hex!("792930bbd5baac43bcc798ee49aa8185ef76bb3b44ba62b91d86ae569e4bb535").into(), blob_gas_used: 0, excess_blob_gas: 0, }), execution_branch: vec![ - hex!("f8c69d3830406d668619bcccc13c8dddde41e863326f7418b241d5924c4ad34a").into(), + hex!("a6833fa629f3286b6916c6e50b8bf089fc9126bee6f64d0413b4e59c1265834d").into(), hex!("b46f0c01805fe212e15907981b757e6c496b0cb06664224655613dcec82505bb").into(), hex!("db56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71").into(), - hex!("f4d6b5cf9c6e212615c3674fa625d04eb1114153fb221ef5ad02aa433fc67cfb").into(), + hex!("d3af7c05c516726be7505239e0b9c7cb53d24abce6b91cdb3b3995f0164a75da").into(), ], }) } + +pub fn make_inbound_fixture() -> InboundQueueFixture { + InboundQueueFixture { + message: Message { + event_log: Log { + address: hex!("eda338e4dc46038493b885327842fd3e301cab39").into(), + topics: vec![ + hex!("7153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84f").into(), + hex!("c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539").into(), + hex!("5f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0").into(), + ], + data: hex!("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002e00a736aa00000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d00e40b54020000000000000000000000000000000000000000000000000000000000").into(), + }, + proof: Proof { + receipt_proof: (vec![ + hex!("dccdfceea05036f7b61dcdabadc937945d31e68a8d3dfd4dc85684457988c284").to_vec(), + hex!("4a98e45a319168b0fc6005ce6b744ee9bf54338e2c0784b976a8578d241ced0f").to_vec(), + ], vec![ + hex!("f851a09c01dd6d2d8de951c45af23d3ad00829ce021c04d6c8acbe1612d456ee320d4980808080808080a04a98e45a319168b0fc6005ce6b744ee9bf54338e2c0784b976a8578d241ced0f8080808080808080").to_vec(), + hex!("f9028c30b9028802f90284018301d205b9010000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000080000000000000000000000000000004000000000080000000000000000000000000000000000010100000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000040004000000000000002000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000200000000000010f90179f85894eda338e4dc46038493b885327842fd3e301cab39e1a0f78bb28d4b1d7da699e5c0bc2be29c2b04b5aab6aacf6298fe5304f9db9c6d7ea000000000000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7df9011c94eda338e4dc46038493b885327842fd3e301cab39f863a07153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84fa0c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539a05f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0b8a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002e00a736aa00000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d00e40b54020000000000000000000000000000000000000000000000000000000000").to_vec(), + ]), + execution_proof: ExecutionProof { + header: BeaconHeader { + slot: 393, + proposer_index: 4, + parent_root: hex!("6545b47a614a1dd4cad042a0cdbbf5be347e8ffcdc02c6c64540d5153acebeef").into(), + state_root: hex!("b62ac34a8cb82497be9542fe2114410c9f6021855b766015406101a1f3d86434").into(), + body_root: hex!("04005fe231e11a5b7b1580cb73b177ae8b338bedd745497e6bb7122126a806db").into(), + }, + ancestry_proof: Some(AncestryProof { + header_branch: vec![ + hex!("6545b47a614a1dd4cad042a0cdbbf5be347e8ffcdc02c6c64540d5153acebeef").into(), + hex!("fa84cc88ca53a72181599ff4eb07d8b444bce023fe2347c3b4f51004c43439d3").into(), + hex!("cadc8ae211c6f2221c9138e829249adf902419c78eb4727a150baa4d9a02cc9d").into(), + hex!("33a89962df08a35c52bd7e1d887cd71fa7803e68787d05c714036f6edf75947c").into(), + hex!("2c9760fce5c2829ef3f25595a703c21eb22d0186ce223295556ed5da663a82cf").into(), + hex!("e1aa87654db79c8a0ecd6c89726bb662fcb1684badaef5cd5256f479e3c622e1").into(), + hex!("aa70d5f314e4a1fbb9c362f3db79b21bf68b328887248651fbd29fc501d0ca97").into(), + hex!("160b6c235b3a1ed4ef5f80b03ee1c76f7bf3f591c92fca9d8663e9221b9f9f0f").into(), + hex!("f68d7dcd6a07a18e9de7b5d2aa1980eb962e11d7dcb584c96e81a7635c8d2535").into(), + hex!("1d5f912dfd6697110dd1ecb5cb8e77952eef57d85deb373572572df62bb157fc").into(), + hex!("ffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b").into(), + hex!("6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220").into(), + hex!("b7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f").into(), + ], + finalized_block_root: hex!("751414cd97c0624f922b3e80285e9f776b08fa22fd5f87391f2ed7ef571a8d46").into(), + }), + execution_header: VersionedExecutionPayloadHeader::Deneb(deneb::ExecutionPayloadHeader { + parent_hash: hex!("8092290aa21b7751576440f77edd02a94058429ce50e63a92d620951fb25eda2").into(), + fee_recipient: hex!("0000000000000000000000000000000000000000").into(), + state_root: hex!("96a83e9ddf745346fafcb0b03d57314623df669ed543c110662b21302a0fae8b").into(), + receipts_root: hex!("dccdfceea05036f7b61dcdabadc937945d31e68a8d3dfd4dc85684457988c284").into(), + logs_bloom: hex!("00000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000080000000400000000000000000000004000000000080000000000000000000000000000000000010100000000000000000000000000000000020000000000000000000000000000000000080000000000000000000000000000040004000000000000002002002000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000200000200000010").into(), + prev_randao: hex!("62e309d4f5119d1f5c783abc20fc1a549efbab546d8d0b25ff1cfd58be524e67").into(), + block_number: 393, + gas_limit: 54492273, + gas_used: 199644, + timestamp: 1710552813, + extra_data: hex!("d983010d0b846765746888676f312e32312e368664617277696e").into(), + base_fee_per_gas: U256::from(7u64), + block_hash: hex!("6a9810efb9581d30c1a5c9074f27c68ea779a8c1ae31c213241df16225f4e131").into(), + transactions_root: hex!("2cfa6ed7327e8807c7973516c5c32a68ef2459e586e8067e113d081c3bd8c07d").into(), + withdrawals_root: hex!("792930bbd5baac43bcc798ee49aa8185ef76bb3b44ba62b91d86ae569e4bb535").into(), + blob_gas_used: 0, + excess_blob_gas: 0, + }), + execution_branch: vec![ + hex!("a6833fa629f3286b6916c6e50b8bf089fc9126bee6f64d0413b4e59c1265834d").into(), + hex!("b46f0c01805fe212e15907981b757e6c496b0cb06664224655613dcec82505bb").into(), + hex!("db56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71").into(), + hex!("d3af7c05c516726be7505239e0b9c7cb53d24abce6b91cdb3b3995f0164a75da").into(), + ], + } + }, + }, + finalized_header: BeaconHeader { + slot: 864, + proposer_index: 4, + parent_root: hex!("614e7672f991ac268cd841055973f55e1e42228831a211adef207bb7329be614").into(), + state_root: hex!("5fa8dfca3d760e4242ab46d529144627aa85348a19173b6e081172c701197a4a").into(), + body_root: hex!("0f34c083b1803666bb1ac5e73fa71582731a2cf37d279ff0a3b0cad5a2ff371e").into(), + }, + block_roots_root: hex!("b9aab9c388c4e4fcd899b71f62c498fc73406e38e8eb14aa440e9affa06f2a10").into(), + } +} diff --git a/bridges/snowbridge/pallets/ethereum-client/src/benchmarking/mod.rs b/bridges/snowbridge/pallets/ethereum-client/src/benchmarking/mod.rs index e1520cd71539..4b8796b628d7 100644 --- a/bridges/snowbridge/pallets/ethereum-client/src/benchmarking/mod.rs +++ b/bridges/snowbridge/pallets/ethereum-client/src/benchmarking/mod.rs @@ -65,24 +65,6 @@ mod benchmarks { Ok(()) } - #[benchmark] - fn submit_execution_header() -> Result<(), BenchmarkError> { - let caller: T::AccountId = whitelisted_caller(); - let checkpoint_update = make_checkpoint(); - let finalized_header_update = make_finalized_header_update(); - let execution_header_update = make_execution_header_update(); - let execution_header_hash = execution_header_update.execution_header.block_hash(); - EthereumBeaconClient::::process_checkpoint_update(&checkpoint_update)?; - EthereumBeaconClient::::process_update(&finalized_header_update)?; - - #[extrinsic_call] - _(RawOrigin::Signed(caller.clone()), Box::new(*execution_header_update)); - - assert!(>::contains_key(execution_header_hash)); - - Ok(()) - } - #[benchmark(extra)] fn bls_fast_aggregate_verify_pre_aggregated() -> Result<(), BenchmarkError> { EthereumBeaconClient::::process_checkpoint_update(&make_checkpoint())?; diff --git a/bridges/snowbridge/pallets/ethereum-client/src/impls.rs b/bridges/snowbridge/pallets/ethereum-client/src/impls.rs index 300431d87707..f600b1f67e29 100644 --- a/bridges/snowbridge/pallets/ethereum-client/src/impls.rs +++ b/bridges/snowbridge/pallets/ethereum-client/src/impls.rs @@ -1,6 +1,8 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: 2023 Snowfork use super::*; +use frame_support::ensure; +use primitives::ExecutionProof; use snowbridge_core::inbound::{ VerificationError::{self, *}, @@ -14,32 +16,13 @@ impl Verifier for Pallet { /// the log should be in the beacon client storage, meaning it has been verified and is an /// ancestor of a finalized beacon block. fn verify(event_log: &Log, proof: &Proof) -> Result<(), VerificationError> { - log::info!( - target: "ethereum-client", - "💫 Verifying message with block hash {}", - proof.block_hash, - ); + Self::verify_execution_proof(&proof.execution_proof) + .map_err(|e| InvalidExecutionProof(e.into()))?; - let header = >::get(proof.block_hash).ok_or(HeaderNotFound)?; - - let receipt = match Self::verify_receipt_inclusion(header.receipts_root, proof) { - Ok(receipt) => receipt, - Err(err) => { - log::error!( - target: "ethereum-client", - "💫 Verification of receipt inclusion failed for block {}: {:?}", - proof.block_hash, - err - ); - return Err(err) - }, - }; - - log::trace!( - target: "ethereum-client", - "💫 Verified receipt inclusion for transaction at index {} in block {}", - proof.tx_index, proof.block_hash, - ); + let receipt = Self::verify_receipt_inclusion( + proof.execution_proof.execution_header.receipts_root(), + &proof.receipt_proof.1, + )?; event_log.validate().map_err(|_| InvalidLog)?; @@ -53,18 +36,11 @@ impl Verifier for Pallet { if !receipt.contains_log(&event_log) { log::error!( target: "ethereum-client", - "💫 Event log not found in receipt for transaction at index {} in block {}", - proof.tx_index, proof.block_hash, + "💫 Event log not found in receipt for transaction", ); return Err(LogNotFound) } - log::info!( - target: "ethereum-client", - "💫 Receipt verification successful for {}", - proof.block_hash, - ); - Ok(()) } } @@ -74,9 +50,9 @@ impl Pallet { /// `proof.block_hash`. pub fn verify_receipt_inclusion( receipts_root: H256, - proof: &Proof, + receipt_proof: &[Vec], ) -> Result { - let result = verify_receipt_proof(receipts_root, &proof.data.1).ok_or(InvalidProof)?; + let result = verify_receipt_proof(receipts_root, receipt_proof).ok_or(InvalidProof)?; match result { Ok(receipt) => Ok(receipt), @@ -90,4 +66,96 @@ impl Pallet { }, } } + + /// Validates an execution header with ancestry_proof against a finalized checkpoint on + /// chain.The beacon header containing the execution header is sent, plus the execution header, + /// along with a proof that the execution header is rooted in the beacon header body. + pub(crate) fn verify_execution_proof(execution_proof: &ExecutionProof) -> DispatchResult { + let latest_finalized_state = + FinalizedBeaconState::::get(LatestFinalizedBlockRoot::::get()) + .ok_or(Error::::NotBootstrapped)?; + // Checks that the header is an ancestor of a finalized header, using slot number. + ensure!( + execution_proof.header.slot <= latest_finalized_state.slot, + Error::::HeaderNotFinalized + ); + + // Gets the hash tree root of the execution header, in preparation for the execution + // header proof (used to check that the execution header is rooted in the beacon + // header body. + let execution_header_root: H256 = execution_proof + .execution_header + .hash_tree_root() + .map_err(|_| Error::::BlockBodyHashTreeRootFailed)?; + + ensure!( + verify_merkle_branch( + execution_header_root, + &execution_proof.execution_branch, + config::EXECUTION_HEADER_SUBTREE_INDEX, + config::EXECUTION_HEADER_DEPTH, + execution_proof.header.body_root + ), + Error::::InvalidExecutionHeaderProof + ); + + let beacon_block_root: H256 = execution_proof + .header + .hash_tree_root() + .map_err(|_| Error::::HeaderHashTreeRootFailed)?; + + match &execution_proof.ancestry_proof { + Some(proof) => { + Self::verify_ancestry_proof( + beacon_block_root, + execution_proof.header.slot, + &proof.header_branch, + proof.finalized_block_root, + )?; + }, + None => { + // If the ancestry proof is not provided, we expect this beacon header to be a + // finalized beacon header. We need to check that the header hash matches the + // finalized header root at the expected slot. + let state = >::get(beacon_block_root) + .ok_or(Error::::ExpectedFinalizedHeaderNotStored)?; + if execution_proof.header.slot != state.slot { + return Err(Error::::ExpectedFinalizedHeaderNotStored.into()) + } + }, + } + + Ok(()) + } + + /// Verify that `block_root` is an ancestor of `finalized_block_root` Used to prove that + /// an execution header is an ancestor of a finalized header (i.e. the blocks are + /// on the same chain). + fn verify_ancestry_proof( + block_root: H256, + block_slot: u64, + block_root_proof: &[H256], + finalized_block_root: H256, + ) -> DispatchResult { + let state = >::get(finalized_block_root) + .ok_or(Error::::ExpectedFinalizedHeaderNotStored)?; + + ensure!(block_slot < state.slot, Error::::HeaderNotFinalized); + + let index_in_array = block_slot % (SLOTS_PER_HISTORICAL_ROOT as u64); + let leaf_index = (SLOTS_PER_HISTORICAL_ROOT as u64) + index_in_array; + + ensure!( + verify_merkle_branch( + block_root, + block_root_proof, + leaf_index as usize, + config::BLOCK_ROOT_AT_INDEX_DEPTH, + state.block_roots_root + ), + Error::::InvalidAncestryMerkleProof + ); + + Ok(()) + } } diff --git a/bridges/snowbridge/pallets/ethereum-client/src/lib.rs b/bridges/snowbridge/pallets/ethereum-client/src/lib.rs index f57f51990209..c1b9e19729bc 100644 --- a/bridges/snowbridge/pallets/ethereum-client/src/lib.rs +++ b/bridges/snowbridge/pallets/ethereum-client/src/lib.rs @@ -15,8 +15,6 @@ //! ## Consensus Updates //! //! * [`Call::submit`]: Submit a finalized beacon header with an optional sync committee update -//! * [`Call::submit_execution_header`]: Submit an execution header together with an ancestry proof -//! that can be verified against an already imported finalized beacon header. #![cfg_attr(not(feature = "std"), no_std)] pub mod config; @@ -40,8 +38,7 @@ use frame_support::{ use frame_system::ensure_signed; use primitives::{ fast_aggregate_verify, verify_merkle_branch, verify_receipt_proof, BeaconHeader, BlsError, - CompactBeaconState, CompactExecutionHeader, ExecutionHeaderState, ForkData, ForkVersion, - ForkVersions, PublicKeyPrepared, SigningData, + CompactBeaconState, ForkData, ForkVersion, ForkVersions, PublicKeyPrepared, SigningData, }; use snowbridge_core::{BasicOperatingMode, RingBufferMap}; use sp_core::H256; @@ -51,11 +48,7 @@ pub use weights::WeightInfo; use functions::{ compute_epoch, compute_period, decompress_sync_committee_bits, sync_committee_sum, }; -pub use types::ExecutionHeaderBuffer; -use types::{ - CheckpointUpdate, ExecutionHeaderUpdate, FinalizedBeaconStateBuffer, SyncCommitteePrepared, - Update, -}; +use types::{CheckpointUpdate, FinalizedBeaconStateBuffer, SyncCommitteePrepared, Update}; pub use pallet::*; @@ -76,10 +69,7 @@ pub mod pallet { pub struct MaxFinalizedHeadersToKeep(PhantomData); impl Get for MaxFinalizedHeadersToKeep { fn get() -> u32 { - // Consider max latency allowed between LatestFinalizedState and LatestExecutionState is - // the total slots in one sync_committee_period so 1 should be fine we keep 2 periods - // here for redundancy. - const MAX_REDUNDANCY: u32 = 2; + const MAX_REDUNDANCY: u32 = 20; config::EPOCHS_PER_SYNC_COMMITTEE_PERIOD as u32 * MAX_REDUNDANCY } } @@ -92,9 +82,6 @@ pub mod pallet { type RuntimeEvent: From> + IsType<::RuntimeEvent>; #[pallet::constant] type ForkVersions: Get; - /// Maximum number of execution headers to keep - #[pallet::constant] - type MaxExecutionHeadersToKeep: Get; type WeightInfo: WeightInfo; } @@ -105,10 +92,6 @@ pub mod pallet { block_hash: H256, slot: u64, }, - ExecutionHeaderImported { - block_hash: H256, - block_number: u64, - }, SyncCommitteeUpdated { period: u64, }, @@ -191,25 +174,6 @@ pub mod pallet { pub(super) type NextSyncCommittee = StorageValue<_, SyncCommitteePrepared, ValueQuery>; - /// Latest imported execution header - #[pallet::storage] - #[pallet::getter(fn latest_execution_state)] - pub(super) type LatestExecutionState = - StorageValue<_, ExecutionHeaderState, ValueQuery>; - - /// Execution Headers - #[pallet::storage] - pub type ExecutionHeaders = - StorageMap<_, Identity, H256, CompactExecutionHeader, OptionQuery>; - - /// Execution Headers: Current position in ring buffer - #[pallet::storage] - pub type ExecutionHeaderIndex = StorageValue<_, u32, ValueQuery>; - - /// Execution Headers: Mapping of ring buffer index to a pruning candidate - #[pallet::storage] - pub type ExecutionHeaderMapping = StorageMap<_, Identity, u32, H256, ValueQuery>; - /// The current operating mode of the pallet. #[pallet::storage] #[pallet::getter(fn operating_mode)] @@ -248,21 +212,6 @@ pub mod pallet { Ok(()) } - #[pallet::call_index(2)] - #[pallet::weight(T::WeightInfo::submit_execution_header())] - #[transactional] - /// Submits a new execution header update. The relevant related beacon header - /// is also included to prove the execution header, as well as ancestry proof data. - pub fn submit_execution_header( - origin: OriginFor, - update: Box, - ) -> DispatchResult { - ensure_signed(origin)?; - ensure!(!Self::operating_mode().is_halted(), Error::::Halted); - Self::process_execution_header_update(&update)?; - Ok(()) - } - /// Halt or resume all pallet operations. May only be called by root. #[pallet::call_index(3)] #[pallet::weight((T::DbWeight::get().reads_writes(1, 1), DispatchClass::Operational))] @@ -325,41 +274,19 @@ pub mod pallet { >::set(sync_committee_prepared); >::kill(); InitialCheckpointRoot::::set(header_root); - >::kill(); Self::store_validators_root(update.validators_root); - Self::store_finalized_header(header_root, update.header, update.block_roots_root)?; + Self::store_finalized_header(update.header, update.block_roots_root)?; Ok(()) } pub(crate) fn process_update(update: &Update) -> DispatchResult { - Self::cross_check_execution_state()?; Self::verify_update(update)?; Self::apply_update(update)?; Ok(()) } - /// Cross check to make sure that execution header import does not fall too far behind - /// finalised beacon header import. If that happens just return an error and pause - /// processing until execution header processing has caught up. - pub(crate) fn cross_check_execution_state() -> DispatchResult { - let latest_finalized_state = - FinalizedBeaconState::::get(LatestFinalizedBlockRoot::::get()) - .ok_or(Error::::NotBootstrapped)?; - let latest_execution_state = Self::latest_execution_state(); - // The execution header import should be at least within the slot range of a sync - // committee period. - let max_latency = config::EPOCHS_PER_SYNC_COMMITTEE_PERIOD * config::SLOTS_PER_EPOCH; - ensure!( - latest_execution_state.beacon_slot == 0 || - latest_finalized_state.slot < - latest_execution_state.beacon_slot + max_latency as u64, - Error::::ExecutionHeaderTooFarBehind - ); - Ok(()) - } - /// References and strictly follows /// Verifies that provided next sync committee is valid through a series of checks /// (including checking that a sync committee period isn't skipped and that the header is @@ -534,130 +461,12 @@ pub mod pallet { }; if update.finalized_header.slot > latest_finalized_state.slot { - let finalized_block_root: H256 = update - .finalized_header - .hash_tree_root() - .map_err(|_| Error::::HeaderHashTreeRootFailed)?; - Self::store_finalized_header( - finalized_block_root, - update.finalized_header, - update.block_roots_root, - )?; + Self::store_finalized_header(update.finalized_header, update.block_roots_root)?; } Ok(()) } - /// Validates an execution header for import. The beacon header containing the execution - /// header is sent, plus the execution header, along with a proof that the execution header - /// is rooted in the beacon header body. - pub(crate) fn process_execution_header_update( - update: &ExecutionHeaderUpdate, - ) -> DispatchResult { - let latest_finalized_state = - FinalizedBeaconState::::get(LatestFinalizedBlockRoot::::get()) - .ok_or(Error::::NotBootstrapped)?; - // Checks that the header is an ancestor of a finalized header, using slot number. - ensure!( - update.header.slot <= latest_finalized_state.slot, - Error::::HeaderNotFinalized - ); - - // Checks that we don't skip execution headers, they need to be imported sequentially. - let latest_execution_state: ExecutionHeaderState = Self::latest_execution_state(); - ensure!( - latest_execution_state.block_number == 0 || - update.execution_header.block_number() == - latest_execution_state.block_number + 1, - Error::::ExecutionHeaderSkippedBlock - ); - - // Gets the hash tree root of the execution header, in preparation for the execution - // header proof (used to check that the execution header is rooted in the beacon - // header body. - let execution_header_root: H256 = update - .execution_header - .hash_tree_root() - .map_err(|_| Error::::BlockBodyHashTreeRootFailed)?; - - ensure!( - verify_merkle_branch( - execution_header_root, - &update.execution_branch, - config::EXECUTION_HEADER_SUBTREE_INDEX, - config::EXECUTION_HEADER_DEPTH, - update.header.body_root - ), - Error::::InvalidExecutionHeaderProof - ); - - let block_root: H256 = update - .header - .hash_tree_root() - .map_err(|_| Error::::HeaderHashTreeRootFailed)?; - - match &update.ancestry_proof { - Some(proof) => { - Self::verify_ancestry_proof( - block_root, - update.header.slot, - &proof.header_branch, - proof.finalized_block_root, - )?; - }, - None => { - // If the ancestry proof is not provided, we expect this header to be a - // finalized header. We need to check that the header hash matches the finalized - // header root at the expected slot. - let state = >::get(block_root) - .ok_or(Error::::ExpectedFinalizedHeaderNotStored)?; - if update.header.slot != state.slot { - return Err(Error::::ExpectedFinalizedHeaderNotStored.into()) - } - }, - } - - Self::store_execution_header( - update.execution_header.block_hash(), - update.execution_header.clone().into(), - update.header.slot, - block_root, - ); - - Ok(()) - } - - /// Verify that `block_root` is an ancestor of `finalized_block_root` Used to prove that - /// an execution header is an ancestor of a finalized header (i.e. the blocks are - /// on the same chain). - fn verify_ancestry_proof( - block_root: H256, - block_slot: u64, - block_root_proof: &[H256], - finalized_block_root: H256, - ) -> DispatchResult { - let state = >::get(finalized_block_root) - .ok_or(Error::::ExpectedFinalizedHeaderNotStored)?; - - ensure!(block_slot < state.slot, Error::::HeaderNotFinalized); - - let index_in_array = block_slot % (SLOTS_PER_HISTORICAL_ROOT as u64); - let leaf_index = (SLOTS_PER_HISTORICAL_ROOT as u64) + index_in_array; - - ensure!( - verify_merkle_branch( - block_root, - block_root_proof, - leaf_index as usize, - config::BLOCK_ROOT_AT_INDEX_DEPTH, - state.block_roots_root - ), - Error::::InvalidAncestryMerkleProof - ); - - Ok(()) - } - /// Computes the signing root for a given beacon header and domain. The hash tree root /// of the beacon header is computed, and then the combination of the beacon header hash /// and the domain makes up the signing root. @@ -679,13 +488,15 @@ pub mod pallet { /// Stores a compacted (slot and block roots root (hash of the `block_roots` beacon state /// field, used for ancestry proof)) beacon state in a ring buffer map, with the header root /// as map key. - fn store_finalized_header( - header_root: H256, + pub fn store_finalized_header( header: BeaconHeader, block_roots_root: H256, ) -> DispatchResult { let slot = header.slot; + let header_root: H256 = + header.hash_tree_root().map_err(|_| Error::::HeaderHashTreeRootFailed)?; + >::insert( header_root, CompactBeaconState { slot: header.slot, block_roots_root }, @@ -704,36 +515,6 @@ pub mod pallet { Ok(()) } - /// Stores the provided execution header in pallet storage. The header is stored - /// in a ring buffer map, with the block hash as map key. The last imported execution - /// header is also kept in storage, for the relayer to check import progress. - pub fn store_execution_header( - block_hash: H256, - header: CompactExecutionHeader, - beacon_slot: u64, - beacon_block_root: H256, - ) { - let block_number = header.block_number; - - >::insert(block_hash, header); - - log::trace!( - target: LOG_TARGET, - "💫 Updated latest execution block at {} to number {}.", - block_hash, - block_number - ); - - LatestExecutionState::::mutate(|s| { - s.beacon_block_root = beacon_block_root; - s.beacon_slot = beacon_slot; - s.block_hash = block_hash; - s.block_number = block_number; - }); - - Self::deposit_event(Event::ExecutionHeaderImported { block_hash, block_number }); - } - /// Stores the validators root in storage. Validators root is the hash tree root of all the /// validators at genesis and is used to used to identify the chain that we are on /// (used in conjunction with the fork version). diff --git a/bridges/snowbridge/pallets/ethereum-client/src/mock.rs b/bridges/snowbridge/pallets/ethereum-client/src/mock.rs index 799b14f4773e..bd6144ebd8f9 100644 --- a/bridges/snowbridge/pallets/ethereum-client/src/mock.rs +++ b/bridges/snowbridge/pallets/ethereum-client/src/mock.rs @@ -2,12 +2,13 @@ // SPDX-FileCopyrightText: 2023 Snowfork use crate as ethereum_beacon_client; use crate::config; -use frame_support::{derive_impl, parameter_types}; -use hex_literal::hex; +use frame_support::{derive_impl, dispatch::DispatchResult, parameter_types}; use pallet_timestamp; -use primitives::{CompactExecutionHeader, Fork, ForkVersions}; +use primitives::{Fork, ForkVersions}; use snowbridge_core::inbound::{Log, Proof}; +use sp_std::default::Default; use std::{fs::File, path::PathBuf}; + type Block = frame_system::mocking::MockBlock; use sp_runtime::BuildStorage; @@ -20,8 +21,8 @@ where serde_json::from_reader(File::open(filepath).unwrap()) } -pub fn load_execution_header_update_fixture() -> primitives::ExecutionHeaderUpdate { - load_fixture("execution-header-update.json".to_string()).unwrap() +pub fn load_execution_proof_fixture() -> primitives::ExecutionProof { + load_fixture("execution-proof.json".to_string()).unwrap() } pub fn load_checkpoint_update_fixture( @@ -50,41 +51,8 @@ pub fn load_next_finalized_header_update_fixture( } pub fn get_message_verification_payload() -> (Log, Proof) { - ( - Log { - address: hex!("ee9170abfbf9421ad6dd07f6bdec9d89f2b581e0").into(), - topics: vec![ - hex!("1b11dcf133cc240f682dab2d3a8e4cd35c5da8c9cf99adac4336f8512584c5ad").into(), - hex!("00000000000000000000000000000000000000000000000000000000000003e8").into(), - hex!("0000000000000000000000000000000000000000000000000000000000000001").into(), - ], - data: hex!("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004b000f000000000000000100d184c103f7acc340847eee82a0b909e3358bc28d440edffa1352b13227e8ee646f3ea37456dec701345772617070656420457468657210574554481235003511000000000000000000000000000000000000000000").into(), - }, - Proof { - block_hash: hex!("05aaa60b0f27cce9e71909508527264b77ee14da7b5bf915fcc4e32715333213").into(), - tx_index: 0, - data: (vec![ - hex!("cf0d1c1ba57d1e0edfb59786c7e30c2b7e12bd54612b00cd21c4eaeecedf44fb").to_vec(), - hex!("d21fc4f68ab05bc4dcb23c67008e92c4d466437cdd6ed7aad0c008944c185510").to_vec(), - hex!("b9890f91ca0d77aa2a4adfaf9b9e40c94cac9e638b6d9797923865872944b646").to_vec(), - ], vec![ - hex!("f90131a0b601337b3aa10a671caa724eba641e759399979856141d3aea6b6b4ac59b889ba00c7d5dd48be9060221a02fb8fa213860b4c50d47046c8fa65ffaba5737d569e0a094601b62a1086cd9c9cb71a7ebff9e718f3217fd6e837efe4246733c0a196f63a06a4b0dd0aefc37b3c77828c8f07d1b7a2455ceb5dbfd3c77d7d6aeeddc2f7e8ca0d6e8e23142cdd8ec219e1f5d8b56aa18e456702b195deeaa210327284d42ade4a08a313d4c87023005d1ab631bbfe3f5de1e405d0e66d0bef3e033f1e5711b5521a0bf09a5d9a48b10ade82b8d6a5362a15921c8b5228a3487479b467db97411d82fa0f95cccae2a7c572ef3c566503e30bac2b2feb2d2f26eebf6d870dcf7f8cf59cea0d21fc4f68ab05bc4dcb23c67008e92c4d466437cdd6ed7aad0c008944c1855108080808080808080").to_vec(), - hex!("f851a0b9890f91ca0d77aa2a4adfaf9b9e40c94cac9e638b6d9797923865872944b646a060a634b9280e3a23fb63375e7bbdd9ab07fd379ab6a67e2312bbc112195fa358808080808080808080808080808080").to_vec(), - hex!("f9030820b9030402f90300018301d6e2b9010000000000000800000000000020040008000000000000000000000000400000008000000000000000000000000000000000000000000000000000000000042010000000001000000000000000000000000000000000040000000000000000000000000000000000000000000000008000000000000000002000000000000000000000000200000000000000200000000000100000000040000001000200008000000000000200000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000f901f5f87a942ffa5ecdbe006d30397c7636d3e015eee251369ff842a0c965575a00553e094ca7c5d14f02e107c258dda06867cbf9e0e69f80e71bbcc1a000000000000000000000000000000000000000000000000000000000000003e8a000000000000000000000000000000000000000000000000000000000000003e8f9011c94ee9170abfbf9421ad6dd07f6bdec9d89f2b581e0f863a01b11dcf133cc240f682dab2d3a8e4cd35c5da8c9cf99adac4336f8512584c5ada000000000000000000000000000000000000000000000000000000000000003e8a00000000000000000000000000000000000000000000000000000000000000001b8a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004b000f000000000000000100d184c103f7acc340847eee82a0b909e3358bc28d440edffa1352b13227e8ee646f3ea37456dec701345772617070656420457468657210574554481235003511000000000000000000000000000000000000000000f858948cf6147918a5cbb672703f879f385036f8793a24e1a01449abf21e49fd025f33495e77f7b1461caefdd3d4bb646424a3f445c4576a5ba0000000000000000000000000440edffa1352b13227e8ee646f3ea37456dec701").to_vec(), - ]), - } - ) -} - -pub fn get_message_verification_header() -> CompactExecutionHeader { - CompactExecutionHeader { - parent_hash: hex!("04a7f6ab8282203562c62f38b0ab41d32aaebe2c7ea687702b463148a6429e04") - .into(), - block_number: 55, - state_root: hex!("894d968712976d613519f973a317cb0781c7b039c89f27ea2b7ca193f7befdb3").into(), - receipts_root: hex!("cf0d1c1ba57d1e0edfb59786c7e30c2b7e12bd54612b00cd21c4eaeecedf44fb") - .into(), - } + let inbound_fixture = snowbridge_pallet_ethereum_client_fixtures::make_inbound_fixture(); + (inbound_fixture.message.event_log, inbound_fixture.message.proof) } frame_support::construct_runtime!( @@ -130,20 +98,25 @@ parameter_types! { epoch: 0, } }; - pub const ExecutionHeadersPruneThreshold: u32 = 8192; } impl ethereum_beacon_client::Config for Test { type RuntimeEvent = RuntimeEvent; type ForkVersions = ChainForkVersions; - type MaxExecutionHeadersToKeep = ExecutionHeadersPruneThreshold; type WeightInfo = (); } // Build genesis storage according to the mock runtime. pub fn new_tester() -> sp_io::TestExternalities { let t = frame_system::GenesisConfig::::default().build_storage().unwrap(); - let mut ext = sp_io::TestExternalities::new(t); - let _ = ext.execute_with(|| Timestamp::set(RuntimeOrigin::signed(1), 30_000)); + let ext = sp_io::TestExternalities::new(t); ext } + +pub fn initialize_storage() -> DispatchResult { + let inbound_fixture = snowbridge_pallet_ethereum_client_fixtures::make_inbound_fixture(); + EthereumBeaconClient::store_finalized_header( + inbound_fixture.finalized_header, + inbound_fixture.block_roots_root, + ) +} diff --git a/bridges/snowbridge/pallets/ethereum-client/src/tests.rs b/bridges/snowbridge/pallets/ethereum-client/src/tests.rs index 20a184490fd7..765958c12821 100644 --- a/bridges/snowbridge/pallets/ethereum-client/src/tests.rs +++ b/bridges/snowbridge/pallets/ethereum-client/src/tests.rs @@ -1,14 +1,13 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: 2023 Snowfork use crate::{ - functions::compute_period, pallet::ExecutionHeaders, sync_committee_sum, verify_merkle_branch, - BeaconHeader, CompactBeaconState, Error, ExecutionHeaderBuffer, FinalizedBeaconState, - LatestExecutionState, LatestFinalizedBlockRoot, NextSyncCommittee, SyncCommitteePrepared, + functions::compute_period, sync_committee_sum, verify_merkle_branch, BeaconHeader, + CompactBeaconState, Error, FinalizedBeaconState, LatestFinalizedBlockRoot, NextSyncCommittee, + SyncCommitteePrepared, }; use crate::mock::{ - get_message_verification_header, get_message_verification_payload, - load_checkpoint_update_fixture, load_execution_header_update_fixture, + get_message_verification_payload, load_checkpoint_update_fixture, load_finalized_header_update_fixture, load_next_finalized_header_update_fixture, load_next_sync_committee_update_fixture, load_sync_committee_update_fixture, }; @@ -19,14 +18,9 @@ use crate::config::{EPOCHS_PER_SYNC_COMMITTEE_PERIOD, SLOTS_PER_EPOCH, SLOTS_PER use frame_support::{assert_err, assert_noop, assert_ok}; use hex_literal::hex; use primitives::{ - CompactExecutionHeader, ExecutionHeaderState, Fork, ForkVersions, NextSyncCommitteeUpdate, - VersionedExecutionPayloadHeader, -}; -use rand::{thread_rng, Rng}; -use snowbridge_core::{ - inbound::{VerificationError, Verifier}, - RingBufferMap, + types::deneb, Fork, ForkVersions, NextSyncCommitteeUpdate, VersionedExecutionPayloadHeader, }; +use snowbridge_core::inbound::{VerificationError, Verifier}; use sp_core::H256; use sp_runtime::DispatchError; @@ -212,61 +206,6 @@ pub fn sync_committee_participation_is_supermajority_errors_when_not_supermajori }); } -#[test] -pub fn execution_header_pruning() { - new_tester().execute_with(|| { - let execution_header_prune_threshold = ExecutionHeadersPruneThreshold::get(); - let to_be_deleted = execution_header_prune_threshold / 2; - - let mut stored_hashes = vec![]; - - for i in 0..execution_header_prune_threshold { - let mut hash = H256::default(); - thread_rng().try_fill(&mut hash.0[..]).unwrap(); - EthereumBeaconClient::store_execution_header( - hash, - CompactExecutionHeader::default(), - i as u64, - hash, - ); - stored_hashes.push(hash); - } - - // We should have stored everything until now - assert_eq!({ ExecutionHeaders::::iter().count() }, stored_hashes.len()); - - // Let's push extra entries so that some of the previous entries are deleted. - for i in 0..to_be_deleted { - let mut hash = H256::default(); - thread_rng().try_fill(&mut hash.0[..]).unwrap(); - EthereumBeaconClient::store_execution_header( - hash, - CompactExecutionHeader::default(), - (i + execution_header_prune_threshold) as u64, - hash, - ); - - stored_hashes.push(hash); - } - - // We should have only stored up to `execution_header_prune_threshold` - assert_eq!( - ExecutionHeaders::::iter().count() as u32, - execution_header_prune_threshold - ); - - // First `to_be_deleted` items must be deleted - for i in 0..to_be_deleted { - assert!(!ExecutionHeaders::::contains_key(stored_hashes[i as usize])); - } - - // Other entries should be part of data - for i in to_be_deleted..(to_be_deleted + execution_header_prune_threshold) { - assert!(ExecutionHeaders::::contains_key(stored_hashes[i as usize])); - } - }); -} - #[test] fn compute_fork_version() { let mock_fork_versions = ForkVersions { @@ -348,34 +287,6 @@ fn find_present_keys() { }); } -#[test] -fn cross_check_execution_state() { - new_tester().execute_with(|| { - let header_root: H256 = TEST_HASH.into(); - >::insert( - header_root, - CompactBeaconState { - // set slot to period 5 - slot: ((EPOCHS_PER_SYNC_COMMITTEE_PERIOD * SLOTS_PER_EPOCH) * 5) as u64, - block_roots_root: Default::default(), - }, - ); - LatestFinalizedBlockRoot::::set(header_root); - >::set(ExecutionHeaderState { - beacon_block_root: Default::default(), - // set slot to period 2 - beacon_slot: ((EPOCHS_PER_SYNC_COMMITTEE_PERIOD * SLOTS_PER_EPOCH) * 2) as u64, - block_hash: Default::default(), - block_number: 0, - }); - - assert_err!( - EthereumBeaconClient::cross_check_execution_state(), - Error::::ExecutionHeaderTooFarBehind - ); - }); -} - /* SYNC PROCESS TESTS */ #[test] @@ -608,40 +519,6 @@ fn submit_update_with_skipped_sync_committee_period() { }); } -#[test] -fn submit_update_execution_headers_too_far_behind() { - let checkpoint = Box::new(load_checkpoint_update_fixture()); - let finalized_header_update = Box::new(load_finalized_header_update_fixture()); - let execution_header_update = Box::new(load_execution_header_update_fixture()); - let next_update = Box::new(load_next_sync_committee_update_fixture()); - - new_tester().execute_with(|| { - let far_ahead_finalized_header_slot = finalized_header_update.finalized_header.slot + - (EPOCHS_PER_SYNC_COMMITTEE_PERIOD * SLOTS_PER_EPOCH * 2) as u64; - assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); - assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), finalized_header_update)); - assert_ok!(EthereumBeaconClient::submit_execution_header( - RuntimeOrigin::signed(1), - execution_header_update - )); - - let header_root: H256 = TEST_HASH.into(); - >::insert( - header_root, - CompactBeaconState { - slot: far_ahead_finalized_header_slot, - block_roots_root: Default::default(), - }, - ); - LatestFinalizedBlockRoot::::set(header_root); - - assert_err!( - EthereumBeaconClient::submit(RuntimeOrigin::signed(1), next_update), - Error::::ExecutionHeaderTooFarBehind - ); - }); -} - #[test] fn submit_irrelevant_update() { let checkpoint = Box::new(load_checkpoint_update_fixture()); @@ -703,187 +580,6 @@ fn submit_update_with_invalid_sync_committee_update() { }); } -#[test] -fn submit_execution_header_update() { - let checkpoint = Box::new(load_checkpoint_update_fixture()); - let finalized_header_update = Box::new(load_finalized_header_update_fixture()); - let execution_header_update = Box::new(load_execution_header_update_fixture()); - - new_tester().execute_with(|| { - assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); - assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), finalized_header_update)); - assert_ok!(EthereumBeaconClient::submit_execution_header( - RuntimeOrigin::signed(1), - execution_header_update.clone() - )); - assert!(>::contains_key( - execution_header_update.execution_header.block_hash() - )); - }); -} - -#[test] -fn submit_execution_header_update_invalid_ancestry_proof() { - let checkpoint = Box::new(load_checkpoint_update_fixture()); - let finalized_header_update = Box::new(load_finalized_header_update_fixture()); - let mut execution_header_update = Box::new(load_execution_header_update_fixture()); - if let Some(ref mut ancestry_proof) = execution_header_update.ancestry_proof { - ancestry_proof.header_branch[0] = TEST_HASH.into() - } - - new_tester().execute_with(|| { - assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); - assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), finalized_header_update)); - assert_err!( - EthereumBeaconClient::submit_execution_header( - RuntimeOrigin::signed(1), - execution_header_update - ), - Error::::InvalidAncestryMerkleProof - ); - }); -} - -#[test] -fn submit_execution_header_update_invalid_execution_header_proof() { - let checkpoint = Box::new(load_checkpoint_update_fixture()); - let finalized_header_update = Box::new(load_finalized_header_update_fixture()); - let mut execution_header_update = Box::new(load_execution_header_update_fixture()); - execution_header_update.execution_branch[0] = TEST_HASH.into(); - - new_tester().execute_with(|| { - assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); - assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), finalized_header_update)); - assert_err!( - EthereumBeaconClient::submit_execution_header( - RuntimeOrigin::signed(1), - execution_header_update - ), - Error::::InvalidExecutionHeaderProof - ); - }); -} - -#[test] -fn submit_execution_header_update_that_skips_block() { - let checkpoint = Box::new(load_checkpoint_update_fixture()); - let finalized_header_update = Box::new(load_finalized_header_update_fixture()); - let execution_header_update = Box::new(load_execution_header_update_fixture()); - let mut skipped_block_execution_header_update = - Box::new(load_execution_header_update_fixture()); - let mut skipped_execution_header = - skipped_block_execution_header_update.execution_header.clone(); - - skipped_execution_header = match skipped_execution_header { - VersionedExecutionPayloadHeader::Capella(execution_payload_header) => { - let mut mut_execution_payload_header = execution_payload_header.clone(); - mut_execution_payload_header.block_number = execution_payload_header.block_number + 2; - VersionedExecutionPayloadHeader::Capella(mut_execution_payload_header) - }, - VersionedExecutionPayloadHeader::Deneb(execution_payload_header) => { - let mut mut_execution_payload_header = execution_payload_header.clone(); - mut_execution_payload_header.block_number = execution_payload_header.block_number + 2; - VersionedExecutionPayloadHeader::Deneb(mut_execution_payload_header) - }, - }; - - skipped_block_execution_header_update.execution_header = skipped_execution_header; - - new_tester().execute_with(|| { - assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); - assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), finalized_header_update)); - assert_ok!(EthereumBeaconClient::submit_execution_header( - RuntimeOrigin::signed(1), - execution_header_update.clone() - )); - assert!(>::contains_key( - execution_header_update.execution_header.block_hash() - )); - assert_err!( - EthereumBeaconClient::submit_execution_header( - RuntimeOrigin::signed(1), - skipped_block_execution_header_update - ), - Error::::ExecutionHeaderSkippedBlock - ); - }); -} - -#[test] -fn submit_execution_header_update_that_is_also_finalized_header_which_is_not_stored() { - let checkpoint = Box::new(load_checkpoint_update_fixture()); - let finalized_header_update = Box::new(load_finalized_header_update_fixture()); - let mut execution_header_update = Box::new(load_execution_header_update_fixture()); - execution_header_update.ancestry_proof = None; - - new_tester().execute_with(|| { - assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); - assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), finalized_header_update)); - assert_err!( - EthereumBeaconClient::submit_execution_header( - RuntimeOrigin::signed(1), - execution_header_update - ), - Error::::ExpectedFinalizedHeaderNotStored - ); - }); -} - -#[test] -fn submit_execution_header_update_that_is_also_finalized_header_which_is_stored_but_slots_dont_match( -) { - let checkpoint = Box::new(load_checkpoint_update_fixture()); - let finalized_header_update = Box::new(load_finalized_header_update_fixture()); - let mut execution_header_update = Box::new(load_execution_header_update_fixture()); - execution_header_update.ancestry_proof = None; - - new_tester().execute_with(|| { - assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); - assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), finalized_header_update)); - - let block_root: H256 = execution_header_update.header.hash_tree_root().unwrap(); - - >::insert( - block_root, - CompactBeaconState { - slot: execution_header_update.header.slot + 1, - block_roots_root: Default::default(), - }, - ); - LatestFinalizedBlockRoot::::set(block_root); - - assert_err!( - EthereumBeaconClient::submit_execution_header( - RuntimeOrigin::signed(1), - execution_header_update - ), - Error::::ExpectedFinalizedHeaderNotStored - ); - }); -} - -#[test] -fn submit_execution_header_not_finalized() { - let checkpoint = Box::new(load_checkpoint_update_fixture()); - let finalized_header_update = Box::new(load_finalized_header_update_fixture()); - let update = Box::new(load_execution_header_update_fixture()); - - new_tester().execute_with(|| { - assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); - assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), finalized_header_update)); - - >::mutate(>::get(), |x| { - let prev = x.unwrap(); - *x = Some(CompactBeaconState { slot: update.header.slot - 1, ..prev }); - }); - - assert_err!( - EthereumBeaconClient::submit_execution_header(RuntimeOrigin::signed(1), update), - Error::::HeaderNotFinalized - ); - }); -} - /// Check that a gap of more than 8192 slots between finalized headers is not allowed. #[test] fn submit_finalized_header_update_with_too_large_gap() { @@ -943,37 +639,21 @@ fn submit_finalized_header_update_with_gap_at_limit() { #[test] fn verify_message() { - let header = get_message_verification_header(); let (event_log, proof) = get_message_verification_payload(); - let block_hash = proof.block_hash; new_tester().execute_with(|| { - >::insert(block_hash, header); + assert_ok!(initialize_storage()); assert_ok!(EthereumBeaconClient::verify(&event_log, &proof)); }); } -#[test] -fn verify_message_missing_header() { - let (event_log, proof) = get_message_verification_payload(); - - new_tester().execute_with(|| { - assert_err!( - EthereumBeaconClient::verify(&event_log, &proof), - VerificationError::HeaderNotFound - ); - }); -} - #[test] fn verify_message_invalid_proof() { - let header = get_message_verification_header(); let (event_log, mut proof) = get_message_verification_payload(); - proof.data.1[0] = TEST_HASH.into(); - let block_hash = proof.block_hash; + proof.receipt_proof.1[0] = TEST_HASH.into(); new_tester().execute_with(|| { - >::insert(block_hash, header); + assert_ok!(initialize_storage()); assert_err!( EthereumBeaconClient::verify(&event_log, &proof), VerificationError::InvalidProof @@ -983,29 +663,28 @@ fn verify_message_invalid_proof() { #[test] fn verify_message_invalid_receipts_root() { - let mut header = get_message_verification_header(); - let (event_log, proof) = get_message_verification_payload(); - let block_hash = proof.block_hash; - header.receipts_root = TEST_HASH.into(); + let (event_log, mut proof) = get_message_verification_payload(); + let mut payload = deneb::ExecutionPayloadHeader::default(); + payload.receipts_root = TEST_HASH.into(); + proof.execution_proof.execution_header = VersionedExecutionPayloadHeader::Deneb(payload); new_tester().execute_with(|| { - >::insert(block_hash, header); + assert_ok!(initialize_storage()); assert_err!( EthereumBeaconClient::verify(&event_log, &proof), - VerificationError::InvalidProof + VerificationError::InvalidExecutionProof( + Error::::BlockBodyHashTreeRootFailed.into() + ) ); }); } #[test] fn verify_message_invalid_log() { - let header = get_message_verification_header(); let (mut event_log, proof) = get_message_verification_payload(); - let block_hash = proof.block_hash; event_log.topics = vec![H256::zero(); 10]; - new_tester().execute_with(|| { - >::insert(block_hash, header); + assert_ok!(initialize_storage()); assert_err!( EthereumBeaconClient::verify(&event_log, &proof), VerificationError::InvalidLog @@ -1015,13 +694,11 @@ fn verify_message_invalid_log() { #[test] fn verify_message_receipt_does_not_contain_log() { - let header = get_message_verification_header(); let (mut event_log, proof) = get_message_verification_payload(); - let block_hash = proof.block_hash; event_log.data = hex!("f9013c94ee9170abfbf9421ad6dd07f6bdec9d89f2b581e0f863a01b11dcf133cc240f682dab2d3a8e4cd35c5da8c9cf99adac4336f8512584c5ada000000000000000000000000000000000000000000000000000000000000003e8a00000000000000000000000000000000000000000000000000000000000000002b8c000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000068000f000000000000000101d184c103f7acc340847eee82a0b909e3358bc28d440edffa1352b13227e8ee646f3ea37456dec70100000101001cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07c0000e8890423c78a0000000000000000000000000000000000000000000000000000000000000000").to_vec(); new_tester().execute_with(|| { - >::insert(block_hash, header); + assert_ok!(initialize_storage()); assert_err!( EthereumBeaconClient::verify(&event_log, &proof), VerificationError::LogNotFound @@ -1033,7 +710,6 @@ fn verify_message_receipt_does_not_contain_log() { fn set_operating_mode() { let checkpoint = Box::new(load_checkpoint_update_fixture()); let update = Box::new(load_finalized_header_update_fixture()); - let execution_header_update = Box::new(load_execution_header_update_fixture()); new_tester().execute_with(|| { assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); @@ -1047,14 +723,6 @@ fn set_operating_mode() { EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update), Error::::Halted ); - - assert_noop!( - EthereumBeaconClient::submit_execution_header( - RuntimeOrigin::signed(1), - execution_header_update - ), - Error::::Halted - ); }); } @@ -1070,3 +738,107 @@ fn set_operating_mode_root_only() { ); }); } + +#[test] +fn verify_execution_proof_invalid_ancestry_proof() { + let checkpoint = Box::new(load_checkpoint_update_fixture()); + let finalized_header_update = Box::new(load_finalized_header_update_fixture()); + let mut execution_header_update = Box::new(load_execution_proof_fixture()); + if let Some(ref mut ancestry_proof) = execution_header_update.ancestry_proof { + ancestry_proof.header_branch[0] = TEST_HASH.into() + } + + new_tester().execute_with(|| { + assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); + assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), finalized_header_update)); + assert_err!( + EthereumBeaconClient::verify_execution_proof(&execution_header_update), + Error::::InvalidAncestryMerkleProof + ); + }); +} + +#[test] +fn verify_execution_proof_invalid_execution_header_proof() { + let checkpoint = Box::new(load_checkpoint_update_fixture()); + let finalized_header_update = Box::new(load_finalized_header_update_fixture()); + let mut execution_header_update = Box::new(load_execution_proof_fixture()); + execution_header_update.execution_branch[0] = TEST_HASH.into(); + + new_tester().execute_with(|| { + assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); + assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), finalized_header_update)); + assert_err!( + EthereumBeaconClient::verify_execution_proof(&execution_header_update), + Error::::InvalidExecutionHeaderProof + ); + }); +} + +#[test] +fn verify_execution_proof_that_is_also_finalized_header_which_is_not_stored() { + let checkpoint = Box::new(load_checkpoint_update_fixture()); + let finalized_header_update = Box::new(load_finalized_header_update_fixture()); + let mut execution_header_update = Box::new(load_execution_proof_fixture()); + execution_header_update.ancestry_proof = None; + + new_tester().execute_with(|| { + assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); + assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), finalized_header_update)); + assert_err!( + EthereumBeaconClient::verify_execution_proof(&execution_header_update), + Error::::ExpectedFinalizedHeaderNotStored + ); + }); +} + +#[test] +fn submit_execution_proof_that_is_also_finalized_header_which_is_stored_but_slots_dont_match() { + let checkpoint = Box::new(load_checkpoint_update_fixture()); + let finalized_header_update = Box::new(load_finalized_header_update_fixture()); + let mut execution_header_update = Box::new(load_execution_proof_fixture()); + execution_header_update.ancestry_proof = None; + + new_tester().execute_with(|| { + assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); + assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), finalized_header_update)); + + let block_root: H256 = execution_header_update.header.hash_tree_root().unwrap(); + + >::insert( + block_root, + CompactBeaconState { + slot: execution_header_update.header.slot + 1, + block_roots_root: Default::default(), + }, + ); + LatestFinalizedBlockRoot::::set(block_root); + + assert_err!( + EthereumBeaconClient::verify_execution_proof(&execution_header_update), + Error::::ExpectedFinalizedHeaderNotStored + ); + }); +} + +#[test] +fn verify_execution_proof_not_finalized() { + let checkpoint = Box::new(load_checkpoint_update_fixture()); + let finalized_header_update = Box::new(load_finalized_header_update_fixture()); + let update = Box::new(load_execution_proof_fixture()); + + new_tester().execute_with(|| { + assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); + assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), finalized_header_update)); + + >::mutate(>::get(), |x| { + let prev = x.unwrap(); + *x = Some(CompactBeaconState { slot: update.header.slot - 1, ..prev }); + }); + + assert_err!( + EthereumBeaconClient::verify_execution_proof(&update), + Error::::HeaderNotFinalized + ); + }); +} diff --git a/bridges/snowbridge/pallets/ethereum-client/src/types.rs b/bridges/snowbridge/pallets/ethereum-client/src/types.rs index 5dcefea9f80f..8808f989754b 100644 --- a/bridges/snowbridge/pallets/ethereum-client/src/types.rs +++ b/bridges/snowbridge/pallets/ethereum-client/src/types.rs @@ -15,17 +15,7 @@ pub type CheckpointUpdate = primitives::CheckpointUpdate; pub type Update = primitives::Update; pub type NextSyncCommitteeUpdate = primitives::NextSyncCommitteeUpdate; -pub use primitives::ExecutionHeaderUpdate; - -/// ExecutionHeader ring buffer implementation -pub type ExecutionHeaderBuffer = RingBufferMapImpl< - u32, - ::MaxExecutionHeadersToKeep, - crate::ExecutionHeaderIndex, - crate::ExecutionHeaderMapping, - crate::ExecutionHeaders, - OptionQuery, ->; +pub use primitives::{AncestryProof, ExecutionProof}; /// FinalizedState ring buffer implementation pub(crate) type FinalizedBeaconStateBuffer = RingBufferMapImpl< diff --git a/bridges/snowbridge/pallets/ethereum-client/src/weights.rs b/bridges/snowbridge/pallets/ethereum-client/src/weights.rs index e1a5578f4661..e4629746aa2d 100644 --- a/bridges/snowbridge/pallets/ethereum-client/src/weights.rs +++ b/bridges/snowbridge/pallets/ethereum-client/src/weights.rs @@ -36,7 +36,6 @@ pub trait WeightInfo { fn force_checkpoint() -> Weight; fn submit() -> Weight; fn submit_with_sync_committee() -> Weight; - fn submit_execution_header() -> Weight; } // For backwards compatibility and tests @@ -59,10 +58,4 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(6)) .saturating_add(RocksDbWeight::get().writes(1)) } - fn submit_execution_header() -> Weight { - Weight::from_parts(113_158_000_u64, 0) - .saturating_add(Weight::from_parts(0, 3537)) - .saturating_add(RocksDbWeight::get().reads(5)) - .saturating_add(RocksDbWeight::get().writes(4)) - } } diff --git a/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/execution-header-update.json b/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/execution-header-update.json deleted file mode 100755 index 319014249c12..000000000000 --- a/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/execution-header-update.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "header": { - "slot": 215, - "proposer_index": 2, - "parent_root": "0x97518f531a252bb6ca547b21aca9da767943ec99211d3b15c804e34c3a523f45", - "state_root": "0xb088b5a3a8c90d6dc919a695cd7bb0267c6f983ea2e675c559ceb8f46cb90b67", - "body_root": "0x0ba23c8224fdd01531d5ad51486353bd524a0b4c20bca704e26d3210616f829b" - }, - "ancestry_proof": { - "header_branch": [ - "0x97518f531a252bb6ca547b21aca9da767943ec99211d3b15c804e34c3a523f45", - "0x5ce0db996bd499c2b4f7a93263d5aafd052f420efb617cce6fdd54e25516aa45", - "0x84f0e373b66011ce774c7061440c0a50a51cce2b4b335395eee3e563d605597f", - "0x48f9ccc5f9594142c18c3b5c39a99f0549329c6ab3ba06c9a50030eadca87770", - "0xf89d6e311e05bc75a6f63ce118bccce254551f1a88d54c3b4f773f81f946bd99", - "0x2edd6d893c22636675147c07dfcdb541a146e87c3f15b51c388be4868246dc9b", - "0xd76b7de5f856e3208a91a42c9c398a7f4fab35e667bf916346050ae742514a2d", - "0x83a2e233e76385953ca41de4c3afe60471a61f0cc1b3846b4a0670e3e563b747", - "0xe783a5a109c2ad74e4eb53e8f6b11b31266a92a9e16c1fd5873109c5d41b282c", - "0xd4ea1ef3869ee6a0fd0b19d7d70027d144eecd4f1d32cbf47632a0a9069164b9", - "0xf8179564b58eb93a850d35e4156a04db651106442ad891c3e85155c1762792f1", - "0x4cbb1edb48cf1e32fb30db60aaaeaf6190ffe4d0c8dbc96cec307daecb78be12", - "0xb7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f" - ], - "finalized_block_root": "0x890a7f23b9ed2160901654be9efc575d6830ca860e2a97866ae3423fb7bd7231" - }, - "execution_header": { - "Deneb": { - "parent_hash": "0xd82ec63f5c5e6ba61d62f09c188f158e6449b94bdcc31941e68639eec3c4cf7a", - "fee_recipient": "0x0000000000000000000000000000000000000000", - "state_root": "0x8b65545fe5f3216b47b6339b9c91ca2b7f1032a970b04246d9e9fb4460ee34c3", - "receipts_root": "0x7b1f61b9714c080ef0be014e01657a15f45f0304b477beebc7ca5596c8033095", - "logs_bloom": "0x00000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000080000000000000000000000000000004000000000080000000000000000000000000000000000010100000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000040004000000000000002000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000200000000000010", - "prev_randao": "0x6d9e2a012d82b1b6cb0a2c1c1ed24cc16dbb56e6e39ae545371e0666ab057862", - "block_number": 215, - "gas_limit": 64842908, - "gas_used": 119301, - "timestamp": 1705859527, - "extra_data": "0xd983010d0a846765746888676f312e32312e358664617277696e", - "base_fee_per_gas": 7, - "block_hash": "0x48498dbfbcfae53a7f4c289ee00747aceea925f6260c50ead5a33e1c55c40f98", - "transactions_root": "0x5ebc1347fe3df0611d4f66b19bd8e1c6f4eaed0371d850f14c83b1c77ea234e6", - "withdrawals_root": "0x792930bbd5baac43bcc798ee49aa8185ef76bb3b44ba62b91d86ae569e4bb535", - "blob_gas_used": 0, - "excess_blob_gas": 0 - } - }, - "execution_branch": [ - "0xf8c69d3830406d668619bcccc13c8dddde41e863326f7418b241d5924c4ad34a", - "0xb46f0c01805fe212e15907981b757e6c496b0cb06664224655613dcec82505bb", - "0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71", - "0xf4d6b5cf9c6e212615c3674fa625d04eb1114153fb221ef5ad02aa433fc67cfb" - ] -} \ No newline at end of file diff --git a/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/execution-proof.json b/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/execution-proof.json new file mode 100755 index 000000000000..f55898087dfe --- /dev/null +++ b/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/execution-proof.json @@ -0,0 +1,54 @@ +{ + "header": { + "slot": 393, + "proposer_index": 4, + "parent_root": "0x6545b47a614a1dd4cad042a0cdbbf5be347e8ffcdc02c6c64540d5153acebeef", + "state_root": "0xb62ac34a8cb82497be9542fe2114410c9f6021855b766015406101a1f3d86434", + "body_root": "0x04005fe231e11a5b7b1580cb73b177ae8b338bedd745497e6bb7122126a806db" + }, + "ancestry_proof": { + "header_branch": [ + "0x6545b47a614a1dd4cad042a0cdbbf5be347e8ffcdc02c6c64540d5153acebeef", + "0xfa84cc88ca53a72181599ff4eb07d8b444bce023fe2347c3b4f51004c43439d3", + "0xcadc8ae211c6f2221c9138e829249adf902419c78eb4727a150baa4d9a02cc9d", + "0x33a89962df08a35c52bd7e1d887cd71fa7803e68787d05c714036f6edf75947c", + "0x2c9760fce5c2829ef3f25595a703c21eb22d0186ce223295556ed5da663a82cf", + "0xe1aa87654db79c8a0ecd6c89726bb662fcb1684badaef5cd5256f479e3c622e1", + "0xaa70d5f314e4a1fbb9c362f3db79b21bf68b328887248651fbd29fc501d0ca97", + "0x160b6c235b3a1ed4ef5f80b03ee1c76f7bf3f591c92fca9d8663e9221b9f9f0f", + "0xf68d7dcd6a07a18e9de7b5d2aa1980eb962e11d7dcb584c96e81a7635c8d2535", + "0x1d5f912dfd6697110dd1ecb5cb8e77952eef57d85deb373572572df62bb157fc", + "0xffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b", + "0x6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220", + "0xb7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f" + ], + "finalized_block_root": "0x751414cd97c0624f922b3e80285e9f776b08fa22fd5f87391f2ed7ef571a8d46" + }, + "execution_header": { + "Deneb": { + "parent_hash": "0x8092290aa21b7751576440f77edd02a94058429ce50e63a92d620951fb25eda2", + "fee_recipient": "0x0000000000000000000000000000000000000000", + "state_root": "0x96a83e9ddf745346fafcb0b03d57314623df669ed543c110662b21302a0fae8b", + "receipts_root": "0xdccdfceea05036f7b61dcdabadc937945d31e68a8d3dfd4dc85684457988c284", + "logs_bloom": "0x00000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000080000000400000000000000000000004000000000080000000000000000000000000000000000010100000000000000000000000000000000020000000000000000000000000000000000080000000000000000000000000000040004000000000000002002002000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000200000200000010", + "prev_randao": "0x62e309d4f5119d1f5c783abc20fc1a549efbab546d8d0b25ff1cfd58be524e67", + "block_number": 393, + "gas_limit": 54492273, + "gas_used": 199644, + "timestamp": 1710552813, + "extra_data": "0xd983010d0b846765746888676f312e32312e368664617277696e", + "base_fee_per_gas": 7, + "block_hash": "0x6a9810efb9581d30c1a5c9074f27c68ea779a8c1ae31c213241df16225f4e131", + "transactions_root": "0x2cfa6ed7327e8807c7973516c5c32a68ef2459e586e8067e113d081c3bd8c07d", + "withdrawals_root": "0x792930bbd5baac43bcc798ee49aa8185ef76bb3b44ba62b91d86ae569e4bb535", + "blob_gas_used": 0, + "excess_blob_gas": 0 + } + }, + "execution_branch": [ + "0xa6833fa629f3286b6916c6e50b8bf089fc9126bee6f64d0413b4e59c1265834d", + "0xb46f0c01805fe212e15907981b757e6c496b0cb06664224655613dcec82505bb", + "0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71", + "0xd3af7c05c516726be7505239e0b9c7cb53d24abce6b91cdb3b3995f0164a75da" + ] +} \ No newline at end of file diff --git a/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/finalized-header-update.json b/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/finalized-header-update.json index f9d5324d57b1..2dec5cc56fac 100755 --- a/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/finalized-header-update.json +++ b/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/finalized-header-update.json @@ -1,38 +1,40 @@ { "attested_header": { - "slot": 2566, - "proposer_index": 6, - "parent_root": "0x6eb9f13a2c496318ce1ab3087bbd872f5c9519a1a7ca8231a2453e3cb523af00", - "state_root": "0xc8cb12766113dff7e46d2917267bf33d0626d99dd47715fcdbc5c65fad3c04b4", - "body_root": "0xd8cfd0d7bc9bc3724417a1655bb0a67c0765ca36197320f4d834150b52ef1420" + "slot": 933, + "proposer_index": 1, + "parent_root": "0xf5fc63e2780ca302b97aea73fc95d74d702b5afe9a772c2b68f695026337b620", + "state_root": "0xd856d11636bc4d866e78be9e747b222b0977556a367ab42e4085277301438050", + "body_root": "0x5689091ab4eb76c2e876271add4924e1c66ce987c300c24aac2ad8c703e9a33f" }, "sync_aggregate": { "sync_committee_bits": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "sync_committee_signature": "0x9296f9a0387f2cac47008e22ad7c3cd3d49d35384c13e6aa1eacca7dca7c3d2ca81515e50eb3396b9550ed20ef7d8fa2049a186598feb2c00e93728045fcff917733d1827481b8fc95f3913e27fc70112c2490496eb57bb7181f02c3f9fd471f" + "sync_committee_signature": "0x93a3d482fe2a2f7fd2b634169752a8fddf1dc28b23a020b398be8526faf37a74ca0f6db1bed78a9c7256c09a6115235e108e0e8a7ce09287317b0856c4b77dfa5adba6cf4c3ebea5bfa4cd2fcde80fd0a532f2defe65d530201d5d2258796559" }, - "signature_slot": 2567, + "signature_slot": 934, "next_sync_committee_update": null, "finalized_header": { - "slot": 2496, - "proposer_index": 2, - "parent_root": "0xc99e49787106733eeebab4d93eb326e1f2214575c9d928f0c4ab0da0776f1622", - "state_root": "0xfbf8a08c86ef36bd173e37e733da4a78aa8e85fee99a990e858dd12a59087fde", - "body_root": "0xa2a8ad06901447b2807a9059580a4c40d8a941f325b1343c69f7c7c6c90e4ab0" + "slot": 864, + "proposer_index": 4, + "parent_root": "0x614e7672f991ac268cd841055973f55e1e42228831a211adef207bb7329be614", + "state_root": "0x5fa8dfca3d760e4242ab46d529144627aa85348a19173b6e081172c701197a4a", + "body_root": "0x0f34c083b1803666bb1ac5e73fa71582731a2cf37d279ff0a3b0cad5a2ff371e" }, "finality_branch": [ - "0x4e00000000000000000000000000000000000000000000000000000000000000", + "0x1b00000000000000000000000000000000000000000000000000000000000000", "0x10c726fac935bf9657cc7476d3cfa7bedec5983dcfb59e8a7df6d0a619e108d7", "0x98e9116c6bb7f20de18800dc63e73e689d06d6a47d35b5e2b32cf093d475840d", - "0x958b8e43347f6df6fa5eb3d62d06a862381a6585aa40640dd1c0de11f1cf89c1", - "0xf107dce04faa86a28fc5d4a618be9cb8d4fc3c23d6c42c3624f3ff4bf6586a03", - "0xa501cdc02e86969ac3e4d0c5a36f4f049efaa1ab8cb6693f51d130eb52a80f30" + "0xf12d9aededc72724e417b518fe6f847684f26f81616243dedf8c551cc7d504f5", + "0x89a85d0907ab3fd6e00ae385f61d456c6191646404ae7b8d23d0e60440cf4d00", + "0x9fc943b6020eb61d780d78bcc6f6102a81d2c868d58f36e61c6e286a2dc4d8c2" ], - "block_roots_root": "0xd160b7687041891b73e54b06fc4e04f82d0fa8fdd76705895e216c6b24709dfe", + "block_roots_root": "0xb9aab9c388c4e4fcd899b71f62c498fc73406e38e8eb14aa440e9affa06f2a10", "block_roots_branch": [ - "0x105290e42d98ab6a0ada6e55453cede36c672abf645eeb986b88d7487616e135", - "0x9da41f274bcdf6122335443d9ce94d07163b48dba3e2f9499ff56f4e48b48b99", - "0xecea7e1d3152d8130e83afdfe34b4de4ba2b69a33c9471991096daf454de9cf5", - "0xb2bf1758e50b2bfff29169fbc70fdb884b2b05bb615dbc53567574da6f4f1ae2", - "0xcd87069daf70975779126d6af833b7d636c75ca4d5e750ebcad0e76408a5e5bf" - ] + "0x733422bd810895dab74cbbe07c69dd440cbb51f573181ad4dddac30fcdd0f41f", + "0x9b9eca73ab01d14549c325ba1b4610bb20bf1f8ec2dbd649f9d8cc7f3cea75fa", + "0xbcc666ad0ad9f9725cbd682bc95589d35b1b53b2a615f1e6e8dd5e086336becf", + "0x3069b547a08f703a1715016e926cbd64e71f93f64fb68d98d8c8f1ab745c46e5", + "0xc2de7e1097239404e17b263cfa0473533cc41e903cb03440d633bc5c27314cb4" + ], + "execution_header": null, + "execution_branch": null } \ No newline at end of file diff --git a/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/inbound-message.json b/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/inbound-message.json index 5aa5a59f0237..6589dca5fb45 100644 --- a/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/inbound-message.json +++ b/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/inbound-message.json @@ -1,31 +1,79 @@ { - "execution_header": { - "parent_hash": "0xd82ec63f5c5e6ba61d62f09c188f158e6449b94bdcc31941e68639eec3c4cf7a", - "state_root": "0x8b65545fe5f3216b47b6339b9c91ca2b7f1032a970b04246d9e9fb4460ee34c3", - "receipts_root": "0x7b1f61b9714c080ef0be014e01657a15f45f0304b477beebc7ca5596c8033095", - "block_number": 215 + "event_log": { + "address": "0xeda338e4dc46038493b885327842fd3e301cab39", + "topics": [ + "0x7153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84f", + "0xc173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539", + "0x5f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002e00a736aa00000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d00e40b54020000000000000000000000000000000000000000000000000000000000" }, - "message": { - "event_log": { - "address": "0xeda338e4dc46038493b885327842fd3e301cab39", - "topics": [ - "0x7153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84f", - "0xc173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539", - "0x5f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0" + "proof": { + "block_hash": "0x6a9810efb9581d30c1a5c9074f27c68ea779a8c1ae31c213241df16225f4e131", + "tx_index": 0, + "receipt_proof": { + "keys": [ + "0xdccdfceea05036f7b61dcdabadc937945d31e68a8d3dfd4dc85684457988c284", + "0x4a98e45a319168b0fc6005ce6b744ee9bf54338e2c0784b976a8578d241ced0f" ], - "data": "0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002e00a736aa00000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d00e40b54020000000000000000000000000000000000000000000000000000000000" + "values": [ + "0xf851a09c01dd6d2d8de951c45af23d3ad00829ce021c04d6c8acbe1612d456ee320d4980808080808080a04a98e45a319168b0fc6005ce6b744ee9bf54338e2c0784b976a8578d241ced0f8080808080808080", + "0xf9028c30b9028802f90284018301d205b9010000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000080000000000000000000000000000004000000000080000000000000000000000000000000000010100000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000040004000000000000002000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000200000000000010f90179f85894eda338e4dc46038493b885327842fd3e301cab39e1a0f78bb28d4b1d7da699e5c0bc2be29c2b04b5aab6aacf6298fe5304f9db9c6d7ea000000000000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7df9011c94eda338e4dc46038493b885327842fd3e301cab39f863a07153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84fa0c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539a05f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0b8a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002e00a736aa00000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d00e40b54020000000000000000000000000000000000000000000000000000000000" + ] }, - "Proof": { - "block_hash": "0x48498dbfbcfae53a7f4c289ee00747aceea925f6260c50ead5a33e1c55c40f98", - "tx_index": 0, - "data": { - "keys": [ - "0x7b1f61b9714c080ef0be014e01657a15f45f0304b477beebc7ca5596c8033095" + "execution_proof": { + "header": { + "slot": 393, + "proposer_index": 4, + "parent_root": "0x6545b47a614a1dd4cad042a0cdbbf5be347e8ffcdc02c6c64540d5153acebeef", + "state_root": "0xb62ac34a8cb82497be9542fe2114410c9f6021855b766015406101a1f3d86434", + "body_root": "0x04005fe231e11a5b7b1580cb73b177ae8b338bedd745497e6bb7122126a806db" + }, + "ancestry_proof": { + "header_branch": [ + "0x6545b47a614a1dd4cad042a0cdbbf5be347e8ffcdc02c6c64540d5153acebeef", + "0xfa84cc88ca53a72181599ff4eb07d8b444bce023fe2347c3b4f51004c43439d3", + "0xcadc8ae211c6f2221c9138e829249adf902419c78eb4727a150baa4d9a02cc9d", + "0x33a89962df08a35c52bd7e1d887cd71fa7803e68787d05c714036f6edf75947c", + "0x2c9760fce5c2829ef3f25595a703c21eb22d0186ce223295556ed5da663a82cf", + "0xe1aa87654db79c8a0ecd6c89726bb662fcb1684badaef5cd5256f479e3c622e1", + "0xaa70d5f314e4a1fbb9c362f3db79b21bf68b328887248651fbd29fc501d0ca97", + "0x160b6c235b3a1ed4ef5f80b03ee1c76f7bf3f591c92fca9d8663e9221b9f9f0f", + "0xf68d7dcd6a07a18e9de7b5d2aa1980eb962e11d7dcb584c96e81a7635c8d2535", + "0x1d5f912dfd6697110dd1ecb5cb8e77952eef57d85deb373572572df62bb157fc", + "0xffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b", + "0x6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220", + "0xb7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f" ], - "values": [ - "0xf9028e822080b9028802f90284018301d205b9010000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000080000000000000000000000000000004000000000080000000000000000000000000000000000010100000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000040004000000000000002000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000200000000000010f90179f85894eda338e4dc46038493b885327842fd3e301cab39e1a0f78bb28d4b1d7da699e5c0bc2be29c2b04b5aab6aacf6298fe5304f9db9c6d7ea000000000000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7df9011c94eda338e4dc46038493b885327842fd3e301cab39f863a07153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84fa0c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539a05f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0b8a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002e00a736aa00000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d00e40b54020000000000000000000000000000000000000000000000000000000000" - ] - } + "finalized_block_root": "0x751414cd97c0624f922b3e80285e9f776b08fa22fd5f87391f2ed7ef571a8d46" + }, + "execution_header": { + "Deneb": { + "parent_hash": "0x8092290aa21b7751576440f77edd02a94058429ce50e63a92d620951fb25eda2", + "fee_recipient": "0x0000000000000000000000000000000000000000", + "state_root": "0x96a83e9ddf745346fafcb0b03d57314623df669ed543c110662b21302a0fae8b", + "receipts_root": "0xdccdfceea05036f7b61dcdabadc937945d31e68a8d3dfd4dc85684457988c284", + "logs_bloom": "0x00000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000080000000400000000000000000000004000000000080000000000000000000000000000000000010100000000000000000000000000000000020000000000000000000000000000000000080000000000000000000000000000040004000000000000002002002000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000200000200000010", + "prev_randao": "0x62e309d4f5119d1f5c783abc20fc1a549efbab546d8d0b25ff1cfd58be524e67", + "block_number": 393, + "gas_limit": 54492273, + "gas_used": 199644, + "timestamp": 1710552813, + "extra_data": "0xd983010d0b846765746888676f312e32312e368664617277696e", + "base_fee_per_gas": 7, + "block_hash": "0x6a9810efb9581d30c1a5c9074f27c68ea779a8c1ae31c213241df16225f4e131", + "transactions_root": "0x2cfa6ed7327e8807c7973516c5c32a68ef2459e586e8067e113d081c3bd8c07d", + "withdrawals_root": "0x792930bbd5baac43bcc798ee49aa8185ef76bb3b44ba62b91d86ae569e4bb535", + "blob_gas_used": 0, + "excess_blob_gas": 0 + } + }, + "execution_branch": [ + "0xa6833fa629f3286b6916c6e50b8bf089fc9126bee6f64d0413b4e59c1265834d", + "0xb46f0c01805fe212e15907981b757e6c496b0cb06664224655613dcec82505bb", + "0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71", + "0xd3af7c05c516726be7505239e0b9c7cb53d24abce6b91cdb3b3995f0164a75da" + ] } } } \ No newline at end of file diff --git a/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/initial-checkpoint.json b/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/initial-checkpoint.json index 202790c1db5b..a62d646617e4 100755 --- a/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/initial-checkpoint.json +++ b/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/initial-checkpoint.json @@ -1,10 +1,10 @@ { "header": { - "slot": 2496, - "proposer_index": 2, - "parent_root": "0xc99e49787106733eeebab4d93eb326e1f2214575c9d928f0c4ab0da0776f1622", - "state_root": "0xfbf8a08c86ef36bd173e37e733da4a78aa8e85fee99a990e858dd12a59087fde", - "body_root": "0xa2a8ad06901447b2807a9059580a4c40d8a941f325b1343c69f7c7c6c90e4ab0" + "slot": 864, + "proposer_index": 4, + "parent_root": "0x614e7672f991ac268cd841055973f55e1e42228831a211adef207bb7329be614", + "state_root": "0x5fa8dfca3d760e4242ab46d529144627aa85348a19173b6e081172c701197a4a", + "body_root": "0x0f34c083b1803666bb1ac5e73fa71582731a2cf37d279ff0a3b0cad5a2ff371e" }, "current_sync_committee": { "pubkeys": [ @@ -525,18 +525,18 @@ }, "current_sync_committee_branch": [ "0x3ade38d498a062b50880a9409e1ca3a7fd4315d91eeb3bb83e56ac6bfe8d6a59", - "0x93880225bf99a0c5ec22b266ff829837754e9c5edf37a68c05b8f803fd82fa45", - "0x4c60656ec9a95fcf11030ad309c716b5b15beb7f60a0bcfc7c9d4eff505472ff", - "0x22d1645fceb4bf9a695043dda19a53e784ec70df6a6b1bd66ea30eba1cca5f2f", - "0xa8fc6cad84ceefc633ec56c2d031d525e1cb4b51c70eb252919fce5bba9a1fde" + "0xa9e90f89e7f90fd5d79a6bbcaf40ba5cfc05ab1b561ac51c84867c32248d5b1e", + "0xbd1a76b03e02402bb24a627de1980a80ab17691980271f597b844b89b497ef75", + "0x07bbcd27c7cad089023db046eda17e8209842b7d97add8b873519e84fe6480e7", + "0x94c11eeee4cb6192bf40810f23486d8c75dfbc2b6f28d988d6f74435ede243b0" ], "validators_root": "0x270d43e74ce340de4bca2b1936beca0f4f5408d9e78aec4850920baf659d5b69", - "block_roots_root": "0xd160b7687041891b73e54b06fc4e04f82d0fa8fdd76705895e216c6b24709dfe", + "block_roots_root": "0xb9aab9c388c4e4fcd899b71f62c498fc73406e38e8eb14aa440e9affa06f2a10", "block_roots_branch": [ - "0x105290e42d98ab6a0ada6e55453cede36c672abf645eeb986b88d7487616e135", - "0x9da41f274bcdf6122335443d9ce94d07163b48dba3e2f9499ff56f4e48b48b99", - "0xecea7e1d3152d8130e83afdfe34b4de4ba2b69a33c9471991096daf454de9cf5", - "0xb2bf1758e50b2bfff29169fbc70fdb884b2b05bb615dbc53567574da6f4f1ae2", - "0xcd87069daf70975779126d6af833b7d636c75ca4d5e750ebcad0e76408a5e5bf" + "0x733422bd810895dab74cbbe07c69dd440cbb51f573181ad4dddac30fcdd0f41f", + "0x9b9eca73ab01d14549c325ba1b4610bb20bf1f8ec2dbd649f9d8cc7f3cea75fa", + "0xbcc666ad0ad9f9725cbd682bc95589d35b1b53b2a615f1e6e8dd5e086336becf", + "0x3069b547a08f703a1715016e926cbd64e71f93f64fb68d98d8c8f1ab745c46e5", + "0xc2de7e1097239404e17b263cfa0473533cc41e903cb03440d633bc5c27314cb4" ] } \ No newline at end of file diff --git a/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/sync-committee-update.json b/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/sync-committee-update.json index 6bf20355c7a3..4d601d7d8f0b 100755 --- a/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/sync-committee-update.json +++ b/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/sync-committee-update.json @@ -2,13 +2,13 @@ "attested_header": { "slot": 129, "proposer_index": 5, - "parent_root": "0xe32b6c18f029e755b0273dc1c4fa2bc4979794c8286ad40276c1b8a8e36049d8", - "state_root": "0x5ec9dacf25a5f09f20be0c59246b3d8dcfe64bd085b4bac5cec180690339801e", - "body_root": "0x4080cf2412d6ff77fc3164ad6155423a7112f207f173145ec16371a93f481f87" + "parent_root": "0xc2def03fe44a2802130ca1a6d8406e4ccf4f344fec7075d4d84431cd4a8b0904", + "state_root": "0xfa62cde6666add7353d7aedcb61ebe3c6c84b5361e34f814825b1250affb5be4", + "body_root": "0x0f9c69f243fe7b5fa5860396c66c720a9e8b1e526e7914188930497cc4a9134c" }, "sync_aggregate": { "sync_committee_bits": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "sync_committee_signature": "0xa761c3333fbb3d36bc8f65454f898da38001499dcd37494cf3d86940a995399ae649216ba4c985af154f83f72c8b1856079b7636a7a8d7d3f7602df2cbf699edb72b65253e82de4d9cc4db7377eafb22f799129f63f094a21c00675bdd5cc243" + "sync_committee_signature": "0x810cfde2afea3e276256c09bdf1cd321c33dcadeefddcfd24f488e6f756d917cfda90b5b437b3a4b4ef880985afa28a40cf565ec0a82877ddee36adc01d55d9d4a911ae3e22556e4c2636f1c707366fba019fb49450440fcd263d0b054b04bf0" }, "signature_slot": 130, "next_sync_committee_update": { @@ -531,33 +531,35 @@ }, "next_sync_committee_branch": [ "0x3ade38d498a062b50880a9409e1ca3a7fd4315d91eeb3bb83e56ac6bfe8d6a59", - "0xfd1e5ff5d4a15081efe3ff17857b1f95984c9a271b1c41c2f81f43e60c2cc541", - "0xe1c97f93bb7352d395d1ff8ee29881572cb7eb5d71634783701171dcd30cd93d", - "0x77fa2170ddbd89b15dae02f2e6cf9f76c8e00d1c4217320acffbe01576d0da61", - "0xe97288e0627219087a024078d69445f34f0583a6350a7c3c40c39fd1fa6f8d68" + "0x43276bee17fc9fba3f4866e902f0e5b5b308d79db91154bb8bf819973837a7d9", + "0x5572348e13ce59446ca0ea7cfeed07579da05f121920a76559e19bda94dd81cd", + "0x2d58adca9f3c742530de037f1933d6de1920ea4b68581613d4bc32b71547f221", + "0x7072b3c6577cd5a89b3234968f316f54630bb97eafbdb59e5b61637a9640255f" ] }, "finalized_header": { "slot": 64, "proposer_index": 4, - "parent_root": "0x0f7bc2353778c14c7f6dba0fc5fe6eec87228b0d3a5447b61dce67b4d9338de3", - "state_root": "0xfeb990de653ce494c0a263f820eaf05a9300dbdc30cb6065ede602827bfccde4", - "body_root": "0xf5235cd8c24f2695fc5b7989926305c10ad8cf5a87d62a739f675f5543df2ec1" + "parent_root": "0xa876486aaad7ddb897f369fd22d0a9903cd61d00c9e0dfe7998dd68d1008c678", + "state_root": "0x818e21c3388575f8ccc9ff17ec79d5a57915bcd31bccf47770f65a18e068416b", + "body_root": "0x1d1f73b864b3bb7e11ff91b56ca1381e0f9ca8122b2c542db88243604c763019" }, "finality_branch": [ "0x0200000000000000000000000000000000000000000000000000000000000000", "0x10c726fac935bf9657cc7476d3cfa7bedec5983dcfb59e8a7df6d0a619e108d7", "0x98e9116c6bb7f20de18800dc63e73e689d06d6a47d35b5e2b32cf093d475840d", - "0xe1c97f93bb7352d395d1ff8ee29881572cb7eb5d71634783701171dcd30cd93d", - "0x77fa2170ddbd89b15dae02f2e6cf9f76c8e00d1c4217320acffbe01576d0da61", - "0xe97288e0627219087a024078d69445f34f0583a6350a7c3c40c39fd1fa6f8d68" + "0x5572348e13ce59446ca0ea7cfeed07579da05f121920a76559e19bda94dd81cd", + "0x2d58adca9f3c742530de037f1933d6de1920ea4b68581613d4bc32b71547f221", + "0x7072b3c6577cd5a89b3234968f316f54630bb97eafbdb59e5b61637a9640255f" ], - "block_roots_root": "0x6fcdfd1c3fb1bdd421fe59dddfff3855b5ed5e30373887991a0059d019ad12bc", + "block_roots_root": "0x715b08694bef183a6d94b3113d16a7129f89fc3edec85a7e0eaf6ef9153552ef", "block_roots_branch": [ - "0x94b59531f172bc24f914bc0c10104ccb158676850f8cc3b47b6ddb7f096ebdd7", - "0x22470ed9155a938587d44d5fa19217c0f939d8862e504e67cd8cb4d1b960795e", - "0xfeec3ef1a68f93849e71e84f90b99602cccc31868137b6887ca8244a4b979e8e", + "0x4028c72c71b6ce80ea7d18b2c9471f4e4fa39746261a9921e832a4a2f9bdf7bb", + "0x75f98062661785d3290b7bd998b64446582baa49210733fd4603e1a97cd45a44", + "0x6fb757f44052f30c464810f01b0132adfa1a5446d8715b41e9af88eee1ee3e65", "0x5340ad5877c72dca689ca04bc8fedb78d67a4801d99887937edd8ccd29f87e82", - "0xf5ff4b0c6190005015889879568f5f0d9c40134c7ec4ffdda47950dcd92395ad" - ] + "0xf2b3cb56753939a728ccad399a434ca490f018f2f331529ec0d8b2d59c509271" + ], + "execution_header": null, + "execution_branch": null } \ No newline at end of file diff --git a/bridges/snowbridge/pallets/inbound-queue/fixtures/src/lib.rs b/bridges/snowbridge/pallets/inbound-queue/fixtures/src/lib.rs index 4f3445b29053..00adcdfa186a 100644 --- a/bridges/snowbridge/pallets/inbound-queue/fixtures/src/lib.rs +++ b/bridges/snowbridge/pallets/inbound-queue/fixtures/src/lib.rs @@ -2,17 +2,6 @@ // SPDX-FileCopyrightText: 2023 Snowfork #![cfg_attr(not(feature = "std"), no_std)] -use snowbridge_beacon_primitives::CompactExecutionHeader; -use snowbridge_core::inbound::Message; -use sp_core::RuntimeDebug; - pub mod register_token; -pub mod register_token_with_insufficient_fee; pub mod send_token; pub mod send_token_to_penpal; - -#[derive(Clone, RuntimeDebug)] -pub struct InboundQueueFixture { - pub execution_header: CompactExecutionHeader, - pub message: Message, -} diff --git a/bridges/snowbridge/pallets/inbound-queue/fixtures/src/register_token.rs b/bridges/snowbridge/pallets/inbound-queue/fixtures/src/register_token.rs index b8d510e6b13d..340b2fadfacf 100644 --- a/bridges/snowbridge/pallets/inbound-queue/fixtures/src/register_token.rs +++ b/bridges/snowbridge/pallets/inbound-queue/fixtures/src/register_token.rs @@ -3,20 +3,16 @@ // Generated, do not edit! // See ethereum client README.md for instructions to generate -use crate::InboundQueueFixture; use hex_literal::hex; -use snowbridge_beacon_primitives::CompactExecutionHeader; -use snowbridge_core::inbound::{Log, Message, Proof}; +use snowbridge_beacon_primitives::{ + types::deneb, AncestryProof, BeaconHeader, ExecutionProof, VersionedExecutionPayloadHeader, +}; +use snowbridge_core::inbound::{InboundQueueFixture, Log, Message, Proof}; +use sp_core::U256; use sp_std::vec; pub fn make_register_token_message() -> InboundQueueFixture { InboundQueueFixture { - execution_header: CompactExecutionHeader{ - parent_hash: hex!("d5de3dd02c96dbdc8aaa4db70a1e9fdab5ded5f4d52f18798acd56a3d37d1ad6").into(), - block_number: 772, - state_root: hex!("49cba2a79b23ad74cefe80c3a96699825d1cda0f75bfceb587c5549211c86245").into(), - receipts_root: hex!("7b1f61b9714c080ef0be014e01657a15f45f0304b477beebc7ca5596c8033095").into(), - }, message: Message { event_log: Log { address: hex!("eda338e4dc46038493b885327842fd3e301cab39").into(), @@ -28,14 +24,74 @@ pub fn make_register_token_message() -> InboundQueueFixture { data: hex!("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002e00a736aa00000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d00e40b54020000000000000000000000000000000000000000000000000000000000").into(), }, proof: Proof { - block_hash: hex!("392182a385b3a417e8ddea8b252953ee81e6ec0fb09d9056c96c89fbeb703a3f").into(), - tx_index: 0, - data: (vec![ - hex!("7b1f61b9714c080ef0be014e01657a15f45f0304b477beebc7ca5596c8033095").to_vec(), + receipt_proof: (vec![ + hex!("dccdfceea05036f7b61dcdabadc937945d31e68a8d3dfd4dc85684457988c284").to_vec(), + hex!("4a98e45a319168b0fc6005ce6b744ee9bf54338e2c0784b976a8578d241ced0f").to_vec(), ], vec![ - hex!("f9028e822080b9028802f90284018301d205b9010000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000080000000000000000000000000000004000000000080000000000000000000000000000000000010100000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000040004000000000000002000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000200000000000010f90179f85894eda338e4dc46038493b885327842fd3e301cab39e1a0f78bb28d4b1d7da699e5c0bc2be29c2b04b5aab6aacf6298fe5304f9db9c6d7ea000000000000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7df9011c94eda338e4dc46038493b885327842fd3e301cab39f863a07153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84fa0c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539a05f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0b8a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002e00a736aa00000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d00e40b54020000000000000000000000000000000000000000000000000000000000").to_vec(), + hex!("f851a09c01dd6d2d8de951c45af23d3ad00829ce021c04d6c8acbe1612d456ee320d4980808080808080a04a98e45a319168b0fc6005ce6b744ee9bf54338e2c0784b976a8578d241ced0f8080808080808080").to_vec(), + hex!("f9028c30b9028802f90284018301d205b9010000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000080000000000000000000000000000004000000000080000000000000000000000000000000000010100000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000040004000000000000002000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000200000000000010f90179f85894eda338e4dc46038493b885327842fd3e301cab39e1a0f78bb28d4b1d7da699e5c0bc2be29c2b04b5aab6aacf6298fe5304f9db9c6d7ea000000000000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7df9011c94eda338e4dc46038493b885327842fd3e301cab39f863a07153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84fa0c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539a05f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0b8a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002e00a736aa00000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d00e40b54020000000000000000000000000000000000000000000000000000000000").to_vec(), ]), + execution_proof: ExecutionProof { + header: BeaconHeader { + slot: 393, + proposer_index: 4, + parent_root: hex!("6545b47a614a1dd4cad042a0cdbbf5be347e8ffcdc02c6c64540d5153acebeef").into(), + state_root: hex!("b62ac34a8cb82497be9542fe2114410c9f6021855b766015406101a1f3d86434").into(), + body_root: hex!("04005fe231e11a5b7b1580cb73b177ae8b338bedd745497e6bb7122126a806db").into(), + }, + ancestry_proof: Some(AncestryProof { + header_branch: vec![ + hex!("6545b47a614a1dd4cad042a0cdbbf5be347e8ffcdc02c6c64540d5153acebeef").into(), + hex!("fa84cc88ca53a72181599ff4eb07d8b444bce023fe2347c3b4f51004c43439d3").into(), + hex!("cadc8ae211c6f2221c9138e829249adf902419c78eb4727a150baa4d9a02cc9d").into(), + hex!("33a89962df08a35c52bd7e1d887cd71fa7803e68787d05c714036f6edf75947c").into(), + hex!("2c9760fce5c2829ef3f25595a703c21eb22d0186ce223295556ed5da663a82cf").into(), + hex!("e1aa87654db79c8a0ecd6c89726bb662fcb1684badaef5cd5256f479e3c622e1").into(), + hex!("aa70d5f314e4a1fbb9c362f3db79b21bf68b328887248651fbd29fc501d0ca97").into(), + hex!("160b6c235b3a1ed4ef5f80b03ee1c76f7bf3f591c92fca9d8663e9221b9f9f0f").into(), + hex!("f68d7dcd6a07a18e9de7b5d2aa1980eb962e11d7dcb584c96e81a7635c8d2535").into(), + hex!("1d5f912dfd6697110dd1ecb5cb8e77952eef57d85deb373572572df62bb157fc").into(), + hex!("ffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b").into(), + hex!("6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220").into(), + hex!("b7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f").into(), + ], + finalized_block_root: hex!("751414cd97c0624f922b3e80285e9f776b08fa22fd5f87391f2ed7ef571a8d46").into(), + }), + execution_header: VersionedExecutionPayloadHeader::Deneb(deneb::ExecutionPayloadHeader { + parent_hash: hex!("8092290aa21b7751576440f77edd02a94058429ce50e63a92d620951fb25eda2").into(), + fee_recipient: hex!("0000000000000000000000000000000000000000").into(), + state_root: hex!("96a83e9ddf745346fafcb0b03d57314623df669ed543c110662b21302a0fae8b").into(), + receipts_root: hex!("dccdfceea05036f7b61dcdabadc937945d31e68a8d3dfd4dc85684457988c284").into(), + logs_bloom: hex!("00000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000080000000400000000000000000000004000000000080000000000000000000000000000000000010100000000000000000000000000000000020000000000000000000000000000000000080000000000000000000000000000040004000000000000002002002000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000200000200000010").into(), + prev_randao: hex!("62e309d4f5119d1f5c783abc20fc1a549efbab546d8d0b25ff1cfd58be524e67").into(), + block_number: 393, + gas_limit: 54492273, + gas_used: 199644, + timestamp: 1710552813, + extra_data: hex!("d983010d0b846765746888676f312e32312e368664617277696e").into(), + base_fee_per_gas: U256::from(7u64), + block_hash: hex!("6a9810efb9581d30c1a5c9074f27c68ea779a8c1ae31c213241df16225f4e131").into(), + transactions_root: hex!("2cfa6ed7327e8807c7973516c5c32a68ef2459e586e8067e113d081c3bd8c07d").into(), + withdrawals_root: hex!("792930bbd5baac43bcc798ee49aa8185ef76bb3b44ba62b91d86ae569e4bb535").into(), + blob_gas_used: 0, + excess_blob_gas: 0, + }), + execution_branch: vec![ + hex!("a6833fa629f3286b6916c6e50b8bf089fc9126bee6f64d0413b4e59c1265834d").into(), + hex!("b46f0c01805fe212e15907981b757e6c496b0cb06664224655613dcec82505bb").into(), + hex!("db56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71").into(), + hex!("d3af7c05c516726be7505239e0b9c7cb53d24abce6b91cdb3b3995f0164a75da").into(), + ], + } }, }, + finalized_header: BeaconHeader { + slot: 864, + proposer_index: 4, + parent_root: hex!("614e7672f991ac268cd841055973f55e1e42228831a211adef207bb7329be614").into(), + state_root: hex!("5fa8dfca3d760e4242ab46d529144627aa85348a19173b6e081172c701197a4a").into(), + body_root: hex!("0f34c083b1803666bb1ac5e73fa71582731a2cf37d279ff0a3b0cad5a2ff371e").into(), + }, + block_roots_root: hex!("b9aab9c388c4e4fcd899b71f62c498fc73406e38e8eb14aa440e9affa06f2a10").into(), } } diff --git a/bridges/snowbridge/pallets/inbound-queue/fixtures/src/register_token_with_insufficient_fee.rs b/bridges/snowbridge/pallets/inbound-queue/fixtures/src/register_token_with_insufficient_fee.rs deleted file mode 100644 index dfda0b2b4278..000000000000 --- a/bridges/snowbridge/pallets/inbound-queue/fixtures/src/register_token_with_insufficient_fee.rs +++ /dev/null @@ -1,42 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2023 Snowfork -// Generated, do not edit! -// See ethereum client README.md for instructions to generate - -use crate::InboundQueueFixture; -use hex_literal::hex; -use snowbridge_beacon_primitives::CompactExecutionHeader; -use snowbridge_core::inbound::{Log, Message, Proof}; -use sp_std::vec; - -pub fn make_register_token_with_insufficient_fee_message() -> InboundQueueFixture { - InboundQueueFixture { - execution_header: CompactExecutionHeader{ - parent_hash: hex!("998e81dc6df788a920b67e058fbde0dc3f4ec6f11f3f7cd8c3148e6d99584885").into(), - block_number: 338, - state_root: hex!("30ef9c9db2609de19bbc6c3cbeddac889e82bbcb2db20304b3abdfbdc7134cbf").into(), - receipts_root: hex!("969335c3132a007cb8b5886a3c23dd8da63cba04aeda29857a86ee1c13dae782").into(), - }, - message: Message { - event_log: Log { - address: hex!("eda338e4dc46038493b885327842fd3e301cab39").into(), - topics: vec![ - hex!("7153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84f").into(), - hex!("c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539").into(), - hex!("5f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0").into(), - ], - // insufficient xcm fee as only 1000(hex:e803) - data: hex!("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002e00a736aa00000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7de8030000000000000000000000000000000000000000000000000000000000000000").into(), - }, - proof: Proof { - block_hash: hex!("5976f37f0e331d194eb331df74355ef47565c3a1bd11c95a45b681f6917085c1").into(), - tx_index: 0, - data: (vec![ - hex!("969335c3132a007cb8b5886a3c23dd8da63cba04aeda29857a86ee1c13dae782").to_vec(), - ], vec![ - hex!("f9028e822080b9028802f90284018301d205b9010000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000080000000000000000000000000000004000000000080000000000000000000000000000000000010100000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000040004000000000000002000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000200000000000010f90179f85894eda338e4dc46038493b885327842fd3e301cab39e1a0f78bb28d4b1d7da699e5c0bc2be29c2b04b5aab6aacf6298fe5304f9db9c6d7ea000000000000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7df9011c94eda338e4dc46038493b885327842fd3e301cab39f863a07153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84fa0c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539a05f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0b8a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002e00a736aa00000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7de8030000000000000000000000000000000000000000000000000000000000000000").to_vec(), - ]), - }, - }, - } -} diff --git a/bridges/snowbridge/pallets/inbound-queue/fixtures/src/send_token.rs b/bridges/snowbridge/pallets/inbound-queue/fixtures/src/send_token.rs index 2562217100ea..4075febab59d 100755 --- a/bridges/snowbridge/pallets/inbound-queue/fixtures/src/send_token.rs +++ b/bridges/snowbridge/pallets/inbound-queue/fixtures/src/send_token.rs @@ -3,20 +3,16 @@ // Generated, do not edit! // See ethereum client README.md for instructions to generate -use crate::InboundQueueFixture; use hex_literal::hex; -use snowbridge_beacon_primitives::CompactExecutionHeader; -use snowbridge_core::inbound::{Log, Message, Proof}; +use snowbridge_beacon_primitives::{ + types::deneb, AncestryProof, BeaconHeader, ExecutionProof, VersionedExecutionPayloadHeader, +}; +use snowbridge_core::inbound::{InboundQueueFixture, Log, Message, Proof}; +use sp_core::U256; use sp_std::vec; pub fn make_send_token_message() -> InboundQueueFixture { InboundQueueFixture { - execution_header: CompactExecutionHeader{ - parent_hash: hex!("920cecde45d428e3a77590b70f8533cf4c2c36917b8a7b74c915e7fa3dae7075").into(), - block_number: 1148, - state_root: hex!("bbc6ba0e9940d641afecbbaf3f97abd2b9ffaf2f6bd4879c4a71e659eca89978").into(), - receipts_root: hex!("9f3340b57eddc1f86de30776db57faeca80269a3dd459031741988dec240ce34").into(), - }, message: Message { event_log: Log { address: hex!("eda338e4dc46038493b885327842fd3e301cab39").into(), @@ -28,14 +24,72 @@ pub fn make_send_token_message() -> InboundQueueFixture { data: hex!("00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000005f00a736aa00000000000187d1f7fdfee7f651fabc8bfcb6e086c278b77a7d008eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48000064a7b3b6e00d000000000000000000e40b5402000000000000000000000000").into(), }, proof: Proof { - block_hash: hex!("d3c155f123c3cbff22f3d7869283e02179edea9ffa7a5e9a4d8414c2a6b8991f").into(), - tx_index: 0, - data: (vec![ - hex!("9f3340b57eddc1f86de30776db57faeca80269a3dd459031741988dec240ce34").to_vec(), + receipt_proof: (vec![ + hex!("f9d844c5b79638609ba385b910fec3b5d891c9d7b189f135f0432f33473de915").to_vec(), ], vec![ - hex!("f90451822080b9044b02f90447018301bcb9b9010000800000000000000000000020000000000000000000004000000000000000000400000000000000000000001000000010000000000000000000000008000000200000000000000001000008000000000000000000000000000000008000080000000000200000000000000000000000000100000000000000000011000000000000020200000000000000000000000000003000000040080008000000000000000000040044000021000000002000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000200800000000000f9033cf89b9487d1f7fdfee7f651fabc8bfcb6e086c278b77a7df863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa000000000000000000000000090a987b944cb1dcce5564e5fdecd7a54d3de27fea000000000000000000000000057a2d4ff0c3866d96556884bf09fecdd7ccd530ca00000000000000000000000000000000000000000000000000de0b6b3a7640000f9015d94eda338e4dc46038493b885327842fd3e301cab39f884a024c5d2de620c6e25186ae16f6919eba93b6e2c1a33857cc419d9f3a00d6967e9a000000000000000000000000090a987b944cb1dcce5564e5fdecd7a54d3de27fea000000000000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7da000000000000000000000000000000000000000000000000000000000000003e8b8c000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000208eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48f9013c94eda338e4dc46038493b885327842fd3e301cab39f863a07153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84fa0c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539a0c8eaf22f2cb07bac4679df0a660e7115ed87fcfd4e32ac269f6540265bbbd26fb8c000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000005f00a736aa00000000000187d1f7fdfee7f651fabc8bfcb6e086c278b77a7d008eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48000064a7b3b6e00d000000000000000000e40b5402000000000000000000000000").to_vec(), + hex!("f90451822080b9044b02f90447018301bcb6b9010000800000000000000000000020000000000000000000004000000000000000000400000000000000000000001000000010000000000000000000000008000000200000000000000001000008000000000000000000000000000000008000080000000000200000000000000000000000000100000000000000000011000000000000020200000000000000000000000000003000000040080008000000000000000000040044000021000000002000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000200800000000000f9033cf89b9487d1f7fdfee7f651fabc8bfcb6e086c278b77a7df863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa000000000000000000000000090a987b944cb1dcce5564e5fdecd7a54d3de27fea000000000000000000000000057a2d4ff0c3866d96556884bf09fecdd7ccd530ca00000000000000000000000000000000000000000000000000de0b6b3a7640000f9015d94eda338e4dc46038493b885327842fd3e301cab39f884a024c5d2de620c6e25186ae16f6919eba93b6e2c1a33857cc419d9f3a00d6967e9a000000000000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7da000000000000000000000000090a987b944cb1dcce5564e5fdecd7a54d3de27fea000000000000000000000000000000000000000000000000000000000000003e8b8c000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000208eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48f9013c94eda338e4dc46038493b885327842fd3e301cab39f863a07153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84fa0c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539a0c8eaf22f2cb07bac4679df0a660e7115ed87fcfd4e32ac269f6540265bbbd26fb8c000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000005f00a736aa00000000000187d1f7fdfee7f651fabc8bfcb6e086c278b77a7d008eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48000064a7b3b6e00d000000000000000000e40b5402000000000000000000000000").to_vec(), ]), + execution_proof: ExecutionProof { + header: BeaconHeader { + slot: 2321, + proposer_index: 5, + parent_root: hex!("2add14727840d3a5ea061e14baa47030bb81380a65999200d119e73b86411d20").into(), + state_root: hex!("d962981467920bb2b7efa4a7a1baf64745582c3250857f49a957c5dae9a0da39").into(), + body_root: hex!("18e3f7f51a350f371ad35d166f2683b42af51d1836b295e4093be08acb0dcb7a").into(), + }, + ancestry_proof: Some(AncestryProof { + header_branch: vec![ + hex!("2add14727840d3a5ea061e14baa47030bb81380a65999200d119e73b86411d20").into(), + hex!("48b2e2f5256906a564e5058698f70e3406765fefd6a2edc064bb5fb88aa2ed0a").into(), + hex!("e5ed7c704e845418219b2fda42cd2f3438ffbe4c4b320935ae49439c6189f7a7").into(), + hex!("4a7ce24526b3f571548ad69679e4e260653a1b3b911a344e7f988f25a5c917a7").into(), + hex!("46fc859727ab0d0e8c344011f7d7a4426ccb537bb51363397e56cc7153f56391").into(), + hex!("f496b6f85a7c6c28a9048f2153550a7c5bcb4b23844ed3b87f6baa646124d8a3").into(), + hex!("7318644e474beb46e595a1875acc7444b937f5208065241911d2a71ac50c2de3").into(), + hex!("5cf48519e518ac64286aef5391319782dd38831d5dcc960578a6b9746d5f8cee").into(), + hex!("efb3e50fa39ca9fe7f76adbfa36fa8451ec2fd5d07b22aaf822137c04cf95a76").into(), + hex!("2206cd50750355ffaef4a67634c21168f2b564c58ffd04f33b0dc7af7dab3291").into(), + hex!("1a4014f6c4fcce9949fba74cb0f9e88df086706f9e05560cc9f0926f8c90e373").into(), + hex!("2df7cc0bcf3060be4132c63da7599c2600d9bbadf37ab001f15629bc2255698e").into(), + hex!("b7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f").into(), + ], + finalized_block_root: hex!("f869dd1c9598043008a3ac2a5d91b3d6c7b0bb3295b3843bc84c083d70b0e604").into(), + }), + execution_header: VersionedExecutionPayloadHeader::Deneb(deneb::ExecutionPayloadHeader { + parent_hash: hex!("5d7859883dde1eba6c98b20eac18426134b25da2a89e5e360f3343b15e0e0a31").into(), + fee_recipient: hex!("0000000000000000000000000000000000000000").into(), + state_root: hex!("f8fbebed4c84d46231bd293bb9fbc9340d5c28c284d99fdaddb77238b8960ae2").into(), + receipts_root: hex!("f9d844c5b79638609ba385b910fec3b5d891c9d7b189f135f0432f33473de915").into(), + logs_bloom: hex!("00800000000000000000000020000000000000000000004000000000000000000400000000000000000000001000000010000000000000000000000008000000200000000000000001000008000000000000000000000000000000008000080000000000200000000000000000000000000100000000000000000011000000000000020200000000000000000000000000003000000040080008000000000000000000040044000021000000002000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000200800000000000").into(), + prev_randao: hex!("15533eeb366c6386bea5aeb8f425871928348c092209e4377f2418a6dedd7fd0").into(), + block_number: 2321, + gas_limit: 30000000, + gas_used: 113846, + timestamp: 1710554741, + extra_data: hex!("d983010d0b846765746888676f312e32312e368664617277696e").into(), + base_fee_per_gas: U256::from(7u64), + block_hash: hex!("585a07122a30339b03b6481eae67c2d3de2b6b64f9f426230986519bf0f1bdfe").into(), + transactions_root: hex!("09cd60ee2207d804397c81f7b7e1e5d3307712b136e5376623a80317a4bdcd7a").into(), + withdrawals_root: hex!("792930bbd5baac43bcc798ee49aa8185ef76bb3b44ba62b91d86ae569e4bb535").into(), + blob_gas_used: 0, + excess_blob_gas: 0, + }), + execution_branch: vec![ + hex!("9d419471a9a4719b40e7607781fbe32d9a7766b79805505c78c0c58133496ba2").into(), + hex!("b46f0c01805fe212e15907981b757e6c496b0cb06664224655613dcec82505bb").into(), + hex!("db56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71").into(), + hex!("bee375b8f1bbe4cd0e783c78026c1829ae72741c2dead5cab05d6834c5e5df65").into(), + ], + } }, }, + finalized_header: BeaconHeader { + slot: 4032, + proposer_index: 5, + parent_root: hex!("180aaaec59d38c3860e8af203f01f41c9bc41665f4d17916567c80f6cd23e8a2").into(), + state_root: hex!("3341790429ed3bf894cafa3004351d0b99e08baf6c38eb2a54d58e69fd2d19c6").into(), + body_root: hex!("a221e0c695ac7b7d04ce39b28b954d8a682ecd57961d81b44783527c6295f455").into(), + }, + block_roots_root: hex!("5744385ef06f82e67606f49aa29cd162f2e837a68fb7bd82f1fc6155d9f8640f").into(), } } diff --git a/bridges/snowbridge/pallets/inbound-queue/fixtures/src/send_token_to_penpal.rs b/bridges/snowbridge/pallets/inbound-queue/fixtures/src/send_token_to_penpal.rs index 86ba3f7ecc18..6a951b568ae5 100755 --- a/bridges/snowbridge/pallets/inbound-queue/fixtures/src/send_token_to_penpal.rs +++ b/bridges/snowbridge/pallets/inbound-queue/fixtures/src/send_token_to_penpal.rs @@ -3,39 +3,93 @@ // Generated, do not edit! // See ethereum client README.md for instructions to generate -use crate::InboundQueueFixture; use hex_literal::hex; -use snowbridge_beacon_primitives::CompactExecutionHeader; -use snowbridge_core::inbound::{Log, Message, Proof}; +use snowbridge_beacon_primitives::{ + types::deneb, AncestryProof, BeaconHeader, ExecutionProof, VersionedExecutionPayloadHeader, +}; +use snowbridge_core::inbound::{InboundQueueFixture, Log, Message, Proof}; +use sp_core::U256; use sp_std::vec; pub fn make_send_token_to_penpal_message() -> InboundQueueFixture { InboundQueueFixture { - execution_header: CompactExecutionHeader{ - parent_hash: hex!("434148c290f27ee4be34fa344cd7608bf942a4541b27c9d868439631b3f37a8d").into(), - block_number: 816, - state_root: hex!("595e643f9095870e30e85e2bbef7d9e3a39df5aae839d26cf455d3dbf3e5a539").into(), - receipts_root: hex!("c40ab2c4abcfdea4f42195e0ad822806e5423108021c3b542646c7193319a6c1").into(), - }, message: Message { event_log: Log { address: hex!("eda338e4dc46038493b885327842fd3e301cab39").into(), topics: vec![ hex!("7153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84f").into(), hex!("c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539").into(), - hex!("c8eaf22f2cb07bac4679df0a660e7115ed87fcfd4e32ac269f6540265bbbd26f").into(), + hex!("be323bced46a1a49c8da2ab62ad5e974fd50f1dabaeed70b23ca5bcf14bfe4aa").into(), ], - data: hex!("00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000007300a736aa00000000000187d1f7fdfee7f651fabc8bfcb6e086c278b77a7d01d00700001cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07c00286bee000000000000000000000000000064a7b3b6e00d000000000000000000e40b5402000000000000000000000000000000000000000000000000").into(), + data: hex!("00000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000007300a736aa00000000000187d1f7fdfee7f651fabc8bfcb6e086c278b77a7d01d00700001cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07c00286bee000000000000000000000000000064a7b3b6e00d000000000000000000e40b5402000000000000000000000000000000000000000000000000").into(), }, proof: Proof { - block_hash: hex!("6c49a7f8fb2014a23e58a949c95a6743174589a7ce83434b073dc05dec402f3d").into(), - tx_index: 0, - data: (vec![ - hex!("c40ab2c4abcfdea4f42195e0ad822806e5423108021c3b542646c7193319a6c1").to_vec(), + receipt_proof: (vec![ + hex!("106f1eaeac04e469da0020ad5c8a72af66323638bd3f561a3c8236063202c120").to_vec(), ], vec![ - hex!("f90471822080b9046b02f90467018301d30fb9010000800000000000000000000000000000000000000000004000000000000000000400000000004000000000001000000010000000000000000000000008000000200000000000000001000008000000000000000000000000000000008000080000000000200000000000000000000000000100000000000000000011000000000000020000000000000000000000000000003000000000080018000000000000000000040044000021000000002000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000200820000000000f9035cf89b9487d1f7fdfee7f651fabc8bfcb6e086c278b77a7df863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa000000000000000000000000090a987b944cb1dcce5564e5fdecd7a54d3de27fea000000000000000000000000057a2d4ff0c3866d96556884bf09fecdd7ccd530ca00000000000000000000000000000000000000000000000000de0b6b3a7640000f9015d94eda338e4dc46038493b885327842fd3e301cab39f884a024c5d2de620c6e25186ae16f6919eba93b6e2c1a33857cc419d9f3a00d6967e9a000000000000000000000000090a987b944cb1dcce5564e5fdecd7a54d3de27fea000000000000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7da000000000000000000000000000000000000000000000000000000000000007d0b8c000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000201cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07cf9015c94eda338e4dc46038493b885327842fd3e301cab39f863a07153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84fa0c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539a0c8eaf22f2cb07bac4679df0a660e7115ed87fcfd4e32ac269f6540265bbbd26fb8e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000007300a736aa00000000000187d1f7fdfee7f651fabc8bfcb6e086c278b77a7d01d00700001cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07c00286bee000000000000000000000000000064a7b3b6e00d000000000000000000e40b5402000000000000000000000000000000000000000000000000").to_vec(), + hex!("f90471822080b9046b02f904670183017d9cb9010000800000000000008000000000000000000000000000004000000000000000000400000000004000000000001000000010000000000000000000001008000000000000000000000001000008000040000000000000000000000000008000080000000000200000000000000000000000000100000000000000000010000000000000020000000000000000000000000000003000000000080018000000000000000000040004000021000000002000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000200820000000000f9035cf89b9487d1f7fdfee7f651fabc8bfcb6e086c278b77a7df863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa000000000000000000000000090a987b944cb1dcce5564e5fdecd7a54d3de27fea000000000000000000000000057a2d4ff0c3866d96556884bf09fecdd7ccd530ca00000000000000000000000000000000000000000000000000de0b6b3a7640000f9015d94eda338e4dc46038493b885327842fd3e301cab39f884a024c5d2de620c6e25186ae16f6919eba93b6e2c1a33857cc419d9f3a00d6967e9a000000000000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7da000000000000000000000000090a987b944cb1dcce5564e5fdecd7a54d3de27fea000000000000000000000000000000000000000000000000000000000000007d0b8c000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000201cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07cf9015c94eda338e4dc46038493b885327842fd3e301cab39f863a07153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84fa0c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539a0be323bced46a1a49c8da2ab62ad5e974fd50f1dabaeed70b23ca5bcf14bfe4aab8e000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000007300a736aa00000000000187d1f7fdfee7f651fabc8bfcb6e086c278b77a7d01d00700001cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07c00286bee000000000000000000000000000064a7b3b6e00d000000000000000000e40b5402000000000000000000000000000000000000000000000000").to_vec(), ]), + execution_proof: ExecutionProof { + header: BeaconHeader { + slot: 4235, + proposer_index: 4, + parent_root: hex!("1b31e6264c19bcad120e434e0aede892e7d7c8ed80ab505cb593d9a4a16bc566").into(), + state_root: hex!("725f51771a0ecf72c647a283ab814ca088f998eb8c203181496b0b8e01f624fa").into(), + body_root: hex!("6f1c326d192e7e97e21e27b16fd7f000b8fa09b435ff028849927e382302b0ce").into(), + }, + ancestry_proof: Some(AncestryProof { + header_branch: vec![ + hex!("1b31e6264c19bcad120e434e0aede892e7d7c8ed80ab505cb593d9a4a16bc566").into(), + hex!("335eb186c077fa7053ec96dcc5d34502c997713d2d5bc4eb74842118d8cd5a64").into(), + hex!("326607faf2a7dfc9cfc4b6895f8f3d92a659552deb2c8fd1e892ec00c86c734c").into(), + hex!("4e20002125d7b6504df7c774f3f48e018e1e6762d03489149670a8335bba1425").into(), + hex!("e76af5cd61aade5aec8282b6f1df9046efa756b0466bba5e49032410f7739a1b").into(), + hex!("ee4dcd9527712116380cddafd120484a3bedf867225bbb86850b84decf6da730").into(), + hex!("e4687a07421d3150439a2cd2f09f3b468145d75b359a2e5fa88dfbec51725b15").into(), + hex!("38eaa78978e95759aa9b6f8504a8dbe36151f20ae41907e6a1ea165700ceefcd").into(), + hex!("1c1b071ec6f13e15c47d07d1bfbcc9135d6a6c819e68e7e6078a2007418c1a23").into(), + hex!("0b3ad7ad193c691c8c4ba1606ad2a90482cd1d033c7db58cfe739d0e20431e9e").into(), + hex!("ffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b").into(), + hex!("6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220").into(), + hex!("b2ffec5f2c14640305dd941330f09216c53b99d198e93735a400a6d3a4de191f").into(), + ], + finalized_block_root: hex!("08be7a59e947f08cd95c4ef470758730bf9e3b0db0824cb663ea541c39b0e65c").into(), + }), + execution_header: VersionedExecutionPayloadHeader::Deneb(deneb::ExecutionPayloadHeader { + parent_hash: hex!("5d1186ae041f58785edb2f01248e95832f2e5e5d6c4eb8f7ff2f58980bfc2de9").into(), + fee_recipient: hex!("0000000000000000000000000000000000000000").into(), + state_root: hex!("2a66114d20e93082c8e9b47c8d401a937013487d757c9c2f3123cf43dc1f656d").into(), + receipts_root: hex!("106f1eaeac04e469da0020ad5c8a72af66323638bd3f561a3c8236063202c120").into(), + logs_bloom: hex!("00800000000000008000000000000000000000000000004000000000000000000400000000004000000000001000000010000000000000000000001008000000000000000000000001000008000040000000000000000000000000008000080000000000200000000000000000000000000100000000000000000010000000000000020000000000000000000000000000003000000000080018000000000000000000040004000021000000002000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000200820000000000").into(), + prev_randao: hex!("92e063c7e369b74149fdd1d7132ed2f635a19b9d8bff57637b8ee4736576426e").into(), + block_number: 4235, + gas_limit: 30000000, + gas_used: 97692, + timestamp: 1710556655, + extra_data: hex!("d983010d0b846765746888676f312e32312e368664617277696e").into(), + base_fee_per_gas: U256::from(7u64), + block_hash: hex!("ce24fe3047aa20a8f222cd1d04567c12b39455400d681141962c2130e690953f").into(), + transactions_root: hex!("0c8388731de94771777c60d452077065354d90d6e5088db61fc6a134684195cc").into(), + withdrawals_root: hex!("792930bbd5baac43bcc798ee49aa8185ef76bb3b44ba62b91d86ae569e4bb535").into(), + blob_gas_used: 0, + excess_blob_gas: 0, + }), + execution_branch: vec![ + hex!("99d397fa180078e66cd3a3b77bcb07553052f4e21d447167f3a406f663b14e6a").into(), + hex!("b46f0c01805fe212e15907981b757e6c496b0cb06664224655613dcec82505bb").into(), + hex!("db56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71").into(), + hex!("53ddf17147819c1abb918178b0230d965d1bc2c0d389f45e91e54cb1d2d468aa").into(), + ], + } }, }, + finalized_header: BeaconHeader { + slot: 4672, + proposer_index: 4, + parent_root: hex!("951233bf9f4bddfb2fa8f54e3bd0c7883779ef850e13e076baae3130dd7732db").into(), + state_root: hex!("4d303003b8cb097cbcc14b0f551ee70dac42de2c1cc2f4acfca7058ca9713291").into(), + body_root: hex!("664d13952b6f369bf4cf3af74d067ec33616eb57ed3a8a403fd5bae4fbf737dd").into(), + }, + block_roots_root: hex!("af71048297c070e6539cf3b9b90ae07d86d363454606bc239734629e6b49b983").into(), } } diff --git a/bridges/snowbridge/pallets/inbound-queue/src/benchmarking/mod.rs b/bridges/snowbridge/pallets/inbound-queue/src/benchmarking/mod.rs index 931befa2ac67..d59d92757721 100644 --- a/bridges/snowbridge/pallets/inbound-queue/src/benchmarking/mod.rs +++ b/bridges/snowbridge/pallets/inbound-queue/src/benchmarking/mod.rs @@ -19,8 +19,8 @@ mod benchmarks { let create_message = make_register_token_message(); T::Helper::initialize_storage( - create_message.message.proof.block_hash, - create_message.execution_header, + create_message.finalized_header, + create_message.block_roots_root, ); let sovereign_account = sibling_sovereign_account::(1000u32.into()); diff --git a/bridges/snowbridge/pallets/inbound-queue/src/lib.rs b/bridges/snowbridge/pallets/inbound-queue/src/lib.rs index bdc21fcf0370..8acbb0c2916e 100644 --- a/bridges/snowbridge/pallets/inbound-queue/src/lib.rs +++ b/bridges/snowbridge/pallets/inbound-queue/src/lib.rs @@ -28,9 +28,6 @@ mod envelope; #[cfg(feature = "runtime-benchmarks")] mod benchmarking; -#[cfg(feature = "runtime-benchmarks")] -use snowbridge_beacon_primitives::CompactExecutionHeader; - pub mod weights; #[cfg(test)] @@ -44,7 +41,7 @@ use envelope::Envelope; use frame_support::{ traits::{ fungible::{Inspect, Mutate}, - tokens::Preservation, + tokens::{Fortitude, Preservation}, }, weights::WeightToFee, PalletError, @@ -52,6 +49,7 @@ use frame_support::{ use frame_system::ensure_signed; use scale_info::TypeInfo; use sp_core::{H160, H256}; +use sp_runtime::traits::Zero; use sp_std::{convert::TryFrom, vec}; use xcm::prelude::{ send_xcm, Instruction::SetTopic, Junction::*, Location, SendError as XcmpSendError, SendXcm, @@ -72,6 +70,9 @@ use sp_runtime::{traits::Saturating, SaturatedConversion, TokenError}; pub use weights::WeightInfo; +#[cfg(feature = "runtime-benchmarks")] +use snowbridge_beacon_primitives::BeaconHeader; + type BalanceOf = <::Token as Inspect<::AccountId>>::Balance; @@ -91,7 +92,7 @@ pub mod pallet { #[cfg(feature = "runtime-benchmarks")] pub trait BenchmarkHelper { - fn initialize_storage(block_hash: H256, header: CompactExecutionHeader); + fn initialize_storage(beacon_header: BeaconHeader, block_roots_root: H256); } #[pallet::config] @@ -261,11 +262,19 @@ pub mod pallet { } })?; - // Reward relayer from the sovereign account of the destination parachain - // Expected to fail if sovereign account has no funds + // Reward relayer from the sovereign account of the destination parachain, only if funds + // are available let sovereign_account = sibling_sovereign_account::(channel.para_id); let delivery_cost = Self::calculate_delivery_cost(message.encode().len() as u32); - T::Token::transfer(&sovereign_account, &who, delivery_cost, Preservation::Preserve)?; + let amount = T::Token::reducible_balance( + &sovereign_account, + Preservation::Preserve, + Fortitude::Polite, + ) + .min(delivery_cost); + if !amount.is_zero() { + T::Token::transfer(&sovereign_account, &who, amount, Preservation::Preserve)?; + } // Decode message into XCM let (xcm, fee) = diff --git a/bridges/snowbridge/pallets/inbound-queue/src/mock.rs b/bridges/snowbridge/pallets/inbound-queue/src/mock.rs index 39e9532ed321..c96c868bc26e 100644 --- a/bridges/snowbridge/pallets/inbound-queue/src/mock.rs +++ b/bridges/snowbridge/pallets/inbound-queue/src/mock.rs @@ -4,11 +4,13 @@ use super::*; use frame_support::{ derive_impl, parameter_types, - traits::{ConstU128, ConstU32, Everything}, + traits::{ConstU32, Everything}, weights::IdentityFee, }; use hex_literal::hex; -use snowbridge_beacon_primitives::{Fork, ForkVersions}; +use snowbridge_beacon_primitives::{ + types::deneb, BeaconHeader, ExecutionProof, Fork, ForkVersions, VersionedExecutionPayloadHeader, +}; use snowbridge_core::{ gwei, inbound::{Log, Proof, VerificationError}, @@ -20,7 +22,7 @@ use sp_runtime::{ traits::{BlakeTwo256, IdentifyAccount, IdentityLookup, Verify}, BuildStorage, FixedU128, MultiSignature, }; -use sp_std::convert::From; +use sp_std::{convert::From, default::Default}; use xcm::{latest::SendXcm, prelude::*}; use xcm_executor::AssetsInHolding; @@ -65,6 +67,10 @@ impl frame_system::Config for Test { type Block = Block; } +parameter_types! { + pub const ExistentialDeposit: u128 = 1; +} + impl pallet_balances::Config for Test { type MaxLocks = (); type MaxReserves = (); @@ -72,7 +78,7 @@ impl pallet_balances::Config for Test { type Balance = Balance; type RuntimeEvent = RuntimeEvent; type DustRemoval = (); - type ExistentialDeposit = ConstU128<1>; + type ExistentialDeposit = ExistentialDeposit; type AccountStore = System; type WeightInfo = (); type FreezeIdentifier = (); @@ -82,7 +88,6 @@ impl pallet_balances::Config for Test { } parameter_types! { - pub const ExecutionHeadersPruneThreshold: u32 = 10; pub const ChainForkVersions: ForkVersions = ForkVersions{ genesis: Fork { version: [0, 0, 0, 1], // 0x00000001 @@ -110,7 +115,6 @@ parameter_types! { impl snowbridge_pallet_ethereum_client::Config for Test { type RuntimeEvent = RuntimeEvent; type ForkVersions = ChainForkVersions; - type MaxExecutionHeadersToKeep = ExecutionHeadersPruneThreshold; type WeightInfo = (); } @@ -139,7 +143,7 @@ parameter_types! { #[cfg(feature = "runtime-benchmarks")] impl BenchmarkHelper for Test { // not implemented since the MockVerifier is used for tests - fn initialize_storage(_: H256, _: CompactExecutionHeader) {} + fn initialize_storage(_: BeaconHeader, _: H256) {} } // Mock XCM sender that always succeeds @@ -335,5 +339,32 @@ pub fn mock_event_log_invalid_gateway() -> Log { } } +pub fn mock_execution_proof() -> ExecutionProof { + ExecutionProof { + header: BeaconHeader::default(), + ancestry_proof: None, + execution_header: VersionedExecutionPayloadHeader::Deneb(deneb::ExecutionPayloadHeader { + parent_hash: Default::default(), + fee_recipient: Default::default(), + state_root: Default::default(), + receipts_root: Default::default(), + logs_bloom: vec![], + prev_randao: Default::default(), + block_number: 0, + gas_limit: 0, + gas_used: 0, + timestamp: 0, + extra_data: vec![], + base_fee_per_gas: Default::default(), + block_hash: Default::default(), + transactions_root: Default::default(), + withdrawals_root: Default::default(), + blob_gas_used: 0, + excess_blob_gas: 0, + }), + execution_branch: vec![], + } +} + pub const ASSET_HUB_PARAID: u32 = 1000u32; pub const TEMPLATE_PARAID: u32 = 1001u32; diff --git a/bridges/snowbridge/pallets/inbound-queue/src/test.rs b/bridges/snowbridge/pallets/inbound-queue/src/test.rs index 9a47e475b8c9..bd993c968df7 100644 --- a/bridges/snowbridge/pallets/inbound-queue/src/test.rs +++ b/bridges/snowbridge/pallets/inbound-queue/src/test.rs @@ -6,7 +6,7 @@ use frame_support::{assert_noop, assert_ok}; use hex_literal::hex; use snowbridge_core::{inbound::Proof, ChannelId}; use sp_keyring::AccountKeyring as Keyring; -use sp_runtime::{DispatchError, TokenError}; +use sp_runtime::DispatchError; use sp_std::convert::From; use crate::{Error, Event as InboundQueueEvent}; @@ -25,9 +25,8 @@ fn test_submit_happy_path() { let message = Message { event_log: mock_event_log(), proof: Proof { - block_hash: Default::default(), - tx_index: Default::default(), - data: Default::default(), + receipt_proof: Default::default(), + execution_proof: mock_execution_proof(), }, }; @@ -77,9 +76,8 @@ fn test_submit_xcm_invalid_channel() { let message = Message { event_log: mock_event_log_invalid_channel(), proof: Proof { - block_hash: Default::default(), - tx_index: Default::default(), - data: Default::default(), + receipt_proof: Default::default(), + execution_proof: mock_execution_proof(), }, }; assert_noop!( @@ -103,9 +101,8 @@ fn test_submit_with_invalid_gateway() { let message = Message { event_log: mock_event_log_invalid_gateway(), proof: Proof { - block_hash: Default::default(), - tx_index: Default::default(), - data: Default::default(), + receipt_proof: Default::default(), + execution_proof: mock_execution_proof(), }, }; assert_noop!( @@ -129,9 +126,8 @@ fn test_submit_with_invalid_nonce() { let message = Message { event_log: mock_event_log(), proof: Proof { - block_hash: Default::default(), - tx_index: Default::default(), - data: Default::default(), + receipt_proof: Default::default(), + execution_proof: mock_execution_proof(), }, }; assert_ok!(InboundQueue::submit(origin.clone(), message.clone())); @@ -150,12 +146,12 @@ fn test_submit_with_invalid_nonce() { } #[test] -fn test_submit_no_funds_to_reward_relayers() { +fn test_submit_no_funds_to_reward_relayers_just_ignore() { new_tester().execute_with(|| { let relayer: AccountId = Keyring::Bob.into(); let origin = RuntimeOrigin::signed(relayer); - // Reset balance of sovereign_account to zero so to trigger the FundsUnavailable error + // Reset balance of sovereign_account to zero first let sovereign_account = sibling_sovereign_account::(ASSET_HUB_PARAID.into()); Balances::set_balance(&sovereign_account, 0); @@ -163,15 +159,12 @@ fn test_submit_no_funds_to_reward_relayers() { let message = Message { event_log: mock_event_log(), proof: Proof { - block_hash: Default::default(), - tx_index: Default::default(), - data: Default::default(), + receipt_proof: Default::default(), + execution_proof: mock_execution_proof(), }, }; - assert_noop!( - InboundQueue::submit(origin.clone(), message.clone()), - TokenError::FundsUnavailable - ); + // Check submit successfully in case no funds available + assert_ok!(InboundQueue::submit(origin.clone(), message.clone())); }); } @@ -183,9 +176,8 @@ fn test_set_operating_mode() { let message = Message { event_log: mock_event_log(), proof: Proof { - block_hash: Default::default(), - tx_index: Default::default(), - data: Default::default(), + receipt_proof: Default::default(), + execution_proof: mock_execution_proof(), }, }; @@ -210,3 +202,44 @@ fn test_set_operating_mode_root_only() { ); }); } + +#[test] +fn test_submit_no_funds_to_reward_relayers_and_ed_preserved() { + new_tester().execute_with(|| { + let relayer: AccountId = Keyring::Bob.into(); + let origin = RuntimeOrigin::signed(relayer); + + // Reset balance of sovereign account to (ED+1) first + let sovereign_account = sibling_sovereign_account::(ASSET_HUB_PARAID.into()); + Balances::set_balance(&sovereign_account, ExistentialDeposit::get() + 1); + + // Submit message successfully + let message = Message { + event_log: mock_event_log(), + proof: Proof { + receipt_proof: Default::default(), + execution_proof: mock_execution_proof(), + }, + }; + assert_ok!(InboundQueue::submit(origin.clone(), message.clone())); + + // Check balance of sovereign account to ED + let amount = Balances::balance(&sovereign_account); + assert_eq!(amount, ExistentialDeposit::get()); + + // Submit another message with nonce set as 2 + let mut event_log = mock_event_log(); + event_log.data[31] = 2; + let message = Message { + event_log, + proof: Proof { + receipt_proof: Default::default(), + execution_proof: mock_execution_proof(), + }, + }; + assert_ok!(InboundQueue::submit(origin.clone(), message.clone())); + // Check balance of sovereign account as ED does not change + let amount = Balances::balance(&sovereign_account); + assert_eq!(amount, ExistentialDeposit::get()); + }); +} diff --git a/bridges/snowbridge/primitives/beacon/src/lib.rs b/bridges/snowbridge/primitives/beacon/src/lib.rs index 4c569d0176c2..6579d0f60966 100644 --- a/bridges/snowbridge/primitives/beacon/src/lib.rs +++ b/bridges/snowbridge/primitives/beacon/src/lib.rs @@ -15,12 +15,12 @@ pub mod updates; mod serde_utils; pub use types::{ - BeaconHeader, CompactBeaconState, CompactExecutionHeader, ExecutionHeaderState, - ExecutionPayloadHeader, FinalizedHeaderState, Fork, ForkData, ForkVersion, ForkVersions, Mode, - PublicKey, Signature, SigningData, SyncAggregate, SyncCommittee, SyncCommitteePrepared, + AncestryProof, BeaconHeader, CompactBeaconState, ExecutionPayloadHeader, ExecutionProof, + FinalizedHeaderState, Fork, ForkData, ForkVersion, ForkVersions, Mode, PublicKey, Signature, + SigningData, SyncAggregate, SyncCommittee, SyncCommitteePrepared, VersionedExecutionPayloadHeader, }; -pub use updates::{CheckpointUpdate, ExecutionHeaderUpdate, NextSyncCommitteeUpdate, Update}; +pub use updates::{CheckpointUpdate, NextSyncCommitteeUpdate, Update}; pub use bits::decompress_sync_committee_bits; pub use bls::{ diff --git a/bridges/snowbridge/primitives/beacon/src/types.rs b/bridges/snowbridge/primitives/beacon/src/types.rs index 2af522f56b0d..e12350510c9b 100644 --- a/bridges/snowbridge/primitives/beacon/src/types.rs +++ b/bridges/snowbridge/primitives/beacon/src/types.rs @@ -110,14 +110,6 @@ impl<'de> Deserialize<'de> for Signature { } } -#[derive(Copy, Clone, Default, Encode, Decode, TypeInfo, MaxEncodedLen)] -pub struct ExecutionHeaderState { - pub beacon_block_root: H256, - pub beacon_slot: u64, - pub block_hash: H256, - pub block_number: u64, -} - #[derive(Copy, Clone, Default, Encode, Decode, TypeInfo, MaxEncodedLen)] pub struct FinalizedHeaderState { pub beacon_block_root: H256, @@ -346,35 +338,6 @@ impl ExecutionPayloadHeader { } } -#[derive( - Default, - Encode, - Decode, - CloneNoBound, - PartialEqNoBound, - RuntimeDebugNoBound, - TypeInfo, - MaxEncodedLen, -)] -pub struct CompactExecutionHeader { - pub parent_hash: H256, - #[codec(compact)] - pub block_number: u64, - pub state_root: H256, - pub receipts_root: H256, -} - -impl From for CompactExecutionHeader { - fn from(execution_payload: ExecutionPayloadHeader) -> Self { - Self { - parent_hash: execution_payload.parent_hash, - block_number: execution_payload.block_number, - state_root: execution_payload.state_root, - receipts_root: execution_payload.receipts_root, - } - } -} - #[derive( Default, Encode, @@ -405,18 +368,6 @@ pub enum VersionedExecutionPayloadHeader { Deneb(deneb::ExecutionPayloadHeader), } -/// Convert VersionedExecutionPayloadHeader to CompactExecutionHeader -impl From for CompactExecutionHeader { - fn from(versioned_execution_header: VersionedExecutionPayloadHeader) -> Self { - match versioned_execution_header { - VersionedExecutionPayloadHeader::Capella(execution_payload_header) => - execution_payload_header.into(), - VersionedExecutionPayloadHeader::Deneb(execution_payload_header) => - execution_payload_header.into(), - } - } -} - impl VersionedExecutionPayloadHeader { pub fn hash_tree_root(&self) -> Result { match self { @@ -448,6 +399,45 @@ impl VersionedExecutionPayloadHeader { execution_payload_header.block_number, } } + + pub fn receipts_root(&self) -> H256 { + match self { + VersionedExecutionPayloadHeader::Capella(execution_payload_header) => + execution_payload_header.receipts_root, + VersionedExecutionPayloadHeader::Deneb(execution_payload_header) => + execution_payload_header.receipts_root, + } + } +} + +#[derive(Encode, Decode, CloneNoBound, PartialEqNoBound, RuntimeDebugNoBound, TypeInfo)] +#[cfg_attr( + feature = "std", + derive(serde::Deserialize), + serde(deny_unknown_fields, bound(serialize = ""), bound(deserialize = "")) +)] +pub struct ExecutionProof { + /// Header for the beacon block containing the execution payload + pub header: BeaconHeader, + /// Proof that `header` is an ancestor of a finalized header + pub ancestry_proof: Option, + /// The execution header to be verified + pub execution_header: VersionedExecutionPayloadHeader, + /// Merkle proof that execution payload is contained within `header` + pub execution_branch: Vec, +} + +#[derive(Encode, Decode, CloneNoBound, PartialEqNoBound, RuntimeDebugNoBound, TypeInfo)] +#[cfg_attr( + feature = "std", + derive(serde::Deserialize), + serde(deny_unknown_fields, bound(serialize = ""), bound(deserialize = "")) +)] +pub struct AncestryProof { + /// Merkle proof that `header` is an ancestor of `finalized_header` + pub header_branch: Vec, + /// Root of a finalized block that has already been imported into the light client + pub finalized_block_root: H256, } #[cfg(test)] @@ -576,7 +566,6 @@ pub enum Mode { } pub mod deneb { - use crate::CompactExecutionHeader; use codec::{Decode, Encode}; use frame_support::{CloneNoBound, PartialEqNoBound, RuntimeDebugNoBound}; use scale_info::TypeInfo; @@ -627,15 +616,4 @@ pub mod deneb { pub blob_gas_used: u64, // [New in Deneb:EIP4844] pub excess_blob_gas: u64, // [New in Deneb:EIP4844] } - - impl From for CompactExecutionHeader { - fn from(execution_payload: ExecutionPayloadHeader) -> Self { - Self { - parent_hash: execution_payload.parent_hash, - block_number: execution_payload.block_number, - state_root: execution_payload.state_root, - receipts_root: execution_payload.receipts_root, - } - } - } } diff --git a/bridges/snowbridge/primitives/beacon/src/updates.rs b/bridges/snowbridge/primitives/beacon/src/updates.rs index 1ecd32c6d7b7..ca651b5806f2 100644 --- a/bridges/snowbridge/primitives/beacon/src/updates.rs +++ b/bridges/snowbridge/primitives/beacon/src/updates.rs @@ -6,7 +6,7 @@ use scale_info::TypeInfo; use sp_core::H256; use sp_std::prelude::*; -use crate::types::{BeaconHeader, SyncAggregate, SyncCommittee, VersionedExecutionPayloadHeader}; +use crate::types::{BeaconHeader, SyncAggregate, SyncCommittee}; #[derive(Encode, Decode, CloneNoBound, PartialEqNoBound, RuntimeDebugNoBound, TypeInfo)] #[cfg_attr( @@ -23,26 +23,13 @@ pub struct CheckpointUpdate { pub block_roots_branch: Vec, } -impl Default for CheckpointUpdate { - fn default() -> Self { - CheckpointUpdate { - header: Default::default(), - current_sync_committee: Default::default(), - current_sync_committee_branch: Default::default(), - validators_root: Default::default(), - block_roots_root: Default::default(), - block_roots_branch: Default::default(), - } - } -} - #[derive( Default, Encode, Decode, CloneNoBound, PartialEqNoBound, RuntimeDebugNoBound, TypeInfo, )] #[cfg_attr( feature = "std", derive(serde::Deserialize), - serde(deny_unknown_fields, bound(serialize = ""), bound(deserialize = "")) + serde(bound(serialize = ""), bound(deserialize = "")) )] pub struct Update { /// A recent header attesting to the finalized header, using its `state_root`. @@ -78,33 +65,3 @@ pub struct NextSyncCommitteeUpdate { pub next_sync_committee: SyncCommittee, pub next_sync_committee_branch: Vec, } - -#[derive(Encode, Decode, CloneNoBound, PartialEqNoBound, RuntimeDebugNoBound, TypeInfo)] -#[cfg_attr( - feature = "std", - derive(serde::Deserialize), - serde(deny_unknown_fields, bound(serialize = ""), bound(deserialize = "")) -)] -pub struct ExecutionHeaderUpdate { - /// Header for the beacon block containing the execution payload - pub header: BeaconHeader, - /// Proof that `header` is an ancestor of a finalized header - pub ancestry_proof: Option, - /// Execution header to be imported - pub execution_header: VersionedExecutionPayloadHeader, - /// Merkle proof that execution payload is contained within `header` - pub execution_branch: Vec, -} - -#[derive(Encode, Decode, CloneNoBound, PartialEqNoBound, RuntimeDebugNoBound, TypeInfo)] -#[cfg_attr( - feature = "std", - derive(serde::Deserialize), - serde(deny_unknown_fields, bound(serialize = ""), bound(deserialize = "")) -)] -pub struct AncestryProof { - /// Merkle proof that `header` is an ancestor of `finalized_header` - pub header_branch: Vec, - /// Root of a finalized block that has already been imported into the light client - pub finalized_block_root: H256, -} diff --git a/bridges/snowbridge/primitives/core/src/inbound.rs b/bridges/snowbridge/primitives/core/src/inbound.rs index 4b04470ad026..9e8ed789ab50 100644 --- a/bridges/snowbridge/primitives/core/src/inbound.rs +++ b/bridges/snowbridge/primitives/core/src/inbound.rs @@ -5,6 +5,7 @@ use codec::{Decode, Encode}; use frame_support::PalletError; use scale_info::TypeInfo; +use snowbridge_beacon_primitives::{BeaconHeader, ExecutionProof}; use sp_core::{H160, H256}; use sp_runtime::RuntimeDebug; use sp_std::vec::Vec; @@ -25,6 +26,8 @@ pub enum VerificationError { InvalidLog, /// Unable to verify the transaction receipt with the provided proof InvalidProof, + /// Unable to verify the execution header with ancestry proof + InvalidExecutionProof(#[codec(skip)] &'static str), } pub type MessageNonce = u64; @@ -65,10 +68,15 @@ impl Log { /// Inclusion proof for a transaction receipt #[derive(Clone, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo)] pub struct Proof { - // The block hash of the block in which the receipt was included. - pub block_hash: H256, - // The index of the transaction (and receipt) within the block. - pub tx_index: u32, // Proof keys and values (receipts tree) - pub data: (Vec>, Vec>), + pub receipt_proof: (Vec>, Vec>), + // Proof that an execution header was finalized by the beacon chain + pub execution_proof: ExecutionProof, +} + +#[derive(Clone, RuntimeDebug)] +pub struct InboundQueueFixture { + pub message: Message, + pub finalized_header: BeaconHeader, + pub block_roots_root: H256, } diff --git a/bridges/snowbridge/runtime/test-common/src/lib.rs b/bridges/snowbridge/runtime/test-common/src/lib.rs index 7455adf76170..3e2de0e481b8 100644 --- a/bridges/snowbridge/runtime/test-common/src/lib.rs +++ b/bridges/snowbridge/runtime/test-common/src/lib.rs @@ -467,7 +467,6 @@ pub fn ethereum_extrinsic( let initial_checkpoint = make_checkpoint(); let update = make_finalized_header_update(); let sync_committee_update = make_sync_committee_update(); - let execution_header_update = make_execution_header_update(); let alice = Alice; let alice_account = alice.to_account_id(); @@ -494,22 +493,12 @@ pub fn ethereum_extrinsic( } .into(); - let execution_header_call: ::RuntimeCall = - snowbridge_pallet_ethereum_client::Call::::submit_execution_header { - update: Box::new(*execution_header_update), - } - .into(); - let update_outcome = construct_and_apply_extrinsic(alice, update_call.into()); assert_ok!(update_outcome); let sync_committee_outcome = construct_and_apply_extrinsic(alice, update_sync_committee_call.into()); assert_ok!(sync_committee_outcome); - - let execution_header_outcome = - construct_and_apply_extrinsic(alice, execution_header_call.into()); - assert_ok!(execution_header_outcome); }); } @@ -548,7 +537,6 @@ pub fn ethereum_to_polkadot_message_extrinsics_work( .execute_with(|| { let initial_checkpoint = make_checkpoint(); let sync_committee_update = make_sync_committee_update(); - let execution_header_update = make_execution_header_update(); let alice = Alice; let alice_account = alice.to_account_id(); @@ -569,18 +557,8 @@ pub fn ethereum_to_polkadot_message_extrinsics_work( } .into(); - let execution_header_call: ::RuntimeCall = - snowbridge_pallet_ethereum_client::Call::::submit_execution_header { - update: Box::new(*execution_header_update), - } - .into(); - let sync_committee_outcome = construct_and_apply_extrinsic(alice, update_sync_committee_call.into()); assert_ok!(sync_committee_outcome); - - let execution_header_outcome = - construct_and_apply_extrinsic(alice, execution_header_call.into()); - assert_ok!(execution_header_outcome); }); } diff --git a/bridges/snowbridge/scripts/contribute-upstream.sh b/bridges/snowbridge/scripts/contribute-upstream.sh index 32005b770ecf..529057c3f26f 100755 --- a/bridges/snowbridge/scripts/contribute-upstream.sh +++ b/bridges/snowbridge/scripts/contribute-upstream.sh @@ -79,4 +79,10 @@ git fetch parity master git checkout parity/master -- .github git add -- .github +git commit -m "cleanup branch" + +# Fetch the latest from parity master +echo "Fetching latest from Parity master. Resolve merge conflicts, if there are any." +git fetch parity master +git merge parity/master echo "OK" diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs index 1804f9d4b67d..780ba57f78a1 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs @@ -20,17 +20,17 @@ use frame_support::pallet_prelude::TypeInfo; use hex_literal::hex; use rococo_system_emulated_network::penpal_emulated_chain::CustomizableAssetFromSystemAssetHub; use rococo_westend_system_emulated_network::BridgeHubRococoParaSender as BridgeHubRococoSender; -use snowbridge_core::outbound::OperatingMode; +use snowbridge_core::{inbound::InboundQueueFixture, outbound::OperatingMode}; use snowbridge_pallet_inbound_queue_fixtures::{ - register_token::make_register_token_message, - register_token_with_insufficient_fee::make_register_token_with_insufficient_fee_message, - send_token::make_send_token_message, send_token_to_penpal::make_send_token_to_penpal_message, - InboundQueueFixture, + register_token::make_register_token_message, send_token::make_send_token_message, + send_token_to_penpal::make_send_token_to_penpal_message, }; use snowbridge_pallet_system; -use snowbridge_router_primitives::inbound::GlobalConsensusEthereumConvertsFor; +use snowbridge_router_primitives::inbound::{ + Command, GlobalConsensusEthereumConvertsFor, MessageV1, VersionedMessage, +}; use sp_core::H256; -use sp_runtime::{ArithmeticError::Underflow, DispatchError::Arithmetic}; +use sp_runtime::{DispatchError::Token, TokenError::FundsUnavailable}; use testnet_parachains_constants::rococo::snowbridge::EthereumNetwork; const INITIAL_FUND: u128 = 5_000_000_000 * ROCOCO_ED; @@ -39,6 +39,7 @@ const TREASURY_ACCOUNT: [u8; 32] = hex!("6d6f646c70792f74727372790000000000000000000000000000000000000000"); const WETH: [u8; 20] = hex!("87d1f7fdfEe7f651FaBc8bFCB6E086C278b77A7d"); const ETHEREUM_DESTINATION_ADDRESS: [u8; 20] = hex!("44a57ee2f2FCcb85FDa2B0B18EBD0D8D2333700e"); +const INSUFFICIENT_XCM_FEE: u128 = 1000; #[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] pub enum ControlCall { @@ -56,13 +57,11 @@ pub enum SnowbridgeControl { } pub fn send_inbound_message(fixture: InboundQueueFixture) -> DispatchResult { - EthereumBeaconClient::store_execution_header( - fixture.message.proof.block_hash, - fixture.execution_header, - 0, - H256::default(), - ); - + EthereumBeaconClient::store_finalized_header( + fixture.finalized_header, + fixture.block_roots_root, + ) + .unwrap(); EthereumInboundQueue::submit( RuntimeOrigin::signed(BridgeHubRococoSender::get()), fixture.message, @@ -237,6 +236,46 @@ fn register_weth_token_from_ethereum_to_asset_hub() { }); } +/// Tests the registering of a token as an asset on AssetHub, and then subsequently sending +/// a token from Ethereum to AssetHub. +#[test] +fn send_token_from_ethereum_to_asset_hub() { + BridgeHubRococo::fund_para_sovereign(AssetHubRococo::para_id().into(), INITIAL_FUND); + + // Fund ethereum sovereign on AssetHub + AssetHubRococo::fund_accounts(vec![(AssetHubRococoReceiver::get(), INITIAL_FUND)]); + + BridgeHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + // Construct RegisterToken message and sent to inbound queue + send_inbound_message(make_register_token_message()).unwrap(); + + // Construct SendToken message and sent to inbound queue + send_inbound_message(make_send_token_message()).unwrap(); + + // Check that the message was sent + assert_expected_events!( + BridgeHubRococo, + vec![ + RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {}, + ] + ); + }); + + AssetHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + // Check that the token was received and issued as a foreign asset on AssetHub + assert_expected_events!( + AssetHubRococo, + vec![ + RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { .. }) => {}, + ] + ); + }); +} + /// Tests sending a token to a 3rd party parachain, called PenPal. The token reserve is /// still located on AssetHub. #[test] @@ -296,6 +335,10 @@ fn send_token_from_ethereum_to_penpal() { // Construct RegisterToken message and sent to inbound queue send_inbound_message(make_register_token_message()).unwrap(); + // Construct SendToken message to AssetHub(only for increase the nonce as the same order in + // smoke test) + send_inbound_message(make_send_token_message()).unwrap(); + // Construct SendToken message and sent to inbound queue send_inbound_message(make_send_token_to_penpal_message()).unwrap(); @@ -331,46 +374,6 @@ fn send_token_from_ethereum_to_penpal() { }); } -/// Tests the registering of a token as an asset on AssetHub, and then subsequently sending -/// a token from Ethereum to AssetHub. -#[test] -fn send_token_from_ethereum_to_asset_hub() { - BridgeHubRococo::fund_para_sovereign(AssetHubRococo::para_id().into(), INITIAL_FUND); - - // Fund ethereum sovereign on AssetHub - AssetHubRococo::fund_accounts(vec![(AssetHubRococoReceiver::get(), INITIAL_FUND)]); - - BridgeHubRococo::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - // Construct RegisterToken message and sent to inbound queue - send_inbound_message(make_register_token_message()).unwrap(); - - // Construct SendToken message and sent to inbound queue - send_inbound_message(make_send_token_message()).unwrap(); - - // Check that the message was sent - assert_expected_events!( - BridgeHubRococo, - vec![ - RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {}, - ] - ); - }); - - AssetHubRococo::execute_with(|| { - type RuntimeEvent = ::RuntimeEvent; - - // Check that the token was received and issued as a foreign asset on AssetHub - assert_expected_events!( - AssetHubRococo, - vec![ - RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued { .. }) => {}, - ] - ); - }); -} - /// Tests the full cycle of token transfers: /// - registering a token on AssetHub /// - sending a token to AssetHub @@ -507,16 +510,35 @@ fn send_weth_asset_from_asset_hub_to_ethereum() { }); } +#[test] +fn send_token_from_ethereum_to_asset_hub_fail_for_insufficient_fund() { + // Insufficient fund + BridgeHubRococo::fund_para_sovereign(AssetHubRococo::para_id().into(), 1_000); + + BridgeHubRococo::execute_with(|| { + assert_err!(send_inbound_message(make_register_token_message()), Token(FundsUnavailable)); + }); +} + #[test] fn register_weth_token_in_asset_hub_fail_for_insufficient_fee() { BridgeHubRococo::fund_para_sovereign(AssetHubRococo::para_id().into(), INITIAL_FUND); BridgeHubRococo::execute_with(|| { type RuntimeEvent = ::RuntimeEvent; - - // Construct RegisterToken message and sent to inbound queue - let message = make_register_token_with_insufficient_fee_message(); - send_inbound_message(message).unwrap(); + type EthereumInboundQueue = + ::EthereumInboundQueue; + let message_id: H256 = [0; 32].into(); + let message = VersionedMessage::V1(MessageV1 { + chain_id: CHAIN_ID, + command: Command::RegisterToken { + token: WETH.into(), + // Insufficient fee which should trigger the trap + fee: INSUFFICIENT_XCM_FEE, + }, + }); + let (xcm, _) = EthereumInboundQueue::do_convert(message_id, message).unwrap(); + let _ = EthereumInboundQueue::send_xcm(xcm, AssetHubRococo::para_id().into()).unwrap(); assert_expected_events!( BridgeHubRococo, @@ -537,13 +559,3 @@ fn register_weth_token_in_asset_hub_fail_for_insufficient_fee() { ); }); } - -#[test] -fn send_token_from_ethereum_to_asset_hub_fail_for_insufficient_fund() { - // Insufficient fund - BridgeHubRococo::fund_para_sovereign(AssetHubRococo::para_id().into(), 1_000); - - BridgeHubRococo::execute_with(|| { - assert_err!(send_inbound_message(make_register_token_message()), Arithmetic(Underflow)); - }); -} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs index 47c3ed368888..f4ff985e2773 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs @@ -286,8 +286,8 @@ impl Contains for SafeCallFilter { match call { RuntimeCall::System(frame_system::Call::set_storage { items }) if items.iter().all(|(k, _)| { - k.eq(&bridging::XcmBridgeHubRouterByteFee::key()) | - k.eq(&bridging::XcmBridgeHubRouterBaseFee::key()) | + k.eq(&bridging::XcmBridgeHubRouterByteFee::key()) || + k.eq(&bridging::XcmBridgeHubRouterBaseFee::key()) || k.eq(&bridging::to_ethereum::BridgeHubEthereumBaseFee::key()) }) => return true, diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs index f0aa4f8e91cc..fd6d44ec2754 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs @@ -100,8 +100,6 @@ use parachains_common::{ AVERAGE_ON_INITIALIZE_RATIO, NORMAL_DISPATCH_RATIO, }; -use polkadot_runtime_common::prod_or_fast; - #[cfg(feature = "runtime-benchmarks")] use benchmark_helpers::DoNothingRouter; @@ -515,14 +513,14 @@ parameter_types! { pub mod benchmark_helpers { use crate::{EthereumBeaconClient, Runtime, RuntimeOrigin}; use codec::Encode; - use snowbridge_beacon_primitives::CompactExecutionHeader; + use snowbridge_beacon_primitives::BeaconHeader; use snowbridge_pallet_inbound_queue::BenchmarkHelper; use sp_core::H256; use xcm::latest::{Assets, Location, SendError, SendResult, SendXcm, Xcm, XcmHash}; impl BenchmarkHelper for Runtime { - fn initialize_storage(block_hash: H256, header: CompactExecutionHeader) { - EthereumBeaconClient::store_execution_header(block_hash, header, 0, H256::default()) + fn initialize_storage(beacon_header: BeaconHeader, block_roots_root: H256) { + EthereumBeaconClient::store_finalized_header(beacon_header, block_roots_root).unwrap(); } } @@ -643,14 +641,9 @@ parameter_types! { }; } -parameter_types! { - pub const MaxExecutionHeadersToKeep: u32 = prod_or_fast!(8192 * 2, 1000); -} - impl snowbridge_pallet_ethereum_client::Config for Runtime { type RuntimeEvent = RuntimeEvent; type ForkVersions = ChainForkVersions; - type MaxExecutionHeadersToKeep = MaxExecutionHeadersToKeep; type WeightInfo = weights::snowbridge_pallet_ethereum_client::WeightInfo; } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/snowbridge_pallet_ethereum_client.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/snowbridge_pallet_ethereum_client.rs index 0d5f29c6ff2f..c8017939b627 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/snowbridge_pallet_ethereum_client.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/snowbridge_pallet_ethereum_client.rs @@ -126,26 +126,4 @@ impl snowbridge_pallet_ethereum_client::WeightInfo for .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: EthereumBeaconClient LatestFinalizedBlockRoot (r:1 w:0) - /// Proof: EthereumBeaconClient LatestFinalizedBlockRoot (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) - /// Storage: EthereumBeaconClient FinalizedBeaconState (r:1 w:0) - /// Proof: EthereumBeaconClient FinalizedBeaconState (max_values: None, max_size: Some(72), added: 2547, mode: MaxEncodedLen) - /// Storage: EthereumBeaconClient LatestExecutionState (r:1 w:1) - /// Proof: EthereumBeaconClient LatestExecutionState (max_values: Some(1), max_size: Some(80), added: 575, mode: MaxEncodedLen) - /// Storage: EthereumBeaconClient ExecutionHeaderIndex (r:1 w:1) - /// Proof: EthereumBeaconClient ExecutionHeaderIndex (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: EthereumBeaconClient ExecutionHeaderMapping (r:1 w:1) - /// Proof: EthereumBeaconClient ExecutionHeaderMapping (max_values: None, max_size: Some(36), added: 2511, mode: MaxEncodedLen) - /// Storage: EthereumBeaconClient ExecutionHeaders (r:0 w:1) - /// Proof: EthereumBeaconClient ExecutionHeaders (max_values: None, max_size: Some(136), added: 2611, mode: MaxEncodedLen) - fn submit_execution_header() -> Weight { - // Proof Size summary in bytes: - // Measured: `386` - // Estimated: `3537` - // Minimum execution time: 108_761_000 picoseconds. - Weight::from_parts(113_158_000, 0) - .saturating_add(Weight::from_parts(0, 3537)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(4)) - } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/snowbridge_pallet_inbound_queue.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/snowbridge_pallet_inbound_queue.rs index faf404f90cb3..153c1d363be1 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/snowbridge_pallet_inbound_queue.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/snowbridge_pallet_inbound_queue.rs @@ -58,12 +58,12 @@ impl snowbridge_pallet_inbound_queue::WeightInfo for We /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn submit() -> Weight { // Proof Size summary in bytes: - // Measured: `457` - // Estimated: `3601` - // Minimum execution time: 69_000_000 picoseconds. - Weight::from_parts(70_000_000, 0) - .saturating_add(Weight::from_parts(0, 3601)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(2)) + // Measured: `800` + // Estimated: `7200` + // Minimum execution time: 200_000_000 picoseconds. + Weight::from_parts(200_000_000, 0) + .saturating_add(Weight::from_parts(0, 7200)) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().writes(6)) } } diff --git a/prdoc/pr_3761.prdoc b/prdoc/pr_3761.prdoc new file mode 100644 index 000000000000..65b8c396fe3b --- /dev/null +++ b/prdoc/pr_3761.prdoc @@ -0,0 +1,25 @@ +title: "Snowbridge: Synchronize from Snowfork repository" + +doc: + - audience: Runtime Dev + description: | + This PR improves the beacon client to send the execution header along with the message as proof and removes the verification and storing of all execution headers. + If the AH sovereign account is depleted and relayer rewards cannot be paid, the message should still be processed. + +crates: +- name: snowbridge-pallet-ethereum-client + bump: minor +- name: snowbridge-pallet-inbound-queue + bump: minor +- name: snowbridge-beacon-primitives + bump: minor +- name: snowbridge-core + bump: minor +- name: snowbridge-runtime-test-common + bump: minor +- name: asset-hub-rococo-runtime + bump: minor +- name: bridge-hub-rococo-runtime + bump: minor +- name: bridge-hub-rococo-integration-tests + bump: minor From 7d6679e8c6e72f1610418506a7d553a23ad8ad19 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Tue, 2 Apr 2024 18:06:01 +0200 Subject: [PATCH 107/257] sp_runtime: TryFrom for &str (#3942) Added `TryFrom<&'a RuntimeString> for &'a str` --- substrate/primitives/runtime/src/runtime_string.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/substrate/primitives/runtime/src/runtime_string.rs b/substrate/primitives/runtime/src/runtime_string.rs index aa0bd52e56fe..607ae59db632 100644 --- a/substrate/primitives/runtime/src/runtime_string.rs +++ b/substrate/primitives/runtime/src/runtime_string.rs @@ -61,6 +61,19 @@ impl From<&'static str> for RuntimeString { } } +impl<'a> TryFrom<&'a RuntimeString> for &'a str { + type Error = core::str::Utf8Error; + fn try_from(from: &'a RuntimeString) -> core::result::Result<&'a str, Self::Error> { + match from { + #[cfg(feature = "std")] + RuntimeString::Owned(string) => Ok(string.as_str()), + #[cfg(not(feature = "std"))] + RuntimeString::Owned(vec) => core::str::from_utf8(&vec), + RuntimeString::Borrowed(str) => Ok(str), + } + } +} + #[cfg(feature = "std")] impl From for String { fn from(string: RuntimeString) -> Self { From 67de6ed4de1488ff5c8fe776c4822eceb595e928 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dino=20Pa=C4=8Dandi?= <3002868+Dinonard@users.noreply.github.com> Date: Tue, 2 Apr 2024 21:08:02 +0200 Subject: [PATCH 108/257] SortedMembers::add for pallet-membership benchmarks (#3729) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds implementation for `SortedMembers::add` for _pallet-membership_ benchmarks. --------- Co-authored-by: Bastian Köcher Co-authored-by: command-bot <> --- substrate/frame/membership/src/lib.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/substrate/frame/membership/src/lib.rs b/substrate/frame/membership/src/lib.rs index 426fc985a52f..aa6be6497eea 100644 --- a/substrate/frame/membership/src/lib.rs +++ b/substrate/frame/membership/src/lib.rs @@ -369,6 +369,18 @@ impl, I: 'static> SortedMembers for Pallet { fn count() -> usize { Members::::decode_len().unwrap_or(0) } + + #[cfg(feature = "runtime-benchmarks")] + fn add(new_member: &T::AccountId) { + use frame_support::{assert_ok, traits::EnsureOrigin}; + let new_member_lookup = T::Lookup::unlookup(new_member.clone()); + + if let Ok(origin) = T::AddOrigin::try_successful_origin() { + assert_ok!(Pallet::::add_member(origin, new_member_lookup,)); + } else { + log::error!(target: LOG_TARGET, "Failed to add `{new_member:?}` in `SortedMembers::add`.") + } + } } #[cfg(feature = "runtime-benchmarks")] From c47d5f4a733badbb8ad6bf4cec5776e25f7d08c7 Mon Sep 17 00:00:00 2001 From: Andrei Eres Date: Tue, 2 Apr 2024 21:27:11 +0200 Subject: [PATCH 109/257] Remove nextest filtration (#3885) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes https://github.com/paritytech/polkadot-sdk/issues/3884#issuecomment-2026058687 After moving regression tests to benchmarks (https://github.com/paritytech/polkadot-sdk/pull/3741) we don't need to filter tests anymore. --------- Signed-off-by: Alexandru Vasile Signed-off-by: Oliver Tale-Yazdi Co-authored-by: Andrei Sandu <54316454+sandreim@users.noreply.github.com> Co-authored-by: Alin Dima Co-authored-by: Andrei Sandu Co-authored-by: Oliver Tale-Yazdi Co-authored-by: Javier Viola <363911+pepoviola@users.noreply.github.com> Co-authored-by: Serban Iorga Co-authored-by: Adrian Catangiu Co-authored-by: Bastian Köcher Co-authored-by: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Co-authored-by: Niklas Adolfsson Co-authored-by: Dastan <88332432+dastansam@users.noreply.github.com> Co-authored-by: Liam Aharon Co-authored-by: Clara van Staden Co-authored-by: Ron Co-authored-by: Vincent Geddes Co-authored-by: Svyatoslav Nikolsky Co-authored-by: Bastian Köcher --- .gitlab/pipeline/test.yml | 3 +-- substrate/frame/core-fellowship/src/benchmarking.rs | 5 +++++ substrate/frame/core-fellowship/src/lib.rs | 3 ++- substrate/frame/scheduler/src/tests.rs | 5 ++++- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/.gitlab/pipeline/test.yml b/.gitlab/pipeline/test.yml index af261a893da5..48c84b472b43 100644 --- a/.gitlab/pipeline/test.yml +++ b/.gitlab/pipeline/test.yml @@ -25,7 +25,6 @@ test-linux-stable: # "upgrade_version_checks_should_work" is currently failing - | time cargo nextest run \ - --filter-expr 'not deps(/polkadot-subsystem-bench/)' \ --workspace \ --locked \ --release \ @@ -70,7 +69,7 @@ test-linux-stable-runtime-benchmarks: # but still want to have debug assertions. RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" script: - - time cargo nextest run --filter-expr 'not deps(/polkadot-subsystem-bench/)' --workspace --features runtime-benchmarks benchmark --locked --cargo-profile testnet + - time cargo nextest run --workspace --features runtime-benchmarks benchmark --locked --cargo-profile testnet # can be used to run all tests # test-linux-stable-all: diff --git a/substrate/frame/core-fellowship/src/benchmarking.rs b/substrate/frame/core-fellowship/src/benchmarking.rs index ddde70bd7ce1..fd5453310be5 100644 --- a/substrate/frame/core-fellowship/src/benchmarking.rs +++ b/substrate/frame/core-fellowship/src/benchmarking.rs @@ -149,6 +149,11 @@ mod benchmarks { #[benchmark] fn promote() -> Result<(), BenchmarkError> { + // Ensure that the `min_promotion_period` wont get in our way. + let mut params = Params::::get(); + params.min_promotion_period = [Zero::zero(); RANK_COUNT]; + Params::::put(¶ms); + let member = make_member::(1)?; ensure_evidence::(&member)?; diff --git a/substrate/frame/core-fellowship/src/lib.rs b/substrate/frame/core-fellowship/src/lib.rs index d1b81c3ca134..afb188261fd4 100644 --- a/substrate/frame/core-fellowship/src/lib.rs +++ b/substrate/frame/core-fellowship/src/lib.rs @@ -149,7 +149,8 @@ pub mod pallet { }; use frame_system::{ensure_root, pallet_prelude::*}; - const RANK_COUNT: usize = 9; + /// Number of available ranks. + pub(crate) const RANK_COUNT: usize = 9; #[pallet::pallet] pub struct Pallet(PhantomData<(T, I)>); diff --git a/substrate/frame/scheduler/src/tests.rs b/substrate/frame/scheduler/src/tests.rs index f251dde99a86..3023a370a4b6 100644 --- a/substrate/frame/scheduler/src/tests.rs +++ b/substrate/frame/scheduler/src/tests.rs @@ -1501,8 +1501,11 @@ fn scheduler_handles_periodic_unavailable_preimage() { run_to_block(4); assert_eq!(logger::log().len(), 1); - // Unnote the preimage + // As the public api doesn't support to remove a noted preimage, we need to first unnote it + // and then request it again. Basically this should not happen in real life (whatever you + // call real life;). Preimage::unnote(&hash); + Preimage::request(&hash); // Does not ever execute again. run_to_block(100); From e4cd533dc8b3c0bed224531a87d719a7af3590e8 Mon Sep 17 00:00:00 2001 From: Andrei Sandu <54316454+sandreim@users.noreply.github.com> Date: Wed, 3 Apr 2024 11:34:50 +0300 Subject: [PATCH 110/257] statement-distribution: fix filtering of statements for elastic parachains (#3879) fixes https://github.com/paritytech/polkadot-sdk/issues/3775 Additionally moves the claim queue fetch utilities into `subsystem-util`. TODO: - [x] fix tests - [x] add elastic scaling tests --------- Signed-off-by: Andrei Sandu --- .../node/collation-generation/src/error.rs | 2 + polkadot/node/collation-generation/src/lib.rs | 54 ++------ .../node/collation-generation/src/tests.rs | 15 +- .../statement-distribution/src/error.rs | 3 + .../statement-distribution/src/v2/mod.rs | 131 +++++++++++++----- .../src/v2/tests/cluster.rs | 60 ++++++++ .../src/v2/tests/grid.rs | 23 ++- .../src/v2/tests/mod.rs | 29 +++- polkadot/node/subsystem-util/src/vstaging.rs | 46 +++++- 9 files changed, 265 insertions(+), 98 deletions(-) diff --git a/polkadot/node/collation-generation/src/error.rs b/polkadot/node/collation-generation/src/error.rs index 852c50f30682..f04e3c4f20b4 100644 --- a/polkadot/node/collation-generation/src/error.rs +++ b/polkadot/node/collation-generation/src/error.rs @@ -27,6 +27,8 @@ pub enum Error { #[error(transparent)] Util(#[from] polkadot_node_subsystem_util::Error), #[error(transparent)] + UtilRuntime(#[from] polkadot_node_subsystem_util::runtime::Error), + #[error(transparent)] Erasure(#[from] polkadot_erasure_coding::Error), #[error("Parachain backing state not available in runtime.")] MissingParaBackingState, diff --git a/polkadot/node/collation-generation/src/lib.rs b/polkadot/node/collation-generation/src/lib.rs index 3164f6078bc0..fb82871bb15a 100644 --- a/polkadot/node/collation-generation/src/lib.rs +++ b/polkadot/node/collation-generation/src/lib.rs @@ -38,25 +38,23 @@ use polkadot_node_primitives::{ SubmitCollationParams, }; use polkadot_node_subsystem::{ - messages::{CollationGenerationMessage, CollatorProtocolMessage, RuntimeApiRequest}, + messages::{CollationGenerationMessage, CollatorProtocolMessage}, overseer, ActiveLeavesUpdate, FromOrchestra, OverseerSignal, RuntimeApiError, SpawnedSubsystem, SubsystemContext, SubsystemError, SubsystemResult, }; use polkadot_node_subsystem_util::{ - has_required_runtime, request_async_backing_params, request_availability_cores, - request_claim_queue, request_para_backing_state, request_persisted_validation_data, - request_validation_code, request_validation_code_hash, request_validators, + request_async_backing_params, request_availability_cores, request_para_backing_state, + request_persisted_validation_data, request_validation_code, request_validation_code_hash, + request_validators, + vstaging::{fetch_claim_queue, fetch_next_scheduled_on_core}, }; use polkadot_primitives::{ collator_signature_payload, CandidateCommitments, CandidateDescriptor, CandidateReceipt, CollatorPair, CoreIndex, CoreState, Hash, Id as ParaId, OccupiedCoreAssumption, - PersistedValidationData, ScheduledCore, ValidationCodeHash, + PersistedValidationData, ValidationCodeHash, }; use sp_core::crypto::Pair; -use std::{ - collections::{BTreeMap, VecDeque}, - sync::Arc, -}; +use std::sync::Arc; mod error; @@ -228,7 +226,9 @@ async fn handle_new_activations( let availability_cores = availability_cores??; let async_backing_params = async_backing_params?.ok(); let n_validators = validators??.len(); - let maybe_claim_queue = fetch_claim_queue(ctx.sender(), relay_parent).await?; + let maybe_claim_queue = fetch_claim_queue(ctx.sender(), relay_parent) + .await + .map_err(crate::error::Error::UtilRuntime)?; // The loop bellow will fill in cores that the para is allowed to build on. let mut cores_to_build_on = Vec::new(); @@ -655,37 +655,3 @@ fn erasure_root( let chunks = polkadot_erasure_coding::obtain_chunks_v1(n_validators, &available_data)?; Ok(polkadot_erasure_coding::branches(&chunks).root()) } - -// Checks if the runtime supports `request_claim_queue` and executes it. Returns `Ok(None)` -// otherwise. Any [`RuntimeApiError`]s are bubbled up to the caller. -async fn fetch_claim_queue( - sender: &mut impl overseer::CollationGenerationSenderTrait, - relay_parent: Hash, -) -> crate::error::Result>>> { - if has_required_runtime( - sender, - relay_parent, - RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT, - ) - .await - { - let res = request_claim_queue(relay_parent, sender).await.await??; - Ok(Some(res)) - } else { - gum::trace!(target: LOG_TARGET, "Runtime doesn't support `request_claim_queue`"); - Ok(None) - } -} - -// Returns the next scheduled `ParaId` for a core in the claim queue, wrapped in `ScheduledCore`. -// This function is supposed to be used in `handle_new_activations` hence the return type. -fn fetch_next_scheduled_on_core( - claim_queue: &BTreeMap>, - core_idx: CoreIndex, -) -> Option { - claim_queue - .get(&core_idx)? - .front() - .cloned() - .map(|para_id| ScheduledCore { para_id, collator: None }) -} diff --git a/polkadot/node/collation-generation/src/tests.rs b/polkadot/node/collation-generation/src/tests.rs index 923a21e86fb1..781d27188df1 100644 --- a/polkadot/node/collation-generation/src/tests.rs +++ b/polkadot/node/collation-generation/src/tests.rs @@ -28,7 +28,7 @@ use polkadot_node_subsystem::{ ActivatedLeaf, }; use polkadot_node_subsystem_test_helpers::{subsystem_test_harness, TestSubsystemContextHandle}; -use polkadot_node_subsystem_util::TimeoutExt; +use polkadot_node_subsystem_util::{vstaging::ClaimQueueSnapshot, TimeoutExt}; use polkadot_primitives::{ async_backing::{BackingState, CandidatePendingAvailability}, AsyncBackingParams, BlockNumber, CollatorPair, HeadData, PersistedValidationData, @@ -36,7 +36,10 @@ use polkadot_primitives::{ }; use rstest::rstest; use sp_keyring::sr25519::Keyring as Sr25519Keyring; -use std::pin::Pin; +use std::{ + collections::{BTreeMap, VecDeque}, + pin::Pin, +}; use test_helpers::{ dummy_candidate_descriptor, dummy_hash, dummy_head_data, dummy_validator, make_candidate, }; @@ -617,7 +620,7 @@ fn fallback_when_no_validation_code_hash_api(#[case] runtime_version: u32) { _hash, RuntimeApiRequest::ClaimQueue(tx), ))) if runtime_version >= RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT => { - let res = BTreeMap::>::new(); + let res = ClaimQueueSnapshot::new(); tx.send(Ok(res)).unwrap(); }, Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( @@ -780,7 +783,7 @@ fn distribute_collation_for_occupied_core_with_async_backing_enabled(#[case] run candidate_hash: Default::default(), candidate_descriptor: dummy_candidate_descriptor(dummy_hash()), })]; - let claim_queue = BTreeMap::from([(CoreIndex::from(0), VecDeque::from([para_id]))]); + let claim_queue = ClaimQueueSnapshot::from([(CoreIndex::from(0), VecDeque::from([para_id]))]); test_harness(|mut virtual_overseer| async move { helpers::initialize_collator(&mut virtual_overseer, para_id).await; @@ -962,7 +965,7 @@ fn no_collation_is_distributed_for_occupied_core_with_async_backing_disabled( candidate_hash: Default::default(), candidate_descriptor: dummy_candidate_descriptor(dummy_hash()), })]; - let claim_queue = BTreeMap::from([(CoreIndex::from(0), VecDeque::from([para_id]))]); + let claim_queue = ClaimQueueSnapshot::from([(CoreIndex::from(0), VecDeque::from([para_id]))]); test_harness(|mut virtual_overseer| async move { helpers::initialize_collator(&mut virtual_overseer, para_id).await; @@ -1050,7 +1053,7 @@ mod helpers { async_backing_params: AsyncBackingParams, cores: Vec, runtime_version: u32, - claim_queue: BTreeMap>, + claim_queue: ClaimQueueSnapshot, ) { assert_matches!( overseer_recv(virtual_overseer).await, diff --git a/polkadot/node/network/statement-distribution/src/error.rs b/polkadot/node/network/statement-distribution/src/error.rs index a712ab6da436..d7f52162fe23 100644 --- a/polkadot/node/network/statement-distribution/src/error.rs +++ b/polkadot/node/network/statement-distribution/src/error.rs @@ -81,6 +81,9 @@ pub enum Error { #[error("Fetching validator groups failed {0:?}")] FetchValidatorGroups(RuntimeApiError), + #[error("Fetching claim queue failed {0:?}")] + FetchClaimQueue(runtime::Error), + #[error("Attempted to share statement when not a validator or not assigned")] InvalidShare, diff --git a/polkadot/node/network/statement-distribution/src/v2/mod.rs b/polkadot/node/network/statement-distribution/src/v2/mod.rs index d782e37f10b4..b9f6f705ed8f 100644 --- a/polkadot/node/network/statement-distribution/src/v2/mod.rs +++ b/polkadot/node/network/statement-distribution/src/v2/mod.rs @@ -46,6 +46,7 @@ use polkadot_node_subsystem_util::{ backing_implicit_view::View as ImplicitView, reputation::ReputationAggregator, runtime::{request_min_backing_votes, ProspectiveParachainsMode}, + vstaging::fetch_claim_queue, }; use polkadot_primitives::{ AuthorityDiscoveryId, CandidateHash, CompactStatement, CoreIndex, CoreState, GroupIndex, @@ -149,10 +150,9 @@ pub(crate) const REQUEST_RETRY_DELAY: Duration = Duration::from_secs(1); struct PerRelayParentState { local_validator: Option, statement_store: StatementStore, - availability_cores: Vec, - group_rotation_info: GroupRotationInfo, seconding_limit: usize, session: SessionIndex, + groups_per_para: HashMap>, } impl PerRelayParentState { @@ -563,11 +563,13 @@ pub(crate) async fn handle_active_leaves_update( activated: &ActivatedLeaf, leaf_mode: ProspectiveParachainsMode, ) -> JfyiErrorResult<()> { - let seconding_limit = match leaf_mode { + let max_candidate_depth = match leaf_mode { ProspectiveParachainsMode::Disabled => return Ok(()), - ProspectiveParachainsMode::Enabled { max_candidate_depth, .. } => max_candidate_depth + 1, + ProspectiveParachainsMode::Enabled { max_candidate_depth, .. } => max_candidate_depth, }; + let seconding_limit = max_candidate_depth + 1; + state .implicit_view .activate_leaf(ctx.sender(), activated.hash) @@ -693,15 +695,23 @@ pub(crate) async fn handle_active_leaves_update( } }); + let groups_per_para = determine_groups_per_para( + ctx.sender(), + new_relay_parent, + availability_cores, + group_rotation_info, + max_candidate_depth, + ) + .await; + state.per_relay_parent.insert( new_relay_parent, PerRelayParentState { local_validator, statement_store: StatementStore::new(&per_session.groups), - availability_cores, - group_rotation_info, seconding_limit, session: session_index, + groups_per_para, }, ); } @@ -2126,17 +2136,64 @@ async fn provide_candidate_to_grid( } } -fn group_for_para( - availability_cores: &[CoreState], - group_rotation_info: &GroupRotationInfo, - para_id: ParaId, -) -> Option { - // Note: this won't work well for on-demand parachains as it assumes that core assignments are - // fixed across blocks. - let core_index = availability_cores.iter().position(|c| c.para_id() == Some(para_id)); +// Utility function to populate per relay parent `ParaId` to `GroupIndex` mappings. +async fn determine_groups_per_para( + sender: &mut impl overseer::StatementDistributionSenderTrait, + relay_parent: Hash, + availability_cores: Vec, + group_rotation_info: GroupRotationInfo, + max_candidate_depth: usize, +) -> HashMap> { + let maybe_claim_queue = fetch_claim_queue(sender, relay_parent) + .await + .unwrap_or_else(|err| { + gum::debug!( + target: LOG_TARGET, + ?relay_parent, + ?err, + "determine_groups_per_para: `claim_queue` API not available, falling back to iterating availability cores" + ); + None + }); + + let n_cores = availability_cores.len(); + + // Determine the core indices occupied by each para at the current relay parent. To support + // on-demand parachains we also consider the core indices at next block if core has a candidate + // pending availability. + let para_core_indices: Vec<_> = if let Some(claim_queue) = maybe_claim_queue { + claim_queue + .into_iter() + .filter_map(|(core_index, paras)| Some((*paras.front()?, core_index))) + .collect() + } else { + availability_cores + .into_iter() + .enumerate() + .filter_map(|(index, core)| match core { + CoreState::Scheduled(scheduled_core) => + Some((scheduled_core.para_id, CoreIndex(index as u32))), + CoreState::Occupied(occupied_core) => + if max_candidate_depth >= 1 { + occupied_core + .next_up_on_available + .map(|scheduled_core| (scheduled_core.para_id, CoreIndex(index as u32))) + } else { + None + }, + CoreState::Free => None, + }) + .collect() + }; - core_index - .map(|c| group_rotation_info.group_for_core(CoreIndex(c as _), availability_cores.len())) + let mut groups_per_para = HashMap::new(); + // Map from `CoreIndex` to `GroupIndex` and collect as `HashMap`. + for (para, core_index) in para_core_indices { + let group_index = group_rotation_info.group_for_core(core_index, n_cores); + groups_per_para.entry(para).or_insert_with(Vec::new).push(group_index) + } + + groups_per_para } #[overseer::contextbounds(StatementDistribution, prefix=self::overseer)] @@ -2192,18 +2249,23 @@ async fn fragment_tree_update_inner( let confirmed_candidate = state.candidates.get_confirmed(&candidate_hash); let prs = state.per_relay_parent.get_mut(&receipt.descriptor().relay_parent); if let (Some(confirmed), Some(prs)) = (confirmed_candidate, prs) { - let group_index = group_for_para( - &prs.availability_cores, - &prs.group_rotation_info, - receipt.descriptor().para_id, - ); - let per_session = state.per_session.get(&prs.session); - if let (Some(per_session), Some(group_index)) = (per_session, group_index) { + let group_index = confirmed.group_index(); + + // Sanity check if group_index is valid for this para at relay parent. + let Some(expected_groups) = prs.groups_per_para.get(&receipt.descriptor().para_id) + else { + continue + }; + if !expected_groups.iter().any(|g| *g == group_index) { + continue + } + + if let Some(per_session) = per_session { send_backing_fresh_statements( ctx, candidate_hash, - group_index, + confirmed.group_index(), &receipt.descriptor().relay_parent, prs, confirmed, @@ -2311,13 +2373,12 @@ async fn handle_incoming_manifest_common<'a, Context>( Some(x) => x, }; - let expected_group = group_for_para( - &relay_parent_state.availability_cores, - &relay_parent_state.group_rotation_info, - para_id, - ); + let Some(expected_groups) = relay_parent_state.groups_per_para.get(¶_id) else { + modify_reputation(reputation, ctx.sender(), peer, COST_MALFORMED_MANIFEST).await; + return None + }; - if expected_group != Some(manifest_summary.claimed_group_index) { + if !expected_groups.iter().any(|g| g == &manifest_summary.claimed_group_index) { modify_reputation(reputation, ctx.sender(), peer, COST_MALFORMED_MANIFEST).await; return None } @@ -3037,13 +3098,11 @@ pub(crate) async fn handle_response( relay_parent_state.session, |v| per_session.session_info.validators.get(v).map(|x| x.clone()), |para, g_index| { - let expected_group = group_for_para( - &relay_parent_state.availability_cores, - &relay_parent_state.group_rotation_info, - para, - ); + let Some(expected_groups) = relay_parent_state.groups_per_para.get(¶) else { + return false + }; - Some(g_index) == expected_group + expected_groups.iter().any(|g| g == &g_index) }, disabled_mask, ); diff --git a/polkadot/node/network/statement-distribution/src/v2/tests/cluster.rs b/polkadot/node/network/statement-distribution/src/v2/tests/cluster.rs index a944a9cd6d02..4fb033e08ce3 100644 --- a/polkadot/node/network/statement-distribution/src/v2/tests/cluster.rs +++ b/polkadot/node/network/statement-distribution/src/v2/tests/cluster.rs @@ -312,6 +312,66 @@ fn useful_cluster_statement_from_non_cluster_peer_rejected() { }); } +// Both validators in the test are part of backing groups assigned to same parachain +#[test] +fn elastic_scaling_useful_cluster_statement_from_non_cluster_peer_rejected() { + let config = TestConfig { + validator_count: 20, + group_size: 3, + local_validator: LocalRole::Validator, + async_backing_params: None, + }; + + let relay_parent = Hash::repeat_byte(1); + let peer_a = PeerId::random(); + + test_harness(config, |state, mut overseer| async move { + let candidate_hash = CandidateHash(Hash::repeat_byte(42)); + + let test_leaf = state.make_dummy_leaf_with_multiple_cores_per_para(relay_parent, 3); + + // Peer A is not in our group, but its group is assigned to same para as we are. + let not_our_group = GroupIndex(1); + + let that_group_validators = state.group_validators(not_our_group, false); + let v_non = that_group_validators[0]; + + connect_peer( + &mut overseer, + peer_a.clone(), + Some(vec![state.discovery_id(v_non)].into_iter().collect()), + ) + .await; + + send_peer_view_change(&mut overseer, peer_a.clone(), view![relay_parent]).await; + activate_leaf(&mut overseer, &test_leaf, &state, true, vec![]).await; + + let statement = state + .sign_statement( + v_non, + CompactStatement::Seconded(candidate_hash), + &SigningContext { parent_hash: relay_parent, session_index: 1 }, + ) + .as_unchecked() + .clone(); + + send_peer_message( + &mut overseer, + peer_a.clone(), + protocol_v2::StatementDistributionMessage::Statement(relay_parent, statement), + ) + .await; + + assert_matches!( + overseer.recv().await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ReportPeer(ReportPeerMessage::Single(p, r))) + if p == peer_a && r == COST_UNEXPECTED_STATEMENT_INVALID_SENDER.into() => { } + ); + + overseer + }); +} + #[test] fn statement_from_non_cluster_originator_unexpected() { let config = TestConfig { diff --git a/polkadot/node/network/statement-distribution/src/v2/tests/grid.rs b/polkadot/node/network/statement-distribution/src/v2/tests/grid.rs index 38a12cf32e3b..9d00a92e742b 100644 --- a/polkadot/node/network/statement-distribution/src/v2/tests/grid.rs +++ b/polkadot/node/network/statement-distribution/src/v2/tests/grid.rs @@ -1829,9 +1829,7 @@ fn advertisement_not_re_sent_when_peer_re_enters_view() { }); } -// Grid statements imported to backing once candidate enters hypothetical frontier. -#[test] -fn grid_statements_imported_to_backing() { +fn inner_grid_statements_imported_to_backing(groups_for_first_para: usize) { let validator_count = 6; let group_size = 3; let config = TestConfig { @@ -1851,9 +1849,12 @@ fn grid_statements_imported_to_backing() { let local_group_index = local_validator.group_index.unwrap(); let other_group = next_group_index(local_group_index, validator_count, group_size); - let other_para = ParaId::from(other_group.0); - let test_leaf = state.make_dummy_leaf(relay_parent); + // Other para is same para for elastic scaling test (groups_for_first_para > 1) + let other_para = ParaId::from((groups_for_first_para == 1) as u32); + + let test_leaf = + state.make_dummy_leaf_with_multiple_cores_per_para(relay_parent, groups_for_first_para); let (candidate, pvd) = make_candidate( relay_parent, @@ -2018,6 +2019,18 @@ fn grid_statements_imported_to_backing() { overseer }); } +// Grid statements imported to backing once candidate enters hypothetical frontier. +#[test] +fn grid_statements_imported_to_backing() { + inner_grid_statements_imported_to_backing(1); +} + +// Grid statements imported to backing once candidate enters hypothetical frontier. +// All statements are for candidates of the same parachain but from different backing groups. +#[test] +fn elastic_scaling_grid_statements_imported_to_backing() { + inner_grid_statements_imported_to_backing(2); +} #[test] fn advertisements_rejected_from_incorrect_peers() { diff --git a/polkadot/node/network/statement-distribution/src/v2/tests/mod.rs b/polkadot/node/network/statement-distribution/src/v2/tests/mod.rs index 82986a0330ec..e98b11079312 100644 --- a/polkadot/node/network/statement-distribution/src/v2/tests/mod.rs +++ b/polkadot/node/network/statement-distribution/src/v2/tests/mod.rs @@ -177,20 +177,39 @@ impl TestState { } fn make_dummy_leaf(&self, relay_parent: Hash) -> TestLeaf { + self.make_dummy_leaf_with_multiple_cores_per_para(relay_parent, 1) + } + + fn make_dummy_leaf_with_multiple_cores_per_para( + &self, + relay_parent: Hash, + groups_for_first_para: usize, + ) -> TestLeaf { TestLeaf { number: 1, hash: relay_parent, parent_hash: Hash::repeat_byte(0), session: 1, availability_cores: self.make_availability_cores(|i| { - CoreState::Scheduled(ScheduledCore { - para_id: ParaId::from(i as u32), - collator: None, - }) + let para_id = if i < groups_for_first_para { + ParaId::from(0u32) + } else { + ParaId::from(i as u32) + }; + + CoreState::Scheduled(ScheduledCore { para_id, collator: None }) }), disabled_validators: Default::default(), para_data: (0..self.session_info.validator_groups.len()) - .map(|i| (ParaId::from(i as u32), PerParaData::new(1, vec![1, 2, 3].into()))) + .map(|i| { + let para_id = if i < groups_for_first_para { + ParaId::from(0u32) + } else { + ParaId::from(i as u32) + }; + + (para_id, PerParaData::new(1, vec![1, 2, 3].into())) + }) .collect(), minimum_backing_votes: 2, } diff --git a/polkadot/node/subsystem-util/src/vstaging.rs b/polkadot/node/subsystem-util/src/vstaging.rs index 3e807eff5387..25ea7ce7c9bd 100644 --- a/polkadot/node/subsystem-util/src/vstaging.rs +++ b/polkadot/node/subsystem-util/src/vstaging.rs @@ -19,14 +19,19 @@ //! This module is intended to contain common boiler plate code handling unreleased runtime API //! calls. +use std::collections::{BTreeMap, VecDeque}; + use polkadot_node_subsystem_types::messages::{RuntimeApiMessage, RuntimeApiRequest}; use polkadot_overseer::SubsystemSender; -use polkadot_primitives::{Hash, ValidatorIndex}; +use polkadot_primitives::{CoreIndex, Hash, Id as ParaId, ScheduledCore, ValidatorIndex}; -use crate::{has_required_runtime, request_disabled_validators, runtime}; +use crate::{has_required_runtime, request_claim_queue, request_disabled_validators, runtime}; const LOG_TARGET: &'static str = "parachain::subsystem-util-vstaging"; +/// A snapshot of the runtime claim queue at an arbitrary relay chain block. +pub type ClaimQueueSnapshot = BTreeMap>; + // TODO: https://github.com/paritytech/polkadot-sdk/issues/1940 /// Returns disabled validators list if the runtime supports it. Otherwise logs a debug messages and /// returns an empty vec. @@ -54,3 +59,40 @@ pub async fn get_disabled_validators_with_fallback, + relay_parent: Hash, +) -> Result, runtime::Error> { + if has_required_runtime( + sender, + relay_parent, + RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT, + ) + .await + { + let res = request_claim_queue(relay_parent, sender) + .await + .await + .map_err(runtime::Error::RuntimeRequestCanceled)??; + Ok(Some(res)) + } else { + gum::trace!(target: LOG_TARGET, "Runtime doesn't support `request_claim_queue`"); + Ok(None) + } +} + +/// Returns the next scheduled `ParaId` for a core in the claim queue, wrapped in `ScheduledCore`. +pub fn fetch_next_scheduled_on_core( + claim_queue: &ClaimQueueSnapshot, + core_idx: CoreIndex, +) -> Option { + claim_queue + .get(&core_idx)? + .front() + .cloned() + .map(|para_id| ScheduledCore { para_id, collator: None }) +} From 5536d86f72d2c219d2fb74825e97fbc2ab259c3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 3 Apr 2024 10:35:53 +0200 Subject: [PATCH 111/257] sp-wasm-interface: `wasmtime` should not be enabled by `std` (#3954) Closes: https://github.com/paritytech/polkadot-sdk/issues/3909 --- substrate/primitives/wasm-interface/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/primitives/wasm-interface/Cargo.toml b/substrate/primitives/wasm-interface/Cargo.toml index c05cc05ff06d..15a20fab5e5d 100644 --- a/substrate/primitives/wasm-interface/Cargo.toml +++ b/substrate/primitives/wasm-interface/Cargo.toml @@ -25,5 +25,5 @@ anyhow = { version = "1.0.81", optional = true } [features] default = ["std"] -std = ["codec/std", "log/std", "wasmtime"] +std = ["codec/std", "log/std"] wasmtime = ["anyhow", "dep:wasmtime"] From 7e437ada8676fa117c70a9ae7b0d0e95b829af1a Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Wed, 3 Apr 2024 13:10:50 +0200 Subject: [PATCH 112/257] Added tests for XCM barriers: `AllowSubscriptions`, `WithUniqueTopic` and `TrailingSetTopicAsId` (#3955) Closes: https://github.com/paritytech/polkadot-sdk/issues/1756 --- .../xcm/xcm-builder/src/tests/barriers.rs | 59 ++++++++++++ polkadot/xcm/xcm-builder/src/tests/mod.rs | 1 + polkadot/xcm/xcm-builder/src/tests/routing.rs | 95 +++++++++++++++++++ .../src/tests/version_subscriptions.rs | 32 +++++-- .../xcm-executor/src/traits/should_execute.rs | 4 +- 5 files changed, 181 insertions(+), 10 deletions(-) create mode 100644 polkadot/xcm/xcm-builder/src/tests/routing.rs diff --git a/polkadot/xcm/xcm-builder/src/tests/barriers.rs b/polkadot/xcm/xcm-builder/src/tests/barriers.rs index 99a9dd5a6609..6516263f57a0 100644 --- a/polkadot/xcm/xcm-builder/src/tests/barriers.rs +++ b/polkadot/xcm/xcm-builder/src/tests/barriers.rs @@ -309,3 +309,62 @@ fn suspension_should_work() { ); assert_eq!(r, Ok(())); } + +#[test] +fn allow_subscriptions_from_should_work() { + // allow only parent + AllowSubsFrom::set(vec![Location::parent()]); + + let valid_xcm_1 = Xcm::(vec![SubscribeVersion { + query_id: 42, + max_response_weight: Weight::from_parts(5000, 5000), + }]); + let valid_xcm_2 = Xcm::(vec![UnsubscribeVersion]); + let invalid_xcm_1 = Xcm::(vec![ + SetAppendix(Xcm(vec![])), + SubscribeVersion { query_id: 42, max_response_weight: Weight::from_parts(5000, 5000) }, + ]); + let invalid_xcm_2 = Xcm::(vec![ + SubscribeVersion { query_id: 42, max_response_weight: Weight::from_parts(5000, 5000) }, + SetTopic([0; 32]), + ]); + + let test_data = vec![ + ( + valid_xcm_1.clone(), + Parachain(1).into_location(), + // not allowed origin + Err(ProcessMessageError::Unsupported), + ), + (valid_xcm_1, Location::parent(), Ok(())), + ( + valid_xcm_2.clone(), + Parachain(1).into_location(), + // not allowed origin + Err(ProcessMessageError::Unsupported), + ), + (valid_xcm_2, Location::parent(), Ok(())), + ( + invalid_xcm_1, + Location::parent(), + // invalid XCM + Err(ProcessMessageError::BadFormat), + ), + ( + invalid_xcm_2, + Location::parent(), + // invalid XCM + Err(ProcessMessageError::BadFormat), + ), + ]; + + for (mut message, origin, expected_result) in test_data { + let r = AllowSubscriptionsFrom::>::should_execute( + &origin, + message.inner_mut(), + Weight::from_parts(10, 10), + &mut props(Weight::zero()), + ); + assert_eq!(r, expected_result, "Failed for origin: {origin:?} and message: {message:?}"); + } +} diff --git a/polkadot/xcm/xcm-builder/src/tests/mod.rs b/polkadot/xcm/xcm-builder/src/tests/mod.rs index e11caf6282be..63d254a10675 100644 --- a/polkadot/xcm/xcm-builder/src/tests/mod.rs +++ b/polkadot/xcm/xcm-builder/src/tests/mod.rs @@ -36,6 +36,7 @@ mod locking; mod origins; mod pay; mod querying; +mod routing; mod transacting; mod version_subscriptions; mod weight; diff --git a/polkadot/xcm/xcm-builder/src/tests/routing.rs b/polkadot/xcm/xcm-builder/src/tests/routing.rs new file mode 100644 index 000000000000..28117d647a08 --- /dev/null +++ b/polkadot/xcm/xcm-builder/src/tests/routing.rs @@ -0,0 +1,95 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +use super::*; +use frame_support::{assert_ok, traits::Everything}; +use xcm_executor::traits::Properties; + +fn props() -> Properties { + Properties { weight_credit: Weight::zero(), message_id: None } +} + +#[test] +fn trailing_set_topic_as_id_with_unique_topic_should_work() { + type AllowSubscriptions = AllowSubscriptionsFrom; + + // check the validity of XCM for the `AllowSubscriptions` barrier + let valid_xcm = Xcm::<()>(vec![SubscribeVersion { + query_id: 42, + max_response_weight: Weight::from_parts(5000, 5000), + }]); + assert_eq!( + AllowSubscriptions::should_execute( + &Location::parent(), + valid_xcm.clone().inner_mut(), + Weight::from_parts(10, 10), + &mut props(), + ), + Ok(()) + ); + + // simulate sending `valid_xcm` with the `WithUniqueTopic` router + let mut sent_xcm = sp_io::TestExternalities::default().execute_with(|| { + assert_ok!(send_xcm::>(Location::parent(), valid_xcm,)); + sent_xcm() + }); + assert_eq!(1, sent_xcm.len()); + + // `sent_xcm` should contain `SubscribeVersion` and have `SetTopic` added + let mut sent_xcm = sent_xcm.remove(0).1; + let _ = sent_xcm + .0 + .matcher() + .assert_remaining_insts(2) + .expect("two instructions") + .match_next_inst(|instr| match instr { + SubscribeVersion { .. } => Ok(()), + _ => Err(ProcessMessageError::BadFormat), + }) + .expect("expected instruction `SubscribeVersion`") + .match_next_inst(|instr| match instr { + SetTopic(..) => Ok(()), + _ => Err(ProcessMessageError::BadFormat), + }) + .expect("expected instruction `SetTopic`"); + + // `sent_xcm` contains `SetTopic` and is now invalid for `AllowSubscriptions` + assert_eq!( + AllowSubscriptions::should_execute( + &Location::parent(), + sent_xcm.clone().inner_mut(), + Weight::from_parts(10, 10), + &mut props(), + ), + Err(ProcessMessageError::BadFormat) + ); + + // let's apply `TrailingSetTopicAsId` before `AllowSubscriptions` + let mut props = props(); + assert!(props.message_id.is_none()); + + // should pass, and the `message_id` is set + assert_eq!( + TrailingSetTopicAsId::::should_execute( + &Location::parent(), + sent_xcm.clone().inner_mut(), + Weight::from_parts(10, 10), + &mut props, + ), + Ok(()) + ); + assert!(props.message_id.is_some()); +} diff --git a/polkadot/xcm/xcm-builder/src/tests/version_subscriptions.rs b/polkadot/xcm/xcm-builder/src/tests/version_subscriptions.rs index e29e3a546615..01047fde989f 100644 --- a/polkadot/xcm/xcm-builder/src/tests/version_subscriptions.rs +++ b/polkadot/xcm/xcm-builder/src/tests/version_subscriptions.rs @@ -27,16 +27,32 @@ fn simple_version_subscriptions_should_work() { ]); let mut hash = fake_message_hash(&message); let weight_limit = Weight::from_parts(20, 20); - let r = XcmExecutor::::prepare_and_execute( - origin, - message, - &mut hash, - weight_limit, - Weight::zero(), + + // this case fails because the origin is not allowed + assert_eq!( + XcmExecutor::::prepare_and_execute( + origin, + message.clone(), + &mut hash, + weight_limit, + Weight::zero(), + ), + Outcome::Error { error: XcmError::Barrier } + ); + + // this case fails because the additional `SetAppendix` instruction is not allowed in the + // `AllowSubscriptionsFrom` + assert_eq!( + XcmExecutor::::prepare_and_execute( + Parent, + message, + &mut hash, + weight_limit, + Weight::zero(), + ), + Outcome::Error { error: XcmError::Barrier } ); - assert_eq!(r, Outcome::Error { error: XcmError::Barrier }); - let origin = Parachain(1000); let message = Xcm::(vec![SubscribeVersion { query_id: 42, max_response_weight: Weight::from_parts(5000, 5000), diff --git a/polkadot/xcm/xcm-executor/src/traits/should_execute.rs b/polkadot/xcm/xcm-executor/src/traits/should_execute.rs index 12e8fd6b87f1..e76d56bfe616 100644 --- a/polkadot/xcm/xcm-executor/src/traits/should_execute.rs +++ b/polkadot/xcm/xcm-executor/src/traits/should_execute.rs @@ -33,9 +33,9 @@ pub struct Properties { /// Trait to determine whether the execution engine should actually execute a given XCM. /// /// Can be amalgamated into a tuple to have multiple trials. If any of the tuple elements returns -/// `Ok()`, the execution stops. Else, `Err(_)` is returned if all elements reject the message. +/// `Ok(())`, the execution stops. Else, `Err(_)` is returned if all elements reject the message. pub trait ShouldExecute { - /// Returns `true` if the given `message` may be executed. + /// Returns `Ok(())` if the given `message` may be executed. /// /// - `origin`: The origin (sender) of the message. /// - `instructions`: The message itself. From 743cfee1c3374d186ed2f08c04725ea8e52842fb Mon Sep 17 00:00:00 2001 From: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Date: Wed, 3 Apr 2024 14:46:08 +0300 Subject: [PATCH 113/257] chainHead: Ensure reasonable distance between leaf and finalized block (#3562) This PR ensure that the distance between any leaf and the finalized block is within a reasonable distance. For a new subscription, the chainHead has to provide all blocks between the leaves of the chain and the finalized block. When the distance between a leaf and the finalized block is large: - The tree route is costly to compute - We could deliver an unbounded number of blocks (potentially millions) (For more details see https://github.com/paritytech/polkadot-sdk/pull/3445#discussion_r1507210283) The configuration of the ChainHead is extended with: - suspend on lagging distance: When the distance between any leaf and the finalized block is greater than this number, the subscriptions are suspended for a given duration. - All active subscriptions are terminated with the `Stop` event, all blocks are unpinned and data discarded. - For incoming subscriptions, until the suspended period expires the subscriptions will immediately receive the `Stop` event. - Defaults to 128 blocks - suspended duration: The amount of time for which subscriptions are suspended - Defaults to 30 seconds cc @paritytech/subxt-team --------- Signed-off-by: Alexandru Vasile Co-authored-by: Sebastian Kunert --- Cargo.lock | 9 +- .../rpc-spec-v2/src/chain_head/chain_head.rs | 25 +- .../src/chain_head/chain_head_follow.rs | 71 +++++- .../src/chain_head/subscription/error.rs | 4 + .../src/chain_head/subscription/inner.rs | 238 +++++++----------- .../src/chain_head/subscription/mod.rs | 9 + .../rpc-spec-v2/src/chain_head/tests.rs | 121 +++++++++ 7 files changed, 313 insertions(+), 164 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5125e46ca89a..3b0242b39c5f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2624,9 +2624,9 @@ dependencies = [ [[package]] name = "clap-num" -version = "1.1.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e063d263364859dc54fb064cedb7c122740cd4733644b14b176c097f51e8ab7" +checksum = "488557e97528174edaa2ee268b23a809e0c598213a4bbcb4f34575a46fda147e" dependencies = [ "num-traits", ] @@ -2844,10 +2844,11 @@ checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "colored" -version = "2.1.0" +version = "2.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" +checksum = "2674ec482fbc38012cf31e6c42ba0177b431a0cb6f15fe40efa5aab1bda516f6" dependencies = [ + "is-terminal", "lazy_static", "windows-sys 0.48.0", ] diff --git a/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs b/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs index 975abbca4b68..86d9a726d7be 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/chain_head.rs @@ -62,6 +62,9 @@ pub struct ChainHeadConfig { pub subscription_max_pinned_duration: Duration, /// The maximum number of ongoing operations per subscription. pub subscription_max_ongoing_operations: usize, + /// Stop all subscriptions if the distance between the leaves and the current finalized + /// block is larger than this value. + pub max_lagging_distance: usize, /// The maximum number of items reported by the `chainHead_storage` before /// pagination is required. pub operation_max_storage_items: usize, @@ -88,6 +91,10 @@ const MAX_ONGOING_OPERATIONS: usize = 16; /// before paginations is required. const MAX_STORAGE_ITER_ITEMS: usize = 5; +/// Stop all subscriptions if the distance between the leaves and the current finalized +/// block is larger than this value. +const MAX_LAGGING_DISTANCE: usize = 128; + /// The maximum number of `chainHead_follow` subscriptions per connection. const MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION: usize = 4; @@ -97,6 +104,7 @@ impl Default for ChainHeadConfig { global_max_pinned_blocks: MAX_PINNED_BLOCKS, subscription_max_pinned_duration: MAX_PINNED_DURATION, subscription_max_ongoing_operations: MAX_ONGOING_OPERATIONS, + max_lagging_distance: MAX_LAGGING_DISTANCE, operation_max_storage_items: MAX_STORAGE_ITER_ITEMS, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, } @@ -116,6 +124,9 @@ pub struct ChainHead, Block: BlockT, Client> { /// The maximum number of items reported by the `chainHead_storage` before /// pagination is required. operation_max_storage_items: usize, + /// Stop all subscriptions if the distance between the leaves and the current finalized + /// block is larger than this value. + max_lagging_distance: usize, /// Phantom member to pin the block type. _phantom: PhantomData, } @@ -140,6 +151,7 @@ impl, Block: BlockT, Client> ChainHead { backend, ), operation_max_storage_items: config.operation_max_storage_items, + max_lagging_distance: config.max_lagging_distance, _phantom: PhantomData, } } @@ -187,6 +199,7 @@ where let subscriptions = self.subscriptions.clone(); let backend = self.backend.clone(); let client = self.client.clone(); + let max_lagging_distance = self.max_lagging_distance; let fut = async move { // Ensure the current connection ID has enough space to accept a new subscription. @@ -207,8 +220,8 @@ where let Some(sub_data) = reserved_subscription.insert_subscription(sub_id.clone(), with_runtime) else { - // Inserting the subscription can only fail if the JsonRPSee - // generated a duplicate subscription ID. + // Inserting the subscription can only fail if the JsonRPSee generated a duplicate + // subscription ID. debug!(target: LOG_TARGET, "[follow][id={:?}] Subscription already accepted", sub_id); let msg = to_sub_message(&sink, &FollowEvent::::Stop); let _ = sink.send(msg).await; @@ -222,9 +235,13 @@ where subscriptions, with_runtime, sub_id.clone(), + max_lagging_distance, ); - - chain_head_follow.generate_events(sink, sub_data).await; + let result = chain_head_follow.generate_events(sink, sub_data).await; + if let Err(SubscriptionManagementError::BlockDistanceTooLarge) = result { + debug!(target: LOG_TARGET, "[follow][id={:?}] All subscriptions are stopped", sub_id); + reserved_subscription.stop_all_subscriptions(); + } debug!(target: LOG_TARGET, "[follow][id={:?}] Subscription removed", sub_id); }; diff --git a/substrate/client/rpc-spec-v2/src/chain_head/chain_head_follow.rs b/substrate/client/rpc-spec-v2/src/chain_head/chain_head_follow.rs index 90cc62a36fa9..0d87a45c07e2 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/chain_head_follow.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/chain_head_follow.rs @@ -41,12 +41,14 @@ use sp_api::CallApiAt; use sp_blockchain::{ Backend as BlockChainBackend, Error as BlockChainError, HeaderBackend, HeaderMetadata, Info, }; -use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor}; +use sp_runtime::{ + traits::{Block as BlockT, Header as HeaderT, NumberFor}, + SaturatedConversion, Saturating, +}; use std::{ collections::{HashSet, VecDeque}, sync::Arc, }; - /// The maximum number of finalized blocks provided by the /// `Initialized` event. const MAX_FINALIZED_BLOCKS: usize = 16; @@ -67,6 +69,9 @@ pub struct ChainHeadFollower, Block: BlockT, Client> { sub_id: String, /// The best reported block by this subscription. best_block_cache: Option, + /// Stop all subscriptions if the distance between the leaves and the current finalized + /// block is larger than this value. + max_lagging_distance: usize, } impl, Block: BlockT, Client> ChainHeadFollower { @@ -77,8 +82,17 @@ impl, Block: BlockT, Client> ChainHeadFollower, with_runtime: bool, sub_id: String, + max_lagging_distance: usize, ) -> Self { - Self { client, backend, sub_handle, with_runtime, sub_id, best_block_cache: None } + Self { + client, + backend, + sub_handle, + with_runtime, + sub_id, + best_block_cache: None, + max_lagging_distance, + } } } @@ -186,6 +200,35 @@ where } } + /// Check the distance between the provided blocks does not exceed a + /// a reasonable range. + /// + /// When the blocks are too far apart (potentially millions of blocks): + /// - Tree route is expensive to calculate. + /// - The RPC layer will not be able to generate the `NewBlock` events for all blocks. + /// + /// This edge-case can happen for parachains where the relay chain syncs slower to + /// the head of the chain than the parachain node that is synced already. + fn distace_within_reason( + &self, + block: Block::Hash, + finalized: Block::Hash, + ) -> Result<(), SubscriptionManagementError> { + let Some(block_num) = self.client.number(block)? else { + return Err(SubscriptionManagementError::BlockHashAbsent) + }; + let Some(finalized_num) = self.client.number(finalized)? else { + return Err(SubscriptionManagementError::BlockHashAbsent) + }; + + let distance: usize = block_num.saturating_sub(finalized_num).saturated_into(); + if distance > self.max_lagging_distance { + return Err(SubscriptionManagementError::BlockDistanceTooLarge); + } + + Ok(()) + } + /// Get the in-memory blocks of the client, starting from the provided finalized hash. /// /// The reported blocks are pinned by this function. @@ -198,6 +241,13 @@ where let mut pruned_forks = HashSet::new(); let mut finalized_block_descendants = Vec::new(); let mut unique_descendants = HashSet::new(); + + // Ensure all leaves are within a reasonable distance from the finalized block, + // before traversing the tree. + for leaf in &leaves { + self.distace_within_reason(*leaf, finalized)?; + } + for leaf in leaves { let tree_route = sp_blockchain::tree_route(blockchain, finalized, leaf)?; @@ -542,7 +592,8 @@ where mut to_ignore: HashSet, sink: SubscriptionSink, rx_stop: oneshot::Receiver<()>, - ) where + ) -> Result<(), SubscriptionManagementError> + where EventStream: Stream> + Unpin, { let mut stream_item = stream.next(); @@ -576,7 +627,7 @@ where ); let msg = to_sub_message(&sink, &FollowEvent::::Stop); let _ = sink.send(msg).await; - return + return Err(err) }, }; @@ -591,7 +642,8 @@ where let msg = to_sub_message(&sink, &FollowEvent::::Stop); let _ = sink.send(msg).await; - return + // No need to propagate this error further, the client disconnected. + return Ok(()) } } @@ -605,6 +657,7 @@ where // - the client disconnected. let msg = to_sub_message(&sink, &FollowEvent::::Stop); let _ = sink.send(msg).await; + Ok(()) } /// Generate the block events for the `chainHead_follow` method. @@ -612,7 +665,7 @@ where &mut self, sink: SubscriptionSink, sub_data: InsertedSubscriptionData, - ) { + ) -> Result<(), SubscriptionManagementError> { // Register for the new block and finalized notifications. let stream_import = self .client @@ -640,7 +693,7 @@ where ); let msg = to_sub_message(&sink, &FollowEvent::::Stop); let _ = sink.send(msg).await; - return + return Err(err) }, }; @@ -650,6 +703,6 @@ where let stream = stream::once(futures::future::ready(initial)).chain(merged); self.submit_events(&startup_point, stream.boxed(), pruned_forks, sink, sub_data.rx_stop) - .await; + .await } } diff --git a/substrate/client/rpc-spec-v2/src/chain_head/subscription/error.rs b/substrate/client/rpc-spec-v2/src/chain_head/subscription/error.rs index 2c22e51ca4dc..91ce26db22a5 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/subscription/error.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/subscription/error.rs @@ -41,6 +41,9 @@ pub enum SubscriptionManagementError { /// The unpin method was called with duplicate hashes. #[error("Duplicate hashes")] DuplicateHashes, + /// The distance between the leaves and the current finalized block is too large. + #[error("Distance too large")] + BlockDistanceTooLarge, /// Custom error. #[error("Subscription error {0}")] Custom(String), @@ -57,6 +60,7 @@ impl PartialEq for SubscriptionManagementError { (Self::BlockHeaderAbsent, Self::BlockHeaderAbsent) | (Self::SubscriptionAbsent, Self::SubscriptionAbsent) | (Self::DuplicateHashes, Self::DuplicateHashes) => true, + (Self::BlockDistanceTooLarge, Self::BlockDistanceTooLarge) => true, (Self::Custom(lhs), Self::Custom(rhs)) => lhs == rhs, _ => false, } diff --git a/substrate/client/rpc-spec-v2/src/chain_head/subscription/inner.rs b/substrate/client/rpc-spec-v2/src/chain_head/subscription/inner.rs index 1ebee3c80fc8..0e5ccb91d39a 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/subscription/inner.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/subscription/inner.rs @@ -560,6 +560,7 @@ pub struct SubscriptionsInner> { max_ongoing_operations: usize, /// Map the subscription ID to internal details of the subscription. subs: HashMap>, + /// Backend pinning / unpinning blocks. /// /// The `Arc` is handled one level-above, but substrate exposes the backend as Arc. @@ -623,6 +624,15 @@ impl> SubscriptionsInner { } } + /// All active subscriptions are removed. + pub fn stop_all_subscriptions(&mut self) { + let to_remove: Vec<_> = self.subs.keys().map(|sub_id| sub_id.clone()).collect(); + + for sub_id in to_remove { + self.remove_subscription(&sub_id); + } + } + /// Ensure that a new block could be pinned. /// /// If the global number of blocks has been reached this method @@ -878,6 +888,30 @@ mod tests { (backend, client) } + fn produce_blocks( + mut client: Arc>>, + num_blocks: usize, + ) -> Vec<::Hash> { + let mut blocks = Vec::with_capacity(num_blocks); + let mut parent_hash = client.chain_info().genesis_hash; + + for i in 0..num_blocks { + let block = BlockBuilderBuilder::new(&*client) + .on_parent_block(parent_hash) + .with_parent_block_number(i as u64) + .build() + .unwrap() + .build() + .unwrap() + .block; + parent_hash = block.header.hash(); + futures::executor::block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); + blocks.push(block.header.hash()); + } + + blocks + } + #[test] fn block_state_machine_register_unpin() { let mut state = BlockStateMachine::new(); @@ -1003,37 +1037,10 @@ mod tests { #[test] fn unpin_duplicate_hashes() { - let (backend, mut client) = init_backend(); - let block = BlockBuilderBuilder::new(&*client) - .on_parent_block(client.chain_info().genesis_hash) - .with_parent_block_number(0) - .build() - .unwrap() - .build() - .unwrap() - .block; - let hash_1 = block.header.hash(); - futures::executor::block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); - let block = BlockBuilderBuilder::new(&*client) - .on_parent_block(hash_1) - .with_parent_block_number(1) - .build() - .unwrap() - .build() - .unwrap() - .block; - let hash_2 = block.header.hash(); - futures::executor::block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); - let block = BlockBuilderBuilder::new(&*client) - .on_parent_block(hash_2) - .with_parent_block_number(2) - .build() - .unwrap() - .build() - .unwrap() - .block; - let hash_3 = block.header.hash(); - futures::executor::block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); + let (backend, client) = init_backend(); + + let hashes = produce_blocks(client, 3); + let (hash_1, hash_2, hash_3) = (hashes[0], hashes[1], hashes[2]); let mut subs = SubscriptionsInner::new(10, Duration::from_secs(10), MAX_OPERATIONS_PER_SUB, backend); @@ -1102,18 +1109,10 @@ mod tests { #[test] fn subscription_check_block() { - let (backend, mut client) = init_backend(); - - let block = BlockBuilderBuilder::new(&*client) - .on_parent_block(client.chain_info().genesis_hash) - .with_parent_block_number(0) - .build() - .unwrap() - .build() - .unwrap() - .block; - let hash = block.hash(); - futures::executor::block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); + let (backend, client) = init_backend(); + + let hashes = produce_blocks(client, 1); + let hash = hashes[0]; let mut subs = SubscriptionsInner::new(10, Duration::from_secs(10), MAX_OPERATIONS_PER_SUB, backend); @@ -1140,17 +1139,10 @@ mod tests { #[test] fn subscription_ref_count() { - let (backend, mut client) = init_backend(); - let block = BlockBuilderBuilder::new(&*client) - .on_parent_block(client.chain_info().genesis_hash) - .with_parent_block_number(0) - .build() - .unwrap() - .build() - .unwrap() - .block; - let hash = block.header.hash(); - futures::executor::block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); + let (backend, client) = init_backend(); + + let hashes = produce_blocks(client, 1); + let hash = hashes[0]; let mut subs = SubscriptionsInner::new(10, Duration::from_secs(10), MAX_OPERATIONS_PER_SUB, backend); @@ -1190,37 +1182,10 @@ mod tests { #[test] fn subscription_remove_subscription() { - let (backend, mut client) = init_backend(); - let block = BlockBuilderBuilder::new(&*client) - .on_parent_block(client.chain_info().genesis_hash) - .with_parent_block_number(0) - .build() - .unwrap() - .build() - .unwrap() - .block; - let hash_1 = block.header.hash(); - futures::executor::block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); - let block = BlockBuilderBuilder::new(&*client) - .on_parent_block(hash_1) - .with_parent_block_number(1) - .build() - .unwrap() - .build() - .unwrap() - .block; - let hash_2 = block.header.hash(); - futures::executor::block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); - let block = BlockBuilderBuilder::new(&*client) - .on_parent_block(hash_2) - .with_parent_block_number(2) - .build() - .unwrap() - .build() - .unwrap() - .block; - let hash_3 = block.header.hash(); - futures::executor::block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); + let (backend, client) = init_backend(); + + let hashes = produce_blocks(client, 3); + let (hash_1, hash_2, hash_3) = (hashes[0], hashes[1], hashes[2]); let mut subs = SubscriptionsInner::new(10, Duration::from_secs(10), MAX_OPERATIONS_PER_SUB, backend); @@ -1256,37 +1221,10 @@ mod tests { #[test] fn subscription_check_limits() { - let (backend, mut client) = init_backend(); - let block = BlockBuilderBuilder::new(&*client) - .on_parent_block(client.chain_info().genesis_hash) - .with_parent_block_number(0) - .build() - .unwrap() - .build() - .unwrap() - .block; - let hash_1 = block.header.hash(); - futures::executor::block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); - let block = BlockBuilderBuilder::new(&*client) - .on_parent_block(hash_1) - .with_parent_block_number(1) - .build() - .unwrap() - .build() - .unwrap() - .block; - let hash_2 = block.header.hash(); - futures::executor::block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); - let block = BlockBuilderBuilder::new(&*client) - .on_parent_block(hash_2) - .with_parent_block_number(2) - .build() - .unwrap() - .build() - .unwrap() - .block; - let hash_3 = block.header.hash(); - futures::executor::block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); + let (backend, client) = init_backend(); + + let hashes = produce_blocks(client, 3); + let (hash_1, hash_2, hash_3) = (hashes[0], hashes[1], hashes[2]); // Maximum number of pinned blocks is 2. let mut subs = @@ -1328,37 +1266,10 @@ mod tests { #[test] fn subscription_check_limits_with_duration() { - let (backend, mut client) = init_backend(); - let block = BlockBuilderBuilder::new(&*client) - .on_parent_block(client.chain_info().genesis_hash) - .with_parent_block_number(0) - .build() - .unwrap() - .build() - .unwrap() - .block; - let hash_1 = block.hash(); - futures::executor::block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); - let block = BlockBuilderBuilder::new(&*client) - .on_parent_block(hash_1) - .with_parent_block_number(1) - .build() - .unwrap() - .build() - .unwrap() - .block; - let hash_2 = block.header.hash(); - futures::executor::block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); - let block = BlockBuilderBuilder::new(&*client) - .on_parent_block(hash_2) - .with_parent_block_number(2) - .build() - .unwrap() - .build() - .unwrap() - .block; - let hash_3 = block.header.hash(); - futures::executor::block_on(client.import(BlockOrigin::Own, block.clone())).unwrap(); + let (backend, client) = init_backend(); + + let hashes = produce_blocks(client, 3); + let (hash_1, hash_2, hash_3) = (hashes[0], hashes[1], hashes[2]); // Maximum number of pinned blocks is 2 and maximum pin duration is 5 second. let mut subs = @@ -1456,6 +1367,39 @@ mod tests { assert_eq!(permit_three.num_ops, 1); } + #[test] + fn stop_all_subscriptions() { + let (backend, client) = init_backend(); + + let hashes = produce_blocks(client, 3); + let (hash_1, hash_2, hash_3) = (hashes[0], hashes[1], hashes[2]); + + let mut subs = + SubscriptionsInner::new(10, Duration::from_secs(10), MAX_OPERATIONS_PER_SUB, backend); + let id_1 = "abc".to_string(); + let id_2 = "abcd".to_string(); + + // Pin all blocks for the first subscription. + let _stop = subs.insert_subscription(id_1.clone(), true).unwrap(); + assert_eq!(subs.pin_block(&id_1, hash_1).unwrap(), true); + assert_eq!(subs.pin_block(&id_1, hash_2).unwrap(), true); + assert_eq!(subs.pin_block(&id_1, hash_3).unwrap(), true); + + // Pin only block 2 for the second subscription. + let _stop = subs.insert_subscription(id_2.clone(), true).unwrap(); + assert_eq!(subs.pin_block(&id_2, hash_2).unwrap(), true); + + // Check reference count. + assert_eq!(*subs.global_blocks.get(&hash_1).unwrap(), 1); + assert_eq!(*subs.global_blocks.get(&hash_2).unwrap(), 2); + assert_eq!(*subs.global_blocks.get(&hash_3).unwrap(), 1); + assert_eq!(subs.global_blocks.len(), 3); + + // Stop all active subscriptions. + subs.stop_all_subscriptions(); + assert!(subs.global_blocks.is_empty()); + } + #[test] fn reserved_subscription_cleans_resources() { let builder = TestClientBuilder::new(); diff --git a/substrate/client/rpc-spec-v2/src/chain_head/subscription/mod.rs b/substrate/client/rpc-spec-v2/src/chain_head/subscription/mod.rs index 5b016af1aa49..f266c9d8b34f 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/subscription/mod.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/subscription/mod.rs @@ -233,6 +233,15 @@ impl> ReservedSubscription { }, } } + + /// Stop all active subscriptions. + /// + /// For all active subscriptions, the internal data is discarded, blocks are unpinned and the + /// `Stop` event will be generated. + pub fn stop_all_subscriptions(&self) { + let mut inner = self.inner.write(); + inner.stop_all_subscriptions() + } } impl> Drop for ReservedSubscription { diff --git a/substrate/client/rpc-spec-v2/src/chain_head/tests.rs b/substrate/client/rpc-spec-v2/src/chain_head/tests.rs index c3f10a201c58..c2bff7c50d5e 100644 --- a/substrate/client/rpc-spec-v2/src/chain_head/tests.rs +++ b/substrate/client/rpc-spec-v2/src/chain_head/tests.rs @@ -63,6 +63,7 @@ const MAX_PINNED_BLOCKS: usize = 32; const MAX_PINNED_SECS: u64 = 60; const MAX_OPERATIONS: usize = 16; const MAX_PAGINATION_LIMIT: usize = 5; +const MAX_LAGGING_DISTANCE: usize = 128; const MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION: usize = 4; const INVALID_HASH: [u8; 32] = [1; 32]; @@ -88,6 +89,7 @@ pub async fn run_server() -> std::net::SocketAddr { subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, max_follow_subscriptions_per_connection: 1, + max_lagging_distance: MAX_LAGGING_DISTANCE, }, ) .into_rpc(); @@ -148,6 +150,7 @@ async fn setup_api() -> ( subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) @@ -199,6 +202,8 @@ async fn follow_subscription_produces_blocks() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + + max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) @@ -268,6 +273,8 @@ async fn follow_with_runtime() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + + max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) @@ -581,6 +588,8 @@ async fn call_runtime_without_flag() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + + max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) @@ -1240,6 +1249,8 @@ async fn separate_operation_ids_for_subscriptions() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + + max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) @@ -1329,6 +1340,8 @@ async fn follow_generates_initial_blocks() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + + max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) @@ -1485,6 +1498,8 @@ async fn follow_exceeding_pinned_blocks() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + + max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) @@ -1562,6 +1577,8 @@ async fn follow_with_unpin() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + + max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) @@ -1674,6 +1691,8 @@ async fn unpin_duplicate_hashes() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + + max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) @@ -1777,6 +1796,8 @@ async fn follow_with_multiple_unpin_hashes() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + + max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) @@ -1931,6 +1952,8 @@ async fn follow_prune_best_block() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + + max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) @@ -2117,6 +2140,8 @@ async fn follow_forks_pruned_block() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + + max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) @@ -2277,6 +2302,8 @@ async fn follow_report_multiple_pruned_block() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + + max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) @@ -2523,6 +2550,8 @@ async fn pin_block_references() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + + max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) @@ -2661,6 +2690,8 @@ async fn follow_finalized_before_new_block() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + + max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) @@ -2776,6 +2807,8 @@ async fn ensure_operation_limits_works() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: 1, operation_max_storage_items: MAX_PAGINATION_LIMIT, + + max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) @@ -2881,6 +2914,8 @@ async fn check_continue_operation() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: 1, + + max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) @@ -3064,6 +3099,8 @@ async fn stop_storage_operation() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: 1, + + max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, }, ) @@ -3351,6 +3388,88 @@ async fn storage_closest_merkle_value() { ); } +#[tokio::test] +async fn chain_head_stop_all_subscriptions() { + let builder = TestClientBuilder::new(); + let backend = builder.backend(); + let mut client = Arc::new(builder.build()); + + // Configure the chainHead to stop all subscriptions on lagging distance of 5 blocks. + let api = ChainHead::new( + client.clone(), + backend, + Arc::new(TaskExecutor::default()), + ChainHeadConfig { + global_max_pinned_blocks: MAX_PINNED_BLOCKS, + subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), + subscription_max_ongoing_operations: MAX_OPERATIONS, + operation_max_storage_items: MAX_PAGINATION_LIMIT, + max_lagging_distance: 5, + max_follow_subscriptions_per_connection: MAX_FOLLOW_SUBSCRIPTIONS_PER_CONNECTION, + }, + ) + .into_rpc(); + + let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [true]).await.unwrap(); + + // Ensure the imported block is propagated and pinned for this subscription. + assert_matches!( + get_next_event::>(&mut sub).await, + FollowEvent::Initialized(_) + ); + + // Import 6 blocks in total to trigger the suspension distance. + let mut parent_hash = client.chain_info().genesis_hash; + for i in 0..6 { + let block = BlockBuilderBuilder::new(&*client) + .on_parent_block(parent_hash) + .with_parent_block_number(i) + .build() + .unwrap() + .build() + .unwrap() + .block; + + let hash = block.hash(); + parent_hash = hash; + client.import(BlockOrigin::Own, block.clone()).await.unwrap(); + + assert_matches!( + get_next_event::>(&mut sub).await, + FollowEvent::NewBlock(_) + ); + assert_matches!( + get_next_event::>(&mut sub).await, + FollowEvent::BestBlockChanged(_) + ); + } + + let mut second_sub = + api.subscribe_unbounded("chainHead_unstable_follow", [true]).await.unwrap(); + // Lagging detected, the stop event is delivered immediately. + assert_matches!( + get_next_event::>(&mut second_sub).await, + FollowEvent::Stop + ); + + // Ensure that all subscriptions are stopped. + assert_matches!(get_next_event::>(&mut sub).await, FollowEvent::Stop); + + // Other subscriptions cannot be started until the suspension period is over. + let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [true]).await.unwrap(); + // Should receive the stop event immediately. + assert_matches!(get_next_event::>(&mut sub).await, FollowEvent::Stop); + + // For the next subscription, lagging distance must be smaller. + client.finalize_block(parent_hash, None).unwrap(); + + let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [true]).await.unwrap(); + assert_matches!( + get_next_event::>(&mut sub).await, + FollowEvent::Initialized(_) + ); +} + #[tokio::test] async fn chain_head_single_connection_context() { let server_addr = run_server().await; @@ -3500,12 +3619,14 @@ async fn chain_head_limit_reached() { subscription_max_pinned_duration: Duration::from_secs(MAX_PINNED_SECS), subscription_max_ongoing_operations: MAX_OPERATIONS, operation_max_storage_items: MAX_PAGINATION_LIMIT, + max_lagging_distance: MAX_LAGGING_DISTANCE, max_follow_subscriptions_per_connection: 1, }, ) .into_rpc(); let mut sub = api.subscribe_unbounded("chainHead_unstable_follow", [true]).await.unwrap(); + // Initialized must always be reported first. let _event: FollowEvent = get_next_event(&mut sub).await; From c5a043f79a862e3c9539813594df9f75029237c9 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Wed, 3 Apr 2024 17:00:38 +0200 Subject: [PATCH 114/257] Enable pov-reclaim on rococo and westend parachains (#3858) Enables pov-reclaim on the rococo/westend parachains, part of https://github.com/paritytech/polkadot-sdk/issues/3622 --- Cargo.lock | 10 ++++++++++ .../runtimes/assets/asset-hub-rococo/Cargo.toml | 2 ++ .../runtimes/assets/asset-hub-rococo/src/lib.rs | 1 + .../runtimes/assets/asset-hub-westend/Cargo.toml | 2 ++ .../runtimes/assets/asset-hub-westend/src/lib.rs | 1 + .../runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml | 2 ++ .../runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs | 4 +++- .../bridge-hubs/bridge-hub-rococo/tests/snowbridge.rs | 1 + .../bridge-hubs/bridge-hub-rococo/tests/tests.rs | 1 + .../runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml | 3 +++ .../runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs | 2 ++ .../bridge-hubs/bridge-hub-westend/tests/tests.rs | 1 + .../collectives/collectives-westend/Cargo.toml | 3 +++ .../collectives/collectives-westend/src/lib.rs | 1 + .../runtimes/contracts/contracts-rococo/Cargo.toml | 3 +++ .../runtimes/contracts/contracts-rococo/src/lib.rs | 1 + .../runtimes/coretime/coretime-rococo/Cargo.toml | 2 ++ .../runtimes/coretime/coretime-rococo/src/lib.rs | 1 + .../runtimes/coretime/coretime-westend/Cargo.toml | 3 +++ .../runtimes/coretime/coretime-westend/src/lib.rs | 1 + .../runtimes/people/people-rococo/Cargo.toml | 2 ++ .../runtimes/people/people-rococo/src/lib.rs | 1 + .../runtimes/people/people-westend/Cargo.toml | 2 ++ .../runtimes/people/people-westend/src/lib.rs | 1 + 24 files changed, 50 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 3b0242b39c5f..47c8d04be942 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -867,6 +867,7 @@ dependencies = [ "cumulus-pallet-xcmp-queue", "cumulus-primitives-aura", "cumulus-primitives-core", + "cumulus-primitives-storage-weight-reclaim", "cumulus-primitives-utility", "frame-benchmarking", "frame-executive", @@ -990,6 +991,7 @@ dependencies = [ "cumulus-pallet-xcmp-queue", "cumulus-primitives-aura", "cumulus-primitives-core", + "cumulus-primitives-storage-weight-reclaim", "cumulus-primitives-utility", "frame-benchmarking", "frame-executive", @@ -2010,6 +2012,7 @@ dependencies = [ "cumulus-pallet-xcmp-queue", "cumulus-primitives-aura", "cumulus-primitives-core", + "cumulus-primitives-storage-weight-reclaim", "cumulus-primitives-utility", "frame-benchmarking", "frame-executive", @@ -2181,6 +2184,7 @@ dependencies = [ "cumulus-pallet-xcmp-queue", "cumulus-primitives-aura", "cumulus-primitives-core", + "cumulus-primitives-storage-weight-reclaim", "cumulus-primitives-utility", "frame-benchmarking", "frame-executive", @@ -2739,6 +2743,7 @@ dependencies = [ "cumulus-pallet-xcmp-queue", "cumulus-primitives-aura", "cumulus-primitives-core", + "cumulus-primitives-storage-weight-reclaim", "cumulus-primitives-utility", "frame-benchmarking", "frame-executive", @@ -2994,6 +2999,7 @@ dependencies = [ "cumulus-pallet-xcmp-queue", "cumulus-primitives-aura", "cumulus-primitives-core", + "cumulus-primitives-storage-weight-reclaim", "cumulus-primitives-utility", "frame-benchmarking", "frame-executive", @@ -3088,6 +3094,7 @@ dependencies = [ "cumulus-pallet-xcmp-queue", "cumulus-primitives-aura", "cumulus-primitives-core", + "cumulus-primitives-storage-weight-reclaim", "cumulus-primitives-utility", "frame-benchmarking", "frame-executive", @@ -3152,6 +3159,7 @@ dependencies = [ "cumulus-pallet-xcmp-queue", "cumulus-primitives-aura", "cumulus-primitives-core", + "cumulus-primitives-storage-weight-reclaim", "cumulus-primitives-utility", "frame-benchmarking", "frame-executive", @@ -11813,6 +11821,7 @@ dependencies = [ "cumulus-pallet-xcmp-queue", "cumulus-primitives-aura", "cumulus-primitives-core", + "cumulus-primitives-storage-weight-reclaim", "cumulus-primitives-utility", "enumflags2", "frame-benchmarking", @@ -11912,6 +11921,7 @@ dependencies = [ "cumulus-pallet-xcmp-queue", "cumulus-primitives-aura", "cumulus-primitives-core", + "cumulus-primitives-storage-weight-reclaim", "cumulus-primitives-utility", "enumflags2", "frame-benchmarking", diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml index f5ea0937dec6..0733156716c1 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml @@ -78,6 +78,7 @@ cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-f cumulus-primitives-aura = { path = "../../../../primitives/aura", default-features = false } cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } cumulus-primitives-utility = { path = "../../../../primitives/utility", default-features = false } +cumulus-primitives-storage-weight-reclaim = { path = "../../../../primitives/storage-weight-reclaim", default-features = false } pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false } parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } parachains-common = { path = "../../../common", default-features = false } @@ -190,6 +191,7 @@ std = [ "cumulus-pallet-xcmp-queue/std", "cumulus-primitives-aura/std", "cumulus-primitives-core/std", + "cumulus-primitives-storage-weight-reclaim/std", "cumulus-primitives-utility/std", "frame-benchmarking?/std", "frame-executive/std", diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs index 293416ab2a9a..7edec45abfbb 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -955,6 +955,7 @@ pub type SignedExtra = ( frame_system::CheckNonce, frame_system::CheckWeight, pallet_asset_conversion_tx_payment::ChargeAssetTxPayment, + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim, ); /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml index b792d64c03e0..e25554ec0a5f 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml @@ -76,6 +76,7 @@ cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-f cumulus-primitives-aura = { path = "../../../../primitives/aura", default-features = false } cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } cumulus-primitives-utility = { path = "../../../../primitives/utility", default-features = false } +cumulus-primitives-storage-weight-reclaim = { path = "../../../../primitives/storage-weight-reclaim", default-features = false } pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false } parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } parachains-common = { path = "../../../common", default-features = false } @@ -178,6 +179,7 @@ std = [ "cumulus-pallet-xcmp-queue/std", "cumulus-primitives-aura/std", "cumulus-primitives-core/std", + "cumulus-primitives-storage-weight-reclaim/std", "cumulus-primitives-utility/std", "frame-benchmarking?/std", "frame-executive/std", diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs index e92e801e9f52..d17d5a707579 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -927,6 +927,7 @@ pub type SignedExtra = ( frame_system::CheckNonce, frame_system::CheckWeight, pallet_asset_conversion_tx_payment::ChargeAssetTxPayment, + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim, ); /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml index 1dd4f499b4dc..f5a75aa03acd 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml @@ -78,6 +78,7 @@ cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-f ] } cumulus-primitives-aura = { path = "../../../../primitives/aura", default-features = false } cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } +cumulus-primitives-storage-weight-reclaim = { path = "../../../../primitives/storage-weight-reclaim", default-features = false } cumulus-primitives-utility = { path = "../../../../primitives/utility", default-features = false } pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false } parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } @@ -156,6 +157,7 @@ std = [ "cumulus-pallet-xcmp-queue/std", "cumulus-primitives-aura/std", "cumulus-primitives-core/std", + "cumulus-primitives-storage-weight-reclaim/std", "cumulus-primitives-utility/std", "frame-benchmarking/std", "frame-executive/std", diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs index fd6d44ec2754..9796a77f994e 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs @@ -130,6 +130,7 @@ pub type SignedExtra = ( bridge_to_westend_config::OnBridgeHubRococoRefundBridgeHubWestendMessages, bridge_to_bulletin_config::OnBridgeHubRococoRefundRococoBulletinMessages, ), + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim, ); /// Unchecked extrinsic type as expected by this runtime. @@ -1493,7 +1494,8 @@ mod tests { ( bridge_to_westend_config::OnBridgeHubRococoRefundBridgeHubWestendMessages::default(), bridge_to_bulletin_config::OnBridgeHubRococoRefundRococoBulletinMessages::default(), - ) + ), + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim::new(), ); // for BridgeHubRococo diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/snowbridge.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/snowbridge.rs index 101b8d86d557..5960ab7b5505 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/snowbridge.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/snowbridge.rs @@ -187,6 +187,7 @@ fn construct_extrinsic( OnBridgeHubRococoRefundBridgeHubWestendMessages::default(), OnBridgeHubRococoRefundRococoBulletinMessages::default(), ), + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim::new(), ); let payload = SignedPayload::new(call.clone(), extra.clone()).unwrap(); let signature = payload.using_encoded(|e| sender.sign(e)); diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs index fad357b09514..776c505fa640 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs @@ -64,6 +64,7 @@ fn construct_extrinsic( bridge_to_westend_config::OnBridgeHubRococoRefundBridgeHubWestendMessages::default(), bridge_to_bulletin_config::OnBridgeHubRococoRefundRococoBulletinMessages::default(), ), + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim::new(), ); let payload = SignedPayload::new(call.clone(), extra.clone()).unwrap(); let signature = payload.using_encoded(|e| sender.sign(e)); diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml index 1501ed12e3ad..86560caca99c 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml @@ -71,6 +71,8 @@ cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-f cumulus-primitives-aura = { path = "../../../../primitives/aura", default-features = false } cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } cumulus-primitives-utility = { path = "../../../../primitives/utility", default-features = false } +cumulus-primitives-storage-weight-reclaim = { path = "../../../../primitives/storage-weight-reclaim", default-features = false } + pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false } parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } parachains-common = { path = "../../../common", default-features = false } @@ -128,6 +130,7 @@ std = [ "cumulus-pallet-xcmp-queue/std", "cumulus-primitives-aura/std", "cumulus-primitives-core/std", + "cumulus-primitives-storage-weight-reclaim/std", "cumulus-primitives-utility/std", "frame-benchmarking/std", "frame-executive/std", diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs index 3b759301d0ed..4318df8f15ed 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/lib.rs @@ -109,6 +109,7 @@ pub type SignedExtra = ( pallet_transaction_payment::ChargeTransactionPayment, BridgeRejectObsoleteHeadersAndMessages, (bridge_to_rococo_config::OnBridgeHubWestendRefundBridgeHubRococoMessages,), + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim, ); /// Unchecked extrinsic type as expected by this runtime. @@ -1154,6 +1155,7 @@ mod tests { ( bridge_to_rococo_config::OnBridgeHubWestendRefundBridgeHubRococoMessages::default(), ), + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim::new() ); { diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs index 235b7f146c8e..988b10e1e2d8 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/tests/tests.rs @@ -78,6 +78,7 @@ fn construct_extrinsic( pallet_transaction_payment::ChargeTransactionPayment::::from(0), BridgeRejectObsoleteHeadersAndMessages::default(), (bridge_to_rococo_config::OnBridgeHubWestendRefundBridgeHubRococoMessages::default(),), + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim::new(), ); let payload = SignedPayload::new(call.clone(), extra.clone()).unwrap(); let signature = payload.using_encoded(|e| sender.sign(e)); diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml b/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml index 9c3acf6ad934..22821170a54c 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml @@ -77,6 +77,8 @@ cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-f cumulus-primitives-aura = { path = "../../../../primitives/aura", default-features = false } cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } cumulus-primitives-utility = { path = "../../../../primitives/utility", default-features = false } +cumulus-primitives-storage-weight-reclaim = { path = "../../../../primitives/storage-weight-reclaim", default-features = false } + pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false } pallet-collective-content = { path = "../../../pallets/collective-content", default-features = false } parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } @@ -172,6 +174,7 @@ std = [ "cumulus-pallet-xcmp-queue/std", "cumulus-primitives-aura/std", "cumulus-primitives-core/std", + "cumulus-primitives-storage-weight-reclaim/std", "cumulus-primitives-utility/std", "frame-benchmarking?/std", "frame-executive/std", diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs index e1c2e1a6237b..170b0a396000 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs @@ -713,6 +713,7 @@ pub type SignedExtra = ( frame_system::CheckEra, frame_system::CheckNonce, frame_system::CheckWeight, + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim, ); /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml index a0aeb642df05..74c5b5f81159 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml @@ -74,6 +74,8 @@ cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-f cumulus-primitives-aura = { path = "../../../../primitives/aura", default-features = false } cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } cumulus-primitives-utility = { path = "../../../../primitives/utility", default-features = false } +cumulus-primitives-storage-weight-reclaim = { path = "../../../../primitives/storage-weight-reclaim", default-features = false } + pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false } parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } parachains-common = { path = "../../../common", default-features = false } @@ -90,6 +92,7 @@ std = [ "cumulus-pallet-xcmp-queue/std", "cumulus-primitives-aura/std", "cumulus-primitives-core/std", + "cumulus-primitives-storage-weight-reclaim/std", "cumulus-primitives-utility/std", "frame-benchmarking?/std", "frame-executive/std", diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs index ec0a5f6fc96c..936d87a23caa 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs @@ -90,6 +90,7 @@ pub type SignedExtra = ( frame_system::CheckNonce, frame_system::CheckWeight, pallet_transaction_payment::ChargeTransactionPayment, + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim, ); /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/Cargo.toml b/cumulus/parachains/runtimes/coretime/coretime-rococo/Cargo.toml index eb92afc43114..ee9f5e87ec87 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/Cargo.toml @@ -72,6 +72,7 @@ cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-f cumulus-primitives-aura = { path = "../../../../primitives/aura", default-features = false } cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } cumulus-primitives-utility = { path = "../../../../primitives/utility", default-features = false } +cumulus-primitives-storage-weight-reclaim = { path = "../../../../primitives/storage-weight-reclaim", default-features = false } pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false } parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } parachains-common = { path = "../../../common", default-features = false } @@ -88,6 +89,7 @@ std = [ "cumulus-pallet-xcmp-queue/std", "cumulus-primitives-aura/std", "cumulus-primitives-core/std", + "cumulus-primitives-storage-weight-reclaim/std", "cumulus-primitives-utility/std", "frame-benchmarking?/std", "frame-executive/std", diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs index 67f486893532..27965aa204f9 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs @@ -99,6 +99,7 @@ pub type SignedExtra = ( frame_system::CheckNonce, frame_system::CheckWeight, pallet_transaction_payment::ChargeTransactionPayment, + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim, ); /// Unchecked extrinsic type as expected by this runtime. diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/Cargo.toml b/cumulus/parachains/runtimes/coretime/coretime-westend/Cargo.toml index b8efecffc507..60cc7e2f7654 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/Cargo.toml @@ -71,6 +71,8 @@ cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-f cumulus-primitives-aura = { path = "../../../../primitives/aura", default-features = false } cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } cumulus-primitives-utility = { path = "../../../../primitives/utility", default-features = false } +cumulus-primitives-storage-weight-reclaim = { path = "../../../../primitives/storage-weight-reclaim", default-features = false } + pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false } parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } parachains-common = { path = "../../../common", default-features = false } @@ -87,6 +89,7 @@ std = [ "cumulus-pallet-xcmp-queue/std", "cumulus-primitives-aura/std", "cumulus-primitives-core/std", + "cumulus-primitives-storage-weight-reclaim/std", "cumulus-primitives-utility/std", "frame-benchmarking?/std", "frame-executive/std", diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs index 609ea5a38a89..8075ffb4f1c2 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs @@ -99,6 +99,7 @@ pub type SignedExtra = ( frame_system::CheckNonce, frame_system::CheckWeight, pallet_transaction_payment::ChargeTransactionPayment, + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim, ); /// Unchecked extrinsic type as expected by this runtime. diff --git a/cumulus/parachains/runtimes/people/people-rococo/Cargo.toml b/cumulus/parachains/runtimes/people/people-rococo/Cargo.toml index eebd662c3fd5..7183be5fc82c 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/people/people-rococo/Cargo.toml @@ -69,6 +69,7 @@ cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-f cumulus-primitives-aura = { path = "../../../../primitives/aura", default-features = false } cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } cumulus-primitives-utility = { path = "../../../../primitives/utility", default-features = false } +cumulus-primitives-storage-weight-reclaim = { path = "../../../../primitives/storage-weight-reclaim", default-features = false } pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false } parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } parachains-common = { path = "../../../common", default-features = false } @@ -85,6 +86,7 @@ std = [ "cumulus-pallet-xcmp-queue/std", "cumulus-primitives-aura/std", "cumulus-primitives-core/std", + "cumulus-primitives-storage-weight-reclaim/std", "cumulus-primitives-utility/std", "enumflags2/std", "frame-benchmarking?/std", diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs index 7c9427a24939..1b6499f5d617 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs @@ -93,6 +93,7 @@ pub type SignedExtra = ( frame_system::CheckNonce, frame_system::CheckWeight, pallet_transaction_payment::ChargeTransactionPayment, + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim, ); /// Unchecked extrinsic type as expected by this runtime. diff --git a/cumulus/parachains/runtimes/people/people-westend/Cargo.toml b/cumulus/parachains/runtimes/people/people-westend/Cargo.toml index 39cb69e679cc..576c3b1aa4e3 100644 --- a/cumulus/parachains/runtimes/people/people-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/people/people-westend/Cargo.toml @@ -69,6 +69,7 @@ cumulus-pallet-xcmp-queue = { path = "../../../../pallets/xcmp-queue", default-f cumulus-primitives-aura = { path = "../../../../primitives/aura", default-features = false } cumulus-primitives-core = { path = "../../../../primitives/core", default-features = false } cumulus-primitives-utility = { path = "../../../../primitives/utility", default-features = false } +cumulus-primitives-storage-weight-reclaim = { path = "../../../../primitives/storage-weight-reclaim", default-features = false } pallet-collator-selection = { path = "../../../../pallets/collator-selection", default-features = false } parachain-info = { package = "staging-parachain-info", path = "../../../pallets/parachain-info", default-features = false } parachains-common = { path = "../../../common", default-features = false } @@ -85,6 +86,7 @@ std = [ "cumulus-pallet-xcmp-queue/std", "cumulus-primitives-aura/std", "cumulus-primitives-core/std", + "cumulus-primitives-storage-weight-reclaim/std", "cumulus-primitives-utility/std", "enumflags2/std", "frame-benchmarking?/std", diff --git a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs index 3e331e5e8ebf..6ae53d641b0c 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs @@ -93,6 +93,7 @@ pub type SignedExtra = ( frame_system::CheckNonce, frame_system::CheckWeight, pallet_transaction_payment::ChargeTransactionPayment, + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim, ); /// Unchecked extrinsic type as expected by this runtime. From 5a1b92d73fd60699e2e42dc87bc89ca4cfe9cd45 Mon Sep 17 00:00:00 2001 From: Andrei Sandu <54316454+sandreim@users.noreply.github.com> Date: Wed, 3 Apr 2024 18:01:34 +0300 Subject: [PATCH 115/257] Add ClaimQueue wrapper (#3950) Remove `fetch_next_scheduled_on_core` in favor of new wrapper and methods for accessing it. --------- Signed-off-by: Andrei Sandu --- polkadot/node/collation-generation/src/lib.rs | 14 +++--- .../node/collation-generation/src/tests.rs | 13 +++--- .../statement-distribution/src/v2/mod.rs | 4 +- polkadot/node/subsystem-util/src/vstaging.rs | 44 ++++++++++++------- prdoc/pr_3950.prdoc | 12 +++++ 5 files changed, 55 insertions(+), 32 deletions(-) create mode 100644 prdoc/pr_3950.prdoc diff --git a/polkadot/node/collation-generation/src/lib.rs b/polkadot/node/collation-generation/src/lib.rs index fb82871bb15a..60ea1cf5ff48 100644 --- a/polkadot/node/collation-generation/src/lib.rs +++ b/polkadot/node/collation-generation/src/lib.rs @@ -45,13 +45,12 @@ use polkadot_node_subsystem::{ use polkadot_node_subsystem_util::{ request_async_backing_params, request_availability_cores, request_para_backing_state, request_persisted_validation_data, request_validation_code, request_validation_code_hash, - request_validators, - vstaging::{fetch_claim_queue, fetch_next_scheduled_on_core}, + request_validators, vstaging::fetch_claim_queue, }; use polkadot_primitives::{ collator_signature_payload, CandidateCommitments, CandidateDescriptor, CandidateReceipt, CollatorPair, CoreIndex, CoreState, Hash, Id as ParaId, OccupiedCoreAssumption, - PersistedValidationData, ValidationCodeHash, + PersistedValidationData, ScheduledCore, ValidationCodeHash, }; use sp_core::crypto::Pair; use std::sync::Arc; @@ -245,11 +244,10 @@ async fn handle_new_activations( // Use claim queue if available, or fallback to `next_up_on_available` let res = match maybe_claim_queue { Some(ref claim_queue) => { - // read what's in the claim queue for this core - fetch_next_scheduled_on_core( - claim_queue, - CoreIndex(core_idx as u32), - ) + // read what's in the claim queue for this core at depth 0. + claim_queue + .get_claim_for(CoreIndex(core_idx as u32), 0) + .map(|para_id| ScheduledCore { para_id, collator: None }) }, None => { // Runtime doesn't support claim queue runtime api. Fallback to diff --git a/polkadot/node/collation-generation/src/tests.rs b/polkadot/node/collation-generation/src/tests.rs index 781d27188df1..1ec2cccfae71 100644 --- a/polkadot/node/collation-generation/src/tests.rs +++ b/polkadot/node/collation-generation/src/tests.rs @@ -28,7 +28,7 @@ use polkadot_node_subsystem::{ ActivatedLeaf, }; use polkadot_node_subsystem_test_helpers::{subsystem_test_harness, TestSubsystemContextHandle}; -use polkadot_node_subsystem_util::{vstaging::ClaimQueueSnapshot, TimeoutExt}; +use polkadot_node_subsystem_util::TimeoutExt; use polkadot_primitives::{ async_backing::{BackingState, CandidatePendingAvailability}, AsyncBackingParams, BlockNumber, CollatorPair, HeadData, PersistedValidationData, @@ -620,8 +620,7 @@ fn fallback_when_no_validation_code_hash_api(#[case] runtime_version: u32) { _hash, RuntimeApiRequest::ClaimQueue(tx), ))) if runtime_version >= RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT => { - let res = ClaimQueueSnapshot::new(); - tx.send(Ok(res)).unwrap(); + tx.send(Ok(Default::default())).unwrap(); }, Some(AllMessages::RuntimeApi(RuntimeApiMessage::Request( _hash, @@ -783,7 +782,7 @@ fn distribute_collation_for_occupied_core_with_async_backing_enabled(#[case] run candidate_hash: Default::default(), candidate_descriptor: dummy_candidate_descriptor(dummy_hash()), })]; - let claim_queue = ClaimQueueSnapshot::from([(CoreIndex::from(0), VecDeque::from([para_id]))]); + let claim_queue = BTreeMap::from([(CoreIndex::from(0), VecDeque::from([para_id]))]).into(); test_harness(|mut virtual_overseer| async move { helpers::initialize_collator(&mut virtual_overseer, para_id).await; @@ -965,7 +964,7 @@ fn no_collation_is_distributed_for_occupied_core_with_async_backing_disabled( candidate_hash: Default::default(), candidate_descriptor: dummy_candidate_descriptor(dummy_hash()), })]; - let claim_queue = ClaimQueueSnapshot::from([(CoreIndex::from(0), VecDeque::from([para_id]))]); + let claim_queue = BTreeMap::from([(CoreIndex::from(0), VecDeque::from([para_id]))]).into(); test_harness(|mut virtual_overseer| async move { helpers::initialize_collator(&mut virtual_overseer, para_id).await; @@ -1053,7 +1052,7 @@ mod helpers { async_backing_params: AsyncBackingParams, cores: Vec, runtime_version: u32, - claim_queue: ClaimQueueSnapshot, + claim_queue: BTreeMap>, ) { assert_matches!( overseer_recv(virtual_overseer).await, @@ -1107,7 +1106,7 @@ mod helpers { RuntimeApiRequest::ClaimQueue(tx), )) => { assert_eq!(hash, activated_hash); - let _ = tx.send(Ok(claim_queue)); + let _ = tx.send(Ok(claim_queue.into())); } ); } diff --git a/polkadot/node/network/statement-distribution/src/v2/mod.rs b/polkadot/node/network/statement-distribution/src/v2/mod.rs index b9f6f705ed8f..f5a8ec4a2696 100644 --- a/polkadot/node/network/statement-distribution/src/v2/mod.rs +++ b/polkadot/node/network/statement-distribution/src/v2/mod.rs @@ -2163,8 +2163,8 @@ async fn determine_groups_per_para( // pending availability. let para_core_indices: Vec<_> = if let Some(claim_queue) = maybe_claim_queue { claim_queue - .into_iter() - .filter_map(|(core_index, paras)| Some((*paras.front()?, core_index))) + .iter_claims_at_depth(0) + .map(|(core_index, para)| (para, core_index)) .collect() } else { availability_cores diff --git a/polkadot/node/subsystem-util/src/vstaging.rs b/polkadot/node/subsystem-util/src/vstaging.rs index 25ea7ce7c9bd..b166a54f75c4 100644 --- a/polkadot/node/subsystem-util/src/vstaging.rs +++ b/polkadot/node/subsystem-util/src/vstaging.rs @@ -23,14 +23,40 @@ use std::collections::{BTreeMap, VecDeque}; use polkadot_node_subsystem_types::messages::{RuntimeApiMessage, RuntimeApiRequest}; use polkadot_overseer::SubsystemSender; -use polkadot_primitives::{CoreIndex, Hash, Id as ParaId, ScheduledCore, ValidatorIndex}; +use polkadot_primitives::{CoreIndex, Hash, Id as ParaId, ValidatorIndex}; use crate::{has_required_runtime, request_claim_queue, request_disabled_validators, runtime}; const LOG_TARGET: &'static str = "parachain::subsystem-util-vstaging"; /// A snapshot of the runtime claim queue at an arbitrary relay chain block. -pub type ClaimQueueSnapshot = BTreeMap>; +#[derive(Default)] +pub struct ClaimQueueSnapshot(BTreeMap>); + +impl From>> for ClaimQueueSnapshot { + fn from(claim_queue_snapshot: BTreeMap>) -> Self { + ClaimQueueSnapshot(claim_queue_snapshot) + } +} + +impl ClaimQueueSnapshot { + /// Returns the `ParaId` that has a claim for `core_index` at the specified `depth` in the + /// claim queue. A depth of `0` means the very next block. + pub fn get_claim_for(&self, core_index: CoreIndex, depth: usize) -> Option { + self.0.get(&core_index)?.get(depth).copied() + } + + /// Returns an iterator over all claimed cores and the claiming `ParaId` at the specified + /// `depth` in the claim queue. + pub fn iter_claims_at_depth( + &self, + depth: usize, + ) -> impl Iterator + '_ { + self.0 + .iter() + .filter_map(move |(core_index, paras)| Some((*core_index, *paras.get(depth)?))) + } +} // TODO: https://github.com/paritytech/polkadot-sdk/issues/1940 /// Returns disabled validators list if the runtime supports it. Otherwise logs a debug messages and @@ -78,21 +104,9 @@ pub async fn fetch_claim_queue( .await .await .map_err(runtime::Error::RuntimeRequestCanceled)??; - Ok(Some(res)) + Ok(Some(res.into())) } else { gum::trace!(target: LOG_TARGET, "Runtime doesn't support `request_claim_queue`"); Ok(None) } } - -/// Returns the next scheduled `ParaId` for a core in the claim queue, wrapped in `ScheduledCore`. -pub fn fetch_next_scheduled_on_core( - claim_queue: &ClaimQueueSnapshot, - core_idx: CoreIndex, -) -> Option { - claim_queue - .get(&core_idx)? - .front() - .cloned() - .map(|para_id| ScheduledCore { para_id, collator: None }) -} diff --git a/prdoc/pr_3950.prdoc b/prdoc/pr_3950.prdoc new file mode 100644 index 000000000000..a333521898bf --- /dev/null +++ b/prdoc/pr_3950.prdoc @@ -0,0 +1,12 @@ +title: Add `ClaimQueue` wrapper + +doc: + - audience: Node Dev + description: | + Intoduces a new wrapper type: `ClaimQueueSnapshot`. It contains a snapshot of the `ClaimQueue` + at an arbitrary relay chain block. Two methods are exposed to allow access to the claims at + specific depths. + +crates: + - name: polkadot-node-subsystem-util + bump: minor From 851859361fcd2861b05caa1829f42028b16dfa1d Mon Sep 17 00:00:00 2001 From: gupnik Date: Thu, 4 Apr 2024 07:50:15 +0530 Subject: [PATCH 116/257] Renames `frame` crate to `polkadot-sdk-frame` (#3813) Step in https://github.com/paritytech/polkadot-sdk/issues/3155 Needed for https://github.com/paritytech/eng-automation/issues/6 This PR renames `frame` crate to `polkadot-sdk-frame` as `frame` is not available on crates.io --------- Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- Cargo.lock | 70 +++++++++---------- docs/sdk/Cargo.toml | 2 +- prdoc/pr_3813.prdoc | 14 ++++ substrate/client/chain-spec/src/lib.rs | 2 +- substrate/frame/Cargo.toml | 4 +- .../frame/examples/frame-crate/Cargo.toml | 2 +- substrate/frame/src/lib.rs | 24 ++++--- substrate/frame/support/procedural/src/lib.rs | 8 +-- .../procedural/src/pallet/parse/config.rs | 42 ++++++++--- .../frame/support/procedural/tools/src/lib.rs | 16 +++-- .../support/test/stg_frame_crate/Cargo.toml | 2 +- ...event_type_invalid_bound_no_frame_crate.rs | 6 +- ...t_type_invalid_bound_no_frame_crate.stderr | 2 +- .../primitives/api/proc-macro/src/utils.rs | 4 +- .../benchmarking-cli/src/pallet/command.rs | 2 +- substrate/utils/frame/rpc/support/src/lib.rs | 2 +- templates/minimal/node/Cargo.toml | 2 +- templates/minimal/pallets/template/Cargo.toml | 2 +- templates/minimal/runtime/Cargo.toml | 2 +- 19 files changed, 130 insertions(+), 78 deletions(-) create mode 100644 prdoc/pr_3813.prdoc diff --git a/Cargo.lock b/Cargo.lock index 47c8d04be942..bbfac2c29bb6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5454,35 +5454,6 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" -[[package]] -name = "frame" -version = "0.0.1-dev" -dependencies = [ - "docify", - "frame-executive", - "frame-support", - "frame-system", - "frame-system-rpc-runtime-api", - "log", - "pallet-examples", - "parity-scale-codec", - "scale-info", - "sp-api", - "sp-arithmetic", - "sp-block-builder", - "sp-consensus-aura", - "sp-consensus-grandpa", - "sp-core", - "sp-inherents", - "sp-io", - "sp-offchain", - "sp-runtime", - "sp-session", - "sp-std 14.0.0", - "sp-transaction-pool", - "sp-version", -] - [[package]] name = "frame-benchmarking" version = "28.0.0" @@ -5820,8 +5791,8 @@ dependencies = [ name = "frame-support-test-stg-frame-crate" version = "0.1.0" dependencies = [ - "frame", "parity-scale-codec", + "polkadot-sdk-frame", "scale-info", ] @@ -8132,11 +8103,11 @@ name = "minimal-template-node" version = "0.0.0" dependencies = [ "clap 4.5.3", - "frame", "futures", "futures-timer", "jsonrpsee", "minimal-template-runtime", + "polkadot-sdk-frame", "sc-basic-authorship", "sc-cli", "sc-client-api", @@ -8166,7 +8137,6 @@ dependencies = [ name = "minimal-template-runtime" version = "0.0.0" dependencies = [ - "frame", "pallet-balances", "pallet-minimal-template", "pallet-sudo", @@ -8174,6 +8144,7 @@ dependencies = [ "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", "parity-scale-codec", + "polkadot-sdk-frame", "scale-info", "sp-genesis-builder", "substrate-wasm-builder", @@ -9867,8 +9838,8 @@ dependencies = [ name = "pallet-example-frame-crate" version = "0.0.1" dependencies = [ - "frame", "parity-scale-codec", + "polkadot-sdk-frame", "scale-info", ] @@ -10201,8 +10172,8 @@ dependencies = [ name = "pallet-minimal-template" version = "0.0.0" dependencies = [ - "frame", "parity-scale-codec", + "polkadot-sdk-frame", "scale-info", ] @@ -13426,7 +13397,6 @@ dependencies = [ "cumulus-pallet-aura-ext", "cumulus-pallet-parachain-system", "docify", - "frame", "frame-executive", "frame-support", "frame-system", @@ -13454,6 +13424,7 @@ dependencies = [ "pallet-uniques", "pallet-utility", "parity-scale-codec", + "polkadot-sdk-frame", "sc-cli", "sc-client-db", "sc-consensus-aura", @@ -13483,6 +13454,35 @@ dependencies = [ "substrate-wasm-builder", ] +[[package]] +name = "polkadot-sdk-frame" +version = "0.1.0" +dependencies = [ + "docify", + "frame-executive", + "frame-support", + "frame-system", + "frame-system-rpc-runtime-api", + "log", + "pallet-examples", + "parity-scale-codec", + "scale-info", + "sp-api", + "sp-arithmetic", + "sp-block-builder", + "sp-consensus-aura", + "sp-consensus-grandpa", + "sp-core", + "sp-inherents", + "sp-io", + "sp-offchain", + "sp-runtime", + "sp-session", + "sp-std 14.0.0", + "sp-transaction-pool", + "sp-version", +] + [[package]] name = "polkadot-service" version = "7.0.0" diff --git a/docs/sdk/Cargo.toml b/docs/sdk/Cargo.toml index 64b23866f0cd..426c5d9de4a0 100644 --- a/docs/sdk/Cargo.toml +++ b/docs/sdk/Cargo.toml @@ -17,7 +17,7 @@ workspace = true # Needed for all FRAME-based code parity-scale-codec = { version = "3.0.0", default-features = false } scale-info = { version = "2.6.0", default-features = false } -frame = { path = "../../substrate/frame", features = [ +frame = { package = "polkadot-sdk-frame", path = "../../substrate/frame", features = [ "experimental", "runtime", ] } diff --git a/prdoc/pr_3813.prdoc b/prdoc/pr_3813.prdoc new file mode 100644 index 000000000000..66dfd70e1b17 --- /dev/null +++ b/prdoc/pr_3813.prdoc @@ -0,0 +1,14 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Renames `frame` crate to `polkadot-sdk-frame` + +doc: + - audience: Runtime Dev + description: | + This PR renames `frame` crate to `polkadot-sdk-frame` as `frame` is not available on crates.io. + Please note that this crate can only be imported as `polkadot-sdk-frame` or `frame`. + +crates: + - name: polkadot-sdk-frame + bump: major diff --git a/substrate/client/chain-spec/src/lib.rs b/substrate/client/chain-spec/src/lib.rs index e8b87a604042..6da5fd26d526 100644 --- a/substrate/client/chain-spec/src/lib.rs +++ b/substrate/client/chain-spec/src/lib.rs @@ -140,7 +140,7 @@ //! A JSON object that provides an explicit and comprehensive representation of the //! RuntimeGenesisConfig struct, which is generated by frame::runtime::prelude::construct_runtime macro (polkadot_sdk_frame::runtime::prelude::construct_runtime macro (example of generated struct). Must contain all the keys of //! the genesis config, no defaults will be used. diff --git a/substrate/frame/Cargo.toml b/substrate/frame/Cargo.toml index 27001ee5afd9..919d6d17ce8b 100644 --- a/substrate/frame/Cargo.toml +++ b/substrate/frame/Cargo.toml @@ -1,6 +1,6 @@ [package] -name = "frame" -version = "0.0.1-dev" +name = "polkadot-sdk-frame" +version = "0.1.0" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" diff --git a/substrate/frame/examples/frame-crate/Cargo.toml b/substrate/frame/examples/frame-crate/Cargo.toml index 76bfd65282a9..3a0e4f720f95 100644 --- a/substrate/frame/examples/frame-crate/Cargo.toml +++ b/substrate/frame/examples/frame-crate/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } -frame = { path = "../..", default-features = false, features = ["experimental", "runtime"] } +frame = { package = "polkadot-sdk-frame", path = "../..", default-features = false, features = ["experimental", "runtime"] } [features] diff --git a/substrate/frame/src/lib.rs b/substrate/frame/src/lib.rs index 52db7c34bfdc..d395b4c1902b 100644 --- a/substrate/frame/src/lib.rs +++ b/substrate/frame/src/lib.rs @@ -45,16 +45,20 @@ //! //! In short, this crate only re-exports types and traits from multiple sources. All of these //! sources are listed (and re-exported again) in [`deps`]. +//! +//! ## Usage +//! +//! Please note that this crate can only be imported as `polkadot-sdk-frame` or `frame`. #![cfg_attr(not(feature = "std"), no_std)] #![cfg(feature = "experimental")] /// Exports the main pallet macro. This can wrap a `mod pallet` and will transform it into -/// being a pallet, eg `#[frame::pallet] mod pallet { .. }`. +/// being a pallet, eg `#[polkadot_sdk_frame::pallet] mod pallet { .. }`. /// /// Note that this is not part of the prelude, in order to make it such that the common way to -/// define a macro is `#[frame::pallet] mod pallet { .. }`, followed by `#[pallet::foo]`, -/// `#[pallet::bar]` inside the mod. +/// define a macro is `#[polkadot_sdk_frame::pallet] mod pallet { .. }`, followed by +/// `#[pallet::foo]`, `#[pallet::bar]` inside the mod. pub use frame_support::pallet; pub use frame_support::pallet_macros::{import_section, pallet_section}; @@ -75,7 +79,7 @@ pub mod pallet_macros { /// This prelude should almost always be the first line of code in any pallet or runtime. /// /// ``` -/// use frame::prelude::*; +/// use polkadot_sdk_frame::prelude::*; /// /// // rest of your pallet.. /// mod pallet {} @@ -84,7 +88,7 @@ pub mod prelude { /// `frame_system`'s parent crate, which is mandatory in all pallets build with this crate. /// /// Conveniently, the keyword `frame_system` is in scope as one uses `use - /// frame::prelude::*` + /// polkadot_sdk_frame::prelude::*` #[doc(inline)] pub use frame_system; @@ -112,7 +116,7 @@ pub mod prelude { /// A test setup typically starts with: /// /// ``` -/// use frame::testing_prelude::*; +/// use polkadot_sdk_frame::testing_prelude::*; /// // rest of your test setup. /// ``` #[cfg(feature = "std")] @@ -141,7 +145,7 @@ pub mod runtime { /// A runtime typically starts with: /// /// ``` - /// use frame::{prelude::*, runtime::prelude::*}; + /// use polkadot_sdk_frame::{prelude::*, runtime::prelude::*}; /// ``` pub mod prelude { /// All of the types related to the FRAME runtime executive. @@ -186,7 +190,7 @@ pub mod runtime { /// A non-testing runtime should have this enabled, as such: /// /// ``` - /// use frame::runtime::{prelude::*, apis::{*,}}; + /// use polkadot_sdk_frame::runtime::{prelude::*, apis::{*,}}; /// ``` // TODO: This is because of wildcard imports, and it should be not needed once we can avoid // that. Imports like that are needed because we seem to need some unknown types in the macro @@ -330,8 +334,8 @@ pub mod derive { /// In most cases, hopefully the answer is yes. pub mod deps { // TODO: It would be great to somehow instruct RA to prefer *not* suggesting auto-imports from - // these. For example, we prefer `frame::derive::CloneNoBound` rather than - // `frame::deps::frame_support::CloneNoBound`. + // these. For example, we prefer `polkadot_sdk_frame::derive::CloneNoBound` rather than + // `polkadot_sdk_frame::deps::frame_support::CloneNoBound`. pub use frame_support; pub use frame_system; diff --git a/substrate/frame/support/procedural/src/lib.rs b/substrate/frame/support/procedural/src/lib.rs index bc62c0509b05..f22be024d3fe 100644 --- a/substrate/frame/support/procedural/src/lib.rs +++ b/substrate/frame/support/procedural/src/lib.rs @@ -665,9 +665,9 @@ pub fn storage_alias(attributes: TokenStream, input: TokenStream) -> TokenStream "{}::macro_magic", match generate_access_from_frame_or_crate("frame-support") { Ok(path) => Ok(path), - Err(_) => generate_access_from_frame_or_crate("frame"), + Err(_) => generate_access_from_frame_or_crate("polkadot-sdk-frame"), } - .expect("Failed to find either `frame-support` or `frame` in `Cargo.toml` dependencies.") + .expect("Failed to find either `frame-support` or `polkadot-sdk-frame` in `Cargo.toml` dependencies.") .to_token_stream() .to_string() ) @@ -1181,9 +1181,9 @@ pub fn pallet_section(attr: TokenStream, tokens: TokenStream) -> TokenStream { "{}::macro_magic", match generate_access_from_frame_or_crate("frame-support") { Ok(path) => Ok(path), - Err(_) => generate_access_from_frame_or_crate("frame"), + Err(_) => generate_access_from_frame_or_crate("polkadot-sdk-frame"), } - .expect("Failed to find either `frame-support` or `frame` in `Cargo.toml` dependencies.") + .expect("Failed to find either `frame-support` or `polkadot-sdk-frame` in `Cargo.toml` dependencies.") .to_token_stream() .to_string() ) diff --git a/substrate/frame/support/procedural/src/pallet/parse/config.rs b/substrate/frame/support/procedural/src/pallet/parse/config.rs index fbab92db196c..406072df4b9d 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/config.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/config.rs @@ -275,7 +275,8 @@ fn check_event_type( } /// Check that the path to `frame_system::Config` is valid, this is that the path is just -/// `frame_system::Config` or when using the `frame` crate it is `frame::xyz::frame_system::Config`. +/// `frame_system::Config` or when using the `frame` crate it is +/// `polkadot_sdk_frame::xyz::frame_system::Config`. fn has_expected_system_config(path: syn::Path, frame_system: &syn::Path) -> bool { // Check if `frame_system` is actually 'frame_system'. if path.segments.iter().all(|s| s.ident != "frame_system") { @@ -293,7 +294,7 @@ fn has_expected_system_config(path: syn::Path, frame_system: &syn::Path) -> bool // `frame` re-exports it as such. syn::parse2::(quote::quote!(frame_system)).expect("is a valid path; qed"), (_, _) => - // They are either both `frame_system` or both `frame::xyz::frame_system`. + // They are either both `frame_system` or both `polkadot_sdk_frame::xyz::frame_system`. frame_system.clone(), }; @@ -516,14 +517,28 @@ mod tests { #[test] fn has_expected_system_config_works_with_frame() { + let path = syn::parse2::(quote::quote!(frame_system::Config)).unwrap(); + + let frame_system = + syn::parse2::(quote::quote!(polkadot_sdk_frame::deps::frame_system)) + .unwrap(); + assert!(has_expected_system_config(path.clone(), &frame_system)); + let frame_system = syn::parse2::(quote::quote!(frame::deps::frame_system)).unwrap(); - let path = syn::parse2::(quote::quote!(frame_system::Config)).unwrap(); assert!(has_expected_system_config(path, &frame_system)); } #[test] fn has_expected_system_config_works_with_frame_full_path() { + let frame_system = + syn::parse2::(quote::quote!(polkadot_sdk_frame::deps::frame_system)) + .unwrap(); + let path = + syn::parse2::(quote::quote!(polkadot_sdk_frame::deps::frame_system::Config)) + .unwrap(); + assert!(has_expected_system_config(path, &frame_system)); + let frame_system = syn::parse2::(quote::quote!(frame::deps::frame_system)).unwrap(); let path = @@ -533,6 +548,13 @@ mod tests { #[test] fn has_expected_system_config_works_with_other_frame_full_path() { + let frame_system = + syn::parse2::(quote::quote!(polkadot_sdk_frame::xyz::frame_system)).unwrap(); + let path = + syn::parse2::(quote::quote!(polkadot_sdk_frame::xyz::frame_system::Config)) + .unwrap(); + assert!(has_expected_system_config(path, &frame_system)); + let frame_system = syn::parse2::(quote::quote!(frame::xyz::frame_system)).unwrap(); let path = @@ -543,18 +565,21 @@ mod tests { #[test] fn has_expected_system_config_does_not_works_with_mixed_frame_full_path() { let frame_system = - syn::parse2::(quote::quote!(frame::xyz::frame_system)).unwrap(); + syn::parse2::(quote::quote!(polkadot_sdk_frame::xyz::frame_system)).unwrap(); let path = - syn::parse2::(quote::quote!(frame::deps::frame_system::Config)).unwrap(); + syn::parse2::(quote::quote!(polkadot_sdk_frame::deps::frame_system::Config)) + .unwrap(); assert!(!has_expected_system_config(path, &frame_system)); } #[test] fn has_expected_system_config_does_not_works_with_other_mixed_frame_full_path() { let frame_system = - syn::parse2::(quote::quote!(frame::deps::frame_system)).unwrap(); + syn::parse2::(quote::quote!(polkadot_sdk_frame::deps::frame_system)) + .unwrap(); let path = - syn::parse2::(quote::quote!(frame::xyz::frame_system::Config)).unwrap(); + syn::parse2::(quote::quote!(polkadot_sdk_frame::xyz::frame_system::Config)) + .unwrap(); assert!(!has_expected_system_config(path, &frame_system)); } @@ -562,7 +587,8 @@ mod tests { fn has_expected_system_config_does_not_work_with_frame_full_path_if_not_frame_crate() { let frame_system = syn::parse2::(quote::quote!(frame_system)).unwrap(); let path = - syn::parse2::(quote::quote!(frame::deps::frame_system::Config)).unwrap(); + syn::parse2::(quote::quote!(polkadot_sdk_frame::deps::frame_system::Config)) + .unwrap(); assert!(!has_expected_system_config(path, &frame_system)); } diff --git a/substrate/frame/support/procedural/tools/src/lib.rs b/substrate/frame/support/procedural/tools/src/lib.rs index be4396133628..8952cd6011ff 100644 --- a/substrate/frame/support/procedural/tools/src/lib.rs +++ b/substrate/frame/support/procedural/tools/src/lib.rs @@ -54,15 +54,19 @@ pub fn generate_crate_access(unique_id: &str, def_crate: &str) -> TokenStream { /// /// This will usually check the output of [`generate_access_from_frame_or_crate`]. /// We want to know if whatever the `path` takes us to, is exported from `frame` or not. In that -/// case `path` would start with `frame`, something like `frame::x::y:z`. +/// case `path` would start with `frame`, something like `polkadot_sdk_frame::x::y:z` or +/// frame::x::y:z. pub fn is_using_frame_crate(path: &syn::Path) -> bool { - path.segments.first().map(|s| s.ident == "frame").unwrap_or(false) + path.segments + .first() + .map(|s| s.ident == "polkadot_sdk_frame" || s.ident == "frame") + .unwrap_or(false) } /// Generate the crate access for the crate using 2018 syntax. /// -/// If `frame` is in scope, it will use `frame::deps::`. Else, it will try and find -/// `` directly. +/// If `frame` is in scope, it will use `polkadot_sdk_frame::deps::`. Else, it will try +/// and find `` directly. pub fn generate_access_from_frame_or_crate(def_crate: &str) -> Result { if let Some(path) = get_frame_crate_path(def_crate) { Ok(path) @@ -114,7 +118,9 @@ pub fn generate_hidden_includes(unique_id: &str, def_crate: &str) -> TokenStream /// Generates the path to the frame crate deps. fn get_frame_crate_path(def_crate: &str) -> Option { // This does not work if the frame crate is renamed. - if let Ok(FoundCrate::Name(name)) = crate_name(&"frame") { + if let Ok(FoundCrate::Name(name)) = + crate_name(&"polkadot-sdk-frame").or_else(|_| crate_name(&"frame")) + { let path = format!("{}::deps::{}", name, def_crate.to_string().replace("-", "_")); Some(syn::parse_str::(&path).expect("is a valid path; qed")) } else { diff --git a/substrate/frame/support/test/stg_frame_crate/Cargo.toml b/substrate/frame/support/test/stg_frame_crate/Cargo.toml index 295b2a1a5247..554c81ab43de 100644 --- a/substrate/frame/support/test/stg_frame_crate/Cargo.toml +++ b/substrate/frame/support/test/stg_frame_crate/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive"] } -frame = { path = "../../..", default-features = false, features = ["experimental", "runtime"] } +frame = { package = "polkadot-sdk-frame", path = "../../..", default-features = false, features = ["experimental", "runtime"] } scale-info = { version = "2.11.1", default-features = false, features = ["derive"] } [features] diff --git a/substrate/frame/support/test/tests/pallet_ui/event_type_invalid_bound_no_frame_crate.rs b/substrate/frame/support/test/tests/pallet_ui/event_type_invalid_bound_no_frame_crate.rs index 573ceb6dfab7..b510beb54dda 100644 --- a/substrate/frame/support/test/tests/pallet_ui/event_type_invalid_bound_no_frame_crate.rs +++ b/substrate/frame/support/test/tests/pallet_ui/event_type_invalid_bound_no_frame_crate.rs @@ -17,13 +17,13 @@ #[frame_support::pallet] mod pallet { - use frame::deps::frame_system::pallet_prelude::BlockNumberFor; + use polkadot_sdk_frame::deps::frame_system::pallet_prelude::BlockNumberFor; use frame_support::pallet_prelude::{Hooks, IsType}; #[pallet::config] - pub trait Config: frame::deps::frame_system::Config { + pub trait Config: polkadot_sdk_frame::deps::frame_system::Config { type Bar: Clone + std::fmt::Debug + Eq; - type RuntimeEvent: IsType<::RuntimeEvent> + type RuntimeEvent: IsType<::RuntimeEvent> + From>; } diff --git a/substrate/frame/support/test/tests/pallet_ui/event_type_invalid_bound_no_frame_crate.stderr b/substrate/frame/support/test/tests/pallet_ui/event_type_invalid_bound_no_frame_crate.stderr index 0f805c972e4d..384e44d97a61 100644 --- a/substrate/frame/support/test/tests/pallet_ui/event_type_invalid_bound_no_frame_crate.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/event_type_invalid_bound_no_frame_crate.stderr @@ -1,5 +1,5 @@ error: Invalid `type RuntimeEvent`, associated type `RuntimeEvent` is reserved and must bound: `IsType<::RuntimeEvent>` --> tests/pallet_ui/event_type_invalid_bound_no_frame_crate.rs:26:3 | -26 | type RuntimeEvent: IsType<::RuntimeEvent> +26 | type RuntimeEvent: IsType<::RuntimeEvent> | ^^^^ diff --git a/substrate/primitives/api/proc-macro/src/utils.rs b/substrate/primitives/api/proc-macro/src/utils.rs index c8c1f12d90a1..a6570a98f1f7 100644 --- a/substrate/primitives/api/proc-macro/src/utils.rs +++ b/substrate/primitives/api/proc-macro/src/utils.rs @@ -34,7 +34,9 @@ pub fn generate_crate_access() -> TokenStream { quote!(#renamed_name::__private) }, Err(e) => - if let Ok(FoundCrate::Name(name)) = crate_name(&"frame") { + if let Ok(FoundCrate::Name(name)) = + crate_name(&"polkadot-sdk-frame").or_else(|_| crate_name(&"frame")) + { let path = format!("{}::deps::sp_api::__private", name); let path = syn::parse_str::(&path).expect("is a valid path; qed"); quote!( #path ) diff --git a/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs b/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs index 80a5d27d8c26..5fbfc0530bb3 100644 --- a/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs +++ b/substrate/utils/frame/benchmarking-cli/src/pallet/command.rs @@ -48,7 +48,7 @@ use std::{ }; /// Logging target -const LOG_TARGET: &'static str = "frame::benchmark::pallet"; +const LOG_TARGET: &'static str = "polkadot_sdk_frame::benchmark::pallet"; /// The inclusive range of a component. #[derive(Serialize, Debug, Clone, Eq, PartialEq)] diff --git a/substrate/utils/frame/rpc/support/src/lib.rs b/substrate/utils/frame/rpc/support/src/lib.rs index a839bbc34021..dea822167ff3 100644 --- a/substrate/utils/frame/rpc/support/src/lib.rs +++ b/substrate/utils/frame/rpc/support/src/lib.rs @@ -161,7 +161,7 @@ impl StorageQuery { /// Send this query over RPC, await the typed result. /// - /// Hash should be `::Hash`. + /// Hash should be `::Hash`. /// /// # Arguments /// diff --git a/templates/minimal/node/Cargo.toml b/templates/minimal/node/Cargo.toml index 0668304e5028..606fd0580356 100644 --- a/templates/minimal/node/Cargo.toml +++ b/templates/minimal/node/Cargo.toml @@ -49,7 +49,7 @@ substrate-frame-rpc-system = { path = "../../../substrate/utils/frame/rpc/system # Once the native runtime is gone, there should be little to no dependency on FRAME here, and # certainly no dependency on the runtime. -frame = { path = "../../../substrate/frame", features = [ +frame = { package = "polkadot-sdk-frame", path = "../../../substrate/frame", features = [ "experimental", "runtime", ] } diff --git a/templates/minimal/pallets/template/Cargo.toml b/templates/minimal/pallets/template/Cargo.toml index a85391f29421..909ba0344548 100644 --- a/templates/minimal/pallets/template/Cargo.toml +++ b/templates/minimal/pallets/template/Cargo.toml @@ -22,7 +22,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", features = [ scale-info = { version = "2.11.1", default-features = false, features = [ "derive", ] } -frame = { path = "../../../../substrate/frame", default-features = false, features = [ +frame = { package = "polkadot-sdk-frame", path = "../../../../substrate/frame", default-features = false, features = [ "experimental", "runtime", ] } diff --git a/templates/minimal/runtime/Cargo.toml b/templates/minimal/runtime/Cargo.toml index a99a1e43f85f..e7f88ca47af7 100644 --- a/templates/minimal/runtime/Cargo.toml +++ b/templates/minimal/runtime/Cargo.toml @@ -17,7 +17,7 @@ parity-scale-codec = { version = "3.0.0", default-features = false } scale-info = { version = "2.6.0", default-features = false } # this is a frame-based runtime, thus importing `frame` with runtime feature enabled. -frame = { path = "../../../substrate/frame", default-features = false, features = [ +frame = { package = "polkadot-sdk-frame", path = "../../../substrate/frame", default-features = false, features = [ "experimental", "runtime", ] } From 23860fcdd0e7bb114291d89779e139942f696db5 Mon Sep 17 00:00:00 2001 From: Vladimir Istyufeev Date: Thu, 4 Apr 2024 12:22:18 +0400 Subject: [PATCH 117/257] Convince GitLab not to crop collapsed multiline strings (#3971) Use of `- >` instead of `- |` workarounds GitLab quirk when it crops collapsed multiline `script:` section commands in its CI job logs. This PR also fixes `- |` based `script:` steps to behave properly after `- >` conversion. Resolves https://github.com/paritytech/ci_cd/issues/972. --- .gitlab-ci.yml | 6 +++--- .gitlab/pipeline/build.yml | 28 ++++++++++++++-------------- .gitlab/pipeline/check.yml | 29 +++++++++++++---------------- .gitlab/pipeline/publish.yml | 14 +++++++------- .gitlab/pipeline/test.yml | 6 +++--- 5 files changed, 40 insertions(+), 43 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 93a6ccb9f8fb..fbcd94b52568 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -125,10 +125,10 @@ default: - cp $FL_FORKLIFT_CONFIG ~/.forklift/config.toml - shopt -s expand_aliases - export PATH=$PATH:$(pwd) - - | + - > if [ "$FORKLIFT_BYPASS" != "true" ]; then - echo "FORKLIFT_BYPASS not set, creating alias cargo='forklift cargo'" - alias cargo="forklift cargo" + echo "FORKLIFT_BYPASS not set, creating alias cargo='forklift cargo'"; + alias cargo="forklift cargo"; fi # - echo "FL_FORKLIFT_VERSION ${FL_FORKLIFT_VERSION}" diff --git a/.gitlab/pipeline/build.yml b/.gitlab/pipeline/build.yml index 44d66eb2f5eb..3c870e576a8d 100644 --- a/.gitlab/pipeline/build.yml +++ b/.gitlab/pipeline/build.yml @@ -105,26 +105,26 @@ build-rustdoc: - mv ./target/doc ./crate-docs # Inject Simple Analytics (https://www.simpleanalytics.com/) privacy preserving tracker into # all .html files - - | + - > inject_simple_analytics() { - local path="$1" - local script_content="" + local path="$1"; + local script_content=""; # Function that inject script into the head of an html file using sed. process_file() { - local file="$1" - echo "Adding Simple Analytics script to $file" - sed -i "s||$script_content|" "$file" - } - export -f process_file - # xargs runs process_file in seperate shells without access to outer variables. - # to make script_content available inside process_file, export it as an env var here. - export script_content + local file="$1"; + echo "Adding Simple Analytics script to $file"; + sed -i "s||$script_content|" "$file"; + }; + export -f process_file; + # xargs runs process_file in separate shells without access to outer variables. + # make script_content available inside process_file, export it as an env var here. + export script_content; # Modify .html files in parallel using xargs, otherwise it can take a long time. - find "$path" -name '*.html' | xargs -I {} -P "$(nproc)" bash -c 'process_file "$@"' _ {} - } - inject_simple_analytics "./crate-docs" + find "$path" -name '*.html' | xargs -I {} -P "$(nproc)" bash -c 'process_file "$@"' _ {}; + }; + inject_simple_analytics "./crate-docs"; - echo "" > ./crate-docs/index.html build-implementers-guide: diff --git a/.gitlab/pipeline/check.yml b/.gitlab/pipeline/check.yml index 52da33550508..4c39539f1e50 100644 --- a/.gitlab/pipeline/check.yml +++ b/.gitlab/pipeline/check.yml @@ -104,23 +104,20 @@ check-toml-format: - .docker-env - .test-pr-refs script: - - | - export RUST_LOG=remote-ext=debug,runtime=debug - - echo "---------- Downloading try-runtime CLI ----------" - curl -sL https://github.com/paritytech/try-runtime-cli/releases/download/v0.5.4/try-runtime-x86_64-unknown-linux-musl -o try-runtime - chmod +x ./try-runtime - echo "Using try-runtime-cli version:" - ./try-runtime --version - - echo "---------- Building ${PACKAGE} runtime ----------" - time cargo build --release --locked -p "$PACKAGE" --features try-runtime - - echo "---------- Executing on-runtime-upgrade for ${NETWORK} ----------" + - export RUST_LOG=remote-ext=debug,runtime=debug + - echo "---------- Downloading try-runtime CLI ----------" + - curl -sL https://github.com/paritytech/try-runtime-cli/releases/download/v0.5.4/try-runtime-x86_64-unknown-linux-musl -o try-runtime + - chmod +x ./try-runtime + - echo "Using try-runtime-cli version:" + - ./try-runtime --version + - echo "---------- Building ${PACKAGE} runtime ----------" + - time cargo build --release --locked -p "$PACKAGE" --features try-runtime + - echo "---------- Executing on-runtime-upgrade for ${NETWORK} ----------" + - > time ./try-runtime ${COMMAND_EXTRA_ARGS} \ - --runtime ./target/release/wbuild/"$PACKAGE"/"$WASM" \ - on-runtime-upgrade --disable-spec-version-check --checks=all ${SUBCOMMAND_EXTRA_ARGS} live --uri ${URI} - sleep 5 + --runtime ./target/release/wbuild/"$PACKAGE"/"$WASM" \ + on-runtime-upgrade --disable-spec-version-check --checks=all ${SUBCOMMAND_EXTRA_ARGS} live --uri ${URI} + - sleep 5 # Check runtime migrations for Parity managed relay chains check-runtime-migration-westend: diff --git a/.gitlab/pipeline/publish.yml b/.gitlab/pipeline/publish.yml index a37ba012a8a7..954df10bef01 100644 --- a/.gitlab/pipeline/publish.yml +++ b/.gitlab/pipeline/publish.yml @@ -113,17 +113,17 @@ trigger_workflow: artifacts: true script: - echo "Triggering workflow" - - | + - > for benchmark in $(ls charts/*.json); do - export bencmark_name=$(basename $benchmark) - echo "Benchmark: $bencmark_name" - export benchmark_dir=$(echo $bencmark_name | sed 's/\.json//') + export benchmark_name=$(basename $benchmark); + echo "Benchmark: $benchmark_name"; + export benchmark_dir=$(echo $benchmark_name | sed 's/\.json//'); curl -q -X POST \ -H "Accept: application/vnd.github.v3+json" \ -H "Authorization: token $GITHUB_TOKEN" \ - https://api.github.com/repos/paritytech/${CI_PROJECT_NAME}/actions/workflows/subsystem-benchmarks.yml/dispatches \ - -d '{"ref":"refs/heads/master","inputs":{"benchmark-data-dir-path":"'$benchmark_dir'","output-file-path":"'$bencmark_name'"}}' - sleep 300 + https://api.github.com/repos/paritytech/${CI_PROJECT_NAME}/actions/workflows/subsystem-benchmarks.yml/dispatches \ + -d "{\"ref\":\"refs/heads/master\",\"inputs\":{\"benchmark-data-dir-path\":\"$benchmark_dir\",\"output-file-path\":\"$benchmark_name\"}}"; + sleep 300; done allow_failure: true diff --git a/.gitlab/pipeline/test.yml b/.gitlab/pipeline/test.yml index 48c84b472b43..9db89b923009 100644 --- a/.gitlab/pipeline/test.yml +++ b/.gitlab/pipeline/test.yml @@ -23,7 +23,7 @@ test-linux-stable: - echo "Node index - ${CI_NODE_INDEX}. Total amount - ${CI_NODE_TOTAL}" # add experimental to features after https://github.com/paritytech/substrate/pull/14502 is merged # "upgrade_version_checks_should_work" is currently failing - - | + - > time cargo nextest run \ --workspace \ --locked \ @@ -34,7 +34,7 @@ test-linux-stable: # Upload tests results to Elasticsearch - echo "Upload test results to Elasticsearch" - cat target/nextest/default/junit.xml | xq . > target/nextest/default/junit.json - - | + - > curl -v -XPOST --http1.1 \ -u ${ELASTIC_USERNAME}:${ELASTIC_PASSWORD} \ https://elasticsearch.parity-build.parity.io/unit-tests/_doc/${CI_JOB_ID} \ @@ -87,7 +87,7 @@ test-linux-stable-runtime-benchmarks: # script: # # Build all but only execute 'runtime' tests. # - echo "Node index - ${CI_NODE_INDEX}. Total amount - ${CI_NODE_TOTAL}" -# - | +# - > # time cargo nextest run \ # --workspace \ # --locked \ From 73fdff81e67da82e93e37a0bc7a91392f5f932e3 Mon Sep 17 00:00:00 2001 From: Lulu Date: Thu, 4 Apr 2024 10:26:53 +0100 Subject: [PATCH 118/257] Use 0.1.0 as minimum version for crates (#3941) CI will be enforcing this with next parity-publish release --- Cargo.lock | 8 ++++---- cumulus/parachains/runtimes/bridge-hubs/common/Cargo.toml | 2 +- substrate/frame/parameters/Cargo.toml | 2 +- substrate/primitives/crypto/hashing/Cargo.toml | 2 +- substrate/primitives/crypto/hashing/proc-macro/Cargo.toml | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bbfac2c29bb6..247009b3c7c7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1922,7 +1922,7 @@ dependencies = [ [[package]] name = "bridge-hub-common" -version = "0.0.0" +version = "0.1.0" dependencies = [ "cumulus-primitives-core", "frame-support", @@ -10518,7 +10518,7 @@ dependencies = [ [[package]] name = "pallet-parameters" -version = "0.0.1" +version = "0.1.0" dependencies = [ "docify", "frame-benchmarking", @@ -18777,7 +18777,7 @@ dependencies = [ [[package]] name = "sp-crypto-hashing" -version = "0.0.0" +version = "0.1.0" dependencies = [ "blake2b_simd", "byteorder", @@ -18791,7 +18791,7 @@ dependencies = [ [[package]] name = "sp-crypto-hashing-proc-macro" -version = "0.0.0" +version = "0.1.0" dependencies = [ "quote", "sp-crypto-hashing", diff --git a/cumulus/parachains/runtimes/bridge-hubs/common/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/common/Cargo.toml index 2ab6ee7995f2..2f5f783ce48f 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/common/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/common/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bridge-hub-common" -version = "0.0.0" +version = "0.1.0" authors.workspace = true edition.workspace = true description = "Bridge hub common utilities" diff --git a/substrate/frame/parameters/Cargo.toml b/substrate/frame/parameters/Cargo.toml index 2527bdf3a71f..b718b391019a 100644 --- a/substrate/frame/parameters/Cargo.toml +++ b/substrate/frame/parameters/Cargo.toml @@ -3,7 +3,7 @@ name = "pallet-parameters" description = "Pallet to store and configure parameters." repository.workspace = true license = "Apache-2.0" -version = "0.0.1" +version = "0.1.0" authors = ["Acala Developers", "Parity Technologies "] edition.workspace = true diff --git a/substrate/primitives/crypto/hashing/Cargo.toml b/substrate/primitives/crypto/hashing/Cargo.toml index 3077e1e715e1..096650e231c8 100644 --- a/substrate/primitives/crypto/hashing/Cargo.toml +++ b/substrate/primitives/crypto/hashing/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-crypto-hashing" -version = "0.0.0" +version = "0.1.0" authors.workspace = true edition.workspace = true license = "Apache-2.0" diff --git a/substrate/primitives/crypto/hashing/proc-macro/Cargo.toml b/substrate/primitives/crypto/hashing/proc-macro/Cargo.toml index f244b02ca101..f988042d3075 100644 --- a/substrate/primitives/crypto/hashing/proc-macro/Cargo.toml +++ b/substrate/primitives/crypto/hashing/proc-macro/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-crypto-hashing-proc-macro" -version = "0.0.0" +version = "0.1.0" authors.workspace = true edition.workspace = true license = "Apache-2.0" From 63064e6b8c76a622690ffb0ae784ba090756c07b Mon Sep 17 00:00:00 2001 From: Liam Aharon Date: Thu, 4 Apr 2024 22:32:01 +1100 Subject: [PATCH 119/257] Fix Mermaid diagram rendering (#3875) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes https://github.com/paritytech/polkadot-sdk/issues/2977 The issue appears to stem from the `aquamarine` crate failing to render diagrams in re-exported crates. e.g. as raised [here](https://github.com/paritytech/polkadot-sdk/issues/2977), diagrams would render at `frame_support::traits::Hooks` but not the re-exported doc `frame::traits::Hooks`, even if I added `aquamarine` as a `frame` crate dependency. To resolve this, I followed advice in https://github.com/mersinvald/aquamarine/issues/20 to instead render mermaid diagrams directly using JS by adding an `after-content.js`. --- Also fixes compile warnings, enables `--all-features` and disallows future warnings in CI. --------- Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: Bastian Köcher --- .gitlab/pipeline/build.yml | 5 ++--- cumulus/test/service/src/chain_spec.rs | 2 +- docs/sdk/assets/after-content.html | 2 ++ docs/sdk/{headers => assets}/header.html | 2 ++ docs/sdk/{headers => assets}/theme.css | 0 prdoc/pr_3875.prdoc | 11 +++++++++++ substrate/frame/assets/src/lib.rs | 3 +-- 7 files changed, 19 insertions(+), 6 deletions(-) create mode 100644 docs/sdk/assets/after-content.html rename docs/sdk/{headers => assets}/header.html (97%) rename docs/sdk/{headers => assets}/theme.css (100%) create mode 100644 prdoc/pr_3875.prdoc diff --git a/.gitlab/pipeline/build.yml b/.gitlab/pipeline/build.yml index 3c870e576a8d..8658e92efc8f 100644 --- a/.gitlab/pipeline/build.yml +++ b/.gitlab/pipeline/build.yml @@ -91,7 +91,7 @@ build-rustdoc: - .run-immediately variables: SKIP_WASM_BUILD: 1 - RUSTDOCFLAGS: "--default-theme=ayu --html-in-header ./docs/sdk/headers/header.html --extend-css ./docs/sdk/headers/theme.css" + RUSTDOCFLAGS: "-Dwarnings --default-theme=ayu --html-in-header ./docs/sdk/assets/header.html --extend-css ./docs/sdk/assets/theme.css --html-after-content ./docs/sdk/assets/after-content.html" artifacts: name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}-doc" when: on_success @@ -99,8 +99,7 @@ build-rustdoc: paths: - ./crate-docs/ script: - # FIXME: it fails with `RUSTDOCFLAGS="-Dwarnings"` and `--all-features` - - time cargo doc --features try-runtime,experimental --workspace --no-deps + - time cargo doc --all-features --workspace --no-deps - rm -f ./target/doc/.lock - mv ./target/doc ./crate-docs # Inject Simple Analytics (https://www.simpleanalytics.com/) privacy preserving tracker into diff --git a/cumulus/test/service/src/chain_spec.rs b/cumulus/test/service/src/chain_spec.rs index 61bbf755d890..e86023576ac5 100644 --- a/cumulus/test/service/src/chain_spec.rs +++ b/cumulus/test/service/src/chain_spec.rs @@ -34,7 +34,7 @@ pub fn get_from_seed(seed: &str) -> ::Pu .public() } -/// The extensions for the [`ChainSpec`](crate::ChainSpec). +/// The extensions for the [`ChainSpec`]. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ChainSpecGroup, ChainSpecExtension)] #[serde(deny_unknown_fields)] pub struct Extensions { diff --git a/docs/sdk/assets/after-content.html b/docs/sdk/assets/after-content.html new file mode 100644 index 000000000000..30ae5c7ec430 --- /dev/null +++ b/docs/sdk/assets/after-content.html @@ -0,0 +1,2 @@ + + diff --git a/docs/sdk/headers/header.html b/docs/sdk/assets/header.html similarity index 97% rename from docs/sdk/headers/header.html rename to docs/sdk/assets/header.html index e28458c4ccc7..f55c31b53216 100644 --- a/docs/sdk/headers/header.html +++ b/docs/sdk/assets/header.html @@ -84,6 +84,8 @@ }); + +