paras.rs 73.4 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Copyright 2020 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.

// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.

ferrell-code's avatar
ferrell-code committed
17
//! The paras pallet is responsible for storing data on parachains and parathreads.
18
19
20
21
22
//!
//! It tracks which paras are parachains, what their current head data is in
//! this fork of the relay chain, what their validation code is, and what their past and upcoming
//! validation code is.
//!
ferrell-code's avatar
ferrell-code committed
23
//! A para is not considered live until it is registered and activated in this pallet. Activation can
24
25
//! only occur at session boundaries.

Shawn Tabrizi's avatar
Shawn Tabrizi committed
26
27
28
29
use crate::{configuration, initializer::SessionChangeNotification, shared};
use frame_support::pallet_prelude::*;
use frame_system::pallet_prelude::*;
use parity_scale_codec::{Decode, Encode};
asynchronous rob's avatar
asynchronous rob committed
30
use primitives::v1::{
31
32
	ConsensusLog, HeadData, Id as ParaId, SessionIndex, UpgradeGoAhead, UpgradeRestriction,
	ValidationCode, ValidationCodeHash,
33
};
34
use scale_info::TypeInfo;
35
use sp_core::RuntimeDebug;
Shawn Tabrizi's avatar
Shawn Tabrizi committed
36
37
use sp_runtime::{traits::One, DispatchResult, SaturatedConversion};
use sp_std::{prelude::*, result};
38
39

#[cfg(feature = "std")]
Shawn Tabrizi's avatar
Shawn Tabrizi committed
40
use serde::{Deserialize, Serialize};
41

ferrell-code's avatar
ferrell-code committed
42
pub use crate::Origin as ParachainOrigin;
43

44
45
46
#[cfg(feature = "runtime-benchmarks")]
mod benchmarking;

ferrell-code's avatar
ferrell-code committed
47
pub use pallet::*;
48
49

// the two key times necessary to track for every code replacement.
50
#[derive(Default, Encode, Decode, TypeInfo)]
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#[cfg_attr(test, derive(Debug, Clone, PartialEq))]
pub struct ReplacementTimes<N> {
	/// The relay-chain block number that the code upgrade was expected to be activated.
	/// This is when the code change occurs from the para's perspective - after the
	/// first parablock included with a relay-parent with number >= this value.
	expected_at: N,
	/// The relay-chain block number at which the parablock activating the code upgrade was
	/// actually included. This means considered included and available, so this is the time at which
	/// that parablock enters the acceptance period in this fork of the relay-chain.
	activated_at: N,
}

/// Metadata used to track previous parachain validation code that we keep in
/// the state.
65
#[derive(Default, Encode, Decode, TypeInfo)]
66
67
68
69
70
71
#[cfg_attr(test, derive(Debug, Clone, PartialEq))]
pub struct ParaPastCodeMeta<N> {
	/// Block numbers where the code was expected to be replaced and where the code
	/// was actually replaced, respectively. The first is used to do accurate lookups
	/// of historic code in historic contexts, whereas the second is used to do
	/// pruning on an accurate timeframe. These can be used as indices
72
	/// into the `PastCodeHash` map along with the `ParaId` to fetch the code itself.
73
	upgrade_times: Vec<ReplacementTimes<N>>,
74
75
	/// Tracks the highest pruned code-replacement, if any. This is the `activated_at` value,
	/// not the `expected_at` value.
76
77
78
79
80
81
82
83
84
85
86
87
88
	last_pruned: Option<N>,
}

#[cfg_attr(test, derive(Debug, PartialEq))]
enum UseCodeAt<N> {
	/// Use the current code.
	Current,
	/// Use the code that was replaced at the given block number.
	/// This is an inclusive endpoint - a parablock in the context of a relay-chain block on this fork
	/// with number N should use the code that is replaced at N.
	ReplacedAt(N),
}

89
/// The possible states of a para, to take into account delayed lifecycle changes.
90
91
92
93
///
/// If the para is in a "transition state", it is expected that the parachain is
/// queued in the `ActionsQueue` to transition it into a stable state. Its lifecycle
/// state will be used to determine the state transition to apply to the para.
94
#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)]
95
96
97
98
99
100
101
102
pub enum ParaLifecycle {
	/// Para is new and is onboarding as a Parathread or Parachain.
	Onboarding,
	/// Para is a Parathread.
	Parathread,
	/// Para is a Parachain.
	Parachain,
	/// Para is a Parathread which is upgrading to a Parachain.
103
	UpgradingParathread,
104
	/// Para is a Parachain which is downgrading to a Parathread.
105
106
107
108
109
	DowngradingParachain,
	/// Parathread is queued to be offboarded.
	OffboardingParathread,
	/// Parachain is queued to be offboarded.
	OffboardingParachain,
110
111
112
}

impl ParaLifecycle {
113
114
115
	/// Returns true if parachain is currently onboarding. To learn if the
	/// parachain is onboarding as a parachain or parathread, look at the
	/// `UpcomingGenesis` storage item.
116
117
118
119
	pub fn is_onboarding(&self) -> bool {
		matches!(self, ParaLifecycle::Onboarding)
	}

120
121
	/// Returns true if para is in a stable state, i.e. it is currently
	/// a parachain or parathread, and not in any transition state.
122
123
124
125
	pub fn is_stable(&self) -> bool {
		matches!(self, ParaLifecycle::Parathread | ParaLifecycle::Parachain)
	}

126
127
128
	/// Returns true if para is currently treated as a parachain.
	/// This also includes transitioning states, so you may want to combine
	/// this check with `is_stable` if you specifically want `Paralifecycle::Parachain`.
129
	pub fn is_parachain(&self) -> bool {
Shawn Tabrizi's avatar
Shawn Tabrizi committed
130
131
		matches!(
			self,
132
			ParaLifecycle::Parachain |
Shawn Tabrizi's avatar
Shawn Tabrizi committed
133
134
				ParaLifecycle::DowngradingParachain |
				ParaLifecycle::OffboardingParachain
135
		)
136
137
	}

138
139
140
	/// Returns true if para is currently treated as a parathread.
	/// This also includes transitioning states, so you may want to combine
	/// this check with `is_stable` if you specifically want `Paralifecycle::Parathread`.
141
	pub fn is_parathread(&self) -> bool {
Shawn Tabrizi's avatar
Shawn Tabrizi committed
142
143
		matches!(
			self,
144
			ParaLifecycle::Parathread |
Shawn Tabrizi's avatar
Shawn Tabrizi committed
145
146
				ParaLifecycle::UpgradingParathread |
				ParaLifecycle::OffboardingParathread
147
		)
148
149
	}

150
151
152
	/// Returns true if para is currently offboarding.
	pub fn is_offboarding(&self) -> bool {
		matches!(self, ParaLifecycle::OffboardingParathread | ParaLifecycle::OffboardingParachain)
153
154
	}

155
	/// Returns true if para is in any transitionary state.
156
157
158
159
160
	pub fn is_transitioning(&self) -> bool {
		!Self::is_stable(self)
	}
}

