Aura consensus for parachains (#371)

* Update polkadot

* Migrate all uses of MQC heads to merkle proofs

* Mass rename `relay_parent_storage_root`

* Restore parachain-system tests

* Update polkadot and libp2p swarm for testing

* Collapse match into an if let

Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>

* Start with something

* Update Substrate & Polkadot

* Start to make it compile

* Make it compile

* Begin with something

* Yep

* I'm a hacker

* Bring back the builder

* Make it work in some way

* Compile

* Parachains use their own "slot"

* Adds cumulus-pallet-aura

* Wrap AuRa import queue to disable equivocation checking by default

* Pass slot duration

* Check the seal when validating a block

* Adds missing file

* Try to make the seal working

* Fix it

* Some fixes

* Bring in the latest features to cleanup the code

* Update and make it compile

* Improve the import

* Start fixing

* More work

* Fix fix fix

* Make everything compile

* Small cleanups

* Rename and more docs

* Docs

* Fixes fixes fixes

* Update rococo-parachains/src/chain_spec.rs

* Update client/consensus/aura/src/lib.rs

Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com>

* Update client/consensus/aura/src/lib.rs

Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com>

* Update primitives/parachain-inherent/Cargo.toml

Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com>

* Update primitives/parachain-inherent/Cargo.toml

* Update primitives/parachain-inherent/Cargo.toml

* Update primitives/parachain-inherent/Cargo.toml

Co-authored-by: Sergei Shulepov <sergei@parity.io>
Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com>
This commit is contained in:
Bastian Köcher
2021-05-10 14:43:00 +02:00
committed by GitHub
parent 78ad174b15
commit d01bc247cb
22 changed files with 1694 additions and 332 deletions
+17 -1
View File
@@ -16,11 +16,12 @@
use cumulus_primitives_core::ParaId;
use hex_literal::hex;
use parachain_runtime::AuraId;
use rococo_parachain_primitives::{AccountId, Signature};
use sc_chain_spec::{ChainSpecExtension, ChainSpecGroup};
use sc_service::ChainType;
use serde::{Deserialize, Serialize};
use sp_core::{sr25519, Pair, Public};
use sp_core::{sr25519, Pair, Public, crypto::UncheckedInto};
use sp_runtime::traits::{IdentifyAccount, Verify};
/// Specialized `ChainSpec` for the normal parachain runtime.
@@ -71,6 +72,10 @@ pub fn get_chain_spec(id: ParaId) -> ChainSpec {
move || {
testnet_genesis(
get_account_id_from_seed::<sr25519::Public>("Alice"),
vec![
get_from_seed::<AuraId>("Alice"),
get_from_seed::<AuraId>("Bob"),
],
vec![
get_account_id_from_seed::<sr25519::Public>("Alice"),
get_account_id_from_seed::<sr25519::Public>("Bob"),
@@ -124,6 +129,12 @@ pub fn staging_test_net(id: ParaId) -> ChainSpec {
move || {
testnet_genesis(
hex!["9ed7705e3c7da027ba0583a22a3212042f7e715d3c168ba14f1424e2bc111d00"].into(),
vec![
// $secret//one
hex!["aad9fa2249f87a210a0f93400b7f90e47b810c6d65caa0ca3f5af982904c2a33"].unchecked_into(),
// $secret//two
hex!["d47753f0cca9dd8da00c70e82ec4fc5501a69c49a5952a643d18802837c88212"].unchecked_into(),
],
vec![
hex!["9ed7705e3c7da027ba0583a22a3212042f7e715d3c168ba14f1424e2bc111d00"].into(),
],
@@ -143,6 +154,7 @@ pub fn staging_test_net(id: ParaId) -> ChainSpec {
fn testnet_genesis(
root_key: AccountId,
initial_authorities: Vec<AuraId>,
endowed_accounts: Vec<AccountId>,
id: ParaId,
) -> parachain_runtime::GenesisConfig {
@@ -162,6 +174,10 @@ fn testnet_genesis(
},
pallet_sudo: parachain_runtime::SudoConfig { key: root_key },
parachain_info: parachain_runtime::ParachainInfoConfig { parachain_id: id },
pallet_aura: parachain_runtime::AuraConfig {
authorities: initial_authorities,
},
cumulus_pallet_aura_ext: Default::default(),
}
}
+31 -19
View File
@@ -19,8 +19,8 @@ use crate::{
cli::{Cli, RelayChainCli, Subcommand},
};
use codec::Encode;
use cumulus_primitives_core::ParaId;
use cumulus_client_service::genesis::generate_genesis_block;
use cumulus_primitives_core::ParaId;
use log::info;
use parachain_runtime::Block;
use polkadot_parachain::primitives::AccountIdConversion;
@@ -28,9 +28,7 @@ use sc_cli::{
ChainSpec, CliConfiguration, DefaultConfigurationValues, ImportParams, KeystoreParams,
NetworkParams, Result, RuntimeVersion, SharedParams, SubstrateCli,
};
use sc_service::{
config::{BasePath, PrometheusConfig},
};
use sc_service::config::{BasePath, PrometheusConfig};
use sp_core::hexdisplay::HexDisplay;
use sp_runtime::traits::Block as BlockT;
use std::{io::Write, net::SocketAddr};
@@ -157,13 +155,19 @@ macro_rules! construct_async_run {
let runner = $cli.create_runner($cmd)?;
if use_shell_runtime(&runner.config().chain_spec) {
runner.async_run(|$config| {
let $components = new_partial::<shell_runtime::RuntimeApi, ShellRuntimeExecutor>(&$config)?;
let $components = new_partial::<shell_runtime::RuntimeApi, ShellRuntimeExecutor, _>(
&$config,
crate::service::shell_build_import_queue,
)?;
let task_manager = $components.task_manager;
{ $( $code )* }.map(|v| (v, task_manager))
})
} else {
runner.async_run(|$config| {
let $components = new_partial::<parachain_runtime::RuntimeApi, RuntimeExecutor>(&$config)?;
let $components = new_partial::<parachain_runtime::RuntimeApi, RuntimeExecutor, _>(
&$config,
crate::service::build_import_queue,
)?;
let task_manager = $components.task_manager;
{ $( $code )* }.map(|v| (v, task_manager))
})
@@ -180,18 +184,26 @@ pub fn run() -> Result<()> {
let runner = cli.create_runner(cmd)?;
runner.sync_run(|config| cmd.run(config.chain_spec, config.network))
}
Some(Subcommand::CheckBlock(cmd)) => construct_async_run! (|components, cli, cmd, config| {
Ok(cmd.run(components.client, components.import_queue))
}),
Some(Subcommand::ExportBlocks(cmd)) => construct_async_run! (|components, cli, cmd, config| {
Ok(cmd.run(components.client, config.database))
}),
Some(Subcommand::ExportState(cmd)) => construct_async_run! (|components, cli, cmd, config| {
Ok(cmd.run(components.client, config.chain_spec))
}),
Some(Subcommand::ImportBlocks(cmd)) => construct_async_run! (|components, cli, cmd, config| {
Ok(cmd.run(components.client, components.import_queue))
}),
Some(Subcommand::CheckBlock(cmd)) => {
construct_async_run!(|components, cli, cmd, config| {
Ok(cmd.run(components.client, components.import_queue))
})
}
Some(Subcommand::ExportBlocks(cmd)) => {
construct_async_run!(|components, cli, cmd, config| {
Ok(cmd.run(components.client, config.database))
})
}
Some(Subcommand::ExportState(cmd)) => {
construct_async_run!(|components, cli, cmd, config| {
Ok(cmd.run(components.client, config.chain_spec))
})
}
Some(Subcommand::ImportBlocks(cmd)) => {
construct_async_run!(|components, cli, cmd, config| {
Ok(cmd.run(components.client, components.import_queue))
})
}
Some(Subcommand::PurgeChain(cmd)) => {
let runner = cli.create_runner(cmd)?;
@@ -213,7 +225,7 @@ pub fn run() -> Result<()> {
cmd.run(config, polkadot_config)
})
}
Some(Subcommand::Revert(cmd)) => construct_async_run! (|components, cli, cmd, config| {
Some(Subcommand::Revert(cmd)) => construct_async_run!(|components, cli, cmd, config| {
Ok(cmd.run(components.client, components.backend))
}),
Some(Subcommand::ExportGenesisState(params)) => {
+275 -41
View File
@@ -14,24 +14,31 @@
// You should have received a copy of the GNU General Public License
// along with Cumulus. If not, see <http://www.gnu.org/licenses/>.
use cumulus_client_consensus_relay_chain::{
build_relay_chain_consensus, BuildRelayChainConsensusParams,
use cumulus_client_consensus_aura::{
build_aura_consensus, BuildAuraConsensusParams, SlotProportion,
};
use cumulus_client_consensus_common::ParachainConsensus;
use cumulus_client_network::build_block_announce_validator;
use cumulus_client_service::{
prepare_node_config, start_collator, start_full_node, StartCollatorParams, StartFullNodeParams,
};
use cumulus_primitives_core::ParaId;
use polkadot_primitives::v0::CollatorPair;
use rococo_parachain_primitives::Block;
use rococo_parachain_primitives::{Block, Hash};
use sc_client_api::ExecutorProvider;
use sc_executor::native_executor_instance;
pub use sc_executor::NativeExecutor;
use sc_network::NetworkService;
use sc_service::{Configuration, PartialComponents, Role, TFullBackend, TFullClient, TaskManager};
use sc_telemetry::{Telemetry, TelemetryWorker, TelemetryWorkerHandle};
use sc_telemetry::{Telemetry, TelemetryHandle, TelemetryWorker, TelemetryWorkerHandle};
use sp_api::ConstructRuntimeApi;
use sp_consensus::SlotData;
use sp_keystore::SyncCryptoStorePtr;
use sp_runtime::traits::BlakeTwo256;
use sp_trie::PrefixedMemoryDB;
use std::sync::Arc;
use substrate_prometheus_endpoint::Registry;
pub use sc_executor::NativeExecutor;
// Native executor instance.
native_executor_instance!(
@@ -51,14 +58,15 @@ native_executor_instance!(
///
/// Use this macro if you don't actually need the full service, but just the builder in order to
/// be able to perform chain operations.
pub fn new_partial<RuntimeApi, Executor>(
pub fn new_partial<RuntimeApi, Executor, BIQ>(
config: &Configuration,
build_import_queue: BIQ,
) -> Result<
PartialComponents<
TFullClient<Block, RuntimeApi, Executor>,
TFullBackend<Block>,
(),
sp_consensus::import_queue::BasicQueue<Block, PrefixedMemoryDB<BlakeTwo256>>,
sp_consensus::DefaultImportQueue<Block, TFullClient<Block, RuntimeApi, Executor>>,
sc_transaction_pool::FullPool<Block, TFullClient<Block, RuntimeApi, Executor>>,
(Option<Telemetry>, Option<TelemetryWorkerHandle>),
>,
@@ -79,6 +87,15 @@ where
+ sp_block_builder::BlockBuilder<Block>,
sc_client_api::StateBackendFor<TFullBackend<Block>, Block>: sp_api::StateBackend<BlakeTwo256>,
Executor: sc_executor::NativeExecutionDispatch + 'static,
BIQ: FnOnce(
Arc<TFullClient<Block, RuntimeApi, Executor>>,
&Configuration,
Option<TelemetryHandle>,
&TaskManager,
) -> Result<
sp_consensus::DefaultImportQueue<Block, TFullClient<Block, RuntimeApi, Executor>>,
sc_service::Error,
>,
{
let telemetry = config
.telemetry_endpoints
@@ -105,8 +122,6 @@ where
telemetry
});
let registry = config.prometheus_registry();
let transaction_pool = sc_transaction_pool::BasicPool::new_full(
config.transaction_pool.clone(),
config.role.is_authority().into(),
@@ -115,12 +130,11 @@ where
client.clone(),
);
let import_queue = cumulus_client_consensus_relay_chain::import_queue(
let import_queue = build_import_queue(
client.clone(),
client.clone(),
|_, _| async { Ok(sp_timestamp::InherentDataProvider::from_system_time()) },
&task_manager.spawn_essential_handle(),
registry.clone(),
config,
telemetry.as_ref().map(|telemetry| telemetry.handle()),
&task_manager,
)?;
let params = PartialComponents {
@@ -141,12 +155,14 @@ where
///
/// This is the actual implementation that is abstract over the executor and the runtime api.
#[sc_tracing::logging::prefix_logs_with("Parachain")]
async fn start_node_impl<RuntimeApi, Executor, RB>(
async fn start_node_impl<RuntimeApi, Executor, RB, BIQ, BIC>(
parachain_config: Configuration,
collator_key: CollatorPair,
polkadot_config: Configuration,
id: ParaId,
rpc_ext_builder: RB,
build_import_queue: BIQ,
build_consensus: BIC,
) -> sc_service::error::Result<(TaskManager, Arc<TFullClient<Block, RuntimeApi, Executor>>)>
where
RuntimeApi: ConstructRuntimeApi<Block, TFullClient<Block, RuntimeApi, Executor>>
@@ -168,6 +184,26 @@ where
) -> jsonrpc_core::IoHandler<sc_rpc::Metadata>
+ Send
+ 'static,
BIQ: FnOnce(
Arc<TFullClient<Block, RuntimeApi, Executor>>,
&Configuration,
Option<TelemetryHandle>,
&TaskManager,
) -> Result<
sp_consensus::DefaultImportQueue<Block, TFullClient<Block, RuntimeApi, Executor>>,
sc_service::Error,
>,
BIC: FnOnce(
Arc<TFullClient<Block, RuntimeApi, Executor>>,
Option<&Registry>,
Option<TelemetryHandle>,
&TaskManager,
&polkadot_service::NewFull<polkadot_service::Client>,
Arc<sc_transaction_pool::FullPool<Block, TFullClient<Block, RuntimeApi, Executor>>>,
Arc<NetworkService<Block, Hash>>,
SyncCryptoStorePtr,
bool,
) -> Result<Box<dyn ParachainConsensus<Block>>, sc_service::Error>,
{
if matches!(parachain_config.role, Role::Light) {
return Err("Light client not supported!".into());
@@ -175,10 +211,10 @@ where
let parachain_config = prepare_node_config(parachain_config);
let params = new_partial::<RuntimeApi, Executor>(&parachain_config)?;
let params = new_partial::<RuntimeApi, Executor, BIQ>(&parachain_config, build_import_queue)?;
let (mut telemetry, telemetry_worker_handle) = params.other;
let polkadot_full_node = cumulus_client_service::build_polkadot_full_node(
let relay_chain_full_node = cumulus_client_service::build_polkadot_full_node(
polkadot_config,
collator_key.clone(),
telemetry_worker_handle,
@@ -191,12 +227,13 @@ where
let client = params.client.clone();
let backend = params.backend.clone();
let block_announce_validator = build_block_announce_validator(
polkadot_full_node.client.clone(),
relay_chain_full_node.client.clone(),
id,
Box::new(polkadot_full_node.network.clone()),
polkadot_full_node.backend.clone(),
Box::new(relay_chain_full_node.network.clone()),
relay_chain_full_node.backend.clone(),
);
let force_authoring = parachain_config.force_authoring;
let validator = parachain_config.role.is_authority();
let prometheus_registry = parachain_config.prometheus_registry().cloned();
let transaction_pool = params.transaction_pool.clone();
@@ -238,25 +275,19 @@ where
};
if validator {
let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording(
task_manager.spawn_handle(),
let parachain_consensus = build_consensus(
client.clone(),
transaction_pool,
prometheus_registry.as_ref(),
telemetry.as_ref().map(|x| x.handle()),
);
let spawner = task_manager.spawn_handle();
telemetry.as_ref().map(|t| t.handle()),
&task_manager,
&relay_chain_full_node,
transaction_pool,
network,
params.keystore_container.sync_keystore(),
force_authoring,
)?;
let parachain_consensus = build_relay_chain_consensus(BuildRelayChainConsensusParams {
para_id: id,
proposer_factory,
create_inherent_data_providers: |_, _| async {
Ok(sp_timestamp::InherentDataProvider::from_system_time())
},
block_import: client.clone(),
relay_chain_client: polkadot_full_node.client.clone(),
relay_chain_backend: polkadot_full_node.backend.clone(),
});
let spawner = task_manager.spawn_handle();
let params = StartCollatorParams {
para_id: id,
@@ -265,7 +296,7 @@ where
client: client.clone(),
task_manager: &mut task_manager,
collator_key,
relay_chain_full_node: polkadot_full_node,
relay_chain_full_node,
spawner,
backend,
parachain_consensus,
@@ -278,7 +309,7 @@ where
announce_block,
task_manager: &mut task_manager,
para_id: id,
polkadot_full_node,
polkadot_full_node: relay_chain_full_node,
};
start_full_node(params)?;
@@ -289,6 +320,58 @@ where
Ok((task_manager, client))
}
/// Build the import queue for the "default" runtime.
pub fn build_import_queue(
client: Arc<TFullClient<Block, parachain_runtime::RuntimeApi, RuntimeExecutor>>,
config: &Configuration,
telemetry: Option<TelemetryHandle>,
task_manager: &TaskManager,
) -> Result<
sp_consensus::DefaultImportQueue<
Block,
TFullClient<Block, shell_runtime::RuntimeApi, ShellRuntimeExecutor>,
>,
sc_service::Error,
> {
let slot_duration = cumulus_client_consensus_aura::slot_duration(&*client)?;
let block_import = cumulus_client_consensus_aura::AuraBlockImport::<
_,
_,
_,
sp_consensus_aura::sr25519::AuthorityPair,
>::new(client.clone(), client.clone());
cumulus_client_consensus_aura::import_queue::<
sp_consensus_aura::sr25519::AuthorityPair,
_,
_,
_,
_,
_,
_,
>(cumulus_client_consensus_aura::ImportQueueParams {
block_import,
client: client.clone(),
create_inherent_data_providers: move |_, _| async move {
let time = sp_timestamp::InherentDataProvider::from_system_time();
let slot =
sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_duration(
*time,
slot_duration.slot_duration(),
);
Ok((time, slot))
},
registry: config.prometheus_registry().clone(),
can_author_with: sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone()),
spawner: &task_manager.spawn_essential_handle(),
telemetry,
})
.map_err(Into::into)
}
/// Start a rococo-test parachain node.
pub async fn start_node(
parachain_config: Configuration,
@@ -298,16 +381,114 @@ pub async fn start_node(
) -> sc_service::error::Result<
(TaskManager, Arc<TFullClient<Block, parachain_runtime::RuntimeApi, RuntimeExecutor>>)
> {
start_node_impl::<parachain_runtime::RuntimeApi, RuntimeExecutor, _>(
start_node_impl::<parachain_runtime::RuntimeApi, RuntimeExecutor, _, _, _>(
parachain_config,
collator_key,
polkadot_config,
id,
|_| Default::default(),
build_import_queue,
|client,
prometheus_registry,
telemetry,
task_manager,
relay_chain_node,
transaction_pool,
sync_oracle,
keystore,
force_authoring| {
let slot_duration = cumulus_client_consensus_aura::slot_duration(&*client)?;
let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording(
task_manager.spawn_handle(),
client.clone(),
transaction_pool,
prometheus_registry.clone(),
telemetry.clone(),
);
let relay_chain_backend = relay_chain_node.backend.clone();
let relay_chain_client = relay_chain_node.client.clone();
Ok(build_aura_consensus::<
sp_consensus_aura::sr25519::AuthorityPair,
_,
_,
_,
_,
_,
_,
_,
_,
_,
>(BuildAuraConsensusParams {
proposer_factory,
create_inherent_data_providers: move |_, (relay_parent, validation_data)| {
let parachain_inherent =
cumulus_primitives_parachain_inherent::ParachainInherentData::create_at_with_client(
relay_parent,
&relay_chain_client,
&*relay_chain_backend,
&validation_data,
id,
);
async move {
let time = sp_timestamp::InherentDataProvider::from_system_time();
let slot =
sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_duration(
*time,
slot_duration.slot_duration(),
);
let parachain_inherent = parachain_inherent.ok_or_else(|| {
Box::<dyn std::error::Error + Send + Sync>::from(
"Failed to create parachain inherent",
)
})?;
Ok((time, slot, parachain_inherent))
}
},
block_import: client.clone(),
relay_chain_client: relay_chain_node.client.clone(),
relay_chain_backend: relay_chain_node.backend.clone(),
para_client: client.clone(),
backoff_authoring_blocks: Option::<()>::None,
sync_oracle,
keystore,
force_authoring,
slot_duration,
// We got around 500ms for proposing
block_proposal_slot_portion: SlotProportion::new(1f32 / 24f32),
telemetry,
}))
},
)
.await
}
/// Build the import queue for the shell runtime.
pub fn shell_build_import_queue(
client: Arc<TFullClient<Block, shell_runtime::RuntimeApi, ShellRuntimeExecutor>>,
config: &Configuration,
_: Option<TelemetryHandle>,
task_manager: &TaskManager,
) -> Result<
sp_consensus::DefaultImportQueue<
Block,
TFullClient<Block, shell_runtime::RuntimeApi, ShellRuntimeExecutor>,
>,
sc_service::Error,
> {
cumulus_client_consensus_relay_chain::import_queue(
client.clone(),
client,
|_, _| async { Ok(()) },
&task_manager.spawn_essential_handle(),
config.prometheus_registry().clone(),
)
.map_err(Into::into)
}
/// Start a rococo-shell parachain node.
pub async fn start_shell_node(
parachain_config: Configuration,
@@ -317,12 +498,65 @@ pub async fn start_shell_node(
) -> sc_service::error::Result<
(TaskManager, Arc<TFullClient<Block, shell_runtime::RuntimeApi, ShellRuntimeExecutor>>)
> {
start_node_impl::<shell_runtime::RuntimeApi, ShellRuntimeExecutor, _>(
start_node_impl::<shell_runtime::RuntimeApi, ShellRuntimeExecutor, _, _, _>(
parachain_config,
collator_key,
polkadot_config,
id,
|_| Default::default(),
shell_build_import_queue,
|client,
prometheus_registry,
telemetry,
task_manager,
relay_chain_node,
transaction_pool,
_,
_,
_| {
let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording(
task_manager.spawn_handle(),
client.clone(),
transaction_pool,
prometheus_registry.clone(),
telemetry.clone(),
);
let relay_chain_backend = relay_chain_node.backend.clone();
let relay_chain_client = relay_chain_node.client.clone();
Ok(
cumulus_client_consensus_relay_chain::build_relay_chain_consensus(
cumulus_client_consensus_relay_chain::BuildRelayChainConsensusParams {
para_id: id,
proposer_factory,
block_import: client.clone(),
relay_chain_client: relay_chain_node.client.clone(),
relay_chain_backend: relay_chain_node.backend.clone(),
create_inherent_data_providers:
move |_, (relay_parent, validation_data)| {
let parachain_inherent =
cumulus_primitives_parachain_inherent::ParachainInherentData::create_at_with_client(
relay_parent,
&relay_chain_client,
&*relay_chain_backend,
&validation_data,
id,
);
async move {
let parachain_inherent =
parachain_inherent.ok_or_else(|| {
Box::<dyn std::error::Error + Send + Sync>::from(
"Failed to create parachain inherent",
)
})?;
Ok(parachain_inherent)
}
},
},
),
)
},
)
.await
}