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

Add support for custom runtime upgrade logic #5782

Merged
merged 1 commit into from
Apr 25, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 113 additions & 12 deletions frame/executive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,19 +60,57 @@
//! # pub type AllModules = u64;
//! # pub enum Runtime {};
//! # use sp_runtime::transaction_validity::{
//! TransactionValidity, UnknownTransaction, TransactionSource,
//! # TransactionValidity, UnknownTransaction, TransactionSource,
//! # };
//! # use sp_runtime::traits::ValidateUnsigned;
//! # impl ValidateUnsigned for Runtime {
//! # type Call = ();
//! # type Call = ();
//! #
//! # fn validate_unsigned(_source: TransactionSource, _call: &Self::Call) -> TransactionValidity {
//! # UnknownTransaction::NoUnsignedValidator.into()
//! # }
//! # fn validate_unsigned(_source: TransactionSource, _call: &Self::Call) -> TransactionValidity {
//! # UnknownTransaction::NoUnsignedValidator.into()
//! # }
//! # }
//! /// Executive: handles dispatch to the various modules.
//! pub type Executive = executive::Executive<Runtime, Block, Context, Runtime, AllModules>;
//! ```
//!
//! ### Custom `OnRuntimeUpgrade` logic
//!
//! You can add custom logic that should be called in your runtime on a runtime upgrade. This is
//! done by setting an optional generic parameter. The custom logic will be called before
//! the on runtime upgrade logic of all modules is called.
//!
//! ```
//! # use sp_runtime::generic;
//! # use frame_executive as executive;
//! # pub struct UncheckedExtrinsic {};
//! # pub struct Header {};
//! # type Context = frame_system::ChainContext<Runtime>;
//! # pub type Block = generic::Block<Header, UncheckedExtrinsic>;
//! # pub type Balances = u64;
//! # pub type AllModules = u64;
//! # pub enum Runtime {};
//! # use sp_runtime::transaction_validity::{
//! # TransactionValidity, UnknownTransaction, TransactionSource,
//! # };
//! # use sp_runtime::traits::ValidateUnsigned;
//! # impl ValidateUnsigned for Runtime {
//! # type Call = ();
//! #
//! # fn validate_unsigned(_source: TransactionSource, _call: &Self::Call) -> TransactionValidity {
//! # UnknownTransaction::NoUnsignedValidator.into()
//! # }
//! # }
//! struct CustomOnRuntimeUpgrade;
//! impl frame_support::traits::OnRuntimeUpgrade for CustomOnRuntimeUpgrade {
//! fn on_runtime_upgrade() -> frame_support::weights::Weight {
//! // Do whatever you want.
//! 0
//! }
//! }
//!
//! pub type Executive = executive::Executive<Runtime, Block, Context, Runtime, AllModules, CustomOnRuntimeUpgrade>;
//! ```

#![cfg_attr(not(feature = "std"), no_std)]

Expand Down Expand Up @@ -102,8 +140,19 @@ pub type CheckedOf<E, C> = <E as Checkable<C>>::Checked;
pub type CallOf<E, C> = <CheckedOf<E, C> as Applyable>::Call;
pub type OriginOf<E, C> = <CallOf<E, C> as Dispatchable>::Origin;

