Skip to content

Commit e484c01

Browse files
[stable2407] Backport #5695 (#5729)
Backport #5695 into `stable2407` from ggwpez. See the [documentation](https://github.com/paritytech/polkadot-sdk/blob/master/docs/BACKPORT.md) on how to use this bot. <!-- # To be used by other automation, do not modify: original-pr-number: #${pull_number} --> Co-authored-by: Oliver Tale-Yazdi <[email protected]>
1 parent deb354e commit e484c01

4 files changed

Lines changed: 50 additions & 6 deletions

File tree

prdoc/pr_5695.prdoc

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
title: 'pallet-migrations: fix index access for singluar migrations'
2+
doc:
3+
- audience: Runtime Dev
4+
description: |-
5+
Discovered a bug in the migrations pallet while debugging https://github.com/paritytech/try-runtime-cli/pull/90.
6+
It only occurs when a single MBM is configured - hence it did not happen when Ajuna Network tried it...
7+
8+
Changes:
9+
- Check len of the tuple before accessing its nth_id
10+
- Make nth_id return `None` on unary tuples and n>0
11+
crates:
12+
- name: pallet-migrations
13+
bump: patch
14+
- name: frame-support
15+
bump: patch

substrate/frame/migrations/src/lib.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -678,7 +678,7 @@ impl<T: Config> Pallet<T> {
678678
return Some(ControlFlow::Break(cursor))
679679
}
680680

681-
let Some(id) = T::Migrations::nth_id(cursor.index) else {
681+
if cursor.index >= T::Migrations::len() {
682682
// No more migrations in the tuple - we are done.
683683
defensive_assert!(cursor.index == T::Migrations::len(), "Inconsistent MBMs tuple");
684684
Self::deposit_event(Event::UpgradeCompleted);
@@ -687,8 +687,9 @@ impl<T: Config> Pallet<T> {
687687
return None;
688688
};
689689

690-
let Ok(bounded_id): Result<IdentifierOf<T>, _> = id.try_into() else {
691-
defensive!("integrity_test ensures that all identifiers' MEL bounds fit into CursorMaxLen; qed.");
690+
let id = T::Migrations::nth_id(cursor.index).map(TryInto::try_into);
691+
let Some(Ok(bounded_id)): Option<Result<IdentifierOf<T>, _>> = id else {
692+
defensive!("integrity_test ensures that all identifiers are present and bounde; qed.");
692693
Self::upgrade_failed(Some(cursor.index));
693694
return None
694695
};

substrate/frame/migrations/src/tests.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,31 @@ use frame_support::{pallet_prelude::Weight, traits::OnRuntimeUpgrade};
2727
#[docify::export]
2828
#[test]
2929
fn simple_works() {
30+
use Event::*;
31+
test_closure(|| {
32+
// Add three migrations, each taking one block longer than the previous.
33+
MockedMigrations::set(vec![(SucceedAfter, 2)]);
34+
35+
System::set_block_number(1);
36+
Migrations::on_runtime_upgrade();
37+
run_to_block(10);
38+
39+
// Check that the executed migrations are recorded in `Historical`.
40+
assert_eq!(historic(), vec![mocked_id(SucceedAfter, 2),]);
41+
42+
// Check that we got all events.
43+
assert_events(vec![
44+
UpgradeStarted { migrations: 1 },
45+
MigrationAdvanced { index: 0, took: 1 },
46+
MigrationAdvanced { index: 0, took: 2 },
47+
MigrationCompleted { index: 0, took: 3 },
48+
UpgradeCompleted,
49+
]);
50+
});
51+
}
52+
53+
#[test]
54+
fn simple_multiple_works() {
3055
use Event::*;
3156
test_closure(|| {
3257
// Add three migrations, each taking one block longer than the previous.

substrate/frame/support/src/migrations.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -673,7 +673,8 @@ pub trait SteppedMigrations {
673673

674674
/// The `n`th [`SteppedMigration::id`].
675675
///
676-
/// Is guaranteed to return `Some` if `n < Self::len()`.
676+
/// Is guaranteed to return `Some` if `n < Self::len()`. Calling this with any index larger or
677+
/// equal to `Self::len()` MUST return `None`.
677678
fn nth_id(n: u32) -> Option<Vec<u8>>;
678679

679680
/// The [`SteppedMigration::max_steps`] of the `n`th migration.
@@ -777,8 +778,10 @@ impl<T: SteppedMigration> SteppedMigrations for T {
777778
1
778779
}
779780

780-
fn nth_id(_n: u32) -> Option<Vec<u8>> {
781-
Some(T::id().encode())
781+
fn nth_id(n: u32) -> Option<Vec<u8>> {
782+
n.is_zero()
783+
.then_some(T::id().encode())
784+
.defensive_proof("nth_id should only be called with n==0")
782785
}
783786

784787
fn nth_max_steps(n: u32) -> Option<Option<u32>> {

0 commit comments

Comments
 (0)