Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.

Commit eb80c4e

Browse files
authored
Contracts: Ensure latest migration match pallet_version (#14676)
* Add version check * fix format * simplify * restructure imports * add version check * Fix benchmarking * Rename migrations -> BenchMigrations * doc * add more docs * fix format string * Update frame/contracts/build.rs * fix * add cargo:rerun-if-changed --------- Co-authored-by: parity-processbot <>
1 parent 1d13511 commit eb80c4e

File tree

7 files changed

+138
-45
lines changed

7 files changed

+138
-45
lines changed

bin/node/runtime/src/lib.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,6 @@ use frame_system::{
5555
pub use node_primitives::{AccountId, Signature};
5656
use node_primitives::{AccountIndex, Balance, BlockNumber, Hash, Moment, Nonce};
5757
use pallet_asset_conversion::{NativeOrAssetId, NativeOrAssetIdConverter};
58-
#[cfg(feature = "runtime-benchmarks")]
59-
use pallet_contracts::NoopMigration;
6058
use pallet_election_provider_multi_phase::SolutionAccuracyOf;
6159
use pallet_im_online::sr25519::AuthorityId as ImOnlineId;
6260
use pallet_nfts::PalletFeatures;
@@ -1257,7 +1255,7 @@ impl pallet_contracts::Config for Runtime {
12571255
#[cfg(not(feature = "runtime-benchmarks"))]
12581256
type Migrations = ();
12591257
#[cfg(feature = "runtime-benchmarks")]
1260-
type Migrations = (NoopMigration<1>, NoopMigration<2>);
1258+
type Migrations = pallet_contracts::migration::codegen::BenchMigrations;
12611259
type MaxDelegateDependencies = ConstU32<32>;
12621260
type CodeHashLockupDepositPercent = CodeHashLockupDepositPercent;
12631261
}

frame/contracts/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ name = "pallet-contracts"
33
version = "4.0.0-dev"
44
authors = ["Parity Technologies <[email protected]>"]
55
edition = "2021"
6+
build = "build.rs"
67
license = "Apache-2.0"
78
homepage = "https://substrate.io"
89
repository = "https://github.com/paritytech/substrate/"

frame/contracts/build.rs

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// This file is part of Substrate.
2+
3+
// Copyright (C) Parity Technologies (UK) Ltd.
4+
// SPDX-License-Identifier: Apache-2.0
5+
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
18+
use std::io::Write;
19+
20+
/// Get the latest migration version.
21+
///
22+
/// Find the highest version number from the available migration files.
23+
/// Each migration file should follow the naming convention `vXX.rs`, where `XX` is the version
24+
/// number.
25+
fn get_latest_version() -> u16 {
26+
std::fs::read_dir("src/migration")
27+
.expect("Folder `src/migration` not found.")
28+
.filter_map(|entry| {
29+
let file_name = entry.as_ref().ok()?.file_name();
30+
let file_name = file_name.to_str()?;
31+
if file_name.starts_with('v') && file_name.ends_with(".rs") {
32+
let version = &file_name[1..&file_name.len() - 3];
33+
let version = version.parse::<u16>().ok()?;
34+
35+
// Ensure that the version matches the one defined in the file.
36+
let path = entry.unwrap().path();
37+
let file_content = std::fs::read_to_string(&path).ok()?;
38+
assert!(
39+
file_content.contains(&format!("const VERSION: u16 = {}", version)),
40+
"Invalid MigrationStep::VERSION in {:?}",
41+
path
42+
);
43+
44+
return Some(version)
45+
}
46+
None
47+
})
48+
.max()
49+
.expect("Failed to find any files matching the 'src/migration/vxx.rs' pattern.")
50+
}
51+
52+
/// Generates a module that exposes the latest migration version, and the benchmark migrations type.
53+
fn main() -> Result<(), Box<dyn std::error::Error>> {
54+
let out_dir = std::env::var("OUT_DIR")?;
55+
let path = std::path::Path::new(&out_dir).join("migration_codegen.rs");
56+
let mut f = std::fs::File::create(&path)?;
57+
let version = get_latest_version();
58+
write!(
59+
f,
60+
"
61+
pub mod codegen {{
62+
use crate::NoopMigration;
63+
/// The latest migration version, pulled from the latest migration file.
64+
pub const LATEST_MIGRATION_VERSION: u16 = {version};
65+
/// The Migration Steps used for benchmarking the migration framework.
66+
pub type BenchMigrations = (NoopMigration<{}>, NoopMigration<{version}>);
67+
}}",
68+
version - 1,
69+
)?;
70+
71+
println!("cargo:rerun-if-changed=src/migration");
72+
Ok(())
73+
}

frame/contracts/src/benchmarking/mod.rs

+13-8
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use self::{
3030
};
3131
use crate::{
3232
exec::{AccountIdOf, Key},
33-
migration::{v09, v10, v11, v12, v13, MigrationStep},
33+
migration::{codegen::LATEST_MIGRATION_VERSION, v09, v10, v11, v12, v13, MigrationStep},
3434
wasm::CallFlags,
3535
Pallet as Contracts, *,
3636
};
@@ -273,29 +273,32 @@ benchmarks! {
273273
// This benchmarks the weight of executing Migration::migrate to execute a noop migration.
274274
#[pov_mode = Measured]
275275
migration_noop {
276-
assert_eq!(StorageVersion::get::<Pallet<T>>(), 2);
276+
let version = LATEST_MIGRATION_VERSION;
277+
assert_eq!(StorageVersion::get::<Pallet<T>>(), version);
277278
}: {
278279
Migration::<T>::migrate(Weight::MAX)
279280
} verify {
280-
assert_eq!(StorageVersion::get::<Pallet<T>>(), 2);
281+
assert_eq!(StorageVersion::get::<Pallet<T>>(), version);
281282
}
282283

283284
// This benchmarks the weight of dispatching migrate to execute 1 `NoopMigraton`
284285
#[pov_mode = Measured]
285286
migrate {
286-
StorageVersion::new(0).put::<Pallet<T>>();
287+
let latest_version = LATEST_MIGRATION_VERSION;
288+
StorageVersion::new(latest_version - 2).put::<Pallet<T>>();
287289
<Migration::<T, false> as frame_support::traits::OnRuntimeUpgrade>::on_runtime_upgrade();
288290
let caller: T::AccountId = whitelisted_caller();
289291
let origin = RawOrigin::Signed(caller.clone());
290292
}: _(origin, Weight::MAX)
291293
verify {
292-
assert_eq!(StorageVersion::get::<Pallet<T>>(), 1);
294+
assert_eq!(StorageVersion::get::<Pallet<T>>(), latest_version - 1);
293295
}
294296

295297
// This benchmarks the weight of running on_runtime_upgrade when there are no migration in progress.
296298
#[pov_mode = Measured]
297299
on_runtime_upgrade_noop {
298-
assert_eq!(StorageVersion::get::<Pallet<T>>(), 2);
300+
let latest_version = LATEST_MIGRATION_VERSION;
301+
assert_eq!(StorageVersion::get::<Pallet<T>>(), latest_version);
299302
}: {
300303
<Migration::<T, false> as frame_support::traits::OnRuntimeUpgrade>::on_runtime_upgrade()
301304
} verify {
@@ -305,7 +308,8 @@ benchmarks! {
305308
// This benchmarks the weight of running on_runtime_upgrade when there is a migration in progress.
306309
#[pov_mode = Measured]
307310
on_runtime_upgrade_in_progress {
308-
StorageVersion::new(0).put::<Pallet<T>>();
311+
let latest_version = LATEST_MIGRATION_VERSION;
312+
StorageVersion::new(latest_version - 2).put::<Pallet<T>>();
309313
let v = vec![42u8].try_into().ok();
310314
MigrationInProgress::<T>::set(v.clone());
311315
}: {
@@ -318,7 +322,8 @@ benchmarks! {
318322
// This benchmarks the weight of running on_runtime_upgrade when there is a migration to process.
319323
#[pov_mode = Measured]
320324
on_runtime_upgrade {
321-
StorageVersion::new(0).put::<Pallet<T>>();
325+
let latest_version = LATEST_MIGRATION_VERSION;
326+
StorageVersion::new(latest_version - 2).put::<Pallet<T>>();
322327
}: {
323328
<Migration::<T, false> as frame_support::traits::OnRuntimeUpgrade>::on_runtime_upgrade()
324329
} verify {

frame/contracts/src/lib.rs

+1-6
Original file line numberDiff line numberDiff line change
@@ -186,12 +186,7 @@ pub mod pallet {
186186
use sp_runtime::Perbill;
187187

188188
/// The current storage version.
189-
#[cfg(not(any(test, feature = "runtime-benchmarks")))]
190-
const STORAGE_VERSION: StorageVersion = StorageVersion::new(13);
191-
192-
/// Hard coded storage version for running tests that depend on the current storage version.
193-
#[cfg(any(test, feature = "runtime-benchmarks"))]
194-
const STORAGE_VERSION: StorageVersion = StorageVersion::new(2);
189+
pub(crate) const STORAGE_VERSION: StorageVersion = StorageVersion::new(13);
195190

196191
#[pallet::pallet]
197192
#[pallet::storage_version(STORAGE_VERSION)]

frame/contracts/src/migration.rs

+32-16
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ pub mod v10;
6161
pub mod v11;
6262
pub mod v12;
6363
pub mod v13;
64+
include!(concat!(env!("OUT_DIR"), "/migration_codegen.rs"));
6465

6566
use crate::{weights::WeightInfo, Config, Error, MigrationInProgress, Pallet, Weight, LOG_TARGET};
6667
use codec::{Codec, Decode};
@@ -522,7 +523,10 @@ impl MigrateSequence for Tuple {
522523
#[cfg(test)]
523524
mod test {
524525
use super::*;
525-
use crate::tests::{ExtBuilder, Test};
526+
use crate::{
527+
migration::codegen::LATEST_MIGRATION_VERSION,
528+
tests::{ExtBuilder, Test},
529+
};
526530

527531
#[derive(Default, Encode, Decode, MaxEncodedLen)]
528532
struct MockMigration<const N: u16> {
@@ -546,6 +550,11 @@ mod test {
546550
}
547551
}
548552

553+
#[test]
554+
fn test_storage_version_matches_last_migration_file() {
555+
assert_eq!(StorageVersion::new(LATEST_MIGRATION_VERSION), crate::pallet::STORAGE_VERSION);
556+
}
557+
549558
#[test]
550559
fn version_range_works() {
551560
let range = <(MockMigration<1>, MockMigration<2>)>::VERSION_RANGE;
@@ -584,7 +593,7 @@ mod test {
584593
type TestMigration = Migration<Test>;
585594

586595
ExtBuilder::default().build().execute_with(|| {
587-
assert_eq!(StorageVersion::get::<Pallet<Test>>(), 2);
596+
assert_eq!(StorageVersion::get::<Pallet<Test>>(), LATEST_MIGRATION_VERSION);
588597
assert_eq!(TestMigration::migrate(Weight::MAX).0, MigrateResult::NoMigrationInProgress)
589598
});
590599
}
@@ -593,21 +602,28 @@ mod test {
593602
fn migration_works() {
594603
type TestMigration = Migration<Test, false>;
595604

596-
ExtBuilder::default().set_storage_version(0).build().execute_with(|| {
597-
assert_eq!(StorageVersion::get::<Pallet<Test>>(), 0);
598-
TestMigration::on_runtime_upgrade();
599-
for (version, status) in
600-
[(1, MigrateResult::InProgress { steps_done: 1 }), (2, MigrateResult::Completed)]
601-
{
602-
assert_eq!(TestMigration::migrate(Weight::MAX).0, status);
605+
ExtBuilder::default()
606+
.set_storage_version(LATEST_MIGRATION_VERSION - 2)
607+
.build()
608+
.execute_with(|| {
609+
assert_eq!(StorageVersion::get::<Pallet<Test>>(), LATEST_MIGRATION_VERSION - 2);
610+
TestMigration::on_runtime_upgrade();
611+
for (version, status) in [
612+
(LATEST_MIGRATION_VERSION - 1, MigrateResult::InProgress { steps_done: 1 }),
613+
(LATEST_MIGRATION_VERSION, MigrateResult::Completed),
614+
] {
615+
assert_eq!(TestMigration::migrate(Weight::MAX).0, status);
616+
assert_eq!(
617+
<Pallet<Test>>::on_chain_storage_version(),
618+
StorageVersion::new(version)
619+
);
620+
}
621+
603622
assert_eq!(
604-
<Pallet<Test>>::on_chain_storage_version(),
605-
StorageVersion::new(version)
623+
TestMigration::migrate(Weight::MAX).0,
624+
MigrateResult::NoMigrationInProgress
606625
);
607-
}
608-
609-
assert_eq!(TestMigration::migrate(Weight::MAX).0, MigrateResult::NoMigrationInProgress);
610-
assert_eq!(StorageVersion::get::<Pallet<Test>>(), 2);
611-
});
626+
assert_eq!(StorageVersion::get::<Pallet<Test>>(), LATEST_MIGRATION_VERSION);
627+
});
612628
}
613629
}

frame/contracts/src/tests.rs

+17-12
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
// This file is part of Substrate.
2-
mod pallet_dummy;
32

43
// Copyright (C) Parity Technologies (UK) Ltd.
54
// SPDX-License-Identifier: Apache-2.0
@@ -16,6 +15,8 @@ mod pallet_dummy;
1615
// See the License for the specific language governing permissions and
1716
// limitations under the License.
1817

18+
mod pallet_dummy;
19+
1920
use self::test_utils::{ensure_stored, expected_deposit, hash};
2021
use crate::{
2122
self as pallet_contracts,
@@ -24,13 +25,14 @@ use crate::{
2425
Result as ExtensionResult, RetVal, ReturnFlags, SysConfig,
2526
},
2627
exec::{Frame, Key},
28+
migration::codegen::LATEST_MIGRATION_VERSION,
2729
storage::DeletionQueueManager,
2830
tests::test_utils::{get_contract, get_contract_checked},
2931
wasm::{Determinism, ReturnCode as RuntimeReturnCode},
3032
weights::WeightInfo,
3133
BalanceOf, Code, CodeHash, CodeInfoOf, CollectEvents, Config, ContractInfo, ContractInfoOf,
32-
DebugInfo, DefaultAddressGenerator, DeletionQueueCounter, Error, MigrationInProgress,
33-
NoopMigration, Origin, Pallet, PristineCode, Schedule,
34+
DebugInfo, DefaultAddressGenerator, DeletionQueueCounter, Error, MigrationInProgress, Origin,
35+
Pallet, PristineCode, Schedule,
3436
};
3537
use assert_matches::assert_matches;
3638
use codec::Encode;
@@ -457,7 +459,7 @@ impl Config for Test {
457459
type MaxStorageKeyLen = ConstU32<128>;
458460
type UnsafeUnstableInterface = UnstableInterface;
459461
type MaxDebugBufferLen = ConstU32<{ 2 * 1024 * 1024 }>;
460-
type Migrations = (NoopMigration<1>, NoopMigration<2>);
462+
type Migrations = crate::migration::codegen::BenchMigrations;
461463
type CodeHashLockupDepositPercent = CodeHashLockupDepositPercent;
462464
type MaxDelegateDependencies = MaxDelegateDependencies;
463465
}
@@ -610,17 +612,20 @@ fn calling_plain_account_fails() {
610612
fn migration_on_idle_hooks_works() {
611613
// Defines expectations of how many migration steps can be done given the weight limit.
612614
let tests = [
613-
(Weight::zero(), 0),
614-
(<Test as Config>::WeightInfo::migrate() + 1.into(), 1),
615-
(Weight::MAX, 2),
615+
(Weight::zero(), LATEST_MIGRATION_VERSION - 2),
616+
(<Test as Config>::WeightInfo::migrate() + 1.into(), LATEST_MIGRATION_VERSION - 1),
617+
(Weight::MAX, LATEST_MIGRATION_VERSION),
616618
];
617619

618620
for (weight, expected_version) in tests {
619-
ExtBuilder::default().set_storage_version(0).build().execute_with(|| {
620-
MigrationInProgress::<Test>::set(Some(Default::default()));
621-
Contracts::on_idle(System::block_number(), weight);
622-
assert_eq!(StorageVersion::get::<Pallet<Test>>(), expected_version);
623-
});
621+
ExtBuilder::default()
622+
.set_storage_version(LATEST_MIGRATION_VERSION - 2)
623+
.build()
624+
.execute_with(|| {
625+
MigrationInProgress::<Test>::set(Some(Default::default()));
626+
Contracts::on_idle(System::block_number(), weight);
627+
assert_eq!(StorageVersion::get::<Pallet<Test>>(), expected_version);
628+
});
624629
}
625630
}
626631

0 commit comments

Comments
 (0)