161
impl<N: Ord + Copy + PartialEq> ParaPastCodeMeta<N> {
162
163
164
165
166
167
	// note a replacement has occurred at a given block number.
	fn note_replacement(&mut self, expected_at: N, activated_at: N) {
		self.upgrade_times.push(ReplacementTimes { expected_at, activated_at })
	}

	// Yields an identifier that should be used for validating a
168
	// parablock in the context of a particular relay-chain block number in this chain.
169
170
171
172
173
	//
	// a return value of `None` means that there is no code we are aware of that
	// should be used to validate at the given height.
	fn code_at(&self, para_at: N) -> Option<UseCodeAt<N>> {
		// Find out
174
175
		// a) if there is a point where code was replaced in the current chain after the context
		//    we are finding out code for.
176
		// b) what the index of that point is.
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
		//
		// The reason we use `activated_at` instead of `expected_at` is that a gap may occur
		// between expectation and actual activation. Any block executed in a context from
		// `expected_at..activated_at` is expected to activate the code upgrade and therefore should
		// use the previous code.
		//
		// A block executed in the context of `activated_at` should use the new code.
		//
		// Cases where `expected_at` and `activated_at` are the same, that is, zero-delay code upgrades
		// are also handled by this rule correctly.
		let replaced_after_pos = self.upgrade_times.iter().position(|t| {
			// example: code replaced at (5, 5)
			//
			// context #4 should use old code
			// context #5 should use new code
			//
			// example: code replaced at (10, 20)
			// context #9 should use the old code
			// context #10 should use the old code
			// context #19 should use the old code
			// context #20 should use the new code
			para_at < t.activated_at
		});
200
201
202
203
204

		if let Some(replaced_after_pos) = replaced_after_pos {
			// The earliest stored code replacement needs to be special-cased, since we need to check
			// against the pruning state to see if this replacement represents the correct code, or
			// is simply after a replacement that actually represents the correct code, but has been pruned.
Shawn Tabrizi's avatar
Shawn Tabrizi committed
205
206
			let was_pruned =
				replaced_after_pos == 0 && self.last_pruned.map_or(false, |t| t >= para_at);
207
208
209
210
211
212
213
214
215
216
217
218

			if was_pruned {
				None
			} else {
				Some(UseCodeAt::ReplacedAt(self.upgrade_times[replaced_after_pos].expected_at))
			}
		} else {
			// No code replacements after this context.
			// This means either that the current code is valid, or `para_at` is so old that
			// we don't know the code necessary anymore. Compare against `last_pruned` to determine.
			self.last_pruned.as_ref().map_or(
				Some(UseCodeAt::Current), // nothing pruned, use current
Shawn Tabrizi's avatar
Shawn Tabrizi committed
219
220
221
222
223
224
				|earliest_activation| {
					if &para_at < earliest_activation {
						None
					} else {
						Some(UseCodeAt::Current)
					}
225
				},
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
			)
		}
	}

	// The block at which the most recently tracked code change occurred, from the perspective
	// of the para.
	fn most_recent_change(&self) -> Option<N> {
		self.upgrade_times.last().map(|x| x.expected_at.clone())
	}

	// prunes all code upgrade logs occurring at or before `max`.
	// note that code replaced at `x` is the code used to validate all blocks before
	// `x`. Thus, `max` should be outside of the slashing window when this is invoked.
	//
	// Since we don't want to prune anything inside the acceptance period, and the parablock only
	// enters the acceptance period after being included, we prune based on the activation height of
	// the code change, not the expected height of the code change.
	//
	// returns an iterator of block numbers at which code was replaced, where the replaced
	// code should be now pruned, in ascending order.
Shawn Tabrizi's avatar
Shawn Tabrizi committed
246
	fn prune_up_to(&'_ mut self, max: N) -> impl Iterator<Item = N> + '_ {
247
248
249
250
251
252
		let to_prune = self.upgrade_times.iter().take_while(|t| t.activated_at <= max).count();
		let drained = if to_prune == 0 {
			// no-op prune.
			self.upgrade_times.drain(self.upgrade_times.len()..)
		} else {
			// if we are actually pruning something, update the last_pruned member.
253
			self.last_pruned = Some(self.upgrade_times[to_prune - 1].activated_at);
254
255
256
257
258
259
260
261
			self.upgrade_times.drain(..to_prune)
		};

		drained.map(|times| times.expected_at)
	}
}

/// Arguments for initializing a para.
262
#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)]
263
264
265
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub struct ParaGenesisArgs {
	/// The initial head data to use.
asynchronous rob's avatar
asynchronous rob committed
266
	pub genesis_head: HeadData,
267
	/// The initial validation code to use.
asynchronous rob's avatar
asynchronous rob committed
268
	pub validation_code: ValidationCode,
269
	/// True if parachain, false if parathread.
asynchronous rob's avatar
asynchronous rob committed
270
	pub parachain: bool,
271
272
}

273
274
275
276
277
278
279
280
pub trait WeightInfo {
	fn force_set_current_code(c: u32) -> Weight;
	fn force_set_current_head(s: u32) -> Weight;
	fn force_schedule_code_upgrade(c: u32) -> Weight;
	fn force_note_new_head(s: u32) -> Weight;
	fn force_queue_action() -> Weight;
}

281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
pub struct TestWeightInfo;
impl WeightInfo for TestWeightInfo {
	fn force_set_current_code(_c: u32) -> Weight {
		Weight::MAX
	}
	fn force_set_current_head(_s: u32) -> Weight {
		Weight::MAX
	}
	fn force_schedule_code_upgrade(_c: u32) -> Weight {
		Weight::MAX
	}
	fn force_note_new_head(_s: u32) -> Weight {
		Weight::MAX
	}
	fn force_queue_action() -> Weight {
		Weight::MAX
	}
}

ferrell-code's avatar
ferrell-code committed
300
301
302
303
304
305
306
307
308
#[frame_support::pallet]
pub mod pallet {
	use super::*;

