Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

omni-node: add metadata checks for runtime/parachain compatibility #6450

Draft
wants to merge 12 commits into
base: master
Choose a base branch
from
3 changes: 3 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 7 additions & 6 deletions cumulus/polkadot-omni-node/lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ workspace = true
path = "src/lib.rs"

[dependencies]
anyhow = { workspace = true }
async-trait = { workspace = true }
clap = { features = ["derive"], workspace = true }
codec = { workspace = true, default-features = true }
Expand All @@ -26,6 +27,10 @@ docify = { workspace = true }
# Local
jsonrpsee = { features = ["server"], workspace = true }
parachains-common = { workspace = true, default-features = true }
frame-metadata = { workspace = true, default-features = true, features = [
"decode",
lexnv marked this conversation as resolved.
Show resolved Hide resolved
] }
scale-info = { workspace = true }

# Substrate
frame-benchmarking = { optional = true, workspace = true, default-features = true }
Expand Down Expand Up @@ -94,12 +99,8 @@ wait-timeout = { workspace = true }

[features]
default = []
rococo-native = [
"polkadot-cli/rococo-native",
]
westend-native = [
"polkadot-cli/westend-native",
]
rococo-native = ["polkadot-cli/rococo-native"]
westend-native = ["polkadot-cli/westend-native"]
runtime-benchmarks = [
"cumulus-primitives-core/runtime-benchmarks",
"frame-benchmarking-cli/runtime-benchmarks",
Expand Down
94 changes: 94 additions & 0 deletions cumulus/polkadot-omni-node/lib/src/common/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@

//! Runtime parameters.

use std::fmt::Display;

use sc_chain_spec::ChainSpec;
use scale_info::{form::PortableForm, TypeDef, TypeDefPrimitive};

/// The Aura ID used by the Aura consensus
#[derive(PartialEq)]
Expand All @@ -43,6 +46,34 @@ pub enum BlockNumber {
U64,
}

impl Display for BlockNumber {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
BlockNumber::U32 => write!(f, "u32"),
BlockNumber::U64 => write!(f, "u64"),
}
}
}

impl Into<TypeDefPrimitive> for BlockNumber {
fn into(self) -> TypeDefPrimitive {
match self {
BlockNumber::U32 => TypeDefPrimitive::U32,
BlockNumber::U64 => TypeDefPrimitive::U64,
}
}
}

impl BlockNumber {
fn from_type_def(type_def: &TypeDef<PortableForm>) -> Option<BlockNumber> {
match type_def {
TypeDef::Primitive(TypeDefPrimitive::U32) => Some(BlockNumber::U32),
TypeDef::Primitive(TypeDefPrimitive::U64) => Some(BlockNumber::U64),
_ => None,
}
}
}

/// Helper enum listing the supported Runtime types
#[derive(PartialEq)]
pub enum Runtime {
Expand All @@ -66,3 +97,66 @@ impl RuntimeResolver for DefaultRuntimeResolver {
Ok(Runtime::Omni(BlockNumber::U32, Consensus::Aura(AuraConsensusId::Sr25519)))
}
}

/// Logic that inspects runtime's metadata for Omni Node compatibility.
pub mod metadata {
use super::BlockNumber;
use frame_metadata::{RuntimeMetadata, RuntimeMetadataPrefixed};

/// Checks if pallet exists in runtime's metadata based on pallet name.
pub fn pallet_exists(
metadata: &RuntimeMetadataPrefixed,
name: &str,
) -> Result<bool, sc_service::error::Error> {
match &metadata.1 {
RuntimeMetadata::V14(inner) => Ok(inner.pallets.iter().any(|p| p.name == name)),
RuntimeMetadata::V15(inner) => Ok(inner.pallets.iter().any(|p| p.name == name)),
_ => Err(sc_service::error::Error::Application(
anyhow::anyhow!(format!(
"Metadata version {} not supported for checking against pallet existence.",
metadata.0
))
.into(),
)),
}
}

/// Get the configured runtime's block number type from `frame-system` pallet storage.
pub fn runtime_block_number(
metadata: &RuntimeMetadataPrefixed,
) -> Result<BlockNumber, sc_service::error::Error> {
// Macro to define reusable logic for processing metadata.
macro_rules! process_metadata {
($metadata:expr) => {{
$metadata
.pallets
.iter()
.find(|p| p.name == "System")
.and_then(|system| system.storage.as_ref())
.and_then(|storage| storage.entries.iter().find(|entry| entry.name == "Number"))
.and_then(|number_ty| match number_ty.ty {
frame_metadata::v14::StorageEntryType::Plain(ty) => Some(ty.id),
_ => None,
})
.and_then(|number_id| $metadata.types.resolve(number_id))
.and_then(|portable_type| BlockNumber::from_type_def(&portable_type.type_def))
}};
}

let err_msg = "Can not get block number type from `frame-system-pallet` storage.";
match &metadata.1 {
RuntimeMetadata::V14(meta) => process_metadata!(meta).ok_or(sc_service::error::Error::Application(
anyhow::anyhow!(err_msg).into())),
RuntimeMetadata::V15(meta) => process_metadata!(meta).ok_or(sc_service::error::Error::Application(
anyhow::anyhow!(err_msg).into())),
_ =>
Err(sc_service::error::Error::Application(
anyhow::anyhow!(format!(
"Metadata version {} not supported for checking block number type stored in `frame-system-pallet` storage.",
metadata.0
))
.into(),
)),
}
}
}
Loading
Loading