mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 07:01:03 +00:00
Pov recovery for parachains (#445)
* Start with a failing integration test & some refactorings * More work * Make it "work" * Add `NullConsensus` for the test * More refactorings * Move stuff over to its own crate * Refactorings * Integrate it into `service` and make the test working * Docs and some exit condition * Use the real import queue * Fix tests * Update client/pov-recovery/src/active_candidate_recovery.rs Co-authored-by: Bernhard Schuster <bernhard@ahoi.io> * Fetch slot duration from the relay chain * Docs * Fixes Co-authored-by: Bernhard Schuster <bernhard@ahoi.io>
This commit is contained in:
@@ -8,6 +8,7 @@ edition = "2018"
|
||||
codec = { package = "parity-scale-codec", version = "2.0.0" }
|
||||
rand = "0.7.3"
|
||||
serde = { version = "1.0.101", features = ["derive"] }
|
||||
async-trait = "0.1.42"
|
||||
|
||||
# Substrate
|
||||
frame-system = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
@@ -49,6 +50,7 @@ polkadot-overseer = { git = "https://github.com/paritytech/polkadot", branch = "
|
||||
cumulus-client-consensus-relay-chain = { path = "../../client/consensus/relay-chain" }
|
||||
cumulus-client-network = { path = "../../client/network" }
|
||||
cumulus-client-service = { path = "../../client/service" }
|
||||
cumulus-client-consensus-common = { path = "../../client/consensus/common" }
|
||||
cumulus-primitives-core = { path = "../../primitives/core" }
|
||||
cumulus-primitives-parachain-inherent = { path = "../../primitives/parachain-inherent" }
|
||||
cumulus-test-runtime = { path = "../runtime" }
|
||||
|
||||
+118
-56
@@ -22,13 +22,14 @@ mod chain_spec;
|
||||
mod genesis;
|
||||
|
||||
use core::future::Future;
|
||||
use cumulus_client_consensus_common::{ParachainCandidate, ParachainConsensus};
|
||||
use cumulus_client_network::BlockAnnounceValidator;
|
||||
use cumulus_client_service::{
|
||||
prepare_node_config, start_collator, start_full_node, StartCollatorParams, StartFullNodeParams,
|
||||
};
|
||||
use cumulus_primitives_core::ParaId;
|
||||
use cumulus_test_runtime::{NodeBlock as Block, RuntimeApi};
|
||||
use polkadot_primitives::v1::CollatorPair;
|
||||
use cumulus_test_runtime::{Hash, Header, NodeBlock as Block, RuntimeApi};
|
||||
use polkadot_primitives::v1::{CollatorPair, Hash as PHash, PersistedValidationData};
|
||||
use sc_client_api::execution_extensions::ExecutionStrategies;
|
||||
use sc_executor::native_executor_instance;
|
||||
pub use sc_executor::NativeExecutor;
|
||||
@@ -45,11 +46,7 @@ use sp_arithmetic::traits::SaturatedConversion;
|
||||
use sp_blockchain::HeaderBackend;
|
||||
use sp_core::{Pair, H256};
|
||||
use sp_keyring::Sr25519Keyring;
|
||||
use sp_runtime::{
|
||||
codec::Encode,
|
||||
generic,
|
||||
traits::BlakeTwo256
|
||||
};
|
||||
use sp_runtime::{codec::Encode, generic, traits::BlakeTwo256};
|
||||
use sp_state_machine::BasicExternalities;
|
||||
use sp_trie::PrefixedMemoryDB;
|
||||
use std::sync::Arc;
|
||||
@@ -62,6 +59,25 @@ pub use cumulus_test_runtime as runtime;
|
||||
pub use genesis::*;
|
||||
pub use sp_keyring::Sr25519Keyring as Keyring;
|
||||
|
||||
/// A consensus that will never produce any block.
|
||||
#[derive(Clone)]
|
||||
struct NullConsensus;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl ParachainConsensus<Block> for NullConsensus {
|
||||
async fn produce_candidate(
|
||||
&mut self,
|
||||
_: &Header,
|
||||
_: PHash,
|
||||
_: &PersistedValidationData,
|
||||
) -> Option<ParachainCandidate<Block>> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// The signature of the announce block fn.
|
||||
pub type AnnounceBlockFn = Arc<dyn Fn(Hash, Option<Vec<u8>>) + Send + Sync>;
|
||||
|
||||
// Native executor instance.
|
||||
native_executor_instance!(
|
||||
pub RuntimeExecutor,
|
||||
@@ -134,7 +150,9 @@ async fn start_node_impl<RB>(
|
||||
collator_key: Option<CollatorPair>,
|
||||
relay_chain_config: Configuration,
|
||||
para_id: ParaId,
|
||||
wrap_announce_block: Option<Box<dyn FnOnce(AnnounceBlockFn) -> AnnounceBlockFn>>,
|
||||
rpc_ext_builder: RB,
|
||||
consensus: Consensus,
|
||||
) -> sc_service::error::Result<(
|
||||
TaskManager,
|
||||
Arc<TFullClient<Block, RuntimeApi, RuntimeExecutor>>,
|
||||
@@ -185,14 +203,14 @@ where
|
||||
let block_announce_validator_builder = move |_| Box::new(block_announce_validator) as Box<_>;
|
||||
|
||||
let prometheus_registry = parachain_config.prometheus_registry().cloned();
|
||||
let import_queue = params.import_queue;
|
||||
let import_queue = cumulus_client_service::SharedImportQueue::new(params.import_queue);
|
||||
let (network, network_status_sinks, system_rpc_tx, start_network) =
|
||||
sc_service::build_network(sc_service::BuildNetworkParams {
|
||||
config: ¶chain_config,
|
||||
client: client.clone(),
|
||||
transaction_pool: transaction_pool.clone(),
|
||||
spawn_handle: task_manager.spawn_handle(),
|
||||
import_queue,
|
||||
import_queue: import_queue.clone(),
|
||||
on_demand: None,
|
||||
block_announce_validator_builder: Some(Box::new(block_announce_validator_builder)),
|
||||
})?;
|
||||
@@ -224,43 +242,57 @@ where
|
||||
Arc::new(move |hash, data| network.announce_block(hash, data))
|
||||
};
|
||||
|
||||
let announce_block = wrap_announce_block
|
||||
.map(|w| (w)(announce_block.clone()))
|
||||
.unwrap_or_else(|| announce_block);
|
||||
|
||||
if let Some(collator_key) = collator_key {
|
||||
let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording(
|
||||
task_manager.spawn_handle(),
|
||||
client.clone(),
|
||||
transaction_pool,
|
||||
prometheus_registry.as_ref(),
|
||||
None,
|
||||
);
|
||||
let parachain_consensus: Box<dyn ParachainConsensus<Block>> = match consensus {
|
||||
Consensus::RelayChain => {
|
||||
let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording(
|
||||
task_manager.spawn_handle(),
|
||||
client.clone(),
|
||||
transaction_pool,
|
||||
prometheus_registry.as_ref(),
|
||||
None,
|
||||
);
|
||||
|
||||
let relay_chain_client = relay_chain_full_node.client.clone();
|
||||
let relay_chain_backend = relay_chain_full_node.backend.clone();
|
||||
let relay_chain_client = relay_chain_full_node.client.clone();
|
||||
let relay_chain_backend = relay_chain_full_node.backend.clone();
|
||||
|
||||
let parachain_consensus = cumulus_client_consensus_relay_chain::RelayChainConsensus::new(
|
||||
para_id,
|
||||
proposer_factory,
|
||||
move |_, (relay_parent, validation_data)| {
|
||||
let parachain_inherent =
|
||||
cumulus_primitives_parachain_inherent::ParachainInherentData::create_at(
|
||||
relay_parent,
|
||||
&*relay_chain_client,
|
||||
&*relay_chain_backend,
|
||||
&validation_data,
|
||||
Box::new(
|
||||
cumulus_client_consensus_relay_chain::RelayChainConsensus::new(
|
||||
para_id,
|
||||
);
|
||||
async move {
|
||||
let time = sp_timestamp::InherentDataProvider::from_system_time();
|
||||
proposer_factory,
|
||||
move |_, (relay_parent, validation_data)| {
|
||||
let parachain_inherent =
|
||||
cumulus_primitives_parachain_inherent::ParachainInherentData::create_at(
|
||||
relay_parent,
|
||||
&*relay_chain_client,
|
||||
&*relay_chain_backend,
|
||||
&validation_data,
|
||||
para_id,
|
||||
);
|
||||
|
||||
let parachain_inherent = parachain_inherent.ok_or_else(|| {
|
||||
Box::<dyn std::error::Error + Send + Sync>::from(String::from("error"))
|
||||
})?;
|
||||
Ok((time, parachain_inherent))
|
||||
}
|
||||
},
|
||||
client.clone(),
|
||||
relay_chain_full_node.client.clone(),
|
||||
relay_chain_full_node.backend.clone(),
|
||||
);
|
||||
async move {
|
||||
let time = sp_timestamp::InherentDataProvider::from_system_time();
|
||||
|
||||
let parachain_inherent = parachain_inherent.ok_or_else(|| {
|
||||
Box::<dyn std::error::Error + Send + Sync>::from(String::from(
|
||||
"error",
|
||||
))
|
||||
})?;
|
||||
Ok((time, parachain_inherent))
|
||||
}
|
||||
},
|
||||
client.clone(),
|
||||
relay_chain_full_node.client.clone(),
|
||||
relay_chain_full_node.backend.clone(),
|
||||
),
|
||||
)
|
||||
}
|
||||
Consensus::Null => Box::new(NullConsensus),
|
||||
};
|
||||
|
||||
let relay_chain_full_node =
|
||||
relay_chain_full_node.with_client(polkadot_test_service::TestClient);
|
||||
@@ -273,8 +305,9 @@ where
|
||||
task_manager: &mut task_manager,
|
||||
para_id,
|
||||
collator_key,
|
||||
parachain_consensus: Box::new(parachain_consensus),
|
||||
parachain_consensus,
|
||||
relay_chain_full_node,
|
||||
import_queue,
|
||||
};
|
||||
|
||||
start_collator(params).await?;
|
||||
@@ -287,7 +320,7 @@ where
|
||||
announce_block,
|
||||
task_manager: &mut task_manager,
|
||||
para_id,
|
||||
polkadot_full_node: relay_chain_full_node,
|
||||
relay_chain_full_node,
|
||||
};
|
||||
|
||||
start_full_node(params)?;
|
||||
@@ -313,6 +346,12 @@ pub struct TestNode {
|
||||
pub rpc_handlers: RpcHandlers,
|
||||
}
|
||||
|
||||
enum Consensus {
|
||||
/// Use the relay-chain provided consensus.
|
||||
RelayChain,
|
||||
/// Use the null consensus that will never produce any block.
|
||||
Null,
|
||||
}
|
||||
|
||||
/// A builder to create a [`TestNode`].
|
||||
pub struct TestNodeBuilder {
|
||||
@@ -323,8 +362,10 @@ pub struct TestNodeBuilder {
|
||||
parachain_nodes: Vec<MultiaddrWithPeerId>,
|
||||
parachain_nodes_exclusive: bool,
|
||||
relay_chain_nodes: Vec<MultiaddrWithPeerId>,
|
||||
wrap_announce_block: Option<Box<dyn FnOnce(AnnounceBlockFn) -> AnnounceBlockFn>>,
|
||||
storage_update_func_parachain: Option<Box<dyn Fn()>>,
|
||||
storage_update_func_relay_chain: Option<Box<dyn Fn()>>,
|
||||
consensus: Consensus,
|
||||
}
|
||||
|
||||
impl TestNodeBuilder {
|
||||
@@ -342,8 +383,10 @@ impl TestNodeBuilder {
|
||||
parachain_nodes: Vec::new(),
|
||||
parachain_nodes_exclusive: false,
|
||||
relay_chain_nodes: Vec::new(),
|
||||
wrap_announce_block: None,
|
||||
storage_update_func_parachain: None,
|
||||
storage_update_func_relay_chain: None,
|
||||
consensus: Consensus::RelayChain,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -404,32 +447,43 @@ impl TestNodeBuilder {
|
||||
mut self,
|
||||
nodes: impl IntoIterator<Item = &'a polkadot_test_service::PolkadotTestNode>,
|
||||
) -> Self {
|
||||
self.relay_chain_nodes.extend(nodes.into_iter().map(|n| n.addr.clone()));
|
||||
self.relay_chain_nodes
|
||||
.extend(nodes.into_iter().map(|n| n.addr.clone()));
|
||||
self
|
||||
}
|
||||
|
||||
/// Wrap the announce block function of this node.
|
||||
pub fn wrap_announce_block(
|
||||
mut self,
|
||||
wrap: impl FnOnce(AnnounceBlockFn) -> AnnounceBlockFn + 'static,
|
||||
) -> Self {
|
||||
self.wrap_announce_block = Some(Box::new(wrap));
|
||||
self
|
||||
}
|
||||
|
||||
/// Allows accessing the parachain storage before the test node is built.
|
||||
pub fn update_storage_parachain(
|
||||
mut self,
|
||||
updater: impl Fn() + 'static,
|
||||
) -> Self {
|
||||
pub fn update_storage_parachain(mut self, updater: impl Fn() + 'static) -> Self {
|
||||
self.storage_update_func_parachain = Some(Box::new(updater));
|
||||
self
|
||||
}
|
||||
|
||||
/// Allows accessing the relay chain storage before the test node is built.
|
||||
pub fn update_storage_relay_chain(
|
||||
mut self,
|
||||
updater: impl Fn() + 'static,
|
||||
) -> Self {
|
||||
pub fn update_storage_relay_chain(mut self, updater: impl Fn() + 'static) -> Self {
|
||||
self.storage_update_func_relay_chain = Some(Box::new(updater));
|
||||
self
|
||||
}
|
||||
|
||||
/// Use the null consensus that will never author any block.
|
||||
pub fn use_null_consensus(mut self) -> Self {
|
||||
self.consensus = Consensus::Null;
|
||||
self
|
||||
}
|
||||
|
||||
/// Build the [`TestNode`].
|
||||
pub async fn build(self) -> TestNode {
|
||||
let parachain_config = node_config(
|
||||
self.storage_update_func_parachain.unwrap_or_else(|| Box::new(|| ())),
|
||||
self.storage_update_func_parachain
|
||||
.unwrap_or_else(|| Box::new(|| ())),
|
||||
self.task_executor.clone(),
|
||||
self.key.clone(),
|
||||
self.parachain_nodes,
|
||||
@@ -439,7 +493,8 @@ impl TestNodeBuilder {
|
||||
)
|
||||
.expect("could not generate Configuration");
|
||||
let mut relay_chain_config = polkadot_test_service::node_config(
|
||||
self.storage_update_func_relay_chain.unwrap_or_else(|| Box::new(|| ())),
|
||||
self.storage_update_func_relay_chain
|
||||
.unwrap_or_else(|| Box::new(|| ())),
|
||||
self.task_executor,
|
||||
self.key,
|
||||
self.relay_chain_nodes,
|
||||
@@ -455,7 +510,9 @@ impl TestNodeBuilder {
|
||||
self.collator_key,
|
||||
relay_chain_config,
|
||||
self.para_id,
|
||||
self.wrap_announce_block,
|
||||
|_| Default::default(),
|
||||
self.consensus,
|
||||
)
|
||||
.await
|
||||
.expect("could not create Cumulus test service");
|
||||
@@ -611,7 +668,9 @@ impl TestNode {
|
||||
self.send_extrinsic(
|
||||
runtime::SudoCall::sudo_unchecked_weight(Box::new(call.into()), 1_000),
|
||||
Sr25519Keyring::Alice,
|
||||
).await.map(drop)
|
||||
)
|
||||
.await
|
||||
.map(drop)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -634,7 +693,10 @@ pub fn construct_extrinsic(
|
||||
let extra: runtime::SignedExtra = (
|
||||
frame_system::CheckSpecVersion::<runtime::Runtime>::new(),
|
||||
frame_system::CheckGenesis::<runtime::Runtime>::new(),
|
||||
frame_system::CheckEra::<runtime::Runtime>::from(generic::Era::mortal(period, current_block)),
|
||||
frame_system::CheckEra::<runtime::Runtime>::from(generic::Era::mortal(
|
||||
period,
|
||||
current_block,
|
||||
)),
|
||||
frame_system::CheckNonce::<runtime::Runtime>::from(nonce),
|
||||
frame_system::CheckWeight::<runtime::Runtime>::new(),
|
||||
pallet_transaction_payment::ChargeTransactionPayment::<runtime::Runtime>::from(tip),
|
||||
|
||||
Reference in New Issue
Block a user