	#[pallet::pallet]
	#[pallet::generate_store(pub(super) trait Store)]
	pub struct Pallet<T>(_);

	#[pallet::config]
Shawn Tabrizi's avatar
Shawn Tabrizi committed
309
	pub trait Config: frame_system::Config + configuration::Config + shared::Config {
ferrell-code's avatar
ferrell-code committed
310
311
312
313
314
315
		/// The outer origin type.
		type Origin: From<Origin>
			+ From<<Self as frame_system::Config>::Origin>
			+ Into<result::Result<Origin, <Self as Config>::Origin>>;

		type Event: From<Event> + IsType<<Self as frame_system::Config>::Event>;
316
317
318

		/// Weight information for extrinsics in this pallet.
		type WeightInfo: WeightInfo;
319
320
	}

ferrell-code's avatar
ferrell-code committed
321
322
323
	#[pallet::event]
	#[pallet::generate_deposit(pub(super) fn deposit_event)]
	pub enum Event {
Denis_P's avatar
Denis_P committed
324
		/// Current code has been updated for a Para. `para_id`
ferrell-code's avatar
ferrell-code committed
325
		CurrentCodeUpdated(ParaId),
Denis_P's avatar
Denis_P committed
326
		/// Current head has been updated for a Para. `para_id`
ferrell-code's avatar
ferrell-code committed
327
		CurrentHeadUpdated(ParaId),
Denis_P's avatar
Denis_P committed
328
		/// A code upgrade has been scheduled for a Para. `para_id`
ferrell-code's avatar
ferrell-code committed
329
		CodeUpgradeScheduled(ParaId),
Denis_P's avatar
Denis_P committed
330
		/// A new head has been noted for a Para. `para_id`
ferrell-code's avatar
ferrell-code committed
331
		NewHeadNoted(ParaId),
Denis_P's avatar
Denis_P committed
332
		/// A para has been queued to execute pending actions. `para_id`
ferrell-code's avatar
ferrell-code committed
333
		ActionQueued(ParaId, SessionIndex),
334
335
	}

ferrell-code's avatar
ferrell-code committed
336
337
	#[pallet::error]
	pub enum Error<T> {
338
339
340
341
342
343
344
345
346
347
348
		/// Para is not registered in our system.
		NotRegistered,
		/// Para cannot be onboarded because it is already tracked by our system.
		CannotOnboard,
		/// Para cannot be offboarded at this time.
		CannotOffboard,
		/// Para cannot be upgraded to a parachain.
		CannotUpgrade,
		/// Para cannot be downgraded to a parathread.
		CannotDowngrade,
	}
349

Denis_P's avatar
Denis_P committed
350
	/// All parachains. Ordered ascending by `ParaId`. Parathreads are not included.
ferrell-code's avatar
ferrell-code committed
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
	#[pallet::storage]
	#[pallet::getter(fn parachains)]
	pub(super) type Parachains<T: Config> = StorageValue<_, Vec<ParaId>, ValueQuery>;

	/// The current lifecycle of a all known Para IDs.
	#[pallet::storage]
	pub(super) type ParaLifecycles<T: Config> = StorageMap<_, Twox64Concat, ParaId, ParaLifecycle>;

	/// The head-data of every registered para.
	#[pallet::storage]
	#[pallet::getter(fn para_head)]
	pub(super) type Heads<T: Config> = StorageMap<_, Twox64Concat, ParaId, HeadData>;

	/// The validation code hash of every live para.
	///
	/// Corresponding code can be retrieved with [`CodeByHash`].
	#[pallet::storage]
Shawn Tabrizi's avatar
Shawn Tabrizi committed
368
369
	pub(super) type CurrentCodeHash<T: Config> =
		StorageMap<_, Twox64Concat, ParaId, ValidationCodeHash>;
ferrell-code's avatar
ferrell-code committed
370
371
372
373
374
375

	/// Actual past code hash, indicated by the para id as well as the block number at which it
	/// became outdated.
	///
	/// Corresponding code can be retrieved with [`CodeByHash`].
	#[pallet::storage]
Shawn Tabrizi's avatar
Shawn Tabrizi committed
376
377
	pub(super) type PastCodeHash<T: Config> =
		StorageMap<_, Twox64Concat, (ParaId, T::BlockNumber), ValidationCodeHash>;
ferrell-code's avatar
ferrell-code committed
378
379
380
381
382
383

	/// Past code of parachains. The parachains themselves may not be registered anymore,
	/// but we also keep their code on-chain for the same amount of time as outdated code
	/// to keep it available for secondary checkers.
	#[pallet::storage]
	#[pallet::getter(fn past_code_meta)]
Shawn Tabrizi's avatar
Shawn Tabrizi committed
384
385
	pub(super) type PastCodeMeta<T: Config> =
		StorageMap<_, Twox64Concat, ParaId, ParaPastCodeMeta<T::BlockNumber>, ValueQuery>;
ferrell-code's avatar
ferrell-code committed
386
387
388
389
390
391
392
393

	/// Which paras have past code that needs pruning and the relay-chain block at which the code was replaced.
	/// Note that this is the actual height of the included block, not the expected height at which the
	/// code upgrade would be applied, although they may be equal.
	/// This is to ensure the entire acceptance period is covered, not an offset acceptance period starting
	/// from the time at which the parachain perceives a code upgrade as having occurred.
	/// Multiple entries for a single para are permitted. Ordered ascending by block number.
	#[pallet::storage]
Shawn Tabrizi's avatar
Shawn Tabrizi committed
394
395
	pub(super) type PastCodePruning<T: Config> =
		StorageValue<_, Vec<(ParaId, T::BlockNumber)>, ValueQuery>;
ferrell-code's avatar
ferrell-code committed
396
397
398
399
400
401

