referrerpolicy=no-referrer-when-downgrade

pallet_contracts/migration/
v09.rs

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//! Update `CodeStorage` with the new `determinism` field.
19
20use crate::{
21	migration::{IsFinished, MigrationStep},
22	weights::WeightInfo,
23	CodeHash, Config, Determinism, Pallet, Weight, LOG_TARGET,
24};
25use alloc::vec::Vec;
26use codec::{Decode, Encode};
27use frame_support::{
28	pallet_prelude::*, storage_alias, weights::WeightMeter, DefaultNoBound, Identity,
29};
30#[cfg(feature = "try-runtime")]
31use sp_runtime::TryRuntimeError;
32
33mod v8 {
34	use super::*;
35
36	#[derive(Encode, Decode)]
37	pub struct PrefabWasmModule {
38		#[codec(compact)]
39		pub instruction_weights_version: u32,
40		#[codec(compact)]
41		pub initial: u32,
42		#[codec(compact)]
43		pub maximum: u32,
44		pub code: Vec<u8>,
45	}
46
47	#[storage_alias]
48	pub type CodeStorage<T: Config> =
49		StorageMap<Pallet<T>, Identity, CodeHash<T>, PrefabWasmModule>;
50}
51
52#[cfg(feature = "runtime-benchmarks")]
53pub fn store_old_dummy_code<T: Config>(len: usize) {
54	use sp_runtime::traits::Hash;
55	let module = v8::PrefabWasmModule {
56		instruction_weights_version: 0,
57		initial: 0,
58		maximum: 0,
59		code: alloc::vec![42u8; len],
60	};
61	let hash = T::Hashing::hash(&module.code);
62	v8::CodeStorage::<T>::insert(hash, module);
63}
64
65#[derive(Encode, Decode)]
66struct PrefabWasmModule {
67	#[codec(compact)]
68	pub instruction_weights_version: u32,
69	#[codec(compact)]
70	pub initial: u32,
71	#[codec(compact)]
72	pub maximum: u32,
73	pub code: Vec<u8>,
74	pub determinism: Determinism,
75}
76
77#[storage_alias]
78type CodeStorage<T: Config> = StorageMap<Pallet<T>, Identity, CodeHash<T>, PrefabWasmModule>;
79
80#[derive(Encode, Decode, MaxEncodedLen, DefaultNoBound)]
81pub struct Migration<T: Config> {
82	last_code_hash: Option<CodeHash<T>>,
83}
84
85impl<T: Config> MigrationStep for Migration<T> {
86	const VERSION: u16 = 9;
87
88	fn max_step_weight() -> Weight {
89		T::WeightInfo::v9_migration_step(T::MaxCodeLen::get())
90	}
91
92	fn step(&mut self, meter: &mut WeightMeter) -> IsFinished {
93		let mut iter = if let Some(last_key) = self.last_code_hash.take() {
94			v8::CodeStorage::<T>::iter_from(v8::CodeStorage::<T>::hashed_key_for(last_key))
95		} else {
96			v8::CodeStorage::<T>::iter()
97		};
98
99		if let Some((key, old)) = iter.next() {
100			log::debug!(target: LOG_TARGET, "Migrating contract code {:?}", key);
101			let len = old.code.len() as u32;
102			let module = PrefabWasmModule {
103				instruction_weights_version: old.instruction_weights_version,
104				initial: old.initial,
105				maximum: old.maximum,
106				code: old.code,
107				determinism: Determinism::Enforced,
108			};
109			CodeStorage::<T>::insert(key, module);
110			self.last_code_hash = Some(key);
111			meter.consume(T::WeightInfo::v9_migration_step(len));
112			IsFinished::No
113		} else {
114			log::debug!(target: LOG_TARGET, "No more contracts code to migrate");
115			meter.consume(T::WeightInfo::v9_migration_step(0));
116			IsFinished::Yes
117		}
118	}
119
120	#[cfg(feature = "try-runtime")]
121	fn pre_upgrade_step() -> Result<Vec<u8>, TryRuntimeError> {
122		let sample: Vec<_> = v8::CodeStorage::<T>::iter().take(100).collect();
123
124		log::debug!(target: LOG_TARGET, "Taking sample of {} contract codes", sample.len());
125		Ok(sample.encode())
126	}
127
128	#[cfg(feature = "try-runtime")]
129	fn post_upgrade_step(state: Vec<u8>) -> Result<(), TryRuntimeError> {
130		let sample = <Vec<(CodeHash<T>, v8::PrefabWasmModule)> as Decode>::decode(&mut &state[..])
131			.expect("pre_upgrade_step provides a valid state; qed");
132
133		log::debug!(target: LOG_TARGET, "Validating sample of {} contract codes", sample.len());
134		for (code_hash, old) in sample {
135			let module = CodeStorage::<T>::get(&code_hash).unwrap();
136			ensure!(
137				module.instruction_weights_version == old.instruction_weights_version,
138				"invalid instruction weights version"
139			);
140			ensure!(module.determinism == Determinism::Enforced, "invalid determinism");
141			ensure!(module.initial == old.initial, "invalid initial");
142			ensure!(module.maximum == old.maximum, "invalid maximum");
143			ensure!(module.code == old.code, "invalid code");
144		}
145
146		Ok(())
147	}
148}