mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-19 22:51:03 +00:00
Emit log on Runtime Code change. (#9580)
* Emit digest item on Runtime Code changes. * Add tests. * cargo +nightly fmt --all * Rename. * Add comment. * Move generic parameter to the trait. * cargo +nightly fmt --all * Elaborate in doc. * Revert to RuntimeUpdated name * cargo +nightly fmt --all * Rename to RuntimeEnvironmentUpdated
This commit is contained in:
@@ -138,14 +138,14 @@ pub type ConsumedWeight = PerDispatchClass<Weight>;
|
|||||||
pub use pallet::*;
|
pub use pallet::*;
|
||||||
|
|
||||||
/// Do something when we should be setting the code.
|
/// Do something when we should be setting the code.
|
||||||
pub trait SetCode {
|
pub trait SetCode<T: Config> {
|
||||||
/// Set the code to the given blob.
|
/// Set the code to the given blob.
|
||||||
fn set_code(code: Vec<u8>) -> DispatchResult;
|
fn set_code(code: Vec<u8>) -> DispatchResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SetCode for () {
|
impl<T: Config> SetCode<T> for () {
|
||||||
fn set_code(code: Vec<u8>) -> DispatchResult {
|
fn set_code(code: Vec<u8>) -> DispatchResult {
|
||||||
storage::unhashed::put_raw(well_known_keys::CODE, &code);
|
<Pallet<T>>::update_code_in_storage(&code)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -296,9 +296,13 @@ pub mod pallet {
|
|||||||
#[pallet::constant]
|
#[pallet::constant]
|
||||||
type SS58Prefix: Get<u16>;
|
type SS58Prefix: Get<u16>;
|
||||||
|
|
||||||
/// What to do if the user wants the code set to something. Just use `()` unless you are in
|
/// What to do if the runtime wants to change the code to something new.
|
||||||
/// cumulus.
|
///
|
||||||
type OnSetCode: SetCode;
|
/// The default (`()`) implementation is responsible for setting the correct storage
|
||||||
|
/// entry and emitting corresponding event and log item. (see [`update_code_in_storage`]).
|
||||||
|
/// It's unlikely that this needs to be customized, unless you are writing a parachain using
|
||||||
|
/// `Cumulus`, where the actual code change is deferred.
|
||||||
|
type OnSetCode: SetCode<Self>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pallet::pallet]
|
#[pallet::pallet]
|
||||||
@@ -350,11 +354,13 @@ pub mod pallet {
|
|||||||
/// - 1 storage write.
|
/// - 1 storage write.
|
||||||
/// - Base Weight: 1.405 µs
|
/// - Base Weight: 1.405 µs
|
||||||
/// - 1 write to HEAP_PAGES
|
/// - 1 write to HEAP_PAGES
|
||||||
|
/// - 1 digest item
|
||||||
/// # </weight>
|
/// # </weight>
|
||||||
#[pallet::weight((T::SystemWeightInfo::set_heap_pages(), DispatchClass::Operational))]
|
#[pallet::weight((T::SystemWeightInfo::set_heap_pages(), DispatchClass::Operational))]
|
||||||
pub fn set_heap_pages(origin: OriginFor<T>, pages: u64) -> DispatchResultWithPostInfo {
|
pub fn set_heap_pages(origin: OriginFor<T>, pages: u64) -> DispatchResultWithPostInfo {
|
||||||
ensure_root(origin)?;
|
ensure_root(origin)?;
|
||||||
storage::unhashed::put_raw(well_known_keys::HEAP_PAGES, &pages.encode());
|
storage::unhashed::put_raw(well_known_keys::HEAP_PAGES, &pages.encode());
|
||||||
|
Self::deposit_log(generic::DigestItem::RuntimeEnvironmentUpdated);
|
||||||
Ok(().into())
|
Ok(().into())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -362,9 +368,10 @@ pub mod pallet {
|
|||||||
///
|
///
|
||||||
/// # <weight>
|
/// # <weight>
|
||||||
/// - `O(C + S)` where `C` length of `code` and `S` complexity of `can_set_code`
|
/// - `O(C + S)` where `C` length of `code` and `S` complexity of `can_set_code`
|
||||||
/// - 1 storage write (codec `O(C)`).
|
|
||||||
/// - 1 call to `can_set_code`: `O(S)` (calls `sp_io::misc::runtime_version` which is
|
/// - 1 call to `can_set_code`: `O(S)` (calls `sp_io::misc::runtime_version` which is
|
||||||
/// expensive).
|
/// expensive).
|
||||||
|
/// - 1 storage write (codec `O(C)`).
|
||||||
|
/// - 1 digest item.
|
||||||
/// - 1 event.
|
/// - 1 event.
|
||||||
/// The weight of this function is dependent on the runtime, but generally this is very
|
/// The weight of this function is dependent on the runtime, but generally this is very
|
||||||
/// expensive. We will treat this as a full block.
|
/// expensive. We will treat this as a full block.
|
||||||
@@ -373,9 +380,7 @@ pub mod pallet {
|
|||||||
pub fn set_code(origin: OriginFor<T>, code: Vec<u8>) -> DispatchResultWithPostInfo {
|
pub fn set_code(origin: OriginFor<T>, code: Vec<u8>) -> DispatchResultWithPostInfo {
|
||||||
ensure_root(origin)?;
|
ensure_root(origin)?;
|
||||||
Self::can_set_code(&code)?;
|
Self::can_set_code(&code)?;
|
||||||
|
|
||||||
T::OnSetCode::set_code(code)?;
|
T::OnSetCode::set_code(code)?;
|
||||||
Self::deposit_event(Event::CodeUpdated);
|
|
||||||
Ok(().into())
|
Ok(().into())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -384,6 +389,7 @@ pub mod pallet {
|
|||||||
/// # <weight>
|
/// # <weight>
|
||||||
/// - `O(C)` where `C` length of `code`
|
/// - `O(C)` where `C` length of `code`
|
||||||
/// - 1 storage write (codec `O(C)`).
|
/// - 1 storage write (codec `O(C)`).
|
||||||
|
/// - 1 digest item.
|
||||||
/// - 1 event.
|
/// - 1 event.
|
||||||
/// The weight of this function is dependent on the runtime. We will treat this as a full
|
/// The weight of this function is dependent on the runtime. We will treat this as a full
|
||||||
/// block. # </weight>
|
/// block. # </weight>
|
||||||
@@ -394,7 +400,6 @@ pub mod pallet {
|
|||||||
) -> DispatchResultWithPostInfo {
|
) -> DispatchResultWithPostInfo {
|
||||||
ensure_root(origin)?;
|
ensure_root(origin)?;
|
||||||
T::OnSetCode::set_code(code)?;
|
T::OnSetCode::set_code(code)?;
|
||||||
Self::deposit_event(Event::CodeUpdated);
|
|
||||||
Ok(().into())
|
Ok(().into())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1071,6 +1076,18 @@ impl<T: Config> Pallet<T> {
|
|||||||
Account::<T>::contains_key(who)
|
Account::<T>::contains_key(who)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Write code to the storage and emit related events and digest items.
|
||||||
|
///
|
||||||
|
/// Note this function almost never should be used directly. It is exposed
|
||||||
|
/// for `OnSetCode` implementations that defer actual code being written to
|
||||||
|
/// the storage (for instance in case of parachains).
|
||||||
|
pub fn update_code_in_storage(code: &[u8]) -> DispatchResult {
|
||||||
|
storage::unhashed::put_raw(well_known_keys::CODE, code);
|
||||||
|
Self::deposit_log(generic::DigestItem::RuntimeEnvironmentUpdated);
|
||||||
|
Self::deposit_event(Event::CodeUpdated);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Increment the reference counter on an account.
|
/// Increment the reference counter on an account.
|
||||||
#[deprecated = "Use `inc_consumers` instead"]
|
#[deprecated = "Use `inc_consumers` instead"]
|
||||||
pub fn inc_ref(who: &T::AccountId) {
|
pub fn inc_ref(who: &T::AccountId) {
|
||||||
|
|||||||
@@ -390,11 +390,24 @@ fn set_code_checks_works() {
|
|||||||
ext.execute_with(|| {
|
ext.execute_with(|| {
|
||||||
let res = System::set_code(RawOrigin::Root.into(), vec![1, 2, 3, 4]);
|
let res = System::set_code(RawOrigin::Root.into(), vec![1, 2, 3, 4]);
|
||||||
|
|
||||||
|
assert_runtime_updated_digest(if res.is_ok() { 1 } else { 0 });
|
||||||
assert_eq!(expected.map_err(DispatchErrorWithPostInfo::from), res);
|
assert_eq!(expected.map_err(DispatchErrorWithPostInfo::from), res);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn assert_runtime_updated_digest(num: usize) {
|
||||||
|
assert_eq!(
|
||||||
|
System::digest()
|
||||||
|
.logs
|
||||||
|
.into_iter()
|
||||||
|
.filter(|item| *item == generic::DigestItem::RuntimeEnvironmentUpdated)
|
||||||
|
.count(),
|
||||||
|
num,
|
||||||
|
"Incorrect number of Runtime Updated digest items",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn set_code_with_real_wasm_blob() {
|
fn set_code_with_real_wasm_blob() {
|
||||||
let executor = substrate_test_runtime_client::new_native_executor();
|
let executor = substrate_test_runtime_client::new_native_executor();
|
||||||
@@ -478,3 +491,12 @@ fn extrinsics_root_is_calculated_correctly() {
|
|||||||
assert_eq!(ext_root, *header.extrinsics_root());
|
assert_eq!(ext_root, *header.extrinsics_root());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn runtime_updated_digest_emitted_when_heap_pages_changed() {
|
||||||
|
new_test_ext().execute_with(|| {
|
||||||
|
System::initialize(&1, &[0u8; 32].into(), &Default::default(), InitKind::Full);
|
||||||
|
System::set_heap_pages(RawOrigin::Root.into(), 5).unwrap();
|
||||||
|
assert_runtime_updated_digest(1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@@ -118,6 +118,14 @@ pub enum DigestItem<Hash> {
|
|||||||
|
|
||||||
/// Some other thing. Unsupported and experimental.
|
/// Some other thing. Unsupported and experimental.
|
||||||
Other(Vec<u8>),
|
Other(Vec<u8>),
|
||||||
|
|
||||||
|
/// An indication for the light clients that the runtime execution
|
||||||
|
/// environment is updated.
|
||||||
|
///
|
||||||
|
/// Currently this is triggered when:
|
||||||
|
/// 1. Runtime code blob is changed or
|
||||||
|
/// 2. `heap_pages` value is changed.
|
||||||
|
RuntimeEnvironmentUpdated,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Available changes trie signals.
|
/// Available changes trie signals.
|
||||||
@@ -184,6 +192,8 @@ pub enum DigestItemRef<'a, Hash: 'a> {
|
|||||||
ChangesTrieSignal(&'a ChangesTrieSignal),
|
ChangesTrieSignal(&'a ChangesTrieSignal),
|
||||||
/// Any 'non-system' digest item, opaque to the native code.
|
/// Any 'non-system' digest item, opaque to the native code.
|
||||||
Other(&'a Vec<u8>),
|
Other(&'a Vec<u8>),
|
||||||
|
/// Runtime code or heap pages updated.
|
||||||
|
RuntimeEnvironmentUpdated,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Type of the digest item. Used to gain explicit control over `DigestItem` encoding
|
/// Type of the digest item. Used to gain explicit control over `DigestItem` encoding
|
||||||
@@ -199,6 +209,7 @@ pub enum DigestItemType {
|
|||||||
Seal = 5,
|
Seal = 5,
|
||||||
PreRuntime = 6,
|
PreRuntime = 6,
|
||||||
ChangesTrieSignal = 7,
|
ChangesTrieSignal = 7,
|
||||||
|
RuntimeEnvironmentUpdated = 8,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Type of a digest item that contains raw data; this also names the consensus engine ID where
|
/// Type of a digest item that contains raw data; this also names the consensus engine ID where
|
||||||
@@ -225,6 +236,7 @@ impl<Hash> DigestItem<Hash> {
|
|||||||
Self::Seal(ref v, ref s) => DigestItemRef::Seal(v, s),
|
Self::Seal(ref v, ref s) => DigestItemRef::Seal(v, s),
|
||||||
Self::ChangesTrieSignal(ref s) => DigestItemRef::ChangesTrieSignal(s),
|
Self::ChangesTrieSignal(ref s) => DigestItemRef::ChangesTrieSignal(s),
|
||||||
Self::Other(ref v) => DigestItemRef::Other(v),
|
Self::Other(ref v) => DigestItemRef::Other(v),
|
||||||
|
Self::RuntimeEnvironmentUpdated => DigestItemRef::RuntimeEnvironmentUpdated,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -322,6 +334,7 @@ impl<Hash: Decode> Decode for DigestItem<Hash> {
|
|||||||
DigestItemType::ChangesTrieSignal =>
|
DigestItemType::ChangesTrieSignal =>
|
||||||
Ok(Self::ChangesTrieSignal(Decode::decode(input)?)),
|
Ok(Self::ChangesTrieSignal(Decode::decode(input)?)),
|
||||||
DigestItemType::Other => Ok(Self::Other(Decode::decode(input)?)),
|
DigestItemType::Other => Ok(Self::Other(Decode::decode(input)?)),
|
||||||
|
DigestItemType::RuntimeEnvironmentUpdated => Ok(Self::RuntimeEnvironmentUpdated),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -457,6 +470,9 @@ impl<'a, Hash: Encode> Encode for DigestItemRef<'a, Hash> {
|
|||||||
DigestItemType::Other.encode_to(&mut v);
|
DigestItemType::Other.encode_to(&mut v);
|
||||||
val.encode_to(&mut v);
|
val.encode_to(&mut v);
|
||||||
},
|
},
|
||||||
|
Self::RuntimeEnvironmentUpdated => {
|
||||||
|
DigestItemType::RuntimeEnvironmentUpdated.encode_to(&mut v);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
v
|
v
|
||||||
|
|||||||
Reference in New Issue
Block a user