	/// The block number at which the planned code change is expected for a para.
	/// The change will be applied after the first parablock for this ID included which executes
	/// in the context of a relay chain block with a number >= `expected_at`.
	#[pallet::storage]
	#[pallet::getter(fn future_code_upgrade_at)]
Shawn Tabrizi's avatar
Shawn Tabrizi committed
402
403
	pub(super) type FutureCodeUpgrades<T: Config> =
		StorageMap<_, Twox64Concat, ParaId, T::BlockNumber>;
ferrell-code's avatar
ferrell-code committed
404
405
406
407
408

	/// The actual future code hash of a para.
	///
	/// Corresponding code can be retrieved with [`CodeByHash`].
	#[pallet::storage]
Shawn Tabrizi's avatar
Shawn Tabrizi committed
409
410
	pub(super) type FutureCodeHash<T: Config> =
		StorageMap<_, Twox64Concat, ParaId, ValidationCodeHash>;
ferrell-code's avatar
ferrell-code committed
411

412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
	/// This is used by the relay-chain to communicate to a parachain a go-ahead with in the upgrade procedure.
	///
	/// This value is absent when there are no upgrades scheduled or during the time the relay chain
	/// performs the checks. It is set at the first relay-chain block when the corresponding parachain
	/// can switch its upgrade function. As soon as the parachain's block is included, the value
	/// gets reset to `None`.
	///
	/// NOTE that this field is used by parachains via merkle storage proofs, therefore changing
	/// the format will require migration of parachains.
	#[pallet::storage]
	pub(super) type UpgradeGoAheadSignal<T: Config> =
		StorageMap<_, Twox64Concat, ParaId, UpgradeGoAhead>;

	/// This is used by the relay-chain to communicate that there are restrictions for performing
	/// an upgrade for this parachain.
	///
	/// This may be a because the parachain waits for the upgrade cooldown to expire. Another
	/// potential use case is when we want to perform some maintenance (such as storage migration)
	/// we could restrict upgrades to make the process simpler.
	///
	/// NOTE that this field is used by parachains via merkle storage proofs, therefore changing
	/// the format will require migration of parachains.
	#[pallet::storage]
	pub(super) type UpgradeRestrictionSignal<T: Config> =
		StorageMap<_, Twox64Concat, ParaId, UpgradeRestriction>;

	/// The list of parachains that are awaiting for their upgrade restriction to cooldown.
	///
	/// Ordered ascending by block number.
	#[pallet::storage]
	pub(super) type UpgradeCooldowns<T: Config> =
		StorageValue<_, Vec<(ParaId, T::BlockNumber)>, ValueQuery>;

	/// The list of upcoming code upgrades. Each item is a pair of which para performs a code
	/// upgrade and at which relay-chain block it is expected at.
	///
	/// Ordered ascending by block number.
	#[pallet::storage]
	pub(super) type UpcomingUpgrades<T: Config> =
		StorageValue<_, Vec<(ParaId, T::BlockNumber)>, ValueQuery>;

ferrell-code's avatar
ferrell-code committed
453
454
455
	/// The actions to perform during the start of a specific session index.
	#[pallet::storage]
	#[pallet::getter(fn actions_queue)]
Shawn Tabrizi's avatar
Shawn Tabrizi committed
456
457
	pub(super) type ActionsQueue<T: Config> =
		StorageMap<_, Twox64Concat, SessionIndex, Vec<ParaId>, ValueQuery>;
ferrell-code's avatar
ferrell-code committed
458
459
460

	/// Upcoming paras instantiation arguments.
	#[pallet::storage]
Shawn Tabrizi's avatar
Shawn Tabrizi committed
461
462
	pub(super) type UpcomingParasGenesis<T: Config> =
		StorageMap<_, Twox64Concat, ParaId, ParaGenesisArgs>;
ferrell-code's avatar
ferrell-code committed
463
464
465

	/// The number of reference on the validation code in [`CodeByHash`] storage.
	#[pallet::storage]
Shawn Tabrizi's avatar
Shawn Tabrizi committed
466
467
	pub(super) type CodeByHashRefs<T: Config> =
		StorageMap<_, Identity, ValidationCodeHash, u32, ValueQuery>;
ferrell-code's avatar
ferrell-code committed
468
469
470
471
472
473
474

	/// Validation code stored by its hash.
	///
	/// This storage is consistent with [`FutureCodeHash`], [`CurrentCodeHash`] and
	/// [`PastCodeHash`].
	#[pallet::storage]
	#[pallet::getter(fn code_by_hash)]
Shawn Tabrizi's avatar
Shawn Tabrizi committed
475
476
	pub(super) type CodeByHash<T: Config> =
		StorageMap<_, Identity, ValidationCodeHash, ValidationCode>;
ferrell-code's avatar
ferrell-code committed
477
478
479
480
481
482
483
484
485

	#[pallet::genesis_config]
	pub struct GenesisConfig {
		pub paras: Vec<(ParaId, ParaGenesisArgs)>,
	}

