Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Limit process redeem requests #2806

Merged
merged 3 commits into from
Sep 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 23 additions & 12 deletions modules/homa/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,10 @@ pub mod module {
/// The XcmInterface to manage the staking of sub-account on relaychain.
type XcmInterface: HomaSubAccountXcm<Self::AccountId, Balance>;

/// The limit for process redeem requests when bump era.
#[pallet::constant]
type ProcessRedeemRequestsLimit: Get<u32>;

/// Weight information for the extrinsics in this module.
type WeightInfo: WeightInfo;

Expand Down Expand Up @@ -383,14 +387,14 @@ pub mod module {
fn on_initialize(_: BlockNumberFor<T>) -> Weight {
let bump_era_number = Self::era_amount_should_to_bump(T::RelayChainBlockNumber::current_block_number());
if !bump_era_number.is_zero() {
let _ = Self::bump_current_era(bump_era_number);
let res = Self::bump_current_era(bump_era_number);
debug_assert_eq!(
TotalStakingBonded::<T>::get(),
StakingLedgers::<T>::iter().fold(Zero::zero(), |total_bonded: Balance, (_, ledger)| {
total_bonded.saturating_add(ledger.bonded)
})
);
<T as Config>::WeightInfo::on_initialize_with_bump_era()
<T as Config>::WeightInfo::on_initialize_with_bump_era(res.unwrap_or_default())
} else {
<T as Config>::WeightInfo::on_initialize()
}
Expand Down Expand Up @@ -659,10 +663,12 @@ pub mod module {
}

#[pallet::call_index(8)]
#[pallet::weight(< T as Config >::WeightInfo::on_initialize_with_bump_era())]
pub fn force_bump_current_era(origin: OriginFor<T>, bump_amount: EraIndex) -> DispatchResult {
#[pallet::weight(< T as Config >::WeightInfo::on_initialize_with_bump_era(T::ProcessRedeemRequestsLimit::get()))]
pub fn force_bump_current_era(origin: OriginFor<T>, bump_amount: EraIndex) -> DispatchResultWithPostInfo {
T::GovernanceOrigin::ensure_origin(origin)?;
Self::bump_current_era(bump_amount)

let res = Self::bump_current_era(bump_amount);
Ok(Some(T::WeightInfo::on_initialize_with_bump_era(res.unwrap_or_default())).into())
}

/// Execute fast match for specific redeem requests, require completely matched.
Expand Down Expand Up @@ -1067,17 +1073,18 @@ pub mod module {

/// Process redeem requests and subaccounts do unbond on relaychain by XCM message.
#[transactional]
pub fn process_redeem_requests(new_era: EraIndex) -> DispatchResult {
pub fn process_redeem_requests(new_era: EraIndex) -> Result<u32, DispatchError> {
let era_index_to_expire = new_era + T::BondingDuration::get();
let total_bonded = TotalStakingBonded::<T>::get();
let mut total_redeem_amount: Balance = Zero::zero();
let mut remain_total_bonded = total_bonded;
let mut handled_requests: u32 = 0;

// iter RedeemRequests and insert to Unbondings if remain_total_bonded is enough.
for (redeemer, (redeem_amount, _)) in RedeemRequests::<T>::iter() {
let redemption_amount = Self::convert_liquid_to_staking(redeem_amount)?;

if remain_total_bonded >= redemption_amount {
if remain_total_bonded >= redemption_amount && handled_requests < T::ProcessRedeemRequestsLimit::get() {
total_redeem_amount = total_redeem_amount.saturating_add(redeem_amount);
remain_total_bonded = remain_total_bonded.saturating_sub(redemption_amount);
RedeemRequests::<T>::remove(&redeemer);
Expand All @@ -1090,6 +1097,8 @@ pub mod module {
liquid_amount: redeem_amount,
unbonding_staking_amount: redemption_amount,
});

handled_requests += 1;
} else {
break;
}
Expand Down Expand Up @@ -1126,7 +1135,9 @@ pub mod module {
}

// burn total_redeem_amount.
Self::burn_liquid_currency(&Self::account_id(), total_redeem_amount)
Self::burn_liquid_currency(&Self::account_id(), total_redeem_amount)?;

Ok(handled_requests)
}

/// Process nominate validators for subaccounts on relaychain.
Expand Down Expand Up @@ -1163,22 +1174,22 @@ pub mod module {
/// The rebalance will send XCM messages to relaychain. Once the XCM message is sent,
/// the execution result cannot be obtained and cannot be rolled back. So the process
/// of rebalance is not atomic.
pub fn bump_current_era(amount: EraIndex) -> DispatchResult {
pub fn bump_current_era(amount: EraIndex) -> Result<u32, DispatchError> {
let previous_era = Self::relay_chain_current_era();
let new_era = previous_era.saturating_add(amount);
RelayChainCurrentEra::<T>::put(new_era);
LastEraBumpedBlock::<T>::put(T::RelayChainBlockNumber::current_block_number());
Self::deposit_event(Event::<T>::CurrentEraBumped { new_era_index: new_era });

// Rebalance:
let res = || -> DispatchResult {
let res = || -> Result<u32, DispatchError> {
TotalVoidLiquid::<T>::put(0);
Self::process_staking_rewards(new_era, previous_era)?;
Self::process_scheduled_unbond(new_era)?;
Self::process_to_bond_pool()?;
Self::process_redeem_requests(new_era)?;
let count = Self::process_redeem_requests(new_era)?;
Self::process_nominate(new_era)?;
Ok(())
Ok(count)
}();

log::debug!(
Expand Down
3 changes: 2 additions & 1 deletion modules/homa/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
use super::*;
use frame_support::{
derive_impl, ord_parameter_types, parameter_types,
traits::{ConstU128, Nothing},
traits::{ConstU128, ConstU32, Nothing},
};
use frame_system::{EnsureRoot, EnsureSignedBy};
use module_support::mocks::MockAddressMapping;
Expand Down Expand Up @@ -216,6 +216,7 @@ impl Config for Runtime {
type XcmInterface = MockHomaSubAccountXcm;
type WeightInfo = ();
type NominationsProvider = MockNominationsProvider;
type ProcessRedeemRequestsLimit = ConstU32<3>;
}

type Block = frame_system::mocking::MockBlock<Runtime>;
Expand Down
79 changes: 73 additions & 6 deletions modules/homa/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1057,7 +1057,7 @@ fn process_redeem_requests_works() {
);

// total_bonded is enough to process all redeem requests
assert_ok!(Homa::process_redeem_requests(1));
assert_eq!(Homa::process_redeem_requests(1), Ok(1));
System::assert_has_event(RuntimeEvent::Homa(crate::Event::RedeemedByUnbond {
redeemer: ALICE,
era_index_when_unbond: 1,
Expand Down Expand Up @@ -1106,7 +1106,7 @@ fn process_redeem_requests_works() {
);

// total_bonded is not enough to process all redeem requests
assert_ok!(Homa::process_redeem_requests(2));
assert_eq!(Homa::process_redeem_requests(2), Ok(2));
System::assert_has_event(RuntimeEvent::Homa(crate::Event::RedeemedByUnbond {
redeemer: BOB,
era_index_when_unbond: 2,
Expand Down Expand Up @@ -1276,7 +1276,7 @@ fn bump_current_era_works() {
// bump era to #1,
// will process to_bond_pool.
MockRelayBlockNumberProvider::set(100);
assert_ok!(Homa::bump_current_era(1));
assert_eq!(Homa::bump_current_era(1), Ok(0));
System::assert_has_event(RuntimeEvent::Homa(crate::Event::CurrentEraBumped { new_era_index: 1 }));
assert_eq!(Homa::last_era_bumped_block(), 100);
assert_eq!(Homa::relay_chain_current_era(), 1);
Expand Down Expand Up @@ -1307,7 +1307,7 @@ fn bump_current_era_works() {
// bump era to #2,
// accumulate staking reward and draw commission
MockRelayBlockNumberProvider::set(200);
assert_ok!(Homa::bump_current_era(1));
assert_eq!(Homa::bump_current_era(1), Ok(0));
System::assert_has_event(RuntimeEvent::Homa(crate::Event::CurrentEraBumped { new_era_index: 2 }));
assert_eq!(Homa::last_era_bumped_block(), 200);
assert_eq!(Homa::relay_chain_current_era(), 2);
Expand Down Expand Up @@ -1358,7 +1358,7 @@ fn bump_current_era_works() {
// bump era to #3,
// will process redeem requests
MockRelayBlockNumberProvider::set(300);
assert_ok!(Homa::bump_current_era(1));
assert_eq!(Homa::bump_current_era(1), Ok(1));
System::assert_has_event(RuntimeEvent::Homa(crate::Event::CurrentEraBumped { new_era_index: 3 }));
System::assert_has_event(RuntimeEvent::Homa(crate::Event::RedeemedByUnbond {
redeemer: ALICE,
Expand Down Expand Up @@ -1404,7 +1404,7 @@ fn bump_current_era_works() {
// bump era to #31,
// will process scheduled unbonded
MockRelayBlockNumberProvider::set(3100);
assert_ok!(Homa::bump_current_era(28));
assert_eq!(Homa::bump_current_era(28), Ok(0));
System::assert_has_event(RuntimeEvent::Homa(crate::Event::CurrentEraBumped { new_era_index: 31 }));
assert_eq!(Homa::last_era_bumped_block(), 3100);
assert_eq!(Homa::relay_chain_current_era(), 31);
Expand Down Expand Up @@ -1483,3 +1483,70 @@ fn last_era_bumped_block_config_check_works() {
assert_eq!(MockRelayBlockNumberProvider::current_block_number(), 100);
});
}

#[test]
fn process_redeem_requests_under_limit_works() {
ExtBuilder::default()
.balances(vec![
(ALICE, LIQUID_CURRENCY_ID, 10_000_000),
(BOB, LIQUID_CURRENCY_ID, 10_000_000),
(CHARLIE, LIQUID_CURRENCY_ID, 10_000_000),
(DAVE, LIQUID_CURRENCY_ID, 10_000_000),
])
.build()
.execute_with(|| {
assert_ok!(Homa::reset_ledgers(
RuntimeOrigin::signed(HomaAdmin::get()),
vec![(0, Some(4_000_000), None)]
));
ToBondPool::<Runtime>::put(4_000_000);

assert_ok!(Homa::request_redeem(RuntimeOrigin::signed(ALICE), 5_000_000, false));
assert_ok!(Homa::request_redeem(RuntimeOrigin::signed(BOB), 5_000_000, false));
assert_ok!(Homa::request_redeem(RuntimeOrigin::signed(CHARLIE), 5_000_000, false));
assert_ok!(Homa::request_redeem(RuntimeOrigin::signed(DAVE), 5_000_000, false));
assert_eq!(Homa::redeem_requests(&ALICE), Some((5_000_000, false)));
assert_eq!(Homa::redeem_requests(&BOB), Some((5_000_000, false)));
assert_eq!(Homa::redeem_requests(&CHARLIE), Some((5_000_000, false)));
assert_eq!(Homa::redeem_requests(&DAVE), Some((5_000_000, false)));
assert_eq!(Homa::unbondings(&ALICE, 1 + BondingDuration::get()), 0);
assert_eq!(Homa::unbondings(&BOB, 1 + BondingDuration::get()), 0);
assert_eq!(Homa::unbondings(&CHARLIE, 1 + BondingDuration::get()), 0);
assert_eq!(Homa::unbondings(&DAVE, 1 + BondingDuration::get()), 0);
assert_eq!(Homa::get_total_bonded(), 4_000_000);
assert_eq!(Currencies::total_issuance(LIQUID_CURRENCY_ID), 40_000_000);

// total_bonded is enough to process all redeem requests, but excceed limit
assert_eq!(Homa::process_redeem_requests(1), Ok(3));
System::assert_has_event(RuntimeEvent::Homa(crate::Event::RedeemedByUnbond {
redeemer: ALICE,
era_index_when_unbond: 1,
liquid_amount: 5_000_000,
unbonding_staking_amount: 1_000_000,
}));
System::assert_has_event(RuntimeEvent::Homa(crate::Event::RedeemedByUnbond {
redeemer: BOB,
era_index_when_unbond: 1,
liquid_amount: 5_000_000,
unbonding_staking_amount: 1_000_000,
}));
System::assert_has_event(RuntimeEvent::Homa(crate::Event::RedeemedByUnbond {
redeemer: CHARLIE,
era_index_when_unbond: 1,
liquid_amount: 5_000_000,
unbonding_staking_amount: 1_000_000,
}));
System::assert_has_event(RuntimeEvent::Homa(crate::Event::HomaUnbond {
sub_account_index: 0,
amount: 3_000_000,
}));
assert_eq!(Homa::redeem_requests(&ALICE), None);
assert_eq!(Homa::redeem_requests(&BOB), None);
assert_eq!(Homa::redeem_requests(&CHARLIE), None);
assert_eq!(Homa::redeem_requests(&DAVE), Some((5_000_000, false)));
assert_eq!(Homa::unbondings(&ALICE, 1 + BondingDuration::get()), 1_000_000);
assert_eq!(Homa::unbondings(&BOB, 1 + BondingDuration::get()), 1_000_000);
assert_eq!(Homa::unbondings(&CHARLIE, 1 + BondingDuration::get()), 1_000_000);
assert_eq!(Homa::unbondings(&DAVE, 1 + BondingDuration::get()), 0);
});
}
10 changes: 7 additions & 3 deletions modules/homa/src/weights.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ use sp_std::marker::PhantomData;
/// Weight functions needed for module_homa.
pub trait WeightInfo {
fn on_initialize() -> Weight;
fn on_initialize_with_bump_era() -> Weight;
fn on_initialize_with_bump_era(n: u32,) -> Weight;
fn mint() -> Weight;
fn request_redeem() -> Weight;
fn fast_match_redeems(n: u32, ) -> Weight;
Expand Down Expand Up @@ -92,10 +92,12 @@ impl<T: frame_system::Config> WeightInfo for AcalaWeight<T> {
// Storage: Homa RedeemRequests (r:2 w:1)
// Storage: Homa Unbondings (r:1 w:1)
// Storage: Homa TotalVoidLiquid (r:0 w:1)
fn on_initialize_with_bump_era() -> Weight {
fn on_initialize_with_bump_era(n: u32,) -> Weight {
Weight::from_parts(253_506_000, 0)
.saturating_add(T::DbWeight::get().reads(31 as u64))
.saturating_add(T::DbWeight::get().reads((2 as u64).saturating_mul(n as u64)))
.saturating_add(T::DbWeight::get().writes(18 as u64))
.saturating_add(T::DbWeight::get().writes((2 as u64).saturating_mul(n as u64)))
}
// Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1)
// Storage: Homa TotalStakingBonded (r:1 w:0)
Expand Down Expand Up @@ -195,10 +197,12 @@ impl WeightInfo for () {
Weight::from_parts(5_281_000, 0)
.saturating_add(RocksDbWeight::get().reads(3 as u64))
}
fn on_initialize_with_bump_era() -> Weight {
fn on_initialize_with_bump_era(n: u32,) -> Weight {
Weight::from_parts(253_506_000, 0)
.saturating_add(RocksDbWeight::get().reads(31 as u64))
.saturating_add(RocksDbWeight::get().reads((2 as u64).saturating_mul(n as u64)))
.saturating_add(RocksDbWeight::get().writes(18 as u64))
.saturating_add(RocksDbWeight::get().writes((2 as u64).saturating_mul(n as u64)))
}
fn mint() -> Weight {
Weight::from_parts(88_950_000, 0)
Expand Down
1 change: 1 addition & 0 deletions runtime/acala/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1594,6 +1594,7 @@ impl module_homa::Config for Runtime {
type XcmInterface = XcmInterface;
type WeightInfo = weights::module_homa::WeightInfo<Runtime>;
type NominationsProvider = NomineesElection;
type ProcessRedeemRequestsLimit = ConstU32<2_000>;
}

parameter_types! {
Expand Down
4 changes: 3 additions & 1 deletion runtime/acala/src/weights/module_homa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,14 +111,16 @@ impl<T: frame_system::Config> module_homa::WeightInfo for WeightInfo<T> {
// Proof: `Homa::Unbondings` (`max_values`: None, `max_size`: None, mode: `Measured`)
// Storage: `Homa::TotalVoidLiquid` (r:0 w:1)
// Proof: `Homa::TotalVoidLiquid` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
fn on_initialize_with_bump_era() -> Weight {
fn on_initialize_with_bump_era(n: u32,) -> Weight {
// Proof Size summary in bytes:
// Measured: `2961`
// Estimated: `13851`
// Minimum execution time: 298_418 nanoseconds.
Weight::from_parts(305_164_000, 13851)
.saturating_add(T::DbWeight::get().reads(32))
.saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(n.into())))
.saturating_add(T::DbWeight::get().writes(18))
.saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(n.into())))
}
// Storage: `Homa::TotalStakingBonded` (r:1 w:0)
// Proof: `Homa::TotalStakingBonded` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
Expand Down
1 change: 1 addition & 0 deletions runtime/common/src/precompile/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -743,6 +743,7 @@ impl module_homa::Config for Test {
type XcmInterface = MockHomaSubAccountXcm;
type WeightInfo = ();
type NominationsProvider = ();
type ProcessRedeemRequestsLimit = ConstU32<2_000>;
}

parameter_type_with_key! {
Expand Down
1 change: 1 addition & 0 deletions runtime/karura/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1619,6 +1619,7 @@ impl module_homa::Config for Runtime {
type XcmInterface = XcmInterface;
type WeightInfo = weights::module_homa::WeightInfo<Runtime>;
type NominationsProvider = NomineesElection;
type ProcessRedeemRequestsLimit = ConstU32<2_000>;
}

parameter_types! {
Expand Down
4 changes: 3 additions & 1 deletion runtime/karura/src/weights/module_homa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,14 +111,16 @@ impl<T: frame_system::Config> module_homa::WeightInfo for WeightInfo<T> {
// Proof: `Homa::Unbondings` (`max_values`: None, `max_size`: None, mode: `Measured`)
// Storage: `Homa::TotalVoidLiquid` (r:0 w:1)
// Proof: `Homa::TotalVoidLiquid` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
fn on_initialize_with_bump_era() -> Weight {
fn on_initialize_with_bump_era(n: u32,) -> Weight {
// Proof Size summary in bytes:
// Measured: `2962`
// Estimated: `13852`
// Minimum execution time: 314_492 nanoseconds.
Weight::from_parts(320_994_000, 13852)
.saturating_add(T::DbWeight::get().reads(34))
.saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(n.into())))
.saturating_add(T::DbWeight::get().writes(19))
.saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(n.into())))
}
// Storage: `Homa::TotalStakingBonded` (r:1 w:0)
// Proof: `Homa::TotalStakingBonded` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
Expand Down
Loading
Loading