Skip to content

Commit c62a288

Browse files
wangjj9219xlc
authored andcommitted
Limit process redeem requests (#2806)
* limit process redeem requests * fix benchmarks * update
1 parent 276434b commit c62a288

File tree

12 files changed

+138
-29
lines changed

12 files changed

+138
-29
lines changed

modules/homa/src/lib.rs

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,10 @@ pub mod module {
156156
/// The XcmInterface to manage the staking of sub-account on relaychain.
157157
type XcmInterface: HomaSubAccountXcm<Self::AccountId, Balance>;
158158

159+
/// The limit for process redeem requests when bump era.
160+
#[pallet::constant]
161+
type ProcessRedeemRequestsLimit: Get<u32>;
162+
159163
/// Weight information for the extrinsics in this module.
160164
type WeightInfo: WeightInfo;
161165

@@ -383,14 +387,14 @@ pub mod module {
383387
fn on_initialize(_: BlockNumberFor<T>) -> Weight {
384388
let bump_era_number = Self::era_amount_should_to_bump(T::RelayChainBlockNumber::current_block_number());
385389
if !bump_era_number.is_zero() {
386-
let _ = Self::bump_current_era(bump_era_number);
390+
let res = Self::bump_current_era(bump_era_number);
387391
debug_assert_eq!(
388392
TotalStakingBonded::<T>::get(),
389393
StakingLedgers::<T>::iter().fold(Zero::zero(), |total_bonded: Balance, (_, ledger)| {
390394
total_bonded.saturating_add(ledger.bonded)
391395
})
392396
);
393-
<T as Config>::WeightInfo::on_initialize_with_bump_era()
397+
<T as Config>::WeightInfo::on_initialize_with_bump_era(res.unwrap_or_default())
394398
} else {
395399
<T as Config>::WeightInfo::on_initialize()
396400
}
@@ -659,10 +663,12 @@ pub mod module {
659663
}
660664

661665
#[pallet::call_index(8)]
662-
#[pallet::weight(< T as Config >::WeightInfo::on_initialize_with_bump_era())]
663-
pub fn force_bump_current_era(origin: OriginFor<T>, bump_amount: EraIndex) -> DispatchResult {
666+
#[pallet::weight(< T as Config >::WeightInfo::on_initialize_with_bump_era(T::ProcessRedeemRequestsLimit::get()))]
667+
pub fn force_bump_current_era(origin: OriginFor<T>, bump_amount: EraIndex) -> DispatchResultWithPostInfo {
664668
T::GovernanceOrigin::ensure_origin(origin)?;
665-
Self::bump_current_era(bump_amount)
669+
670+
let res = Self::bump_current_era(bump_amount);
671+
Ok(Some(T::WeightInfo::on_initialize_with_bump_era(res.unwrap_or_default())).into())
666672
}
667673

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

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

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

1080-
if remain_total_bonded >= redemption_amount {
1087+
if remain_total_bonded >= redemption_amount && handled_requests < T::ProcessRedeemRequestsLimit::get() {
10811088
total_redeem_amount = total_redeem_amount.saturating_add(redeem_amount);
10821089
remain_total_bonded = remain_total_bonded.saturating_sub(redemption_amount);
10831090
RedeemRequests::<T>::remove(&redeemer);
@@ -1090,6 +1097,8 @@ pub mod module {
10901097
liquid_amount: redeem_amount,
10911098
unbonding_staking_amount: redemption_amount,
10921099
});
1100+
1101+
handled_requests += 1;
10931102
} else {
10941103
break;
10951104
}
@@ -1126,7 +1135,9 @@ pub mod module {
11261135
}
11271136

11281137
// burn total_redeem_amount.
1129-
Self::burn_liquid_currency(&Self::account_id(), total_redeem_amount)
1138+
Self::burn_liquid_currency(&Self::account_id(), total_redeem_amount)?;
1139+
1140+
Ok(handled_requests)
11301141
}
11311142

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

11731184
// Rebalance:
1174-
let res = || -> DispatchResult {
1185+
let res = || -> Result<u32, DispatchError> {
11751186
TotalVoidLiquid::<T>::put(0);
11761187
Self::process_staking_rewards(new_era, previous_era)?;
11771188
Self::process_scheduled_unbond(new_era)?;
11781189
Self::process_to_bond_pool()?;
1179-
Self::process_redeem_requests(new_era)?;
1190+
let count = Self::process_redeem_requests(new_era)?;
11801191
Self::process_nominate(new_era)?;
1181-
Ok(())
1192+
Ok(count)
11821193
}();
11831194

11841195
log::debug!(

modules/homa/src/mock.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
use super::*;
2424
use frame_support::{
2525
derive_impl, ord_parameter_types, parameter_types,
26-
traits::{ConstU128, Nothing},
26+
traits::{ConstU128, ConstU32, Nothing},
2727
};
2828
use frame_system::{EnsureRoot, EnsureSignedBy};
2929
use module_support::mocks::MockAddressMapping;
@@ -216,6 +216,7 @@ impl Config for Runtime {
216216
type XcmInterface = MockHomaSubAccountXcm;
217217
type WeightInfo = ();
218218
type NominationsProvider = MockNominationsProvider;
219+
type ProcessRedeemRequestsLimit = ConstU32<3>;
219220
}
220221

221222
type Block = frame_system::mocking::MockBlock<Runtime>;

modules/homa/src/tests.rs

Lines changed: 73 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1057,7 +1057,7 @@ fn process_redeem_requests_works() {
10571057
);
10581058

10591059
// total_bonded is enough to process all redeem requests
1060-
assert_ok!(Homa::process_redeem_requests(1));
1060+
assert_eq!(Homa::process_redeem_requests(1), Ok(1));
10611061
System::assert_has_event(RuntimeEvent::Homa(crate::Event::RedeemedByUnbond {
10621062
redeemer: ALICE,
10631063
era_index_when_unbond: 1,
@@ -1106,7 +1106,7 @@ fn process_redeem_requests_works() {
11061106
);
11071107

11081108
// total_bonded is not enough to process all redeem requests
1109-
assert_ok!(Homa::process_redeem_requests(2));
1109+
assert_eq!(Homa::process_redeem_requests(2), Ok(2));
11101110
System::assert_has_event(RuntimeEvent::Homa(crate::Event::RedeemedByUnbond {
11111111
redeemer: BOB,
11121112
era_index_when_unbond: 2,
@@ -1276,7 +1276,7 @@ fn bump_current_era_works() {
12761276
// bump era to #1,
12771277
// will process to_bond_pool.
12781278
MockRelayBlockNumberProvider::set(100);
1279-
assert_ok!(Homa::bump_current_era(1));
1279+
assert_eq!(Homa::bump_current_era(1), Ok(0));
12801280
System::assert_has_event(RuntimeEvent::Homa(crate::Event::CurrentEraBumped { new_era_index: 1 }));
12811281
assert_eq!(Homa::last_era_bumped_block(), 100);
12821282
assert_eq!(Homa::relay_chain_current_era(), 1);
@@ -1307,7 +1307,7 @@ fn bump_current_era_works() {
13071307
// bump era to #2,
13081308
// accumulate staking reward and draw commission
13091309
MockRelayBlockNumberProvider::set(200);
1310-
assert_ok!(Homa::bump_current_era(1));
1310+
assert_eq!(Homa::bump_current_era(1), Ok(0));
13111311
System::assert_has_event(RuntimeEvent::Homa(crate::Event::CurrentEraBumped { new_era_index: 2 }));
13121312
assert_eq!(Homa::last_era_bumped_block(), 200);
13131313
assert_eq!(Homa::relay_chain_current_era(), 2);
@@ -1358,7 +1358,7 @@ fn bump_current_era_works() {
13581358
// bump era to #3,
13591359
// will process redeem requests
13601360
MockRelayBlockNumberProvider::set(300);
1361-
assert_ok!(Homa::bump_current_era(1));
1361+
assert_eq!(Homa::bump_current_era(1), Ok(1));
13621362
System::assert_has_event(RuntimeEvent::Homa(crate::Event::CurrentEraBumped { new_era_index: 3 }));
13631363
System::assert_has_event(RuntimeEvent::Homa(crate::Event::RedeemedByUnbond {
13641364
redeemer: ALICE,
@@ -1404,7 +1404,7 @@ fn bump_current_era_works() {
14041404
// bump era to #31,
14051405
// will process scheduled unbonded
14061406
MockRelayBlockNumberProvider::set(3100);
1407-
assert_ok!(Homa::bump_current_era(28));
1407+
assert_eq!(Homa::bump_current_era(28), Ok(0));
14081408
System::assert_has_event(RuntimeEvent::Homa(crate::Event::CurrentEraBumped { new_era_index: 31 }));
14091409
assert_eq!(Homa::last_era_bumped_block(), 3100);
14101410
assert_eq!(Homa::relay_chain_current_era(), 31);
@@ -1483,3 +1483,70 @@ fn last_era_bumped_block_config_check_works() {
14831483
assert_eq!(MockRelayBlockNumberProvider::current_block_number(), 100);
14841484
});
14851485
}
1486+
1487+
#[test]
1488+
fn process_redeem_requests_under_limit_works() {
1489+
ExtBuilder::default()
1490+
.balances(vec![
1491+
(ALICE, LIQUID_CURRENCY_ID, 10_000_000),
1492+
(BOB, LIQUID_CURRENCY_ID, 10_000_000),
1493+
(CHARLIE, LIQUID_CURRENCY_ID, 10_000_000),
1494+
(DAVE, LIQUID_CURRENCY_ID, 10_000_000),
1495+
])
1496+
.build()
1497+
.execute_with(|| {
1498+
assert_ok!(Homa::reset_ledgers(
1499+
RuntimeOrigin::signed(HomaAdmin::get()),
1500+
vec![(0, Some(4_000_000), None)]
1501+
));
1502+
ToBondPool::<Runtime>::put(4_000_000);
1503+
1504+
assert_ok!(Homa::request_redeem(RuntimeOrigin::signed(ALICE), 5_000_000, false));
1505+
assert_ok!(Homa::request_redeem(RuntimeOrigin::signed(BOB), 5_000_000, false));
1506+
assert_ok!(Homa::request_redeem(RuntimeOrigin::signed(CHARLIE), 5_000_000, false));
1507+
assert_ok!(Homa::request_redeem(RuntimeOrigin::signed(DAVE), 5_000_000, false));
1508+
assert_eq!(Homa::redeem_requests(&ALICE), Some((5_000_000, false)));
1509+
assert_eq!(Homa::redeem_requests(&BOB), Some((5_000_000, false)));
1510+
assert_eq!(Homa::redeem_requests(&CHARLIE), Some((5_000_000, false)));
1511+
assert_eq!(Homa::redeem_requests(&DAVE), Some((5_000_000, false)));
1512+
assert_eq!(Homa::unbondings(&ALICE, 1 + BondingDuration::get()), 0);
1513+
assert_eq!(Homa::unbondings(&BOB, 1 + BondingDuration::get()), 0);
1514+
assert_eq!(Homa::unbondings(&CHARLIE, 1 + BondingDuration::get()), 0);
1515+
assert_eq!(Homa::unbondings(&DAVE, 1 + BondingDuration::get()), 0);
1516+
assert_eq!(Homa::get_total_bonded(), 4_000_000);
1517+
assert_eq!(Currencies::total_issuance(LIQUID_CURRENCY_ID), 40_000_000);
1518+
1519+
// total_bonded is enough to process all redeem requests, but excceed limit
1520+
assert_eq!(Homa::process_redeem_requests(1), Ok(3));
1521+
System::assert_has_event(RuntimeEvent::Homa(crate::Event::RedeemedByUnbond {
1522+
redeemer: ALICE,
1523+
era_index_when_unbond: 1,
1524+
liquid_amount: 5_000_000,
1525+
unbonding_staking_amount: 1_000_000,
1526+
}));
1527+
System::assert_has_event(RuntimeEvent::Homa(crate::Event::RedeemedByUnbond {
1528+
redeemer: BOB,
1529+
era_index_when_unbond: 1,
1530+
liquid_amount: 5_000_000,
1531+
unbonding_staking_amount: 1_000_000,
1532+
}));
1533+
System::assert_has_event(RuntimeEvent::Homa(crate::Event::RedeemedByUnbond {
1534+
redeemer: CHARLIE,
1535+
era_index_when_unbond: 1,
1536+
liquid_amount: 5_000_000,
1537+
unbonding_staking_amount: 1_000_000,
1538+
}));
1539+
System::assert_has_event(RuntimeEvent::Homa(crate::Event::HomaUnbond {
1540+
sub_account_index: 0,
1541+
amount: 3_000_000,
1542+
}));
1543+
assert_eq!(Homa::redeem_requests(&ALICE), None);
1544+
assert_eq!(Homa::redeem_requests(&BOB), None);
1545+
assert_eq!(Homa::redeem_requests(&CHARLIE), None);
1546+
assert_eq!(Homa::redeem_requests(&DAVE), Some((5_000_000, false)));
1547+
assert_eq!(Homa::unbondings(&ALICE, 1 + BondingDuration::get()), 1_000_000);
1548+
assert_eq!(Homa::unbondings(&BOB, 1 + BondingDuration::get()), 1_000_000);
1549+
assert_eq!(Homa::unbondings(&CHARLIE, 1 + BondingDuration::get()), 1_000_000);
1550+
assert_eq!(Homa::unbondings(&DAVE, 1 + BondingDuration::get()), 0);
1551+
});
1552+
}

modules/homa/src/weights.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ use sp_std::marker::PhantomData;
4848
/// Weight functions needed for module_homa.
4949
pub trait WeightInfo {
5050
fn on_initialize() -> Weight;
51-
fn on_initialize_with_bump_era() -> Weight;
51+
fn on_initialize_with_bump_era(n: u32,) -> Weight;
5252
fn mint() -> Weight;
5353
fn request_redeem() -> Weight;
5454
fn fast_match_redeems(n: u32, ) -> Weight;
@@ -92,10 +92,12 @@ impl<T: frame_system::Config> WeightInfo for AcalaWeight<T> {
9292
// Storage: Homa RedeemRequests (r:2 w:1)
9393
// Storage: Homa Unbondings (r:1 w:1)
9494
// Storage: Homa TotalVoidLiquid (r:0 w:1)
95-
fn on_initialize_with_bump_era() -> Weight {
95+
fn on_initialize_with_bump_era(n: u32,) -> Weight {
9696
Weight::from_parts(253_506_000, 0)
9797
.saturating_add(T::DbWeight::get().reads(31 as u64))
98+
.saturating_add(T::DbWeight::get().reads((2 as u64).saturating_mul(n as u64)))
9899
.saturating_add(T::DbWeight::get().writes(18 as u64))
100+
.saturating_add(T::DbWeight::get().writes((2 as u64).saturating_mul(n as u64)))
99101
}
100102
// Storage: unknown [0x3a7472616e73616374696f6e5f6c6576656c3a] (r:1 w:1)
101103
// Storage: Homa TotalStakingBonded (r:1 w:0)
@@ -195,10 +197,12 @@ impl WeightInfo for () {
195197
Weight::from_parts(5_281_000, 0)
196198
.saturating_add(RocksDbWeight::get().reads(3 as u64))
197199
}
198-
fn on_initialize_with_bump_era() -> Weight {
200+
fn on_initialize_with_bump_era(n: u32,) -> Weight {
199201
Weight::from_parts(253_506_000, 0)
200202
.saturating_add(RocksDbWeight::get().reads(31 as u64))
203+
.saturating_add(RocksDbWeight::get().reads((2 as u64).saturating_mul(n as u64)))
201204
.saturating_add(RocksDbWeight::get().writes(18 as u64))
205+
.saturating_add(RocksDbWeight::get().writes((2 as u64).saturating_mul(n as u64)))
202206
}
203207
fn mint() -> Weight {
204208
Weight::from_parts(88_950_000, 0)

runtime/acala/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1592,6 +1592,7 @@ impl module_homa::Config for Runtime {
15921592
type XcmInterface = XcmInterface;
15931593
type WeightInfo = weights::module_homa::WeightInfo<Runtime>;
15941594
type NominationsProvider = NomineesElection;
1595+
type ProcessRedeemRequestsLimit = ConstU32<2_000>;
15951596
}
15961597

15971598
parameter_types! {

runtime/acala/src/weights/module_homa.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,14 +111,16 @@ impl<T: frame_system::Config> module_homa::WeightInfo for WeightInfo<T> {
111111
// Proof: `Homa::Unbondings` (`max_values`: None, `max_size`: None, mode: `Measured`)
112112
// Storage: `Homa::TotalVoidLiquid` (r:0 w:1)
113113
// Proof: `Homa::TotalVoidLiquid` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
114-
fn on_initialize_with_bump_era() -> Weight {
114+
fn on_initialize_with_bump_era(n: u32,) -> Weight {
115115
// Proof Size summary in bytes:
116116
// Measured: `2961`
117117
// Estimated: `13851`
118118
// Minimum execution time: 298_418 nanoseconds.
119119
Weight::from_parts(305_164_000, 13851)
120120
.saturating_add(T::DbWeight::get().reads(32))
121+
.saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(n.into())))
121122
.saturating_add(T::DbWeight::get().writes(18))
123+
.saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(n.into())))
122124
}
123125
// Storage: `Homa::TotalStakingBonded` (r:1 w:0)
124126
// Proof: `Homa::TotalStakingBonded` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)

runtime/common/src/precompile/mock.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -743,6 +743,7 @@ impl module_homa::Config for Test {
743743
type XcmInterface = MockHomaSubAccountXcm;
744744
type WeightInfo = ();
745745
type NominationsProvider = ();
746+
type ProcessRedeemRequestsLimit = ConstU32<2_000>;
746747
}
747748

748749
parameter_type_with_key! {

runtime/karura/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1617,6 +1617,7 @@ impl module_homa::Config for Runtime {
16171617
type XcmInterface = XcmInterface;
16181618
type WeightInfo = weights::module_homa::WeightInfo<Runtime>;
16191619
type NominationsProvider = NomineesElection;
1620+
type ProcessRedeemRequestsLimit = ConstU32<2_000>;
16201621
}
16211622

16221623
parameter_types! {

runtime/karura/src/weights/module_homa.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,14 +111,16 @@ impl<T: frame_system::Config> module_homa::WeightInfo for WeightInfo<T> {
111111
// Proof: `Homa::Unbondings` (`max_values`: None, `max_size`: None, mode: `Measured`)
112112
// Storage: `Homa::TotalVoidLiquid` (r:0 w:1)
113113
// Proof: `Homa::TotalVoidLiquid` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
114-
fn on_initialize_with_bump_era() -> Weight {
114+
fn on_initialize_with_bump_era(n: u32,) -> Weight {
115115
// Proof Size summary in bytes:
116116
// Measured: `2962`
117117
// Estimated: `13852`
118118
// Minimum execution time: 314_492 nanoseconds.
119119
Weight::from_parts(320_994_000, 13852)
120120
.saturating_add(T::DbWeight::get().reads(34))
121+
.saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(n.into())))
121122
.saturating_add(T::DbWeight::get().writes(19))
123+
.saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(n.into())))
122124
}
123125
// Storage: `Homa::TotalStakingBonded` (r:1 w:0)
124126
// Proof: `Homa::TotalStakingBonded` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)

0 commit comments

Comments
 (0)