Skip to content

Commit c167ef9

Browse files
committed
dapp-staking mbm
1 parent 9a03163 commit c167ef9

File tree

10 files changed

+279
-10
lines changed

10 files changed

+279
-10
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pallets/dapp-staking/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ frame-benchmarking = { workspace = true, optional = true }
2929

3030
[dev-dependencies]
3131
pallet-balances = { workspace = true }
32+
pallet-migrations = { workspace = true }
3233

3334
[features]
3435
default = ["std"]

pallets/dapp-staking/src/benchmarking/mod.rs

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use super::{Pallet as DappStaking, *};
2121
use astar_primitives::Balance;
2222
use frame_benchmarking::v2::*;
2323

24-
use frame_support::assert_ok;
24+
use frame_support::{assert_ok, migrations::SteppedMigration, weights::WeightMeter};
2525
use frame_system::{Pallet as System, RawOrigin};
2626
use sp_std::prelude::*;
2727

@@ -1070,6 +1070,73 @@ mod benchmarks {
10701070
);
10711071
}
10721072

1073+
/// Benchmark a single step of mbm migration.
1074+
#[benchmark]
1075+
fn step() {
1076+
let alice: T::AccountId = account("alice", 0, 1);
1077+
1078+
Ledger::<T>::set(
1079+
&alice,
1080+
AccountLedger {
1081+
locked: 1000,
1082+
unlocking: vec![
1083+
UnlockingChunk {
1084+
amount: 100,
1085+
unlock_block: 5,
1086+
},
1087+
UnlockingChunk {
1088+
amount: 100,
1089+
unlock_block: 20,
1090+
},
1091+
]
1092+
.try_into()
1093+
.unwrap(),
1094+
staked: Default::default(),
1095+
staked_future: None,
1096+
contract_stake_count: 0,
1097+
},
1098+
);
1099+
CurrentEraInfo::<T>::put(EraInfo {
1100+
total_locked: 1000,
1101+
unlocking: 200,
1102+
current_stake_amount: Default::default(),
1103+
next_stake_amount: Default::default(),
1104+
});
1105+
1106+
System::<T>::set_block_number(10u32.into());
1107+
let mut meter = WeightMeter::new();
1108+
1109+
#[block]
1110+
{
1111+
crate::migration::LazyMigration::<T, weights::SubstrateWeight<T>>::step(
1112+
None, &mut meter,
1113+
)
1114+
.unwrap();
1115+
}
1116+
1117+
assert_eq!(
1118+
Ledger::<T>::get(&alice),
1119+
AccountLedger {
1120+
locked: 1000,
1121+
unlocking: vec![
1122+
UnlockingChunk {
1123+
amount: 100,
1124+
unlock_block: 5, // already unlocked
1125+
},
1126+
UnlockingChunk {
1127+
amount: 100,
1128+
unlock_block: 30, // double remaining blocks
1129+
},
1130+
]
1131+
.try_into()
1132+
.unwrap(),
1133+
staked: Default::default(),
1134+
staked_future: None,
1135+
contract_stake_count: 0,
1136+
}
1137+
);
1138+
}
1139+
10731140
impl_benchmark_test_suite!(
10741141
Pallet,
10751142
crate::benchmarking::tests::new_test_ext(),

pallets/dapp-staking/src/migration.rs

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,12 @@
1717
// along with Astar. If not, see <http://www.gnu.org/licenses/>.
1818

1919
use super::*;
20-
use frame_support::{storage_alias, traits::UncheckedOnRuntimeUpgrade};
20+
use frame_support::{
21+
migrations::{MigrationId, SteppedMigration, SteppedMigrationError},
22+
storage_alias,
23+
traits::UncheckedOnRuntimeUpgrade,
24+
weights::WeightMeter,
25+
};
2126

2227
#[cfg(feature = "try-runtime")]
2328
use sp_std::vec::Vec;
@@ -412,3 +417,80 @@ pub mod v6 {
412417
pub period: PeriodNumber,
413418
}
414419
}
420+
421+
const PALLET_MIGRATIONS_ID: &[u8; 16] = b"dapp-staking-mbm";
422+
423+
pub struct LazyMigration<T, W: WeightInfo>(PhantomData<(T, W)>);
424+
425+
impl<T: Config, W: WeightInfo> SteppedMigration for LazyMigration<T, W> {
426+
type Cursor = <T as frame_system::Config>::AccountId;
427+
// Without the explicit length here the construction of the ID would not be infallible.
428+
type Identifier = MigrationId<16>;
429+
430+
/// The identifier of this migration. Which should be globally unique.
431+
fn id() -> Self::Identifier {
432+
MigrationId {
433+
pallet_id: *PALLET_MIGRATIONS_ID,
434+
version_from: 0,
435+
version_to: 1,
436+
}
437+
}
438+
439+
fn step(
440+
mut cursor: Option<Self::Cursor>,
441+
meter: &mut WeightMeter,
442+
) -> Result<Option<Self::Cursor>, SteppedMigrationError> {
443+
let required = W::step();
444+
// If there is not enough weight for a single step, return an error. This case can be
445+
// problematic if it is the first migration that ran in this block. But there is nothing
446+
// that we can do about it here.
447+
if meter.remaining().any_lt(required) {
448+
return Err(SteppedMigrationError::InsufficientWeight { required });
449+
}
450+
451+
let mut count = 0u32;
452+
let current_block_number =
453+
frame_system::Pallet::<T>::block_number().saturated_into::<u32>();
454+
455+
// We loop here to do as much progress as possible per step.
456+
loop {
457+
if meter.try_consume(required).is_err() {
458+
break;
459+
}
460+
461+
let mut iter = if let Some(last_key) = cursor {
462+
// If a cursor is provided, start iterating from the stored value
463+
// corresponding to the last key processed in the previous step.
464+
// Note that this only works if the old and the new map use the same way to hash
465+
// storage keys.
466+
Ledger::<T>::iter_from(Ledger::<T>::hashed_key_for(last_key))
467+
} else {
468+
// If no cursor is provided, start iterating from the beginning.
469+
Ledger::<T>::iter()
470+
};
471+
472+
// If there's a next item in the iterator, perform the migration.
473+
if let Some((ref last_key, mut ledger)) = iter.next() {
474+
for chunk in ledger.unlocking.iter_mut() {
475+
let remaining_blocks = chunk.unlock_block.saturating_sub(current_block_number);
476+
chunk.unlock_block.saturating_accrue(remaining_blocks);
477+
}
478+
479+
// Override ledger
480+
Ledger::<T>::insert(last_key, ledger);
481+
482+
// inc counter
483+
count.saturating_inc();
484+
485+
// Return the processed key as the new cursor.
486+
cursor = Some(last_key.clone())
487+
} else {
488+
// Signal that the migration is complete (no more items to process).
489+
cursor = None;
490+
break;
491+
}
492+
}
493+
log::debug!(target: LOG_TARGET, "migrated {count:?} entries");
494+
Ok(cursor)
495+
}
496+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// This file is part of Astar.
2+
3+
// Copyright (C) Stake Technologies Pte.Ltd.
4+
// SPDX-License-Identifier: GPL-3.0-or-later
5+
6+
// Astar is free software: you can redistribute it and/or modify
7+
// it under the terms of the GNU General Public License as published by
8+
// the Free Software Foundation, either version 3 of the License, or
9+
// (at your option) any later version.
10+
11+
// Astar is distributed in the hope that it will be useful,
12+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
// GNU General Public License for more details.
15+
16+
// You should have received a copy of the GNU General Public License
17+
// along with Astar. If not, see <http://www.gnu.org/licenses/>.
18+
19+
#![cfg(all(test, not(feature = "runtime-benchmarks")))]
20+
21+
use crate::test::mock::*;
22+
use crate::{AccountLedger, CurrentEraInfo, EraInfo, Ledger, UnlockingChunk};
23+
use frame_support::traits::OnRuntimeUpgrade;
24+
25+
#[test]
26+
fn lazy_migrations() {
27+
ExtBuilder::default().build_and_execute(|| {
28+
Ledger::<Test>::set(
29+
&1,
30+
AccountLedger {
31+
locked: 1000,
32+
unlocking: vec![
33+
UnlockingChunk {
34+
amount: 100,
35+
unlock_block: 5,
36+
},
37+
UnlockingChunk {
38+
amount: 100,
39+
unlock_block: 20,
40+
},
41+
]
42+
.try_into()
43+
.unwrap(),
44+
staked: Default::default(),
45+
staked_future: None,
46+
contract_stake_count: 0,
47+
},
48+
);
49+
CurrentEraInfo::<Test>::put(EraInfo {
50+
total_locked: 1000,
51+
unlocking: 200,
52+
current_stake_amount: Default::default(),
53+
next_stake_amount: Default::default(),
54+
});
55+
56+
// go to block before migration
57+
run_to_block(9);
58+
59+
// onboard MBMs
60+
AllPalletsWithSystem::on_runtime_upgrade();
61+
run_to_block(10);
62+
63+
assert_eq!(
64+
Ledger::<Test>::get(&1),
65+
AccountLedger {
66+
locked: 1000,
67+
unlocking: vec![
68+
UnlockingChunk {
69+
amount: 100,
70+
unlock_block: 5, // already unlocked
71+
},
72+
UnlockingChunk {
73+
amount: 100,
74+
unlock_block: 30, // double remaining blocks
75+
},
76+
]
77+
.try_into()
78+
.unwrap(),
79+
staked: Default::default(),
80+
staked_future: None,
81+
contract_stake_count: 0,
82+
}
83+
);
84+
})
85+
}

pallets/dapp-staking/src/test/mock.rs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ use crate::{
2323
};
2424

2525
use frame_support::{
26-
construct_runtime, ord_parameter_types, parameter_types,
26+
construct_runtime, derive_impl,
27+
migrations::MultiStepMigrator,
28+
ord_parameter_types, parameter_types,
2729
traits::{fungible::Mutate as FunMutate, ConstBool, ConstU128, ConstU32, EitherOfDiverse},
2830
weights::Weight,
2931
};
@@ -54,6 +56,7 @@ construct_runtime!(
5456
System: frame_system,
5557
Balances: pallet_balances,
5658
DappStaking: pallet_dapp_staking,
59+
MultiBlockMigrations: pallet_migrations,
5760
}
5861
);
5962

