Skip to content

Commit 5843e53

Browse files
committed
Refactor session pallet to replace NamedReservableCurrency with hold functionality for key management. Update related types and events to reflect changes from reservation to holding of funds.
1 parent 734ffc6 commit 5843e53

File tree

2 files changed

+136
-105
lines changed

2 files changed

+136
-105
lines changed

substrate/frame/session/src/lib.rs

+31-32
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,8 @@ use frame_support::{
130130
ensure,
131131
traits::{
132132
Defensive, EstimateNextNewSession, EstimateNextSessionRotation, FindAuthor, Get,
133-
OneSessionHandler, ValidatorRegistration, ValidatorSet, Currency, NamedReservableCurrency,
134-
ReservableCurrency,
133+
OneSessionHandler, ValidatorRegistration, ValidatorSet,
134+
fungible::{hold::Mutate as HoldMutate, hold::Inspect as HoldInspect, Inspect},
135135
},
136136
weights::Weight,
137137
Parameter,
@@ -398,9 +398,9 @@ pub mod pallet {
398398
#[pallet::without_storage_info]
399399
pub struct Pallet<T>(_);
400400

401-
/// A simple identifier for session keys.
401+
/// A simple identifier for session keys hold reason.
402402
#[derive(codec::Encode, codec::Decode, codec::MaxEncodedLen, scale_info::TypeInfo, Debug, PartialEq, Eq, Clone)]
403-
pub struct SessionKeysReserveId;
403+
pub struct SessionKeysHoldReason;
404404

405405
#[pallet::config]
406406
pub trait Config: frame_system::Config {
@@ -442,19 +442,19 @@ pub mod pallet {
442442
/// Weight information for extrinsics in this pallet.
443443
type WeightInfo: WeightInfo;
444444

445-
/// The currency type for reserving when setting keys.
446-
type Currency: NamedReservableCurrency<Self::AccountId>;
445+
/// The currency type for placing holds when setting keys.
446+
type Currency: HoldMutate<Self::AccountId> + Inspect<Self::AccountId>;
447447

448-
/// The reserve identifier type.
449-
type ReserveIdentifier: Get<<Self::Currency as NamedReservableCurrency<Self::AccountId>>::ReserveIdentifier> + TypeInfo + 'static;
448+
/// The hold reason type.
449+
type HoldReason: Get<<Self::Currency as HoldInspect<Self::AccountId>>::Reason> + TypeInfo + 'static;
450450

451-
/// The amount to be reserved when setting keys.
451+
/// The amount to be held when setting keys.
452452
#[pallet::constant]
453453
type KeyDeposit: Get<BalanceOf<Self>>;
454454
}
455455

456456
// Add a type alias for the balance
457-
type BalanceOf<T> = <<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance;
457+
type BalanceOf<T> = <<T as Config>::Currency as Inspect<<T as frame_system::Config>::AccountId>>::Balance;
458458

459459
#[pallet::genesis_config]
460460
#[derive(frame_support::DefaultNoBound)]
@@ -576,10 +576,10 @@ pub mod pallet {
576576
ValidatorDisabled { validator: T::ValidatorId },
577577
/// Validator has been re-enabled.
578578
ValidatorReenabled { validator: T::ValidatorId },
579-
/// Funds have been reserved for setting keys.
580-
KeysFundsReserved { account: T::AccountId, amount: <<T as Config>::Currency as Currency<T::AccountId>>::Balance },
581-
/// Funds have been unreserved when purging keys.
582-
KeysFundsUnreserved { account: T::AccountId, amount: <<T as Config>::Currency as Currency<T::AccountId>>::Balance },
579+
/// Funds have been held for setting keys.
580+
KeysFundsHeld { account: T::AccountId, amount: BalanceOf<T> },
581+
/// Funds have been released when purging keys.
582+
KeysFundsReleased { account: T::AccountId, amount: BalanceOf<T> },
583583
}
584584

585585
/// Error for the session pallet.
@@ -868,11 +868,9 @@ impl<T: Config> Pallet<T> {
868868
// For new registrations, ensure the account has enough funds for the deposit
869869
if is_new_registration {
870870
let deposit = T::KeyDeposit::get();
871-
let _= T::ReserveIdentifier::get();
872-
// Since NamedReservableCurrency doesn't directly expose can_reserve,
873-
// we need to use the normal reserve method for checking
871+
let reason = T::HoldReason::get();
874872
ensure!(
875-
<T::Currency as ReservableCurrency<_>>::can_reserve(account, deposit),
873+
<T::Currency as HoldInspect<_>>::can_hold(&reason, account, deposit),
876874
Error::<T>::InsufficientFunds
877875
);
878876
}
@@ -881,17 +879,17 @@ impl<T: Config> Pallet<T> {
881879
// Pass old_keys to avoid another storage read
882880
Self::inner_set_keys(&who, keys, old_keys)?;
883881

884-
// Reserve deposit if this is a new registration
882+
// Place deposit on hold if this is a new registration
885883
if is_new_registration {
886884
let deposit = T::KeyDeposit::get();
887-
let id = T::ReserveIdentifier::get();
888-
T::Currency::reserve_named(&id, account, deposit)?;
885+
let reason = T::HoldReason::get();
886+
T::Currency::hold(&reason, account, deposit)?;
889887

890888
let assertion = frame_system::Pallet::<T>::inc_consumers(account).is_ok();
891889
debug_assert!(assertion, "can_inc_consumer() returned true; no change since; qed");
892890

893-
// Emit an event for the reserved funds
894-
Self::deposit_event(Event::<T>::KeysFundsReserved {
891+
// Emit an event for the held funds
892+
Self::deposit_event(Event::<T>::KeysFundsHeld {
895893
account: account.clone(),
896894
amount: deposit,
897895
});
@@ -952,16 +950,17 @@ impl<T: Config> Pallet<T> {
952950
Self::clear_key_owner(*id, key_data);
953951
}
954952

955-
// Unreserve the deposit using the named reserve
956-
let deposit = T::KeyDeposit::get();
957-
let id = T::ReserveIdentifier::get();
958-
let _ = T::Currency::unreserve_named(&id, account, deposit);
953+
// Release the deposit from hold
954+
let reason = T::HoldReason::get();
959955

960-
// Emit an event for the unreserved funds
961-
Self::deposit_event(Event::<T>::KeysFundsUnreserved {
962-
account: account.clone(),
963-
amount: deposit,
964-
});
956+
// Use release_all to handle the case where the exact amount might not be available
957+
if let Ok(released) = T::Currency::release_all(&reason, account, frame_support::traits::tokens::Precision::BestEffort) {
958+
// Emit an event for the released funds
959+
Self::deposit_event(Event::<T>::KeysFundsReleased {
960+
account: account.clone(),
961+
amount: released,
962+
});
963+
}
965964

966965
frame_system::Pallet::<T>::dec_consumers(account);
967966

substrate/frame/session/src/mock.rs

+105-73
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,10 @@ use sp_state_machine::BasicExternalities;
3131

3232
use frame_support::{
3333
derive_impl, parameter_types, traits::{ConstU64, WithdrawReasons, Currency, ReservableCurrency,
34-
SignedImbalance, NamedReservableCurrency, BalanceStatus}
34+
SignedImbalance, tokens::{fungible::{
35+
hold::{Mutate as HoldMutate, Inspect as HoldInspect, Unbalanced as UnbalancedHold},
36+
Inspect as FungibleInspect, Unbalanced as FungibleUnbalanced, Dust
37+
}, Preservation, Fortitude}},
3538
};
3639

3740
impl_opaque_keys! {
@@ -263,10 +266,10 @@ pub(crate) const DISABLING_LIMIT_FACTOR: usize = 3;
263266
pub type SessionKeysId = [u8; 12];
264267
pub const TEST_SESSION_KEYS_ID: SessionKeysId = *b"session_keys";
265268

266-
// Define TestReserveIdentifier with the necessary traits
269+
// Define TestHoldReason with the necessary traits
267270
#[derive(Debug, Clone, PartialEq, Eq, codec::Encode, codec::Decode, scale_info::TypeInfo)]
268-
pub struct TestReserveIdentifier;
269-
impl Get<SessionKeysId> for TestReserveIdentifier {
271+
pub struct TestHoldReason;
272+
impl Get<SessionKeysId> for TestHoldReason {
270273
fn get() -> SessionKeysId {
271274
TEST_SESSION_KEYS_ID
272275
}
@@ -288,7 +291,7 @@ impl Config for Test {
288291
disabling::UpToLimitWithReEnablingDisablingStrategy<DISABLING_LIMIT_FACTOR>;
289292
type WeightInfo = ();
290293
type Currency = pallet_balances::Pallet<Test>;
291-
type ReserveIdentifier = TestReserveIdentifier;
294+
type HoldReason = TestHoldReason;
292295
type KeyDeposit = KeyDeposit;
293296
}
294297

@@ -301,6 +304,10 @@ impl crate::historical::Config for Test {
301304
pub mod pallet_balances {
302305
use super::*;
303306
use frame_support::pallet_prelude::*;
307+
use frame_support::traits::{
308+
tokens::{WithdrawConsequence, Provenance, DepositConsequence},
309+
fungible::Dust,
310+
};
304311

305312
pub struct Pallet<T>(core::marker::PhantomData<T>);
306313

@@ -466,12 +473,76 @@ pub mod pallet_balances {
466473
}
467474
}
468475

469-
impl<T> NamedReservableCurrency<u64> for Pallet<T> {
470-
type ReserveIdentifier = [u8; 12];
476+
impl<T> FungibleInspect<u64> for Pallet<T> {
477+
type Balance = u64;
478+
479+
fn total_issuance() -> Self::Balance {
480+
CurrencyBalance::get()
481+
}
482+
483+
fn minimum_balance() -> Self::Balance {
484+
0
485+
}
486+
487+
fn balance(_who: &u64) -> Self::Balance {
488+
CurrencyBalance::get()
489+
}
490+
491+
fn total_balance(_who: &u64) -> Self::Balance {
492+
CurrencyBalance::get()
493+
}
494+
495+
fn reducible_balance(
496+
_who: &u64,
497+
_keep_alive: Preservation,
498+
_force: Fortitude,
499+
) -> Self::Balance {
500+
CurrencyBalance::get()
501+
}
502+
503+
fn can_deposit(
504+
_who: &u64,
505+
_amount: Self::Balance,
506+
_provenance: Provenance,
507+
) -> DepositConsequence {
508+
DepositConsequence::Success
509+
}
510+
511+
fn can_withdraw(
512+
who: &u64,
513+
amount: Self::Balance,
514+
) -> WithdrawConsequence<Self::Balance> {
515+
if *who == 999 || amount > CurrencyBalance::get() {
516+
WithdrawConsequence::BalanceLow
517+
} else {
518+
WithdrawConsequence::Success
519+
}
520+
}
521+
}
522+
523+
impl<T> FungibleUnbalanced<u64> for Pallet<T> {
524+
fn handle_dust(_dust: Dust<u64, Self>) {
525+
// No-op in mock
526+
}
527+
528+
fn write_balance(
529+
_who: &u64,
530+
_amount: Self::Balance
531+
) -> Result<Option<Self::Balance>, DispatchError> {
532+
Ok(None)
533+
}
534+
535+
fn set_total_issuance(_amount: Self::Balance) {
536+
// No-op in mock
537+
}
538+
}
539+
540+
impl<T> HoldInspect<u64> for Pallet<T> {
541+
type Reason = SessionKeysId;
471542

472-
fn reserved_balance_named(id: &Self::ReserveIdentifier, who: &u64) -> Self::Balance {
543+
fn balance_on_hold(reason: &Self::Reason, who: &u64) -> Self::Balance {
473544
// Convert fixed array to Vec for lookup
474-
let id_vec = id.to_vec();
545+
let id_vec = reason.to_vec();
475546

476547
ReservedBalances::get()
477548
.get(who)
@@ -480,81 +551,42 @@ pub mod pallet_balances {
480551
.unwrap_or(0)
481552
}
482553

483-
fn slash_reserved_named(
484-
_id: &Self::ReserveIdentifier,
485-
_who: &u64,
486-
_amount: Self::Balance,
487-
) -> (Self::NegativeImbalance, Self::Balance) {
488-
((), 0)
554+
fn total_balance_on_hold(who: &u64) -> Self::Balance {
555+
// Sum up all held balances for the account
556+
ReservedBalances::get()
557+
.get(who)
558+
.map(|holds| holds.values().sum())
559+
.unwrap_or(0)
489560
}
490561

491-
fn reserve_named(
492-
id: &Self::ReserveIdentifier,
562+
fn can_hold(_reason: &Self::Reason, who: &u64, amount: Self::Balance) -> bool {
563+
// Account 999 is special and always has insufficient funds for testing
564+
if *who == 999 {
565+
return false
566+
}
567+
CurrencyBalance::get() >= amount
568+
}
569+
}
570+
571+
impl<T> UnbalancedHold<u64> for Pallet<T> {
572+
fn set_balance_on_hold(
573+
reason: &Self::Reason,
493574
who: &u64,
494575
amount: Self::Balance,
495576
) -> DispatchResult {
496-
if !Self::can_reserve(who, amount) {
497-
return Err(DispatchError::Other("InsufficientBalance"))
498-
}
499-
500577
// Convert fixed array to Vec for storage
501-
let id_vec = id.to_vec();
578+
let id_vec = reason.to_vec();
502579

503-
// Update the reserved balance
580+
// Update the held balance
504581
ReservedBalances::mutate(|balances| {
505-
let account_reserves = balances.entry(*who).or_insert_with(BTreeMap::new);
506-
let reserved = account_reserves.entry(id_vec).or_insert(0);
507-
*reserved += amount;
582+
let account_holds = balances.entry(*who).or_insert_with(BTreeMap::new);
583+
account_holds.insert(id_vec, amount);
508584
});
509585

510586
Ok(())
511587
}
512-
513-
fn unreserve_named(
514-
id: &Self::ReserveIdentifier,
515-
who: &u64,
516-
amount: Self::Balance,
517-
) -> Self::Balance {
518-
// Convert fixed array to Vec for lookup/storage
519-
let id_vec = id.to_vec();
520-
521-
// Get the current reserved amount
522-
let mut remaining = amount;
523-
ReservedBalances::mutate(|balances| {
524-
if let Some(account_reserves) = balances.get_mut(who) {
525-
if let Some(reserved) = account_reserves.get_mut(&id_vec) {
526-
if *reserved >= amount {
527-
*reserved -= amount;
528-
remaining = 0;
529-
} else {
530-
remaining = amount - *reserved;
531-
*reserved = 0;
532-
}
533-
534-
// Clean up empty reserves
535-
if *reserved == 0 {
536-
account_reserves.remove(&id_vec);
537-
}
538-
}
539-
540-
// Clean up empty accounts
541-
if account_reserves.is_empty() {
542-
balances.remove(who);
543-
}
544-
}
545-
});
546-
547-
remaining
548-
}
549-
550-
fn repatriate_reserved_named(
551-
_id: &Self::ReserveIdentifier,
552-
_slashed: &u64,
553-
_beneficiary: &u64,
554-
_amount: Self::Balance,
555-
_status: BalanceStatus,
556-
) -> Result<Self::Balance, DispatchError> {
557-
Ok(0)
558-
}
559588
}
589+
590+
impl<T> HoldMutate<u64> for Pallet<T> {}
560591
}
592+

0 commit comments

Comments
 (0)