	#[cfg(feature = "std")]
	impl Default for GenesisConfig {
		fn default() -> Self {
Shawn Tabrizi's avatar
Shawn Tabrizi committed
486
			GenesisConfig { paras: Default::default() }
ferrell-code's avatar
ferrell-code committed
487
		}
488
489
	}

ferrell-code's avatar
ferrell-code committed
490
491
492
	#[pallet::genesis_build]
	impl<T: Config> GenesisBuild<T> for GenesisConfig {
		fn build(&self) {
Shawn Tabrizi's avatar
Shawn Tabrizi committed
493
494
			let mut parachains: Vec<_> = self
				.paras
ferrell-code's avatar
ferrell-code committed
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
				.iter()
				.filter(|(_, args)| args.parachain)
				.map(|&(ref id, _)| id)
				.cloned()
				.collect();

			parachains.sort();
			parachains.dedup();

			Parachains::<T>::put(&parachains);

			for (id, genesis_args) in &self.paras {
				let code_hash = genesis_args.validation_code.hash();
				<Pallet<T>>::increase_code_ref(&code_hash, &genesis_args.validation_code);
				<Pallet<T> as Store>::CurrentCodeHash::insert(&id, &code_hash);
				<Pallet<T> as Store>::Heads::insert(&id, &genesis_args.genesis_head);
				if genesis_args.parachain {
					ParaLifecycles::<T>::insert(&id, ParaLifecycle::Parachain);
				} else {
					ParaLifecycles::<T>::insert(&id, ParaLifecycle::Parathread);
				}
			}
		}
	}
519

ferrell-code's avatar
ferrell-code committed
520
521
	#[pallet::origin]
	pub type Origin = ParachainOrigin;
522

ferrell-code's avatar
ferrell-code committed
523
524
	#[pallet::call]
	impl<T: Config> Pallet<T> {
525
		/// Set the storage for the parachain validation code immediately.
526
		#[pallet::weight(<T as Config>::WeightInfo::force_set_current_code(new_code.0.len() as u32))]
Shawn Tabrizi's avatar
Shawn Tabrizi committed
527
528
529
530
531
		pub fn force_set_current_code(
			origin: OriginFor<T>,
			para: ParaId,
			new_code: ValidationCode,
		) -> DispatchResult {
532
			ensure_root(origin)?;
533
534
535
536
			let prior_code_hash = <Self as Store>::CurrentCodeHash::get(&para).unwrap_or_default();
			let new_code_hash = new_code.hash();
			Self::increase_code_ref(&new_code_hash, &new_code);
			<Self as Store>::CurrentCodeHash::insert(&para, new_code_hash);
537
538

			let now = frame_system::Pallet::<T>::block_number();
539
			Self::note_past_code(para, now, now, prior_code_hash);
540
			Self::deposit_event(Event::CurrentCodeUpdated(para));
ferrell-code's avatar
ferrell-code committed
541
			Ok(())
542
543
544
		}

		/// Set the storage for the current parachain head data immediately.
545
		#[pallet::weight(<T as Config>::WeightInfo::force_set_current_head(new_head.0.len() as u32))]
Shawn Tabrizi's avatar
Shawn Tabrizi committed
546
547
548
549
550
		pub fn force_set_current_head(
			origin: OriginFor<T>,
			para: ParaId,
			new_head: HeadData,
		) -> DispatchResult {
551
552
553
			ensure_root(origin)?;
			<Self as Store>::Heads::insert(&para, new_head);
			Self::deposit_event(Event::CurrentHeadUpdated(para));
ferrell-code's avatar
ferrell-code committed
554
			Ok(())
555
556
		}

557
		/// Schedule an upgrade as if it was scheduled in the given relay parent block.
558
		#[pallet::weight(<T as Config>::WeightInfo::force_schedule_code_upgrade(new_code.0.len() as u32))]
ferrell-code's avatar
ferrell-code committed
559
560
561
562
		pub fn force_schedule_code_upgrade(
			origin: OriginFor<T>,
			para: ParaId,
			new_code: ValidationCode,
563
			relay_parent_number: T::BlockNumber,
ferrell-code's avatar
ferrell-code committed
564
		) -> DispatchResult {
565
			ensure_root(origin)?;
566
567
			let config = configuration::Pallet::<T>::config();
			Self::schedule_code_upgrade(para, new_code, relay_parent_number, &config);
568
			Self::deposit_event(Event::CodeUpgradeScheduled(para));
ferrell-code's avatar
ferrell-code committed
569
			Ok(())
570
571
572
		}

		/// Note a new block head for para within the context of the current block.
573
		#[pallet::weight(<T as Config>::WeightInfo::force_note_new_head(new_head.0.len() as u32))]
Shawn Tabrizi's avatar
Shawn Tabrizi committed
574
575
576
577
578
		pub fn force_note_new_head(
			origin: OriginFor<T>,
			para: ParaId,
			new_head: HeadData,
		) -> DispatchResult {
579
580
581
582
			ensure_root(origin)?;
			let now = frame_system::Pallet::<T>::block_number();
			Self::note_new_head(para, new_head, now);
			Self::deposit_event(Event::NewHeadNoted(para));
ferrell-code's avatar
ferrell-code committed
583
			Ok(())
584
585
586
587
588
		}

		/// Put a parachain directly into the next session's action queue.
		/// We can't queue it any sooner than this without going into the
		/// initializer...
589
		#[pallet::weight(<T as Config>::WeightInfo::force_queue_action())]
ferrell-code's avatar
ferrell-code committed
590
		pub fn force_queue_action(origin: OriginFor<T>, para: ParaId) -> DispatchResult {
591
			ensure_root(origin)?;
ferrell-code's avatar
ferrell-code committed
592
593
			let next_session = shared::Pallet::<T>::session_index().saturating_add(One::one());
			ActionsQueue::<T>::mutate(next_session, |v| {
594
595
596
597
598
				if let Err(i) = v.binary_search(&para) {
					v.insert(i, para);
				}
			});
			Self::deposit_event(Event::ActionQueued(para, next_session));
ferrell-code's avatar
ferrell-code committed
599
			Ok(())
600
		}
601
602
603
	}
}

ferrell-code's avatar
ferrell-code committed
604
605
impl<T: Config> Pallet<T> {
	/// Called by the initializer to initialize the configuration pallet.
606
	pub(crate) fn initializer_initialize(now: T::BlockNumber) -> Weight {
607
608
		let weight = Self::prune_old_code(now);
		weight + Self::process_scheduled_upgrade_changes(now)
609
610
	}

ferrell-code's avatar
ferrell-code committed
611
	/// Called by the initializer to finalize the configuration pallet.
Shawn Tabrizi's avatar
Shawn Tabrizi committed
612
	pub(crate) fn initializer_finalize() {}
613
614