pub struct Executive<System, Block, Context, UnsignedValidator, AllModules>(
PhantomData<(System, Block, Context, UnsignedValidator, AllModules)>
/// Main entry point for certain runtime actions as e.g. `execute_block`.
///
/// Generic parameters:
/// - `System`: Something that implements `frame_system::Trait`
/// - `Block`: The block type of the runtime
/// - `Context`: The context that is used when checking an extrinsic.
/// - `UnsignedValidator`: The unsigned transaction validator of the runtime.
/// - `AllModules`: Tuple that contains all modules. Will be used to call e.g. `on_initialize`.
/// - `OnRuntimeUpgrade`: Custom logic that should be called after a runtime upgrade. Modules are
/// already called by `AllModules`. It will be called before all modules will
/// be called.
pub struct Executive<System, Block, Context, UnsignedValidator, AllModules, OnRuntimeUpgrade = ()>(
PhantomData<(System, Block, Context, UnsignedValidator, AllModules, OnRuntimeUpgrade)>
);

impl<
Expand All @@ -116,7 +165,9 @@ impl<
OnInitialize<System::BlockNumber> +
OnFinalize<System::BlockNumber> +
OffchainWorker<System::BlockNumber>,
> ExecuteBlock<Block> for Executive<System, Block, Context, UnsignedValidator, AllModules>
COnRuntimeUpgrade: OnRuntimeUpgrade,
> ExecuteBlock<Block> for
Executive<System, Block, Context, UnsignedValidator, AllModules, COnRuntimeUpgrade>
where
Block::Extrinsic: Checkable<Context> + Codec,
CheckedOf<Block::Extrinsic, Context>:
Expand All @@ -141,7 +192,8 @@ impl<
OnInitialize<System::BlockNumber> +
OnFinalize<System::BlockNumber> +
OffchainWorker<System::BlockNumber>,
> Executive<System, Block, Context, UnsignedValidator, AllModules>
COnRuntimeUpgrade: OnRuntimeUpgrade,
> Executive<System, Block, Context, UnsignedValidator, AllModules, COnRuntimeUpgrade>
where
Block::Extrinsic: Checkable<Context> + Codec,
CheckedOf<Block::Extrinsic, Context>:
Expand Down Expand Up @@ -180,8 +232,9 @@ where
) {
if Self::runtime_upgraded() {
// System is not part of `AllModules`, so we need to call this manually.
<frame_system::Module::<System> as OnRuntimeUpgrade>::on_runtime_upgrade();
let weight = <AllModules as OnRuntimeUpgrade>::on_runtime_upgrade();
let mut weight = <frame_system::Module::<System> as OnRuntimeUpgrade>::on_runtime_upgrade();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was this a bug before?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was discarded before, so I would say yes.

weight = weight.saturating_add(COnRuntimeUpgrade::on_runtime_upgrade());
weight = weight.saturating_add(<AllModules as OnRuntimeUpgrade>::on_runtime_upgrade());
<frame_system::Module<System>>::register_extra_weight_unchecked(weight);
}
<frame_system::Module<System>>::initialize(
Expand Down Expand Up @@ -410,6 +463,7 @@ mod tests {
use frame_system::{self as system, Call as SystemCall, ChainContext, LastRuntimeUpgradeInfo};
use pallet_balances::Call as BalancesCall;
use hex_literal::hex;
const TEST_KEY: &[u8] = &*b":test:key:";

mod custom {
use frame_support::weights::{Weight, DispatchClass};
Expand Down Expand Up @@ -442,6 +496,11 @@ mod tests {
fn on_finalize() {
println!("on_finalize(?)");
}

fn on_runtime_upgrade() -> Weight {
sp_io::storage::set(super::TEST_KEY, "module".as_bytes());
0
}
}
}
}
Expand Down Expand Up @@ -570,7 +629,27 @@ mod tests {
);
type AllModules = (System, Balances, Custom);
type TestXt = sp_runtime::testing::TestXt<Call, SignedExtra>;
type Executive = super::Executive<Runtime, Block<TestXt>, ChainContext<Runtime>, Runtime, AllModules>;

// Will contain `true` when the custom runtime logic was called.
const CUSTOM_ON_RUNTIME_KEY: &[u8] = &*b":custom:on_runtime";

struct CustomOnRuntimeUpgrade;
impl OnRuntimeUpgrade for CustomOnRuntimeUpgrade {
fn on_runtime_upgrade() -> Weight {
sp_io::storage::set(TEST_KEY, "custom_upgrade".as_bytes());
sp_io::storage::set(CUSTOM_ON_RUNTIME_KEY, &true.encode());
0
}
}

type Executive = super::Executive<
Runtime,
Block<TestXt>,
ChainContext<Runtime>,
Runtime,
AllModules,
CustomOnRuntimeUpgrade
>;

fn extra(nonce: u64, fee: Balance) -> SignedExtra {
(
Expand Down Expand Up @@ -899,4 +978,26 @@ mod tests {
assert_eq!(result, last.was_upgraded(&current));
}
}

#[test]
fn custom_runtime_upgrade_is_called_before_modules() {
new_test_ext(1).execute_with(|| {
// Make sure `on_runtime_upgrade` is called.
RUNTIME_VERSION.with(|v| *v.borrow_mut() = sp_version::RuntimeVersion {
spec_version: 1,
..Default::default()
});

Executive::initialize_block(&Header::new(
1,
H256::default(),
H256::default(),
[69u8; 32].into(),
Digest::default(),
));

assert_eq!(&sp_io::storage::get(TEST_KEY).unwrap()[..], *b"module");
assert_eq!(sp_io::storage::get(CUSTOM_ON_RUNTIME_KEY).unwrap(), true.encode());
});
}
}