Skip to content

Commit ea4085a

Browse files
bkchrliamaharonggwpez
authored
frame-system: Add last_runtime_upgrade_spec_version (#2351)
Adds a function for querying the last runtime upgrade spec version. This can be useful for when writing runtime level migrations to ensure that they are not executed multiple times. An example would be a session key migration. --------- Co-authored-by: Liam Aharon <liam.aharon@hotmail.com> Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
1 parent f4bb17c commit ea4085a

5 files changed

Lines changed: 71 additions & 27 deletions

File tree

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.

substrate/frame/executive/src/lib.rs

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,12 @@ where
487487
let mut weight = Weight::zero();
488488
if Self::runtime_upgraded() {
489489
weight = weight.saturating_add(Self::execute_on_runtime_upgrade());
490+
491+
frame_system::LastRuntimeUpgrade::<System>::put(
492+
frame_system::LastRuntimeUpgradeInfo::from(
493+
<System::Version as frame_support::traits::Get<_>>::get(),
494+
),
495+
);
490496
}
491497
<frame_system::Pallet<System>>::initialize(block_number, parent_hash, digest);
492498
weight = weight.saturating_add(<AllPalletsWithSystem as OnInitialize<
@@ -503,19 +509,12 @@ where
503509
frame_system::Pallet::<System>::note_finished_initialize();
504510
}
505511

506-
/// Returns if the runtime was upgraded since the last time this function was called.
512+
/// Returns if the runtime has been upgraded, based on [`frame_system::LastRuntimeUpgrade`].
507513
fn runtime_upgraded() -> bool {
508514
let last = frame_system::LastRuntimeUpgrade::<System>::get();
509515
let current = <System::Version as frame_support::traits::Get<_>>::get();
510516

511-
if last.map(|v| v.was_upgraded(&current)).unwrap_or(true) {
512-
frame_system::LastRuntimeUpgrade::<System>::put(
513-
frame_system::LastRuntimeUpgradeInfo::from(current),
514-
);
515-
true
516-
} else {
517-
false
518-
}
517+
last.map(|v| v.was_upgraded(&current)).unwrap_or(true)
519518
}
520519

521520
fn initial_checks(block: &Block) {
@@ -755,7 +754,7 @@ mod tests {
755754
traits::{fungible, ConstU32, ConstU64, ConstU8, Currency},
756755
weights::{ConstantMultiplier, IdentityFee, RuntimeDbWeight, Weight, WeightToFee},
757756
};
758-
use frame_system::{ChainContext, LastRuntimeUpgradeInfo};
757+
use frame_system::{ChainContext, LastRuntimeUpgrade, LastRuntimeUpgradeInfo};
759758
use pallet_balances::Call as BalancesCall;
760759
use pallet_transaction_payment::CurrencyAdapter;
761760

@@ -994,6 +993,9 @@ mod tests {
994993
sp_io::storage::set(TEST_KEY, "custom_upgrade".as_bytes());
995994
sp_io::storage::set(CUSTOM_ON_RUNTIME_KEY, &true.encode());
996995
System::deposit_event(frame_system::Event::CodeUpdated);
996+
997+
assert_eq!(0, System::last_runtime_upgrade_spec_version());
998+
997999
Weight::from_parts(100, 0)
9981000
}
9991001
}
@@ -1356,17 +1358,13 @@ mod tests {
13561358
new_test_ext(1).execute_with(|| {
13571359
RuntimeVersionTestValues::mutate(|v| *v = Default::default());
13581360
// It should be added at genesis
1359-
assert!(frame_system::LastRuntimeUpgrade::<Runtime>::exists());
1361+
assert!(LastRuntimeUpgrade::<Runtime>::exists());
13601362
assert!(!Executive::runtime_upgraded());
13611363

13621364
RuntimeVersionTestValues::mutate(|v| {
13631365
*v = sp_version::RuntimeVersion { spec_version: 1, ..Default::default() }
13641366
});
13651367
assert!(Executive::runtime_upgraded());
1366-
assert_eq!(
1367-
Some(LastRuntimeUpgradeInfo { spec_version: 1.into(), spec_name: "".into() }),
1368-
frame_system::LastRuntimeUpgrade::<Runtime>::get(),
1369-
);
13701368

13711369
RuntimeVersionTestValues::mutate(|v| {
13721370
*v = sp_version::RuntimeVersion {
@@ -1376,27 +1374,18 @@ mod tests {
13761374
}
13771375
});
13781376
assert!(Executive::runtime_upgraded());
1379-
assert_eq!(
1380-
Some(LastRuntimeUpgradeInfo { spec_version: 1.into(), spec_name: "test".into() }),
1381-
frame_system::LastRuntimeUpgrade::<Runtime>::get(),
1382-
);
13831377

13841378
RuntimeVersionTestValues::mutate(|v| {
13851379
*v = sp_version::RuntimeVersion {
1386-
spec_version: 1,
1387-
spec_name: "test".into(),
1380+
spec_version: 0,
13881381
impl_version: 2,
13891382
..Default::default()
13901383
}
13911384
});
13921385
assert!(!Executive::runtime_upgraded());
13931386

1394-
frame_system::LastRuntimeUpgrade::<Runtime>::take();
1387+
LastRuntimeUpgrade::<Runtime>::take();
13951388
assert!(Executive::runtime_upgraded());
1396-
assert_eq!(
1397-
Some(LastRuntimeUpgradeInfo { spec_version: 1.into(), spec_name: "test".into() }),
1398-
frame_system::LastRuntimeUpgrade::<Runtime>::get(),
1399-
);
14001389
})
14011390
}
14021391

@@ -1444,6 +1433,10 @@ mod tests {
14441433

14451434
assert_eq!(&sp_io::storage::get(TEST_KEY).unwrap()[..], *b"module");
14461435
assert_eq!(sp_io::storage::get(CUSTOM_ON_RUNTIME_KEY).unwrap(), true.encode());
1436+
assert_eq!(
1437+
Some(RuntimeVersionTestValues::get().into()),
1438+
LastRuntimeUpgrade::<Runtime>::get(),
1439+
)
14471440
});
14481441
}
14491442