	/// Called by the initializer to note that a new session has started.
615
	///
616
	/// Returns the list of outgoing paras from the actions queue.
Shawn Tabrizi's avatar
Shawn Tabrizi committed
617
618
619
	pub(crate) fn initializer_on_new_session(
		notification: &SessionChangeNotification<T::BlockNumber>,
	) -> Vec<ParaId> {
620
621
		let outgoing_paras = Self::apply_actions_queue(notification.session_index);
		outgoing_paras
622
623
	}

624
625
	/// The validation code of live para.
	pub(crate) fn current_code(para_id: &ParaId) -> Option<ValidationCode> {
ferrell-code's avatar
ferrell-code committed
626
627
		CurrentCodeHash::<T>::get(para_id).and_then(|code_hash| {
			let code = CodeByHash::<T>::get(&code_hash);
628
629
630
631
632
633
634
635
636
637
638
			if code.is_none() {
				log::error!(
					"Pallet paras storage is inconsistent, code not found for hash {}",
					code_hash,
				);
				debug_assert!(false, "inconsistent paras storages");
			}
			code
		})
	}

639
640
641
642
643
644
645
646
647
	// Apply all para actions queued for the given session index.
	//
	// The actions to take are based on the lifecycle of of the paras.
	//
	// The final state of any para after the actions queue should be as a
	// parachain, parathread, or not registered. (stable states)
	//
	// Returns the list of outgoing paras from the actions queue.
	fn apply_actions_queue(session: SessionIndex) -> Vec<ParaId> {
ferrell-code's avatar
ferrell-code committed
648
		let actions = ActionsQueue::<T>::take(session);
649
		let mut parachains = <Self as Store>::Parachains::get();
650
		let now = <frame_system::Pallet<T>>::block_number();
651
652
653
		let mut outgoing = Vec::new();

		for para in actions {
ferrell-code's avatar
ferrell-code committed
654
			let lifecycle = ParaLifecycles::<T>::get(&para);
655
			match lifecycle {
Shawn Tabrizi's avatar
Shawn Tabrizi committed
656
657
				None | Some(ParaLifecycle::Parathread) | Some(ParaLifecycle::Parachain) => { /* Nothing to do... */
				},
658
659
660
661
662
663
664
				// Onboard a new parathread or parachain.
				Some(ParaLifecycle::Onboarding) => {
					if let Some(genesis_data) = <Self as Store>::UpcomingParasGenesis::take(&para) {
						if genesis_data.parachain {
							if let Err(i) = parachains.binary_search(&para) {
								parachains.insert(i, para);
							}
ferrell-code's avatar
ferrell-code committed
665
							ParaLifecycles::<T>::insert(&para, ParaLifecycle::Parachain);
666
						} else {
ferrell-code's avatar
ferrell-code committed
667
							ParaLifecycles::<T>::insert(&para, ParaLifecycle::Parathread);
668
						}
669

670
						let code_hash = genesis_data.validation_code.hash();
671
						<Self as Store>::Heads::insert(&para, genesis_data.genesis_head);
672
673
						Self::increase_code_ref(&code_hash, &genesis_data.validation_code);
						<Self as Store>::CurrentCodeHash::insert(&para, code_hash);
674
675
676
677
					}
				},
				// Upgrade a parathread to a parachain
				Some(ParaLifecycle::UpgradingParathread) => {
678
679
680
					if let Err(i) = parachains.binary_search(&para) {
						parachains.insert(i, para);
					}
ferrell-code's avatar
ferrell-code committed
681
					ParaLifecycles::<T>::insert(&para, ParaLifecycle::Parachain);
682
683
684
				},
				// Downgrade a parachain to a parathread
				Some(ParaLifecycle::DowngradingParachain) => {
685
686
687
					if let Ok(i) = parachains.binary_search(&para) {
						parachains.remove(i);
					}
ferrell-code's avatar
ferrell-code committed
688
					ParaLifecycles::<T>::insert(&para, ParaLifecycle::Parathread);
689
690
				},
				// Offboard a parathread or parachain from the system
Shawn Tabrizi's avatar
Shawn Tabrizi committed
691
692
				Some(ParaLifecycle::OffboardingParachain) |
				Some(ParaLifecycle::OffboardingParathread) => {
693
694
695
696
697
698
					if let Ok(i) = parachains.binary_search(&para) {
						parachains.remove(i);
					}

					<Self as Store>::Heads::remove(&para);
					<Self as Store>::FutureCodeUpgrades::remove(&para);
699
700
					<Self as Store>::UpgradeGoAheadSignal::remove(&para);
					<Self as Store>::UpgradeRestrictionSignal::remove(&para);
ferrell-code's avatar
ferrell-code committed
701
					ParaLifecycles::<T>::remove(&para);
702
703
704
705
					let removed_future_code_hash = <Self as Store>::FutureCodeHash::take(&para);
					if let Some(removed_future_code_hash) = removed_future_code_hash {
						Self::decrease_code_ref(&removed_future_code_hash);
					}
706

707
708
709
					let removed_code_hash = <Self as Store>::CurrentCodeHash::take(&para);
					if let Some(removed_code_hash) = removed_code_hash {
						Self::note_past_code(para, now, now, removed_code_hash);
710
711
712
713
714
					}

					outgoing.push(para);
				},
			}
715
		}
716

717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
		if !outgoing.is_empty() {
			// Filter offboarded parachains from the upcoming upgrades and upgrade cooldowns list.
			//
			// We do it after the offboarding to get away with only a single read/write per list.
			//
			// NOTE both of those iterates over the list and the outgoing. We do not expect either
			//      of these to be large. Thus should be fine.
			<Self as Store>::UpcomingUpgrades::mutate(|upcoming_upgrades| {
				*upcoming_upgrades = sp_std::mem::take(upcoming_upgrades)
					.into_iter()
					.filter(|&(ref para, _)| !outgoing.contains(para))
					.collect();
			});
			<Self as Store>::UpgradeCooldowns::mutate(|upgrade_cooldowns| {
				*upgrade_cooldowns = sp_std::mem::take(upgrade_cooldowns)
					.into_iter()
					.filter(|&(ref para, _)| !outgoing.contains(para))
					.collect();
			});
		}

738
739
740
741
		// Place the new parachains set in storage.
		<Self as Store>::Parachains::set(parachains);

		return outgoing
742
743
	}

744
745
746
747
748
749
750
751
752
753
	// note replacement of the code of para with given `id`, which occured in the
	// context of the given relay-chain block number. provide the replaced code.
	//
	// `at` for para-triggered replacement is the block number of the relay-chain
	// block in whose context the parablock was executed
	// (i.e. number of `relay_parent` in the receipt)
	fn note_past_code(
		id: ParaId,
		at: T::BlockNumber,
		now: T::BlockNumber,
754
		old_code_hash: ValidationCodeHash,
755
756
757
758
759
	) -> Weight {
		<Self as Store>::PastCodeMeta::mutate(&id, |past_meta| {
			past_meta.note_replacement(at, now);
		});

760
		<Self as Store>::PastCodeHash::insert(&(id, at), old_code_hash);
761
762
763
764

		// Schedule pruning for this past-code to be removed as soon as it
		// exits the slashing window.
		<Self as Store>::PastCodePruning::mutate(|pruning| {
Shawn Tabrizi's avatar
Shawn Tabrizi committed
765
766
			let insert_idx =
				pruning.binary_search_by_key(&at, |&(_, b)| b).unwrap_or_else(|idx| idx);
767
768
769
770
771
772
773
774
775
			pruning.insert(insert_idx, (id, now));
		});

		T::DbWeight::get().reads_writes(2, 3)
	}