@@ -89,7 +92,7 @@ impl frame_system::Config for Test {
8992
type MaxConsumers = frame_support::traits::ConstU32<16>;
9093
type RuntimeTask = RuntimeTask;
9194
type SingleBlockMigrations = ();
92-
type MultiBlockMigrator = ();
95+
type MultiBlockMigrator = MultiBlockMigrations;
9396
type PreInherents = ();
9497
type PostInherents = ();
9598
type PostTransactions = ();
@@ -111,6 +114,21 @@ impl pallet_balances::Config for Test {
111114
type WeightInfo = ();
112115
}
113116

117+
parameter_types! {
118+
pub const MaxServiceWeight: Weight = Weight::from_parts(1_000_000_000, 1_000_000);
119+
}
120+
121+
#[derive_impl(pallet_migrations::config_preludes::TestDefaultConfig)]
122+
impl pallet_migrations::Config for Test {
123+
#[cfg(not(feature = "runtime-benchmarks"))]
124+
type Migrations =
125+
(crate::migration::LazyMigration<Test, crate::weights::SubstrateWeight<Test>>,);
126+
#[cfg(feature = "runtime-benchmarks")]
127+
type Migrations = pallet_migrations::mock_helpers::MockedMigrations;
128+
type MigrationStatusHandler = ();
129+
type MaxServiceWeight = MaxServiceWeight;
130+
}
131+
114132
pub struct DummyPriceProvider;
115133
impl PriceProvider for DummyPriceProvider {
116134
fn average_price() -> FixedU128 {
@@ -397,6 +415,9 @@ pub(crate) fn run_to_block(n: BlockNumber) {
397415
System::set_block_number(System::block_number() + 1);
398416
// This is performed outside of dapps staking but we expect it before on_initialize
399417

418+
// Done by Executive:
419+
<Test as frame_system::Config>::MultiBlockMigrator::step();
420+
400421
let pre_snapshot = MemorySnapshot::new();
401422
DappStaking::on_initialize(System::block_number());
402423
assert_block_bump(&pre_snapshot);

pallets/dapp-staking/src/test/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
// You should have received a copy of the GNU General Public License
1717
// along with Astar. If not, see <http://www.gnu.org/licenses/>.
1818

19+
mod migrations;
1920
pub(crate) mod mock;
2021
mod testing_utils;
2122
mod tests;

pallets/dapp-staking/src/weights.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ pub trait WeightInfo {
7373
fn on_initialize_build_and_earn_to_build_and_earn() -> Weight;
7474
fn dapp_tier_assignment(x: u32, ) -> Weight;
7575
fn on_idle_cleanup() -> Weight;
76+
fn step() -> Weight;
7677
}
7778

7879
/// Weights for pallet_dapp_staking using the Substrate node and recommended hardware.
@@ -477,6 +478,10 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
477478
.saturating_add(T::DbWeight::get().reads(2_u64))
478479
.saturating_add(T::DbWeight::get().writes(3_u64))
479480
}
481+
482+
fn step() -> Weight {
483+
Weight::default()
484+
}
480485
}
481486

482487
// For backwards compatibility and tests
@@ -880,4 +885,8 @@ impl WeightInfo for () {
880885
.saturating_add(RocksDbWeight::get().reads(2_u64))
881886
.saturating_add(RocksDbWeight::get().writes(3_u64))
882887
}
888+
889+
fn step() -> Weight {
890+
Weight::default()
891+
}
883892
}

pallets/vesting-mbm/src/lib.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,7 @@ const PALLET_MIGRATIONS_ID: &[u8; 18] = b"pallet-vesting-mbm";
4242

4343
pub struct LazyMigration<T, W: weights::WeightInfo>(core::marker::PhantomData<(T, W)>);
4444

45-
impl<T, W: weights::WeightInfo> SteppedMigration for LazyMigration<T, W>
46-
where
47-
T: frame_system::Config + pallet_vesting::Config,
48-
{
45+
impl<T: pallet_vesting::Config, W: weights::WeightInfo> SteppedMigration for LazyMigration<T, W> {
4946
type Cursor = <T as frame_system::Config>::AccountId;
5047
// Without the explicit length here the construction of the ID would not be infallible.
5148
type Identifier = MigrationId<18>;

0 commit comments

Comments
 (0)