From 14cb5298c0023cc38285ebd9cdbfd910f2186565 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Sat, 6 May 2023 15:52:16 -0500 Subject: [PATCH 01/11] add digest item for relay-parent to primitives --- primitives/core/src/lib.rs | 40 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/primitives/core/src/lib.rs b/primitives/core/src/lib.rs index 52770cdf716..59ff463df84 100644 --- a/primitives/core/src/lib.rs +++ b/primitives/core/src/lib.rs @@ -24,6 +24,8 @@ use scale_info::TypeInfo; use sp_runtime::{traits::Block as BlockT, RuntimeDebug}; use sp_std::prelude::*; +use crate::substrate::{generic::{Digest, DigestItem}, traits::Block as BlockT, ConsensusEngineId}; + pub use polkadot_core_primitives::InboundDownwardMessage; pub use polkadot_parachain::primitives::{ DmpMessageHandler, Id as ParaId, IsSystem, UpwardMessage, ValidationParams, XcmpMessageFormat, @@ -41,6 +43,11 @@ pub mod relay_chain { pub use polkadot_primitives::*; } +/// A module that re-exports relevant Substrate primitive types. +pub mod substrate { + pub use sp_runtime::*; +} + /// An inbound HRMP message. pub type InboundHrmpMessage = polkadot_primitives::InboundHrmpMessage; @@ -198,6 +205,39 @@ impl ParachainBlockData { } } +/// A consensus engine ID indicating that this is a Cumulus Parachain. +pub const CUMULUS_CONSENSUS_ID: ConsensusEngineId = *b"CMLS"; + +/// Consensus header digests for Cumulus parachains. +#[derive(Clone, RuntimeDebug, Decode, Encode, PartialEq)] +pub enum CumulusDigestItem { + /// A digest item indicating that the parachain block has the provided relay-parent. + #[codec(index = 0)] + RelayParent(relay_chain::Hash), +} + +impl CumulusDigestItem { + /// Encode this as a Substrate [`DigestItem`]. + pub fn to_digest_item(&self) -> DigestItem { + DigestItem::Consensus(CUMULUS_CONSENSUS_ID, self.encode()) + } +} + +/// Extract the relay-parent from the provided header digest. Returns `None` if none were found. +/// +/// If there are multiple valid digests, this returns the value of the first one, although +/// well-behaving runtimes should not produce headers with more than one. +pub fn extract_relay_parent(digest: &Digest) -> Option { + digest.convert_first(|d| match d { + DigestItem::Consensus(id, val) if id == &CUMULUS_CONSENSUS_ID + => match CumulusDigestItem::decode(&mut &val[..]) { + Ok(CumulusDigestItem::RelayParent(hash)) => Some(hash), + _ => None, + } + _ => None, + }) +} + /// Information about a collation. /// /// This was used in version 1 of the [`CollectCollationInfo`] runtime api. From 39cff81974a3855997be36f073541bc63775ff19 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Wed, 10 May 2023 00:03:49 -0500 Subject: [PATCH 02/11] add a relay-parent-storage-root digest as a workaround --- primitives/core/src/lib.rs | 44 +++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/primitives/core/src/lib.rs b/primitives/core/src/lib.rs index 59ff463df84..8421e26a295 100644 --- a/primitives/core/src/lib.rs +++ b/primitives/core/src/lib.rs @@ -18,6 +18,11 @@ #![cfg_attr(not(feature = "std"), no_std)] +use crate::substrate::{ + generic::{Digest, DigestItem}, + traits::Block as BlockT, + ConsensusEngineId, +}; use codec::{Decode, Encode}; use polkadot_parachain::primitives::HeadData; use scale_info::TypeInfo; @@ -229,15 +234,48 @@ impl CumulusDigestItem { /// well-behaving runtimes should not produce headers with more than one. pub fn extract_relay_parent(digest: &Digest) -> Option { digest.convert_first(|d| match d { - DigestItem::Consensus(id, val) if id == &CUMULUS_CONSENSUS_ID - => match CumulusDigestItem::decode(&mut &val[..]) { + DigestItem::Consensus(id, val) if id == &CUMULUS_CONSENSUS_ID => + match CumulusDigestItem::decode(&mut &val[..]) { Ok(CumulusDigestItem::RelayParent(hash)) => Some(hash), _ => None, - } + }, _ => None, }) } +/// Utilities for handling the relay-parent storage root as a digest item. +/// +/// This is not intended to be part of the public API, as it is a workaround for +/// https://github.com/paritytech/cumulus/issues/303 via +/// https://github.com/paritytech/polkadot/issues/7191 +#[doc(hidden)] +pub mod rpsr_digest { + use super::{relay_chain, ConsensusEngineId, Decode, Digest, DigestItem, Encode}; + + /// A consensus engine ID for relay-parent storage root digests. + pub const RPSR_CONSENSUS_ID: ConsensusEngineId = *b"RPSR"; + + /// Construct a digest item for relay-parent storage roots. + pub fn relay_parent_storage_root_item( + relay_parent_storage_root: relay_chain::Hash, + ) -> DigestItem { + DigestItem::Consensus(RPSR_CONSENSUS_ID, relay_parent_storage_root.encode()) + } + + /// Extract the relay-parent storage root from the provided header digest. Returns `None` + /// if none were found. + pub fn extract_relay_parent_storage_root(digest: &Digest) -> Option { + digest.convert_first(|d| match d { + DigestItem::Consensus(id, val) if id == &RPSR_CONSENSUS_ID => + match relay_chain::Hash::decode(&mut &val[..]) { + Ok(hash) => Some(hash), + _ => None, + }, + _ => None, + }) + } +} + /// Information about a collation. /// /// This was used in version 1 of the [`CollectCollationInfo`] runtime api. From 664852f7e72d6cb2fcfc0d982b0cf4698f2f96f1 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Wed, 10 May 2023 00:07:36 -0500 Subject: [PATCH 03/11] more docs --- primitives/core/src/lib.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/primitives/core/src/lib.rs b/primitives/core/src/lib.rs index 8421e26a295..646398844a7 100644 --- a/primitives/core/src/lib.rs +++ b/primitives/core/src/lib.rs @@ -247,7 +247,10 @@ pub fn extract_relay_parent(digest: &Digest) -> Option { /// /// This is not intended to be part of the public API, as it is a workaround for /// https://github.com/paritytech/cumulus/issues/303 via -/// https://github.com/paritytech/polkadot/issues/7191 +/// https://github.com/paritytech/polkadot/issues/7191. +/// +/// Runtimes using the parachain-system pallet are expected produce this digest item, +/// but will stop as soon as they are able to provide the relay-parent hash directly. #[doc(hidden)] pub mod rpsr_digest { use super::{relay_chain, ConsensusEngineId, Decode, Digest, DigestItem, Encode}; From b540df6bb2cd1eff0645deda1dfda26d7d85b169 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Wed, 10 May 2023 00:28:23 -0500 Subject: [PATCH 04/11] deposit log in pallet-parachain-system --- pallets/parachain-system/src/lib.rs | 9 +++++++++ pallets/parachain-system/src/tests.rs | 15 +++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/pallets/parachain-system/src/lib.rs b/pallets/parachain-system/src/lib.rs index 36ef8d57195..d9b4bf00250 100644 --- a/pallets/parachain-system/src/lib.rs +++ b/pallets/parachain-system/src/lib.rs @@ -385,6 +385,15 @@ pub mod pallet { ) .expect("Invalid relay chain state proof"); + // Deposit a log indicating the relay-parent storage root. + // TODO: remove this in favor of the relay-parent's hash after + // https://github.com/paritytech/cumulus/issues/303 + frame_system::Pallet::::deposit_log( + cumulus_primitives_core::rpsr_digest::relay_parent_storage_root_item( + vfp.relay_parent_storage_root, + ), + ); + // initialization logic: we know that this runs exactly once every block, // which means we can put the initialization logic here to remove the // sequencing problem. diff --git a/pallets/parachain-system/src/tests.rs b/pallets/parachain-system/src/tests.rs index a4b1c275b7a..cfbe834983c 100755 --- a/pallets/parachain-system/src/tests.rs +++ b/pallets/parachain-system/src/tests.rs @@ -1006,3 +1006,18 @@ fn upgrade_version_checks_should_work() { }); } } + +#[test] +fn deposits_relay_parent_storage_root() { + BlockTests::new().add_with_post_test( + 123, + || {}, + || { + let digest = System::digest(); + assert!(cumulus_primitives_core::rpsr_digest::extract_relay_parent_storage_root( + &digest + ) + .is_some()); + }, + ); +} From 9e84d8ec245a1b28d314b775544ea02da5d719c9 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Wed, 10 May 2023 00:28:46 -0500 Subject: [PATCH 05/11] even more docs --- primitives/core/src/lib.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/primitives/core/src/lib.rs b/primitives/core/src/lib.rs index 646398844a7..691ae36876b 100644 --- a/primitives/core/src/lib.rs +++ b/primitives/core/src/lib.rs @@ -251,6 +251,14 @@ pub fn extract_relay_parent(digest: &Digest) -> Option { /// /// Runtimes using the parachain-system pallet are expected produce this digest item, /// but will stop as soon as they are able to provide the relay-parent hash directly. +/// +/// The relay-chain storage root is, in practice, a unique identifier of a block +/// in the absence of equivocations (which are slashable). This assumes that the relay chain +/// uses BABE or SASSAFRAS, because the slot and the author's VRF randomness are both included +/// in the relay-chain storage root in both cases. +/// +/// Therefore, the relay-parent storage root is a suitable identifier of unique relay chain +/// blocks in low-value scenarios such as performance optimizations. #[doc(hidden)] pub mod rpsr_digest { use super::{relay_chain, ConsensusEngineId, Decode, Digest, DigestItem, Encode}; From 0abeed6e337931f89685dca954d8ef8c652db991 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Wed, 10 May 2023 16:04:33 -0500 Subject: [PATCH 06/11] fix duplicate imports after botched mertge --- primitives/core/src/lib.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/primitives/core/src/lib.rs b/primitives/core/src/lib.rs index 691ae36876b..f83bac691a7 100644 --- a/primitives/core/src/lib.rs +++ b/primitives/core/src/lib.rs @@ -26,11 +26,9 @@ use crate::substrate::{ use codec::{Decode, Encode}; use polkadot_parachain::primitives::HeadData; use scale_info::TypeInfo; -use sp_runtime::{traits::Block as BlockT, RuntimeDebug}; +use sp_runtime::RuntimeDebug; use sp_std::prelude::*; -use crate::substrate::{generic::{Digest, DigestItem}, traits::Block as BlockT, ConsensusEngineId}; - pub use polkadot_core_primitives::InboundDownwardMessage; pub use polkadot_parachain::primitives::{ DmpMessageHandler, Id as ParaId, IsSystem, UpwardMessage, ValidationParams, XcmpMessageFormat, From 640d45158e9d63bec694b2aafa8a07ad4b1740e9 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Wed, 10 May 2023 16:32:31 -0500 Subject: [PATCH 07/11] fix hyperlinks in docs --- primitives/core/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/primitives/core/src/lib.rs b/primitives/core/src/lib.rs index f83bac691a7..8e7775acd04 100644 --- a/primitives/core/src/lib.rs +++ b/primitives/core/src/lib.rs @@ -244,8 +244,8 @@ pub fn extract_relay_parent(digest: &Digest) -> Option { /// Utilities for handling the relay-parent storage root as a digest item. /// /// This is not intended to be part of the public API, as it is a workaround for -/// https://github.com/paritytech/cumulus/issues/303 via -/// https://github.com/paritytech/polkadot/issues/7191. +/// via +/// . /// /// Runtimes using the parachain-system pallet are expected produce this digest item, /// but will stop as soon as they are able to provide the relay-parent hash directly. From a0726c502eac56a7645e9249fd80a37b58378ad2 Mon Sep 17 00:00:00 2001 From: asynchronous rob Date: Thu, 11 May 2023 12:26:24 -0500 Subject: [PATCH 08/11] clean up match MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bastian Köcher --- primitives/core/src/lib.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/primitives/core/src/lib.rs b/primitives/core/src/lib.rs index 8e7775acd04..a80622d2a59 100644 --- a/primitives/core/src/lib.rs +++ b/primitives/core/src/lib.rs @@ -276,10 +276,7 @@ pub mod rpsr_digest { pub fn extract_relay_parent_storage_root(digest: &Digest) -> Option { digest.convert_first(|d| match d { DigestItem::Consensus(id, val) if id == &RPSR_CONSENSUS_ID => - match relay_chain::Hash::decode(&mut &val[..]) { - Ok(hash) => Some(hash), - _ => None, - }, + relay_chain::Hash::decode(&mut &val[..]).ok(), _ => None, }) } From 2e2d813ef221253d291f5ee82a56b7e8e5d5f429 Mon Sep 17 00:00:00 2001 From: asynchronous rob Date: Thu, 11 May 2023 12:37:41 -0500 Subject: [PATCH 09/11] improve docs --- primitives/core/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/primitives/core/src/lib.rs b/primitives/core/src/lib.rs index a80622d2a59..a7666f59709 100644 --- a/primitives/core/src/lib.rs +++ b/primitives/core/src/lib.rs @@ -214,7 +214,7 @@ pub const CUMULUS_CONSENSUS_ID: ConsensusEngineId = *b"CMLS"; /// Consensus header digests for Cumulus parachains. #[derive(Clone, RuntimeDebug, Decode, Encode, PartialEq)] pub enum CumulusDigestItem { - /// A digest item indicating that the parachain block has the provided relay-parent. + /// A digest item indicating the relay-parent a parachain block was built against. #[codec(index = 0)] RelayParent(relay_chain::Hash), } From 6fd7b773ca1124e927912e6a5319e516a0796368 Mon Sep 17 00:00:00 2001 From: asynchronous rob Date: Thu, 11 May 2023 12:39:10 -0500 Subject: [PATCH 10/11] fix typo --- primitives/core/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/primitives/core/src/lib.rs b/primitives/core/src/lib.rs index a7666f59709..23df8c25d06 100644 --- a/primitives/core/src/lib.rs +++ b/primitives/core/src/lib.rs @@ -247,7 +247,7 @@ pub fn extract_relay_parent(digest: &Digest) -> Option { /// via /// . /// -/// Runtimes using the parachain-system pallet are expected produce this digest item, +/// Runtimes using the parachain-system pallet are expected to produce this digest item, /// but will stop as soon as they are able to provide the relay-parent hash directly. /// /// The relay-chain storage root is, in practice, a unique identifier of a block From de9ded4aef3061dea0a9b45119bf12f764e69249 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Sat, 13 May 2023 00:14:30 -0500 Subject: [PATCH 11/11] add number to the digest item --- pallets/parachain-system/src/lib.rs | 1 + primitives/core/src/lib.rs | 36 ++++++++++++++++------------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/pallets/parachain-system/src/lib.rs b/pallets/parachain-system/src/lib.rs index d9b4bf00250..b841820acfc 100644 --- a/pallets/parachain-system/src/lib.rs +++ b/pallets/parachain-system/src/lib.rs @@ -391,6 +391,7 @@ pub mod pallet { frame_system::Pallet::::deposit_log( cumulus_primitives_core::rpsr_digest::relay_parent_storage_root_item( vfp.relay_parent_storage_root, + vfp.relay_parent_number, ), ); diff --git a/primitives/core/src/lib.rs b/primitives/core/src/lib.rs index 23df8c25d06..752e1aee474 100644 --- a/primitives/core/src/lib.rs +++ b/primitives/core/src/lib.rs @@ -18,11 +18,6 @@ #![cfg_attr(not(feature = "std"), no_std)] -use crate::substrate::{ - generic::{Digest, DigestItem}, - traits::Block as BlockT, - ConsensusEngineId, -}; use codec::{Decode, Encode}; use polkadot_parachain::primitives::HeadData; use scale_info::TypeInfo; @@ -38,6 +33,12 @@ pub use polkadot_primitives::{ AbridgedHostConfiguration, AbridgedHrmpChannel, PersistedValidationData, }; +pub use sp_runtime::{ + generic::{Digest, DigestItem}, + traits::Block as BlockT, + ConsensusEngineId, +}; + pub use xcm::latest::prelude::*; /// A module that re-exports relevant relay chain definitions. @@ -46,11 +47,6 @@ pub mod relay_chain { pub use polkadot_primitives::*; } -/// A module that re-exports relevant Substrate primitive types. -pub mod substrate { - pub use sp_runtime::*; -} - /// An inbound HRMP message. pub type InboundHrmpMessage = polkadot_primitives::InboundHrmpMessage; @@ -260,23 +256,31 @@ pub fn extract_relay_parent(digest: &Digest) -> Option { #[doc(hidden)] pub mod rpsr_digest { use super::{relay_chain, ConsensusEngineId, Decode, Digest, DigestItem, Encode}; + use codec::Compact; /// A consensus engine ID for relay-parent storage root digests. pub const RPSR_CONSENSUS_ID: ConsensusEngineId = *b"RPSR"; /// Construct a digest item for relay-parent storage roots. pub fn relay_parent_storage_root_item( - relay_parent_storage_root: relay_chain::Hash, + storage_root: relay_chain::Hash, + number: impl Into>, ) -> DigestItem { - DigestItem::Consensus(RPSR_CONSENSUS_ID, relay_parent_storage_root.encode()) + DigestItem::Consensus(RPSR_CONSENSUS_ID, (storage_root, number.into()).encode()) } - /// Extract the relay-parent storage root from the provided header digest. Returns `None` + /// Extract the relay-parent storage root and number from the provided header digest. Returns `None` /// if none were found. - pub fn extract_relay_parent_storage_root(digest: &Digest) -> Option { + pub fn extract_relay_parent_storage_root( + digest: &Digest, + ) -> Option<(relay_chain::Hash, relay_chain::BlockNumber)> { digest.convert_first(|d| match d { - DigestItem::Consensus(id, val) if id == &RPSR_CONSENSUS_ID => - relay_chain::Hash::decode(&mut &val[..]).ok(), + DigestItem::Consensus(id, val) if id == &RPSR_CONSENSUS_ID => { + let (h, n): (relay_chain::Hash, Compact) = + Decode::decode(&mut &val[..]).ok()?; + + Some((h, n.0)) + }, _ => None, }) }