	// looks at old code metadata, compares them to the current acceptance window, and prunes those
	// that are too old.
	fn prune_old_code(now: T::BlockNumber) -> Weight {
ferrell-code's avatar
ferrell-code committed
776
		let config = configuration::Pallet::<T>::config();
777
778
		let code_retention_period = config.code_retention_period;
		if now <= code_retention_period {
779
			let weight = T::DbWeight::get().reads_writes(1, 0);
Shawn Tabrizi's avatar
Shawn Tabrizi committed
780
			return weight
781
782
783
		}

		// The height of any changes we no longer should keep around.
784
		let pruning_height = now - (code_retention_period + One::one());
785

Shawn Tabrizi's avatar
Shawn Tabrizi committed
786
787
		let pruning_tasks_done = <Self as Store>::PastCodePruning::mutate(
			|pruning_tasks: &mut Vec<(_, T::BlockNumber)>| {
788
789
				let (pruning_tasks_done, pruning_tasks_to_do) = {
					// find all past code that has just exited the pruning window.
Shawn Tabrizi's avatar
Shawn Tabrizi committed
790
791
					let up_to_idx =
						pruning_tasks.iter().take_while(|&(_, at)| at <= &pruning_height).count();
792
793
794
795
796
797
					(up_to_idx, pruning_tasks.drain(..up_to_idx))
				};

				for (para_id, _) in pruning_tasks_to_do {
					let full_deactivate = <Self as Store>::PastCodeMeta::mutate(&para_id, |meta| {
						for pruned_repl_at in meta.prune_up_to(pruning_height) {
798
799
800
801
802
803
804
805
806
807
808
809
							let removed_code_hash =
								<Self as Store>::PastCodeHash::take(&(para_id, pruned_repl_at));

							if let Some(removed_code_hash) = removed_code_hash {
								Self::decrease_code_ref(&removed_code_hash);
							} else {
								log::warn!(
									target: "runtime::paras",
									"Missing code for removed hash {:?}",
									removed_code_hash,
								);
							}
810
811
						}

asynchronous rob's avatar
asynchronous rob committed
812
						meta.most_recent_change().is_none() && Self::para_head(&para_id).is_none()
813
814
815
816
817
818
819
820
821
822
					});

					// This parachain has been removed and now the vestigial code
					// has been removed from the state. clean up meta as well.
					if full_deactivate {
						<Self as Store>::PastCodeMeta::remove(&para_id);
					}
				}

				pruning_tasks_done as u64
Shawn Tabrizi's avatar
Shawn Tabrizi committed
823
824
			},
		);
825
826
827
828
829
830

		// 1 read for the meta for each pruning task, 1 read for the config
		// 2 writes: updating the meta and pruning the code
		T::DbWeight::get().reads_writes(1 + pruning_tasks_done, 2 * pruning_tasks_done)
	}

831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
	/// Process the timers related to upgrades. Specifically, the upgrade go ahead signals toggle
	/// and the upgrade cooldown restrictions.
	///
	/// Takes the current block number and returns the weight consumed.
	fn process_scheduled_upgrade_changes(now: T::BlockNumber) -> Weight {
		let upgrades_signaled = <Self as Store>::UpcomingUpgrades::mutate(
			|upcoming_upgrades: &mut Vec<(ParaId, T::BlockNumber)>| {
				let num = upcoming_upgrades.iter().take_while(|&(_, at)| at <= &now).count();
				for (para, _) in upcoming_upgrades.drain(..num) {
					<Self as Store>::UpgradeGoAheadSignal::insert(&para, UpgradeGoAhead::GoAhead);
				}
				num
			},
		);
		let cooldowns_expired = <Self as Store>::UpgradeCooldowns::mutate(
			|upgrade_cooldowns: &mut Vec<(ParaId, T::BlockNumber)>| {
				let num = upgrade_cooldowns.iter().take_while(|&(_, at)| at <= &now).count();
				for (para, _) in upgrade_cooldowns.drain(..num) {
					<Self as Store>::UpgradeRestrictionSignal::remove(&para);
				}
				num
			},
		);

		T::DbWeight::get().reads_writes(2, upgrades_signaled as u64 + cooldowns_expired as u64)
	}

858
859
860
861
	/// Verify that `schedule_para_initialize` can be called successfully.
	///
	/// Returns false if para is already registered in the system.
	pub fn can_schedule_para_initialize(id: &ParaId, _: &ParaGenesisArgs) -> bool {
ferrell-code's avatar
ferrell-code committed
862
		let lifecycle = ParaLifecycles::<T>::get(id);
863
864
865
		lifecycle.is_none()
	}

866
	/// Schedule a para to be initialized at the start of the next session.
867
	///
868
869
870
	/// Will return error if para is already registered in the system.
	pub(crate) fn schedule_para_initialize(id: ParaId, genesis: ParaGenesisArgs) -> DispatchResult {
		let scheduled_session = Self::scheduled_session();
871
872

		// Make sure parachain isn't already in our system.
873
		ensure!(Self::can_schedule_para_initialize(&id, &genesis), Error::<T>::CannotOnboard);
874

ferrell-code's avatar
ferrell-code committed
875
876
877
		ParaLifecycles::<T>::insert(&id, ParaLifecycle::Onboarding);
		UpcomingParasGenesis::<T>::insert(&id, genesis);
		ActionsQueue::<T>::mutate(scheduled_session, |v| {
878
879
			if let Err(i) = v.binary_search(&id) {
				v.insert(i, id);
880
881
882
			}
		});

883
		Ok(())
884
885
886
	}