@@ -1519,6 +1512,9 @@ mod tests {
15191512

15201513
#[test]
15211514
fn all_weights_are_recorded_correctly() {
1515+
// Reset to get the correct new genesis below.
1516+
RuntimeVersionTestValues::take();
1517+
15221518
new_test_ext(1).execute_with(|| {
15231519
// Make sure `on_runtime_upgrade` is called for maximum complexity
15241520
RuntimeVersionTestValues::mutate(|v| {
@@ -1535,6 +1531,10 @@ mod tests {
15351531
Digest::default(),
15361532
));
15371533

1534+
// Reset the last runtime upgrade info, to make the second call to `on_runtime_upgrade`
1535+
// succeed.
1536+
LastRuntimeUpgrade::<Runtime>::take();
1537+
15381538
// All weights that show up in the `initialize_block_impl`
15391539
let custom_runtime_upgrade_weight = CustomOnRuntimeUpgrade::on_runtime_upgrade();
15401540
let runtime_upgrade_weight =

substrate/frame/system/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ sp-runtime = { path = "../../primitives/runtime", default-features = false, feat
2525
sp-std = { path = "../../primitives/std", default-features = false}
2626
sp-version = { path = "../../primitives/version", default-features = false, features = ["serde"] }
2727
sp-weights = { path = "../../primitives/weights", default-features = false, features = ["serde"] }
28+
docify = "0.2.0"
2829

2930
[dev-dependencies]
3031
criterion = "0.4.0"

substrate/frame/system/src/lib.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1094,6 +1094,25 @@ pub enum DecRefStatus {
10941094
}
10951095

10961096
impl<T: Config> Pallet<T> {
1097+
/// Returns the `spec_version` of the last runtime upgrade.
1098+
///
1099+
/// This function is useful for writing guarded runtime migrations in the runtime. A runtime
1100+
/// migration can use the `spec_version` to ensure that it isn't applied twice. This works
1101+
/// similar as the storage version for pallets.
1102+
///
1103+
/// This functions returns the `spec_version` of the last runtime upgrade while executing the
1104+
/// runtime migrations
1105+
/// [`on_runtime_upgrade`](frame_support::traits::OnRuntimeUpgrade::on_runtime_upgrade)
1106+
/// function. After all migrations are executed, this will return the `spec_version` of the
1107+
/// current runtime until there is another runtime upgrade.
1108+
///
1109+
/// Example:
1110+
#[doc = docify::embed!("src/tests.rs", last_runtime_upgrade_spec_version_usage)]
1111+
pub fn last_runtime_upgrade_spec_version() -> u32 {
1112+
LastRuntimeUpgrade::<T>::get().map_or(0, |l| l.spec_version.0)
1113+
}
1114+
1115+
/// Returns true if the given account exists.
10971116
pub fn account_exists(who: &T::AccountId) -> bool {
10981117
Account::<T>::contains_key(who)
10991118
}

substrate/frame/system/src/tests.rs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use crate::*;
1919
use frame_support::{
2020
assert_noop, assert_ok,
2121
dispatch::{Pays, PostDispatchInfo, WithPostDispatchInfo},
22-
traits::WhitelistedStorageKeys,
22+
traits::{OnRuntimeUpgrade, WhitelistedStorageKeys},
2323
};
2424
use std::collections::BTreeSet;
2525

@@ -773,3 +773,26 @@ pub fn from_actual_ref_time(ref_time: Option<u64>) -> PostDispatchInfo {
773773
pub fn from_post_weight_info(ref_time: Option<u64>, pays_fee: Pays) -> PostDispatchInfo {
774774
PostDispatchInfo { actual_weight: ref_time.map(|t| Weight::from_all(t)), pays_fee }
775775
}
776+
777+
#[docify::export]
778+
#[test]
779+
fn last_runtime_upgrade_spec_version_usage() {
780+
struct Migration;
781+
782+
impl OnRuntimeUpgrade for Migration {
783+
fn on_runtime_upgrade() -> Weight {
784+
// Ensure to compare the spec version against some static version to prevent applying
785+
// the same migration multiple times.
786+
//
787+
// `1337` here is the spec version of the runtime running on chain. If there is maybe
788+
// a runtime upgrade in the pipeline of being applied, you should use the spec version
789+
// of this upgrade.
790+
if System::last_runtime_upgrade_spec_version() > 1337 {
791+
return Weight::zero();
792+
}
793+
794+
// Do the migration.
795+
Weight::zero()
796+
}
797+
}
798+
}

0 commit comments

Comments
 (0)