diff --git a/prdoc/pr_11215.prdoc b/prdoc/pr_11215.prdoc new file mode 100644 index 0000000000000..0cada6dc81413 --- /dev/null +++ b/prdoc/pr_11215.prdoc @@ -0,0 +1,10 @@ +title: try state hook for pallet authorship +doc: +- audience: Runtime Dev + description: |- + This PR introduces the try_state hook to pallet-authorship to verify a key storage invariant. + + closes part of https://github.com/paritytech/polkadot-sdk/issues/239 +crates: +- name: pallet-authorship + bump: minor diff --git a/substrate/frame/authorship/src/lib.rs b/substrate/frame/authorship/src/lib.rs index 4c3061ef8fde7..a7189a4ea4529 100644 --- a/substrate/frame/authorship/src/lib.rs +++ b/substrate/frame/authorship/src/lib.rs @@ -64,6 +64,11 @@ pub mod pallet { // ensure we never go to trie with these values. >::kill(); } + + #[cfg(feature = "try-runtime")] + fn try_state(_n: BlockNumberFor) -> Result<(), sp_runtime::TryRuntimeError> { + Self::do_try_state() + } } #[pallet::storage] @@ -91,6 +96,32 @@ impl Pallet { } } +#[cfg(any(feature = "try-runtime", test))] +impl Pallet { + /// Ensure the correctness of the state of this pallet. + /// + /// # Invariants + /// + /// * If `Author` storage contains a value, it must match the author derived from the current + /// block's digest via `FindAuthor`. + pub fn do_try_state() -> Result<(), sp_runtime::TryRuntimeError> { + use frame_support::ensure; + + if let Some(stored_author) = >::get() { + let digest = >::digest(); + let pre_runtime_digests = digest.logs.iter().filter_map(|d| d.as_pre_runtime()); + if let Some(expected_author) = T::FindAuthor::find_author(pre_runtime_digests) { + ensure!( + stored_author == expected_author, + "Stored author does not match the author derived from digest" + ); + } + } + + Ok(()) + } +} + #[cfg(test)] mod tests { use super::*; @@ -172,6 +203,7 @@ mod tests { System::initialize(&1, &Default::default(), header.digest()); assert_eq!(Authorship::author(), Some(author)); + Authorship::do_try_state().unwrap(); }); } }