	/// Schedule a para to be cleaned up at the start of the next session.
887
	///
888
	/// Will return error if para is not a stable parachain or parathread.
889
890
	///
	/// No-op if para is not registered at all.
891
	pub(crate) fn schedule_para_cleanup(id: ParaId) -> DispatchResult {
ferrell-code's avatar
ferrell-code committed
892
		let lifecycle = ParaLifecycles::<T>::get(&id);
893
		match lifecycle {
894
			// If para is not registered, nothing to do!
Shawn Tabrizi's avatar
Shawn Tabrizi committed
895
			None => return Ok(()),
896
			Some(ParaLifecycle::Parathread) => {
ferrell-code's avatar
ferrell-code committed
897
				ParaLifecycles::<T>::insert(&id, ParaLifecycle::OffboardingParathread);
898
			},
899
			Some(ParaLifecycle::Parachain) => {
ferrell-code's avatar
ferrell-code committed
900
				ParaLifecycles::<T>::insert(&id, ParaLifecycle::OffboardingParachain);
901
			},
902
			_ => return Err(Error::<T>::CannotOffboard)?,
903
		}
904

905
		let scheduled_session = Self::scheduled_session();
ferrell-code's avatar
ferrell-code committed
906
		ActionsQueue::<T>::mutate(scheduled_session, |v| {
907
908
909
910
911
912
			if let Err(i) = v.binary_search(&id) {
				v.insert(i, id);
			}
		});

		Ok(())
913
914
915
916
	}

	/// Schedule a parathread to be upgraded to a parachain.
	///
917
918
919
	/// Will return error if `ParaLifecycle` is not `Parathread`.
	pub(crate) fn schedule_parathread_upgrade(id: ParaId) -> DispatchResult {
		let scheduled_session = Self::scheduled_session();
ferrell-code's avatar
ferrell-code committed
920
		let lifecycle = ParaLifecycles::<T>::get(&id).ok_or(Error::<T>::NotRegistered)?;
921

922
923
		ensure!(lifecycle == ParaLifecycle::Parathread, Error::<T>::CannotUpgrade);

ferrell-code's avatar
ferrell-code committed
924
925
		ParaLifecycles::<T>::insert(&id, ParaLifecycle::UpgradingParathread);
		ActionsQueue::<T>::mutate(scheduled_session, |v| {
926
927
			if let Err(i) = v.binary_search(&id) {
				v.insert(i, id);
928
929
930
			}
		});

931
		Ok(())
932
933
934
935
936
	}

	/// Schedule a parachain to be downgraded to a parathread.
	///
	/// Noop if `ParaLifecycle` is not `Parachain`.
937
938
	pub(crate) fn schedule_parachain_downgrade(id: ParaId) -> DispatchResult {
		let scheduled_session = Self::scheduled_session();
ferrell-code's avatar
ferrell-code committed
939
		let lifecycle = ParaLifecycles::<T>::get(&id).ok_or(Error::<T>::NotRegistered)?;
940

941
942
		ensure!(lifecycle == ParaLifecycle::Parachain, Error::<T>::CannotDowngrade);

ferrell-code's avatar
ferrell-code committed
943
944
		ParaLifecycles::<T>::insert(&id, ParaLifecycle::DowngradingParachain);
		ActionsQueue::<T>::mutate(scheduled_session, |v| {
945
946
			if let Err(i) = v.binary_search(&id) {
				v.insert(i, id);
947
			}
948
949
		});

950
		Ok(())
951
952
953
954
955
956
957
958
959
960
	}

	/// Schedule a future code upgrade of the given parachain, to be applied after inclusion
	/// of a block of the same parachain executed in the context of a relay-chain block
	/// with number >= `expected_at`
	///
	/// If there is already a scheduled code upgrade for the para, this is a no-op.
	pub(crate) fn schedule_code_upgrade(
		id: ParaId,
		new_code: ValidationCode,
961
962
		relay_parent_number: T::BlockNumber,
		cfg: &configuration::HostConfiguration<T::BlockNumber>,
963
964
965
966
967
	) -> Weight {
		<Self as Store>::FutureCodeUpgrades::mutate(&id, |up| {
			if up.is_some() {
				T::DbWeight::get().reads_writes(1, 0)
			} else {
968
969
970
971
				let expected_at = relay_parent_number + cfg.validation_upgrade_delay;
				let next_possible_upgrade_at =
					relay_parent_number + cfg.validation_upgrade_frequency;

972
				*up = Some(expected_at);
973

974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
				<Self as Store>::UpcomingUpgrades::mutate(|upcoming_upgrades| {
					let insert_idx = upcoming_upgrades
						.binary_search_by_key(&expected_at, |&(_, b)| b)
						.unwrap_or_else(|idx| idx);
					upcoming_upgrades.insert(insert_idx, (id, expected_at));
				});

				// From the moment of signalling of the upgrade until the cooldown expires, the
				// parachain is disallowed to make further upgrades. Therefore set the upgrade
				// permission signal to disallowed and activate the cooldown timer.
				<Self as Store>::UpgradeRestrictionSignal::insert(&id, UpgradeRestriction::Present);
				<Self as Store>::UpgradeCooldowns::mutate(|upgrade_cooldowns| {
					let insert_idx = upgrade_cooldowns
						.binary_search_by_key(&next_possible_upgrade_at, |&(_, b)| b)
						.unwrap_or_else(|idx| idx);
					upgrade_cooldowns.insert(insert_idx, (id, next_possible_upgrade_at));
				});

992
993
994
995
996
997
				let new_code_hash = new_code.hash();
				let expected_at_u32 = expected_at.saturated_into();
				let log = ConsensusLog::ParaScheduleUpgradeCode(id, new_code_hash, expected_at_u32);
				<frame_system::Pallet<T>>::deposit_log(log.into());

				let (reads, writes) = Self::increase_code_ref(&new_code_hash, &new_code);
ferrell-code's avatar
ferrell-code committed
998
				FutureCodeHash::<T>::insert(&id, new_code_hash);
999
				T::DbWeight::get().reads_writes(2 + reads, 3 + writes)
1000
			}
For faster browsing, not all history is shown. View entire blame