From 3d4e7741a9bf5c4ec26a317e674a075e8562705e Mon Sep 17 00:00:00 2001 From: Lola Aimar Date: Thu, 29 Jan 2026 14:21:28 -0300 Subject: [PATCH 1/3] add dependencies --- Cargo.lock | 84 ++++++++++++++++++++++++++++++++++++++++--------- Cargo.toml | 2 ++ node/Cargo.toml | 4 +++ 3 files changed, 75 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3deffcd..855ba86 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3521,6 +3521,8 @@ dependencies = [ "sc-cli", "sc-client-api", "sc-consensus", + "sc-consensus-aura", + "sc-consensus-grandpa", "sc-consensus-manual-seal", "sc-executor", "sc-network", @@ -3532,6 +3534,8 @@ dependencies = [ "sp-api", "sp-block-builder", "sp-blockchain", + "sp-consensus-aura", + "sp-consensus-grandpa", "sp-genesis-builder", "sp-io", "sp-runtime", @@ -3604,7 +3608,7 @@ dependencies = [ "sc-client-api", "sc-executor", "scale-info", - "schemars 1.0.4", + "schemars 0.8.22", "secp256k1 0.26.0", "serde", "serde_json", @@ -8703,6 +8707,50 @@ dependencies = [ "sp-runtime", ] +[[package]] +name = "sc-consensus-grandpa" +version = "0.36.0" +source = "git+https://github.com/paritytech/polkadot-sdk.git?tag=polkadot-stable2506-2#2caeef482a437414c6bed2395a16abe08fccbfbb" +dependencies = [ + "ahash 0.8.12", + "array-bytes", + "async-trait", + "dyn-clone", + "finality-grandpa", + "fork-tree", + "futures", + "futures-timer", + "log", + "parity-scale-codec", + "parking_lot 0.12.3", + "rand 0.8.5", + "sc-block-builder", + "sc-chain-spec", + "sc-client-api", + "sc-consensus", + "sc-network", + "sc-network-common", + "sc-network-gossip", + "sc-network-sync", + "sc-network-types", + "sc-telemetry", + "sc-transaction-pool-api", + "sc-utils", + "serde_json", + "sp-api", + "sp-application-crypto", + "sp-arithmetic", + "sp-blockchain", + "sp-consensus", + "sp-consensus-grandpa", + "sp-core", + "sp-crypto-hashing", + "sp-keystore", + "sp-runtime", + "substrate-prometheus-endpoint", + "thiserror 1.0.69", +] + [[package]] name = "sc-consensus-manual-seal" version = "0.52.0" @@ -8942,6 +8990,25 @@ dependencies = [ "sp-runtime", ] +[[package]] +name = "sc-network-gossip" +version = "0.51.0" +source = "git+https://github.com/paritytech/polkadot-sdk.git?tag=polkadot-stable2506-2#2caeef482a437414c6bed2395a16abe08fccbfbb" +dependencies = [ + "ahash 0.8.12", + "futures", + "futures-timer", + "log", + "sc-network", + "sc-network-common", + "sc-network-sync", + "sc-network-types", + "schnellru", + "sp-runtime", + "substrate-prometheus-endpoint", + "tracing", +] + [[package]] name = "sc-network-light" version = "0.50.0" @@ -9413,7 +9480,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615" dependencies = [ "dyn-clone", - "schemars_derive 0.8.22", + "schemars_derive", "serde", "serde_json", ] @@ -9438,7 +9505,6 @@ checksum = "82d20c4491bc164fa2f6c5d44565947a52ad80b9505d8e36f8d54c27c739fcd0" dependencies = [ "dyn-clone", "ref-cast", - "schemars_derive 1.0.4", "serde", "serde_json", ] @@ -9455,18 +9521,6 @@ dependencies = [ "syn 2.0.101", ] -[[package]] -name = "schemars_derive" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d020396d1d138dc19f1165df7545479dcd58d93810dc5d646a16e55abefa80" -dependencies = [ - "proc-macro2", - "quote", - "serde_derive_internals", - "syn 2.0.101", -] - [[package]] name = "schnellru" version = "0.2.4" diff --git a/Cargo.toml b/Cargo.toml index 521b330..ceb69fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -114,6 +114,8 @@ sc-cli = { default-features = false, git = "https://github.com/paritytech/polkad sc-client-api = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2506-2" } sc-consensus = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2506-2" } sc-consensus-manual-seal = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2506-2" } +sc-consensus-aura = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2506-2" } +sc-consensus-grandpa = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2506-2" } sc-executor = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2506-2" } sc-keystore = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2506-2" } sc-network = { default-features = false, git = "https://github.com/paritytech/polkadot-sdk.git", tag = "polkadot-stable2506-2" } diff --git a/node/Cargo.toml b/node/Cargo.toml index 15bedda..7ae44ed 100644 --- a/node/Cargo.toml +++ b/node/Cargo.toml @@ -29,6 +29,8 @@ sc-cli = { workspace = true } sc-client-api = { workspace = true } sc-consensus = { workspace = true } sc-consensus-manual-seal = { workspace = true } +sc-consensus-aura = { workspace = true } +sc-consensus-grandpa = { workspace = true } sc-executor = { workspace = true } sc-network = { workspace = true } sc-service = { workspace = true } @@ -39,6 +41,8 @@ serde_json = { workspace = true } sp-api = { workspace = true } sp-block-builder = { workspace = true } sp-blockchain = { workspace = true } +sp-consensus-aura = { workspace = true } +sp-consensus-grandpa = { workspace = true } sp-genesis-builder = { workspace = true } sp-io = { workspace = true } sp-timestamp = { workspace = true } From d7c3b569d112acdf5a215bac6a99e4236be10cb1 Mon Sep 17 00:00:00 2001 From: Lola Aimar Date: Thu, 29 Jan 2026 14:22:10 -0300 Subject: [PATCH 2/3] implements aura and grandpa consensus --- griffin-core/src/executive.rs | 3 +- node/src/command.rs | 14 +- node/src/service.rs | 250 +++++++++++++++++++++++----------- 3 files changed, 178 insertions(+), 89 deletions(-) diff --git a/griffin-core/src/executive.rs b/griffin-core/src/executive.rs index afa19ab..013853b 100644 --- a/griffin-core/src/executive.rs +++ b/griffin-core/src/executive.rs @@ -346,8 +346,7 @@ where // performing pool validations and other off-chain runtime calls. sp_io::storage::set(HEIGHT_KEY, &header.number().encode()); - if let Some(mut data) = ExtendedHeader::get_pcdata_storage() { - data.count += 1; + if let Some(data) = ExtendedHeader::get_pcdata_storage() { sp_io::storage::set(DATA_KEY, &(data).encode()); } diff --git a/node/src/command.rs b/node/src/command.rs index b07b78e..e49a25f 100644 --- a/node/src/command.rs +++ b/node/src/command.rs @@ -156,16 +156,12 @@ pub fn run() -> sc_cli::Result<()> { griffin_core::types::OpaqueBlock, ::Hash, >, - >( - config, cli.consensus - ) - .map_err(sc_cli::Error::Service), - sc_network::config::NetworkBackendType::Litep2p => service::new_full::< - sc_network::Litep2pNetworkBackend, - >( - config, cli.consensus - ) + >(config) .map_err(sc_cli::Error::Service), + sc_network::config::NetworkBackendType::Litep2p => { + service::new_full::(config) + .map_err(sc_cli::Error::Service) + } } }) } diff --git a/node/src/service.rs b/node/src/service.rs index 0fb926a..8e7bcdd 100644 --- a/node/src/service.rs +++ b/node/src/service.rs @@ -1,12 +1,15 @@ //! Service and ServiceFactory implementation. Specialized wrapper over substrate service. -use crate::cli::Consensus; use griffin_core::{genesis::GriffinGenesisBlockBuilder, types::OpaqueBlock as Block}; use griffin_partner_chains_runtime::{self, RuntimeApi}; +use sc_client_api::client::BlockBackend; +use sc_consensus_aura::ImportQueueParams; use sc_executor::WasmExecutor; use sc_network::peer_store::LOG_TARGET; use sc_service::{error::Error as ServiceError, Configuration, TaskManager}; use sc_telemetry::{log, Telemetry, TelemetryWorker}; +use sc_transaction_pool_api::OffchainTransactionPoolFactory; +use sp_consensus_aura::sr25519::AuthorityPair as AuraPair; use sp_runtime::traits::Block as BlockT; use std::{ sync::Arc, @@ -15,6 +18,10 @@ use std::{ time::{SystemTime, UNIX_EPOCH}, }; +/// The minimum period of blocks on which justifications will be +/// imported and generated. +const GRANDPA_JUSTIFICATION_PERIOD: u32 = 512; + type HostFunctions = sp_io::SubstrateHostFunctions; #[docify::export] @@ -31,7 +38,11 @@ pub type Service = sc_service::PartialComponents< FullSelectChain, sc_consensus::DefaultImportQueue, sc_transaction_pool::TransactionPoolHandle, - Option, + ( + sc_consensus_grandpa::GrandpaBlockImport, + sc_consensus_grandpa::LinkHalf, + Option, + ), >; pub fn new_partial(config: &Configuration) -> Result { @@ -87,11 +98,44 @@ pub fn new_partial(config: &Configuration) -> Result { .build(), ); - let import_queue = sc_consensus_manual_seal::import_queue( - Box::new(client.clone()), - &task_manager.spawn_essential_handle(), - config.prometheus_registry(), - ); + let (grandpa_block_import, grandpa_link) = sc_consensus_grandpa::block_import( + client.clone(), + GRANDPA_JUSTIFICATION_PERIOD, + &client, + select_chain.clone(), + telemetry.as_ref().map(|x| x.handle()), + )?; + + let cidp_client = client.clone(); + let import_queue = + sc_consensus_aura::import_queue::(ImportQueueParams { + block_import: grandpa_block_import.clone(), + justification_import: Some(Box::new(grandpa_block_import.clone())), + client: client.clone(), + create_inherent_data_providers: move |parent_hash, _| { + let cidp_client = cidp_client.clone(); + async move { + let slot_duration = sc_consensus_aura::standalone::slot_duration_at( + &*cidp_client, + parent_hash, + )?; + let timestamp = sp_timestamp::InherentDataProvider::from_system_time(); + + let slot = + sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration( + *timestamp, + slot_duration, + ); + + Ok((slot, timestamp)) + } + }, + spawner: &task_manager.spawn_essential_handle(), + registry: config.prometheus_registry(), + check_for_equivocation: Default::default(), + telemetry: telemetry.as_ref().map(|x| x.handle()), + compatibility_mode: Default::default(), + })?; Ok(sc_service::PartialComponents { client, @@ -101,14 +145,13 @@ pub fn new_partial(config: &Configuration) -> Result { keystore_container, select_chain, transaction_pool, - other: (telemetry), + other: (grandpa_block_import, grandpa_link, telemetry), }) } /// Builds a new service for a full client. pub fn new_full::Hash>>( config: Configuration, - consensus: Consensus, ) -> Result { let sc_service::PartialComponents { client, @@ -118,10 +161,10 @@ pub fn new_full::Ha keystore_container, select_chain, transaction_pool, - other: mut telemetry, + other: (block_import, grandpa_link, mut telemetry), } = new_partial(&config)?; - let net_config = sc_network::config::FullNetworkConfiguration::< + let mut net_config = sc_network::config::FullNetworkConfiguration::< Block, ::Hash, Network, @@ -136,6 +179,23 @@ pub fn new_full::Ha config.prometheus_config.as_ref().map(|cfg| &cfg.registry), ); + let grandpa_protocol_name = sc_consensus_grandpa::protocol_standard_name( + &client + .block_hash(0) + .ok() + .flatten() + .expect("Genesis block exists; qed"), + &config.chain_spec, + ); + let peer_store_handle = net_config.peer_store_handle(); + let (grandpa_protocol_config, grandpa_notification_service) = + sc_consensus_grandpa::grandpa_peers_set_config::<_, Network>( + grandpa_protocol_name.clone(), + metrics.clone(), + Arc::clone(&peer_store_handle), + ); + net_config.add_notification_protocol(grandpa_protocol_config); + let (network, system_rpc_tx, tx_handler_controller, sync_service) = sc_service::build_network(sc_service::BuildNetworkParams { config: &config, @@ -163,6 +223,11 @@ pub fn new_full::Ha }) }; + let role = config.role; + let force_authoring = config.force_authoring; + let backoff_authoring_blocks: Option<()> = None; + let name = config.network.node_name.clone(); + let enable_grandpa = !config.disable_grandpa; let prometheus_registry = config.prometheus_registry().cloned(); let chain_spec = @@ -179,7 +244,7 @@ pub fn new_full::Ha ); let _rpc_handlers = sc_service::spawn_tasks(sc_service::SpawnTasksParams { - network, + network: network.clone(), client: client.clone(), keystore: keystore_container.keystore(), task_manager: &mut task_manager, @@ -188,19 +253,11 @@ pub fn new_full::Ha backend, system_rpc_tx, tx_handler_controller, - sync_service, + sync_service: sync_service.clone(), config, telemetry: telemetry.as_mut(), })?; - let proposer = sc_basic_authorship::ProposerFactory::new( - task_manager.spawn_handle(), - client.clone(), - transaction_pool.clone(), - prometheus_registry.as_ref(), - telemetry.as_ref().map(|x| x.handle()), - ); - let now = SystemTime::now() .duration_since(UNIX_EPOCH) .unwrap() @@ -211,67 +268,104 @@ pub fn new_full::Ha zero_time.checked_sub(now).unwrap_or(0), )); - match consensus { - Consensus::InstantSeal => { - let params = sc_consensus_manual_seal::InstantSealParams { - block_import: client.clone(), - env: proposer, - client, - pool: transaction_pool, - select_chain, - consensus_data_provider: None, - create_inherent_data_providers: move |_, ()| async move { - Ok(sp_timestamp::InherentDataProvider::from_system_time()) - }, - }; + if role.is_authority() { + let proposer_factory = sc_basic_authorship::ProposerFactory::new( + task_manager.spawn_handle(), + client.clone(), + transaction_pool.clone(), + prometheus_registry.as_ref(), + telemetry.as_ref().map(|x| x.handle()), + ); + + let sc = chain_spec["genesis"]["runtimeGenesis"]["patch"]["slot_length"] + .as_u64() + .unwrap(); + + let slot_duration = sc_consensus_aura::SlotDuration::from_millis(sc); - let authorship_future = sc_consensus_manual_seal::run_instant_seal(params); - - task_manager.spawn_essential_handle().spawn_blocking( - "instant-seal", - None, - authorship_future, - ); - } - Consensus::ManualSeal(block_time) => { - let (mut sink, commands_stream) = futures::channel::mpsc::channel(1024); - task_manager - .spawn_handle() - .spawn("block_authoring", None, async move { - loop { - futures_timer::Delay::new(std::time::Duration::from_millis(block_time)) - .await; - sink.try_send(sc_consensus_manual_seal::EngineCommand::SealNewBlock { - create_empty: true, - finalize: true, - parent_hash: None, - sender: None, - }) - .unwrap(); - } - }); - - let params = sc_consensus_manual_seal::ManualSealParams { - block_import: client.clone(), - env: proposer, - client, - pool: transaction_pool, + let aura = sc_consensus_aura::start_aura::( + sc_consensus_aura::StartAuraParams { + slot_duration, + client: client.clone(), select_chain, - commands_stream: Box::pin(commands_stream), - consensus_data_provider: None, + block_import, + proposer_factory, create_inherent_data_providers: move |_, ()| async move { - Ok(sp_timestamp::InherentDataProvider::from_system_time()) + let timestamp = sp_timestamp::InherentDataProvider::from_system_time(); + + let slot = + sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration( + *timestamp, + slot_duration, + ); + + Ok((slot, timestamp)) }, - }; - let authorship_future = sc_consensus_manual_seal::run_manual_seal(params); - - task_manager.spawn_essential_handle().spawn_blocking( - "manual-seal", - None, - authorship_future, - ); - } - _ => {} + force_authoring, + backoff_authoring_blocks, + keystore: keystore_container.keystore(), + sync_oracle: sync_service.clone(), + justification_sync_link: sync_service.clone(), + block_proposal_slot_portion: sc_consensus_aura::SlotProportion::new(2f32 / 3f32), + max_block_proposal_slot_portion: None, + telemetry: telemetry.as_ref().map(|x| x.handle()), + compatibility_mode: Default::default(), + }, + )?; + + // the AURA authoring task is considered essential, i.e. if it + // fails we take down the service with it. + task_manager + .spawn_essential_handle() + .spawn_blocking("aura", Some("block-authoring"), aura); + } + + if enable_grandpa { + // if the node isn't actively participating in consensus then it doesn't + // need a keystore, regardless of which protocol we use below. + let keystore = if role.is_authority() { + Some(keystore_container.keystore()) + } else { + None + }; + + let grandpa_config = sc_consensus_grandpa::Config { + gossip_duration: Duration::from_millis(333), + justification_generation_period: GRANDPA_JUSTIFICATION_PERIOD, + name: Some(name), + observer_enabled: false, + keystore, + local_role: role, + telemetry: telemetry.as_ref().map(|x| x.handle()), + protocol_name: grandpa_protocol_name, + }; + + // start the full GRANDPA voter + // NOTE: non-authorities could run the GRANDPA observer protocol, but at + // this point the full voter should provide better guarantees of block + // and vote data availability than the observer. The observer has not + // been tested extensively yet and having most nodes in a network run it + // could lead to finality stalls. + let grandpa_config = sc_consensus_grandpa::GrandpaParams { + config: grandpa_config, + link: grandpa_link, + network, + sync: Arc::new(sync_service), + notification_service: grandpa_notification_service, + voting_rule: sc_consensus_grandpa::VotingRulesBuilder::default().build(), + prometheus_registry, + shared_voter_state: sc_consensus_grandpa::SharedVoterState::empty(), + telemetry: telemetry.as_ref().map(|x| x.handle()), + offchain_tx_pool_factory: OffchainTransactionPoolFactory::new(transaction_pool), + }; + + // the GRANDPA voter task is considered infallible, i.e. + // if it fails we take down the service with it. + task_manager.spawn_essential_handle().spawn_blocking( + "grandpa-voter", + None, + sc_consensus_grandpa::run_grandpa_voter(grandpa_config)?, + ); } Ok(task_manager) From dbae888a006703a0b376d2875a54ead44f35fd40 Mon Sep 17 00:00:00 2001 From: Lola Aimar Date: Thu, 29 Jan 2026 16:31:44 -0300 Subject: [PATCH 3/3] remove unused structs --- node/src/cli.rs | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/node/src/cli.rs b/node/src/cli.rs index 2798a4d..040a2d0 100644 --- a/node/src/cli.rs +++ b/node/src/cli.rs @@ -4,13 +4,6 @@ use griffin_partner_chains_runtime::opaque::SessionKeys; use partner_chains_cli::{KeyDefinition, AURA, GRANDPA}; use partner_chains_node_commands::{PartnerChainRuntime, PartnerChainsSubcommand}; -#[derive(Debug, Clone)] -pub enum Consensus { - ManualSeal(u64), - InstantSeal, - None, -} - #[derive(Debug, Clone)] pub struct WizardBindings; @@ -72,30 +65,11 @@ impl PartnerChainRuntime for WizardBindings { } } -impl std::str::FromStr for Consensus { - type Err = String; - - fn from_str(s: &str) -> Result { - Ok(if s == "instant-seal" { - Consensus::InstantSeal - } else if let Some(block_time) = s.strip_prefix("manual-seal-") { - Consensus::ManualSeal(block_time.parse().map_err(|_| "invalid block time")?) - } else if s.to_lowercase() == "none" { - Consensus::None - } else { - return Err("incorrect consensus identifier".into()); - }) - } -} - #[derive(Debug, clap::Parser)] pub struct Cli { #[command(subcommand)] pub subcommand: Option, - #[clap(long, default_value = "manual-seal-3000")] - pub consensus: Consensus, - #[clap(flatten)] pub run: sc_cli::RunCmd, }