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

Relay-parent digest logs for parachains #2552

Merged
merged 11 commits into from
May 13, 2023
9 changes: 9 additions & 0 deletions pallets/parachain-system/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<T>::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.
Expand Down
15 changes: 15 additions & 0 deletions pallets/parachain-system/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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());
},
);
}
89 changes: 88 additions & 1 deletion primitives/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,15 @@

#![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;
use sp_runtime::{traits::Block as BlockT, RuntimeDebug};
use sp_runtime::RuntimeDebug;
use sp_std::prelude::*;

pub use polkadot_core_primitives::InboundDownwardMessage;
Expand All @@ -41,6 +46,11 @@ pub mod relay_chain {
pub use polkadot_primitives::*;
}

/// A module that re-exports relevant Substrate primitive types.
pub mod substrate {
rphmeier marked this conversation as resolved.
Show resolved Hide resolved
pub use sp_runtime::*;
}

/// An inbound HRMP message.
pub type InboundHrmpMessage = polkadot_primitives::InboundHrmpMessage<relay_chain::BlockNumber>;

Expand Down Expand Up @@ -198,6 +208,83 @@ impl<B: BlockT> ParachainBlockData<B> {
}
}

/// 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.
rphmeier marked this conversation as resolved.
Show resolved Hide resolved
#[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<relay_chain::Hash> {
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,
})
}

/// 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>.
///
/// Runtimes using the parachain-system pallet are expected produce this digest item,
rphmeier marked this conversation as resolved.
Show resolved Hide resolved
/// 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};

/// 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,
rphmeier marked this conversation as resolved.
Show resolved Hide resolved
) -> 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<relay_chain::Hash> {
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,
},
rphmeier marked this conversation as resolved.
Show resolved Hide resolved
_ => None,
})
}
}

/// Information about a collation.
///
/// This was used in version 1 of the [`CollectCollationInfo`] runtime api.
Expand Down