diff --git a/Cargo.lock b/Cargo.lock
index 6d692e1..7fcb142 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -593,6 +593,14 @@ version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9"
+[[package]]
+name = "async-backing-primitives"
+version = "0.9.0"
+dependencies = [
+ "sp-api",
+ "sp-consensus-slots",
+]
+
[[package]]
name = "async-channel"
version = "1.9.0"
@@ -1948,6 +1956,21 @@ dependencies = [
"tracing",
]
+[[package]]
+name = "cumulus-client-consensus-proposer"
+version = "0.1.0"
+source = "git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.3.0#401f8a3e9448db854f5605b679fa085b8f445039"
+dependencies = [
+ "anyhow",
+ "async-trait",
+ "cumulus-primitives-parachain-inherent",
+ "sp-consensus",
+ "sp-inherents",
+ "sp-runtime",
+ "sp-state-machine",
+ "thiserror",
+]
+
[[package]]
name = "cumulus-client-network"
version = "0.1.0"
@@ -5720,6 +5743,7 @@ dependencies = [
"cumulus-client-cli",
"cumulus-client-collator",
"cumulus-client-consensus-common",
+ "cumulus-client-consensus-proposer",
"cumulus-client-network",
"cumulus-client-service",
"cumulus-primitives-core",
@@ -5785,6 +5809,7 @@ dependencies = [
name = "moonkit-template-runtime"
version = "0.9.0"
dependencies = [
+ "async-backing-primitives",
"cumulus-pallet-dmp-queue",
"cumulus-pallet-parachain-system",
"cumulus-pallet-xcm",
@@ -5801,6 +5826,7 @@ dependencies = [
"hex-literal 0.3.4",
"log",
"nimbus-primitives",
+ "pallet-async-backing",
"pallet-author-inherent",
"pallet-author-slot-filter",
"pallet-balances",
@@ -6031,15 +6057,22 @@ dependencies = [
name = "nimbus-consensus"
version = "0.9.0"
dependencies = [
+ "async-backing-primitives",
"async-trait",
+ "cumulus-client-collator",
"cumulus-client-consensus-common",
+ "cumulus-client-consensus-proposer",
"cumulus-primitives-core",
"cumulus-primitives-parachain-inherent",
+ "cumulus-relay-chain-interface",
"futures 0.3.28",
"log",
"nimbus-primitives",
"parity-scale-codec",
"parking_lot 0.12.1",
+ "polkadot-node-primitives",
+ "polkadot-node-subsystem",
+ "polkadot-primitives",
"sc-client-api",
"sc-consensus",
"sc-consensus-manual-seal",
@@ -6048,6 +6081,7 @@ dependencies = [
"sp-block-builder",
"sp-blockchain",
"sp-consensus",
+ "sp-consensus-slots",
"sp-core",
"sp-inherents",
"sp-keystore",
@@ -6345,6 +6379,26 @@ dependencies = [
"sp-std",
]
+[[package]]
+name = "pallet-async-backing"
+version = "0.9.0"
+dependencies = [
+ "cumulus-pallet-parachain-system",
+ "cumulus-primitives-core",
+ "frame-support",
+ "frame-system",
+ "log",
+ "nimbus-primitives",
+ "pallet-timestamp",
+ "parity-scale-codec",
+ "scale-info",
+ "sp-consensus-slots",
+ "sp-core",
+ "sp-io",
+ "sp-runtime",
+ "sp-std",
+]
+
[[package]]
name = "pallet-aura-style-filter"
version = "0.9.0"
diff --git a/Cargo.toml b/Cargo.toml
index b6adc92..520efeb 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,14 +1,8 @@
[workspace]
members = [
"client/consensus/nimbus-consensus",
- "pallets/aura-style-filter",
- "pallets/author-inherent",
- "pallets/author-mapping",
- "pallets/author-slot-filter",
- "pallets/migrations",
- "pallets/maintenance-mode",
- "pallets/randomness",
- "primitives/nimbus-primitives",
+ "pallets/*",
+ "primitives/*",
"template/node",
"template/runtime",
"template/pallets/template",
@@ -87,6 +81,7 @@ sp-api = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release
sp-application-crypto = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.3.0", default-features = false }
sp-block-builder = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.3.0", default-features = false }
sp-consensus-babe = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.3.0", default-features = false }
+sp-consensus-slots = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.3.0", default-features = false }
sp-core = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.3.0", default-features = false }
sp-debug-derive = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.3.0", default-features = false }
sp-externalities = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.3.0", default-features = false }
@@ -159,6 +154,7 @@ parachain-info = { git = "https://github.com/paritytech/polkadot-sdk", branch =
cumulus-client-cli = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.3.0" }
cumulus-client-collator = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.3.0" }
cumulus-client-consensus-common = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.3.0" }
+cumulus-client-consensus-proposer = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.3.0" }
cumulus-client-consensus-relay-chain = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.3.0" }
cumulus-client-network = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.3.0" }
cumulus-client-service = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.3.0" }
@@ -171,6 +167,7 @@ cumulus-relay-chain-rpc-interface = { git = "https://github.com/paritytech/polka
pallet-xcm = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.3.0", default-features = false }
pallet-xcm-benchmarks = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.3.0", default-features = false }
polkadot-core-primitives = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.3.0", default-features = false }
+polkadot-node-primitives = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.3.0", default-features = false }
polkadot-parachain-primitives = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.3.0", default-features = false }
polkadot-runtime = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.3.0", default-features = false }
polkadot-runtime-common = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.3.0", default-features = false }
@@ -182,6 +179,7 @@ staging-xcm-executor = { git = "https://github.com/paritytech/polkadot-sdk", bra
# Polkadot (client)
kusama-runtime = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.3.0" }
polkadot-cli = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.3.0" }
+polkadot-node-subsystem = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.3.0" }
polkadot-primitives = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.3.0" }
polkadot-service = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.3.0" }
rococo-runtime = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.3.0" }
@@ -189,9 +187,11 @@ westend-runtime = { git = "https://github.com/paritytech/polkadot-sdk", branch =
xcm-simulator = { git = "https://github.com/paritytech/polkadot-sdk", branch = "release-polkadot-v1.3.0" }
# Local (wasm)
+async-backing-primitives = { path = "primitives/async-backing", default-features = false }
pallet-author-inherent = { path = "pallets/author-inherent", default-features = false }
pallet-author-mapping = { path = "pallets/author-mapping", default-features = false }
pallet-author-slot-filter = { path = "pallets/author-slot-filter", default-features = false }
+pallet-async-backing = { path = "pallets/async-backing", default-features = false }
pallet-maintenance_mode = { path = "pallets/maintenance_mode", default-features = false }
pallet-migrations = { path = "pallets/migrations", default-features = false }
nimbus-primitives = { path = "primitives/nimbus-primitives", default-features = false }
diff --git a/client/consensus/nimbus-consensus/Cargo.toml b/client/consensus/nimbus-consensus/Cargo.toml
index 0b346a4..0be2f00 100644
--- a/client/consensus/nimbus-consensus/Cargo.toml
+++ b/client/consensus/nimbus-consensus/Cargo.toml
@@ -8,6 +8,7 @@ version = "0.9.0"
sc-client-api = { workspace = true }
sc-consensus = { workspace = true }
sc-consensus-manual-seal = { workspace = true }
+sp-consensus-slots = { workspace = true }
sp-api = { workspace = true }
sp-application-crypto = { workspace = true }
sp-block-builder = { workspace = true }
@@ -20,12 +21,21 @@ sp-runtime = { workspace = true }
substrate-prometheus-endpoint = { workspace = true }
# Cumulus dependencies
+cumulus-client-collator = { workspace = true }
cumulus-client-consensus-common = { workspace = true }
+cumulus-client-consensus-proposer = { workspace = true }
cumulus-primitives-core = { workspace = true }
cumulus-primitives-parachain-inherent = { workspace = true }
+cumulus-relay-chain-interface = { workspace = true }
+
+# Polkadot dependencies
+polkadot-node-primitives = { workspace = true }
+polkadot-node-subsystem = { workspace = true }
+polkadot-primitives = { workspace = true }
# Nimbus Dependencies
-nimbus-primitives = { workspace = true }
+async-backing-primitives = { workspace = true, features = ["std"] }
+nimbus-primitives = { workspace = true, features = ["std"] }
# Other deps
async-trait = { workspace = true }
diff --git a/client/consensus/nimbus-consensus/src/collators.rs b/client/consensus/nimbus-consensus/src/collators.rs
new file mode 100644
index 0000000..608b5f8
--- /dev/null
+++ b/client/consensus/nimbus-consensus/src/collators.rs
@@ -0,0 +1,196 @@
+// Copyright Moonsong Labs
+// This file is part of Moonkit.
+
+// Moonkit is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Moonkit is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Moonkit. If not, see .
+
+//! Stock, pure Nimbus collators.
+//!
+//! This includes the [`basic`] collator, which only builds on top of the most recently
+//! included parachain block, as well as the [`lookahead`] collator, which prospectively
+//! builds on parachain blocks which have not yet been included in the relay chain.
+
+pub mod basic;
+pub mod lookahead;
+
+use crate::*;
+use cumulus_client_collator::service::ServiceInterface as CollatorServiceInterface;
+use cumulus_client_consensus_common::{ParachainBlockImportMarker, ParachainCandidate};
+use cumulus_client_consensus_proposer::ProposerInterface;
+use cumulus_primitives_core::ParachainBlockData;
+use cumulus_primitives_parachain_inherent::ParachainInherentData;
+use futures::prelude::*;
+use log::{debug, info};
+use nimbus_primitives::{CompatibleDigestItem, DigestsProvider, NimbusId, NIMBUS_KEY_ID};
+use polkadot_node_primitives::{Collation, MaybeCompressedPoV};
+use sc_consensus::{BlockImport, BlockImportParams};
+use sp_application_crypto::ByteArray;
+use sp_consensus::{BlockOrigin, Proposal};
+use sp_core::{crypto::CryptoTypeId, sr25519, Encode};
+use sp_inherents::InherentData;
+use sp_keystore::Keystore;
+use sp_runtime::{
+ traits::{Block as BlockT, Header as HeaderT},
+ DigestItem,
+};
+use std::convert::TryInto;
+use std::error::Error;
+use std::time::Duration;
+
+/// Propose, seal, and import a block, packaging it into a collation.
+///
+/// Provide the slot to build at as well as any other necessary pre-digest logs,
+/// the inherent data, and the proposal duration and PoV size limits.
+///
+/// The Aura pre-digest should not be explicitly provided and is set internally.
+///
+/// This does not announce the collation to the parachain network or the relay chain.
+pub(crate) async fn collate(
+ additional_digests_provider: &ADP,
+ author_id: NimbusId,
+ block_import: &mut BI,
+ collator_service: &CS,
+ keystore: &dyn Keystore,
+ parent_header: &Block::Header,
+ proposer: &mut Proposer,
+ inherent_data: (ParachainInherentData, InherentData),
+ proposal_duration: Duration,
+ max_pov_size: usize,
+) -> Result<(Collation, ParachainBlockData, Block::Hash), Box>
+where
+ ADP: DigestsProvider::Hash> + 'static,
+ Block: BlockT,
+ BI: BlockImport + ParachainBlockImportMarker + Send + Sync + 'static,
+ CS: CollatorServiceInterface,
+ Proposer: ProposerInterface + Send + Sync + 'static,
+{
+ let mut logs = vec![CompatibleDigestItem::nimbus_pre_digest(author_id.clone())];
+ logs.extend(
+ additional_digests_provider.provide_digests(author_id.clone(), parent_header.hash()),
+ );
+
+ let Proposal {
+ block,
+ storage_changes,
+ proof,
+ } = proposer
+ .propose(
+ &parent_header,
+ &inherent_data.0,
+ inherent_data.1,
+ sp_runtime::generic::Digest { logs },
+ proposal_duration,
+ Some(max_pov_size),
+ )
+ .await
+ .map_err(|e| Box::new(e) as Box)?;
+
+ let (header, extrinsics) = block.clone().deconstruct();
+
+ let sig_digest = seal_header::(
+ &header,
+ keystore,
+ &author_id.to_raw_vec(),
+ &sr25519::CRYPTO_ID,
+ );
+
+ let mut block_import_params = BlockImportParams::new(BlockOrigin::Own, header.clone());
+ block_import_params.post_digests.push(sig_digest.clone());
+ block_import_params.body = Some(extrinsics.clone());
+ block_import_params.state_action = sc_consensus::StateAction::ApplyChanges(
+ sc_consensus::StorageChanges::Changes(storage_changes),
+ );
+
+ let post_hash = block_import_params.post_hash();
+
+ // Print the same log line as slots (aura and babe)
+ info!(
+ "🔖 Sealed block for proposal at {}. Hash now {:?}, previously {:?}.",
+ *header.number(),
+ block_import_params.post_hash(),
+ header.hash(),
+ );
+
+ block_import
+ .import_block(block_import_params)
+ .map_err(|e| Box::new(e) as Box)
+ .await?;
+
+ // Compute info about the block after the digest is added
+ let mut post_header = header.clone();
+ post_header.digest_mut().logs.push(sig_digest.clone());
+ let post_block = Block::new(post_header, extrinsics);
+
+ if let Some((collation, block_data)) = collator_service.build_collation(
+ parent_header,
+ post_hash,
+ ParachainCandidate {
+ block: post_block,
+ proof: proof,
+ },
+ ) {
+ tracing::info!(
+ target: crate::LOG_TARGET,
+ "PoV size {{ header: {}kb, extrinsics: {}kb, storage_proof: {}kb }}",
+ block_data.header().encode().len() as f64 / 1024f64,
+ block_data.extrinsics().encode().len() as f64 / 1024f64,
+ block_data.storage_proof().encode().len() as f64 / 1024f64,
+ );
+
+ if let MaybeCompressedPoV::Compressed(ref pov) = collation.proof_of_validity {
+ tracing::info!(
+ target: crate::LOG_TARGET,
+ "Compressed PoV size: {}kb",
+ pov.block_data.0.len() as f64 / 1024f64,
+ );
+ }
+
+ Ok((collation, block_data, post_hash))
+ } else {
+ Err(
+ Box::::from("Unable to produce collation")
+ as Box,
+ )
+ }
+}
+
+pub(crate) fn seal_header(
+ header: &Block::Header,
+ keystore: &dyn Keystore,
+ public_pair: &Vec,
+ crypto_id: &CryptoTypeId,
+) -> DigestItem
+where
+ Block: BlockT,
+{
+ let pre_hash = header.hash();
+
+ let raw_sig = Keystore::sign_with(
+ keystore,
+ NIMBUS_KEY_ID,
+ *crypto_id,
+ public_pair,
+ pre_hash.as_ref(),
+ )
+ .expect("Keystore should be able to sign")
+ .expect("We already checked that the key was present");
+
+ debug!(target: LOG_TARGET, "The signature is \n{:?}", raw_sig);
+
+ let signature = raw_sig
+ .clone()
+ .try_into()
+ .expect("signature bytes produced by keystore should be right length");
+
+ ::nimbus_seal(signature)
+}
diff --git a/client/consensus/nimbus-consensus/src/collators/basic.rs b/client/consensus/nimbus-consensus/src/collators/basic.rs
new file mode 100644
index 0000000..9e26390
--- /dev/null
+++ b/client/consensus/nimbus-consensus/src/collators/basic.rs
@@ -0,0 +1,205 @@
+// Copyright Moonsong Labs
+// This file is part of Moonkit.
+
+// Moonkit is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Moonkit is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Moonkit. If not, see .
+
+use crate::*;
+use cumulus_client_collator::service::ServiceInterface as CollatorServiceInterface;
+use cumulus_client_consensus_common::ParachainBlockImportMarker;
+use cumulus_client_consensus_proposer::ProposerInterface;
+use cumulus_primitives_core::{
+ relay_chain::{BlockId as RBlockId, Hash as PHash},
+ CollectCollationInfo, ParaId, PersistedValidationData,
+};
+use cumulus_relay_chain_interface::{OverseerHandle, RelayChainInterface};
+use futures::prelude::*;
+use nimbus_primitives::{DigestsProvider, NimbusApi, NimbusId};
+use polkadot_node_primitives::CollationResult;
+use polkadot_primitives::CollatorPair;
+use sc_client_api::{BlockBackend, BlockOf};
+use sp_api::ProvideRuntimeApi;
+use sp_blockchain::HeaderBackend;
+use sp_core::Decode;
+use sp_inherents::CreateInherentDataProviders;
+use sp_keystore::KeystorePtr;
+use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
+use std::{sync::Arc, time::Duration};
+
+/// Parameters for [`run`].
+pub struct Params {
+ /// Additional digest provider
+ pub additional_digests_provider: ADP,
+ /// Parachain id
+ pub para_id: ParaId,
+ /// A handle to the relay-chain client's "Overseer" or task orchestrator.
+ pub overseer_handle: OverseerHandle,
+ /// The underlying block proposer this should call into.
+ pub proposer: Proposer,
+ /// The block import handle.
+ pub block_import: BI,
+ /// The underlying para client.
+ pub para_client: Arc,
+ /// An interface to the relay-chain client.
+ pub relay_client: RClient,
+ /// The underlying keystore, which should contain Nimbus consensus keys.
+ pub keystore: KeystorePtr,
+ /// The collator key used to sign collations before submitting to validators.
+ pub collator_key: CollatorPair,
+ /// Force production of the block even if the collator is not eligible
+ pub force_authoring: bool,
+ /// A builder for inherent data builders.
+ pub create_inherent_data_providers: CIDP,
+ /// The collator service used for bundling proposals into collations and announcing
+ /// to the network.
+ pub collator_service: CS,
+}
+
+/// Run bare Nimbus consensus as a relay-chain-driven collator.
+pub fn run(
+ params: Params,
+) -> impl Future