mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 10:31:03 +00:00
Fix block propagation between non-collator nodes (#363)
* Create builder for test nodes * Fix syncing issue * Adds missing file
This commit is contained in:
Generated
+155
-152
File diff suppressed because it is too large
Load Diff
@@ -79,7 +79,7 @@ where
|
|||||||
fn new(
|
fn new(
|
||||||
block_status: Arc<BS>,
|
block_status: Arc<BS>,
|
||||||
spawner: Arc<dyn SpawnNamed + Send + Sync>,
|
spawner: Arc<dyn SpawnNamed + Send + Sync>,
|
||||||
announce_block: Arc<dyn Fn(Block::Hash, Vec<u8>) + Send + Sync>,
|
announce_block: Arc<dyn Fn(Block::Hash, Option<Vec<u8>>) + Send + Sync>,
|
||||||
backend: Arc<Backend>,
|
backend: Arc<Backend>,
|
||||||
parachain_consensus: Box<dyn ParachainConsensus<Block>>,
|
parachain_consensus: Box<dyn ParachainConsensus<Block>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
@@ -337,7 +337,7 @@ pub struct StartCollatorParams<Block: BlockT, Backend, BS, Spawner> {
|
|||||||
pub para_id: ParaId,
|
pub para_id: ParaId,
|
||||||
pub backend: Arc<Backend>,
|
pub backend: Arc<Backend>,
|
||||||
pub block_status: Arc<BS>,
|
pub block_status: Arc<BS>,
|
||||||
pub announce_block: Arc<dyn Fn(Block::Hash, Vec<u8>) + Send + Sync>,
|
pub announce_block: Arc<dyn Fn(Block::Hash, Option<Vec<u8>>) + Send + Sync>,
|
||||||
pub overseer_handler: OverseerHandler,
|
pub overseer_handler: OverseerHandler,
|
||||||
pub spawner: Spawner,
|
pub spawner: Spawner,
|
||||||
pub key: CollatorPair,
|
pub key: CollatorPair,
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ polkadot-runtime = { git = "https://github.com/paritytech/polkadot", branch = "m
|
|||||||
futures = { version = "0.3.8", features = ["compat"] }
|
futures = { version = "0.3.8", features = ["compat"] }
|
||||||
tokio = "0.1.22"
|
tokio = "0.1.22"
|
||||||
codec = { package = "parity-scale-codec", version = "2.0.0", features = [ "derive" ] }
|
codec = { package = "parity-scale-codec", version = "2.0.0", features = [ "derive" ] }
|
||||||
tracing = "0.1.22"
|
tracing = "0.1.25"
|
||||||
async-trait = "0.1.42"
|
async-trait = "0.1.42"
|
||||||
dyn-clone = "1.0.4"
|
dyn-clone = "1.0.4"
|
||||||
|
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ pub async fn run_parachain_consensus<P, R, Block, B>(
|
|||||||
para_id: ParaId,
|
para_id: ParaId,
|
||||||
parachain: Arc<P>,
|
parachain: Arc<P>,
|
||||||
relay_chain: R,
|
relay_chain: R,
|
||||||
announce_block: Arc<dyn Fn(Block::Hash, Vec<u8>) + Send + Sync>,
|
announce_block: Arc<dyn Fn(Block::Hash, Option<Vec<u8>>) + Send + Sync>,
|
||||||
) -> ClientResult<()>
|
) -> ClientResult<()>
|
||||||
where
|
where
|
||||||
Block: BlockT,
|
Block: BlockT,
|
||||||
@@ -175,7 +175,7 @@ async fn follow_new_best<P, R, Block, B>(
|
|||||||
para_id: ParaId,
|
para_id: ParaId,
|
||||||
parachain: Arc<P>,
|
parachain: Arc<P>,
|
||||||
relay_chain: R,
|
relay_chain: R,
|
||||||
announce_block: Arc<dyn Fn(Block::Hash, Vec<u8>) + Send + Sync>,
|
announce_block: Arc<dyn Fn(Block::Hash, Option<Vec<u8>>) + Send + Sync>,
|
||||||
) -> ClientResult<()>
|
) -> ClientResult<()>
|
||||||
where
|
where
|
||||||
Block: BlockT,
|
Block: BlockT,
|
||||||
@@ -203,7 +203,6 @@ where
|
|||||||
Some(h) => handle_new_best_parachain_head(
|
Some(h) => handle_new_best_parachain_head(
|
||||||
h,
|
h,
|
||||||
&*parachain,
|
&*parachain,
|
||||||
&*announce_block,
|
|
||||||
&mut unset_best_header,
|
&mut unset_best_header,
|
||||||
),
|
),
|
||||||
None => {
|
None => {
|
||||||
@@ -241,12 +240,19 @@ fn handle_new_block_imported<Block, P>(
|
|||||||
notification: BlockImportNotification<Block>,
|
notification: BlockImportNotification<Block>,
|
||||||
unset_best_header_opt: &mut Option<Block::Header>,
|
unset_best_header_opt: &mut Option<Block::Header>,
|
||||||
parachain: &P,
|
parachain: &P,
|
||||||
announce_block: &dyn Fn(Block::Hash, Vec<u8>),
|
announce_block: &dyn Fn(Block::Hash, Option<Vec<u8>>),
|
||||||
) where
|
) where
|
||||||
Block: BlockT,
|
Block: BlockT,
|
||||||
P: UsageProvider<Block> + Send + Sync + BlockBackend<Block>,
|
P: UsageProvider<Block> + Send + Sync + BlockBackend<Block>,
|
||||||
for<'a> &'a P: BlockImport<Block>,
|
for<'a> &'a P: BlockImport<Block>,
|
||||||
{
|
{
|
||||||
|
// HACK
|
||||||
|
//
|
||||||
|
// Remove after https://github.com/paritytech/substrate/pull/8052 or similar is merged
|
||||||
|
if notification.origin != BlockOrigin::Own {
|
||||||
|
announce_block(notification.hash, None);
|
||||||
|
}
|
||||||
|
|
||||||
let unset_best_header = match (notification.is_new_best, &unset_best_header_opt) {
|
let unset_best_header = match (notification.is_new_best, &unset_best_header_opt) {
|
||||||
// If this is the new best block or we don't have any unset block, we can end it here.
|
// If this is the new best block or we don't have any unset block, we can end it here.
|
||||||
(true, _) | (_, None) => return,
|
(true, _) | (_, None) => return,
|
||||||
@@ -274,12 +280,12 @@ fn handle_new_block_imported<Block, P>(
|
|||||||
.take()
|
.take()
|
||||||
.expect("We checked above that the value is set; qed");
|
.expect("We checked above that the value is set; qed");
|
||||||
|
|
||||||
import_block_as_new_best(unset_hash, unset_best_header, parachain, announce_block);
|
import_block_as_new_best(unset_hash, unset_best_header, parachain);
|
||||||
}
|
}
|
||||||
state => tracing::debug!(
|
state => tracing::debug!(
|
||||||
target: "cumulus-consensus",
|
target: "cumulus-consensus",
|
||||||
unset_best_header = ?unset_best_header,
|
?unset_best_header,
|
||||||
imported_header = ?notification.header,
|
?notification.header,
|
||||||
?state,
|
?state,
|
||||||
"Unexpected state for unset best header.",
|
"Unexpected state for unset best header.",
|
||||||
),
|
),
|
||||||
@@ -290,7 +296,6 @@ fn handle_new_block_imported<Block, P>(
|
|||||||
fn handle_new_best_parachain_head<Block, P>(
|
fn handle_new_best_parachain_head<Block, P>(
|
||||||
head: Vec<u8>,
|
head: Vec<u8>,
|
||||||
parachain: &P,
|
parachain: &P,
|
||||||
announce_block: &dyn Fn(Block::Hash, Vec<u8>),
|
|
||||||
unset_best_header: &mut Option<Block::Header>,
|
unset_best_header: &mut Option<Block::Header>,
|
||||||
) where
|
) where
|
||||||
Block: BlockT,
|
Block: BlockT,
|
||||||
@@ -323,7 +328,7 @@ fn handle_new_best_parachain_head<Block, P>(
|
|||||||
Ok(BlockStatus::InChainWithState) => {
|
Ok(BlockStatus::InChainWithState) => {
|
||||||
unset_best_header.take();
|
unset_best_header.take();
|
||||||
|
|
||||||
import_block_as_new_best(hash, parachain_head, parachain, announce_block);
|
import_block_as_new_best(hash, parachain_head, parachain);
|
||||||
}
|
}
|
||||||
Ok(BlockStatus::InChainPruned) => {
|
Ok(BlockStatus::InChainPruned) => {
|
||||||
tracing::error!(
|
tracing::error!(
|
||||||
@@ -358,7 +363,6 @@ fn import_block_as_new_best<Block, P>(
|
|||||||
hash: Block::Hash,
|
hash: Block::Hash,
|
||||||
header: Block::Header,
|
header: Block::Header,
|
||||||
parachain: &P,
|
parachain: &P,
|
||||||
announce_block: &dyn Fn(Block::Hash, Vec<u8>),
|
|
||||||
) where
|
) where
|
||||||
Block: BlockT,
|
Block: BlockT,
|
||||||
P: UsageProvider<Block> + Send + Sync + BlockBackend<Block>,
|
P: UsageProvider<Block> + Send + Sync + BlockBackend<Block>,
|
||||||
@@ -376,8 +380,6 @@ fn import_block_as_new_best<Block, P>(
|
|||||||
error = ?err,
|
error = ?err,
|
||||||
"Failed to set new best block.",
|
"Failed to set new best block.",
|
||||||
);
|
);
|
||||||
} else {
|
|
||||||
(*announce_block)(hash, Vec::new());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,11 +30,15 @@ parking_lot = "0.10.2"
|
|||||||
derive_more = "0.99.2"
|
derive_more = "0.99.2"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
tokio = { version = "0.2.21", features = ["macros"] }
|
||||||
|
|
||||||
# Cumulus deps
|
# Cumulus deps
|
||||||
cumulus-test-service = { path = "../../test/service" }
|
cumulus-test-service = { path = "../../test/service" }
|
||||||
|
cumulus-primitives-core = { path = "../../primitives/core" }
|
||||||
|
|
||||||
# Polkadot deps
|
# Polkadot deps
|
||||||
polkadot-test-client = { git = "https://github.com/paritytech/polkadot", branch = "master" }
|
polkadot-test-client = { git = "https://github.com/paritytech/polkadot", branch = "master" }
|
||||||
|
polkadot-test-service = { git = "https://github.com/paritytech/polkadot", branch = "master" }
|
||||||
|
|
||||||
# substrate deps
|
# substrate deps
|
||||||
sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
@@ -42,3 +46,6 @@ sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
|||||||
sp-keyring = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
sp-keyring = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
sp-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
sp-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
sp-consensus = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
sp-consensus = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
|
sc-cli = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
|
substrate-test-utils = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
|
sc-service = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
|
|||||||
@@ -473,14 +473,14 @@ where
|
|||||||
/// the previous task running.
|
/// the previous task running.
|
||||||
pub struct WaitToAnnounce<Block: BlockT> {
|
pub struct WaitToAnnounce<Block: BlockT> {
|
||||||
spawner: Arc<dyn SpawnNamed + Send + Sync>,
|
spawner: Arc<dyn SpawnNamed + Send + Sync>,
|
||||||
announce_block: Arc<dyn Fn(Block::Hash, Vec<u8>) + Send + Sync>,
|
announce_block: Arc<dyn Fn(Block::Hash, Option<Vec<u8>>) + Send + Sync>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Block: BlockT> WaitToAnnounce<Block> {
|
impl<Block: BlockT> WaitToAnnounce<Block> {
|
||||||
/// Create the `WaitToAnnounce` object
|
/// Create the `WaitToAnnounce` object
|
||||||
pub fn new(
|
pub fn new(
|
||||||
spawner: Arc<dyn SpawnNamed + Send + Sync>,
|
spawner: Arc<dyn SpawnNamed + Send + Sync>,
|
||||||
announce_block: Arc<dyn Fn(Block::Hash, Vec<u8>) + Send + Sync>,
|
announce_block: Arc<dyn Fn(Block::Hash, Option<Vec<u8>>) + Send + Sync>,
|
||||||
) -> WaitToAnnounce<Block> {
|
) -> WaitToAnnounce<Block> {
|
||||||
WaitToAnnounce {
|
WaitToAnnounce {
|
||||||
spawner,
|
spawner,
|
||||||
@@ -522,7 +522,7 @@ impl<Block: BlockT> WaitToAnnounce<Block> {
|
|||||||
async fn wait_to_announce<Block: BlockT>(
|
async fn wait_to_announce<Block: BlockT>(
|
||||||
block_hash: <Block as BlockT>::Hash,
|
block_hash: <Block as BlockT>::Hash,
|
||||||
pov_hash: PHash,
|
pov_hash: PHash,
|
||||||
announce_block: Arc<dyn Fn(Block::Hash, Vec<u8>) + Send + Sync>,
|
announce_block: Arc<dyn Fn(Block::Hash, Option<Vec<u8>>) + Send + Sync>,
|
||||||
signed_stmt_recv: oneshot::Receiver<SignedFullStatement>,
|
signed_stmt_recv: oneshot::Receiver<SignedFullStatement>,
|
||||||
) {
|
) {
|
||||||
let statement = match signed_stmt_recv.await {
|
let statement = match signed_stmt_recv.await {
|
||||||
@@ -541,7 +541,7 @@ async fn wait_to_announce<Block: BlockT>(
|
|||||||
match statement.payload() {
|
match statement.payload() {
|
||||||
Statement::Seconded(c) if &c.descriptor.pov_hash == &pov_hash => {
|
Statement::Seconded(c) if &c.descriptor.pov_hash == &pov_hash => {
|
||||||
if let Ok(data) = BlockAnnounceData::try_from(statement) {
|
if let Ok(data) = BlockAnnounceData::try_from(statement) {
|
||||||
announce_block(block_hash, data.encode());
|
announce_block(block_hash, Some(data.encode()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => tracing::debug!(
|
_ => tracing::debug!(
|
||||||
|
|||||||
@@ -0,0 +1,86 @@
|
|||||||
|
// Copyright 2021 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Substrate.
|
||||||
|
|
||||||
|
// Substrate 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.
|
||||||
|
|
||||||
|
// Substrate 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 Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use cumulus_primitives_core::ParaId;
|
||||||
|
use cumulus_test_service::{initial_head_data, Keyring::*};
|
||||||
|
use futures::join;
|
||||||
|
use sc_service::TaskExecutor;
|
||||||
|
|
||||||
|
#[substrate_test_utils::test]
|
||||||
|
async fn sync_blocks_from_tip_without_being_connected_to_a_collator(task_executor: TaskExecutor) {
|
||||||
|
let mut builder = sc_cli::LoggerBuilder::new("");
|
||||||
|
builder.with_colors(false);
|
||||||
|
let _ = builder.init();
|
||||||
|
|
||||||
|
let para_id = ParaId::from(100);
|
||||||
|
|
||||||
|
// start alice
|
||||||
|
let alice =
|
||||||
|
polkadot_test_service::run_validator_node(task_executor.clone(), Alice, || {}, vec![]);
|
||||||
|
|
||||||
|
// start bob
|
||||||
|
let bob = polkadot_test_service::run_validator_node(
|
||||||
|
task_executor.clone(),
|
||||||
|
Bob,
|
||||||
|
|| {},
|
||||||
|
vec![alice.addr.clone()],
|
||||||
|
);
|
||||||
|
|
||||||
|
// register parachain
|
||||||
|
alice
|
||||||
|
.register_parachain(
|
||||||
|
para_id,
|
||||||
|
cumulus_test_service::runtime::WASM_BINARY
|
||||||
|
.expect("You need to build the WASM binary to run this test!")
|
||||||
|
.to_vec(),
|
||||||
|
initial_head_data(para_id),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// run charlie as parachain collator
|
||||||
|
let charlie =
|
||||||
|
cumulus_test_service::TestNodeBuilder::new(para_id, task_executor.clone(), Charlie)
|
||||||
|
.enable_collator()
|
||||||
|
.connect_to_relay_chain_nodes(vec![&alice, &bob])
|
||||||
|
.build()
|
||||||
|
.await;
|
||||||
|
|
||||||
|
// run dave as parachain full node
|
||||||
|
let dave = cumulus_test_service::TestNodeBuilder::new(para_id, task_executor.clone(), Dave)
|
||||||
|
.connect_to_parachain_node(&charlie)
|
||||||
|
.connect_to_relay_chain_nodes(vec![&alice, &bob])
|
||||||
|
.build()
|
||||||
|
.await;
|
||||||
|
|
||||||
|
// run eve as parachain full node that is only connected to dave
|
||||||
|
let eve = cumulus_test_service::TestNodeBuilder::new(para_id, task_executor.clone(), Eve)
|
||||||
|
.connect_to_parachain_node(&dave)
|
||||||
|
.exclusively_connect_to_registered_parachain_nodes()
|
||||||
|
.connect_to_relay_chain_nodes(vec![&alice, &bob])
|
||||||
|
.build()
|
||||||
|
.await;
|
||||||
|
|
||||||
|
eve.wait_for_blocks(7).await;
|
||||||
|
|
||||||
|
join!(
|
||||||
|
alice.task_manager.clean_shutdown(),
|
||||||
|
bob.task_manager.clean_shutdown(),
|
||||||
|
charlie.task_manager.clean_shutdown(),
|
||||||
|
dave.task_manager.clean_shutdown(),
|
||||||
|
eve.task_manager.clean_shutdown(),
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -44,7 +44,7 @@ pub struct StartCollatorParams<'a, Block: BlockT, BS, Client, Backend, Spawner,
|
|||||||
pub backend: Arc<Backend>,
|
pub backend: Arc<Backend>,
|
||||||
pub block_status: Arc<BS>,
|
pub block_status: Arc<BS>,
|
||||||
pub client: Arc<Client>,
|
pub client: Arc<Client>,
|
||||||
pub announce_block: Arc<dyn Fn(Block::Hash, Vec<u8>) + Send + Sync>,
|
pub announce_block: Arc<dyn Fn(Block::Hash, Option<Vec<u8>>) + Send + Sync>,
|
||||||
pub spawner: Spawner,
|
pub spawner: Spawner,
|
||||||
pub para_id: ParaId,
|
pub para_id: ParaId,
|
||||||
pub collator_key: CollatorPair,
|
pub collator_key: CollatorPair,
|
||||||
@@ -121,7 +121,7 @@ pub struct StartFullNodeParams<'a, Block: BlockT, Client, PClient> {
|
|||||||
pub client: Arc<Client>,
|
pub client: Arc<Client>,
|
||||||
pub polkadot_full_node: RFullNode<PClient>,
|
pub polkadot_full_node: RFullNode<PClient>,
|
||||||
pub task_manager: &'a mut TaskManager,
|
pub task_manager: &'a mut TaskManager,
|
||||||
pub announce_block: Arc<dyn Fn(Block::Hash, Vec<u8>) + Send + Sync>,
|
pub announce_block: Arc<dyn Fn(Block::Hash, Option<Vec<u8>>) + Send + Sync>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Start a full node for a parachain.
|
/// Start a full node for a parachain.
|
||||||
@@ -165,7 +165,7 @@ where
|
|||||||
|
|
||||||
struct StartConsensus<'a, Block: BlockT, Client, Backend> {
|
struct StartConsensus<'a, Block: BlockT, Client, Backend> {
|
||||||
para_id: ParaId,
|
para_id: ParaId,
|
||||||
announce_block: Arc<dyn Fn(Block::Hash, Vec<u8>) + Send + Sync>,
|
announce_block: Arc<dyn Fn(Block::Hash, Option<Vec<u8>>) + Send + Sync>,
|
||||||
client: Arc<Client>,
|
client: Arc<Client>,
|
||||||
task_manager: &'a mut TaskManager,
|
task_manager: &'a mut TaskManager,
|
||||||
_phantom: PhantomData<Backend>,
|
_phantom: PhantomData<Backend>,
|
||||||
|
|||||||
@@ -207,7 +207,7 @@ where
|
|||||||
|
|
||||||
let announce_block = {
|
let announce_block = {
|
||||||
let network = network.clone();
|
let network = network.clone();
|
||||||
Arc::new(move |hash, data| network.announce_block(hash, Some(data)))
|
Arc::new(move |hash, data| network.announce_block(hash, data))
|
||||||
};
|
};
|
||||||
|
|
||||||
if validator {
|
if validator {
|
||||||
|
|||||||
@@ -56,12 +56,6 @@ jsonrpc-core = "15.1.0"
|
|||||||
futures = { version = "0.3.5" }
|
futures = { version = "0.3.5" }
|
||||||
tokio = { version = "0.2.21", features = ["macros"] }
|
tokio = { version = "0.2.21", features = ["macros"] }
|
||||||
|
|
||||||
# Polkadot dependencies
|
|
||||||
polkadot-test-runtime = { git = "https://github.com/paritytech/polkadot", branch = "master" }
|
|
||||||
polkadot-test-service = { git = "https://github.com/paritytech/polkadot", branch = "master" }
|
|
||||||
|
|
||||||
# Substrate dependencies
|
# Substrate dependencies
|
||||||
pallet-sudo = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
|
||||||
substrate-test-runtime-client = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
|
||||||
substrate-test-utils = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
substrate-test-utils = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
sc-cli = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
sc-cli = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
|
|||||||
+135
-42
@@ -21,10 +21,6 @@
|
|||||||
mod chain_spec;
|
mod chain_spec;
|
||||||
mod genesis;
|
mod genesis;
|
||||||
|
|
||||||
pub use chain_spec::*;
|
|
||||||
pub use cumulus_test_runtime as runtime;
|
|
||||||
pub use genesis::*;
|
|
||||||
|
|
||||||
use core::future::Future;
|
use core::future::Future;
|
||||||
use cumulus_client_network::BlockAnnounceValidator;
|
use cumulus_client_network::BlockAnnounceValidator;
|
||||||
use cumulus_client_service::{
|
use cumulus_client_service::{
|
||||||
@@ -53,6 +49,11 @@ use sp_trie::PrefixedMemoryDB;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use substrate_test_client::BlockchainEventsExt;
|
use substrate_test_client::BlockchainEventsExt;
|
||||||
|
|
||||||
|
pub use chain_spec::*;
|
||||||
|
pub use cumulus_test_runtime as runtime;
|
||||||
|
pub use genesis::*;
|
||||||
|
pub use sp_keyring::Sr25519Keyring as Keyring;
|
||||||
|
|
||||||
// Native executor instance.
|
// Native executor instance.
|
||||||
native_executor_instance!(
|
native_executor_instance!(
|
||||||
pub RuntimeExecutor,
|
pub RuntimeExecutor,
|
||||||
@@ -122,10 +123,9 @@ pub fn new_partial(
|
|||||||
#[sc_tracing::logging::prefix_logs_with(parachain_config.network.node_name.as_str())]
|
#[sc_tracing::logging::prefix_logs_with(parachain_config.network.node_name.as_str())]
|
||||||
async fn start_node_impl<RB>(
|
async fn start_node_impl<RB>(
|
||||||
parachain_config: Configuration,
|
parachain_config: Configuration,
|
||||||
collator_key: CollatorPair,
|
collator_key: Option<CollatorPair>,
|
||||||
relay_chain_config: Configuration,
|
relay_chain_config: Configuration,
|
||||||
para_id: ParaId,
|
para_id: ParaId,
|
||||||
is_collator: bool,
|
|
||||||
rpc_ext_builder: RB,
|
rpc_ext_builder: RB,
|
||||||
) -> sc_service::error::Result<(
|
) -> sc_service::error::Result<(
|
||||||
TaskManager,
|
TaskManager,
|
||||||
@@ -157,7 +157,11 @@ where
|
|||||||
|
|
||||||
let relay_chain_full_node = polkadot_test_service::new_full(
|
let relay_chain_full_node = polkadot_test_service::new_full(
|
||||||
relay_chain_config,
|
relay_chain_config,
|
||||||
polkadot_service::IsCollator::Yes(collator_key.public()),
|
if let Some(ref key) = collator_key {
|
||||||
|
polkadot_service::IsCollator::Yes(key.public())
|
||||||
|
} else {
|
||||||
|
polkadot_service::IsCollator::No
|
||||||
|
},
|
||||||
)
|
)
|
||||||
.map_err(|e| match e {
|
.map_err(|e| match e {
|
||||||
polkadot_service::Error::Sub(x) => x,
|
polkadot_service::Error::Sub(x) => x,
|
||||||
@@ -212,10 +216,10 @@ where
|
|||||||
|
|
||||||
let announce_block = {
|
let announce_block = {
|
||||||
let network = network.clone();
|
let network = network.clone();
|
||||||
Arc::new(move |hash, data| network.announce_block(hash, Some(data)))
|
Arc::new(move |hash, data| network.announce_block(hash, data))
|
||||||
};
|
};
|
||||||
|
|
||||||
if is_collator {
|
if let Some(collator_key) = collator_key {
|
||||||
let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording(
|
let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording(
|
||||||
task_manager.spawn_handle(),
|
task_manager.spawn_handle(),
|
||||||
client.clone(),
|
client.clone(),
|
||||||
@@ -270,7 +274,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A Cumulus test node instance used for testing.
|
/// A Cumulus test node instance used for testing.
|
||||||
pub struct CumulusTestNode {
|
pub struct TestNode {
|
||||||
/// TaskManager's instance.
|
/// TaskManager's instance.
|
||||||
pub task_manager: TaskManager,
|
pub task_manager: TaskManager,
|
||||||
/// Client's instance.
|
/// Client's instance.
|
||||||
@@ -284,35 +288,114 @@ pub struct CumulusTestNode {
|
|||||||
pub rpc_handlers: RpcHandlers,
|
pub rpc_handlers: RpcHandlers,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Run a Cumulus test node using the Cumulus test runtime. The node will be using an in-memory
|
|
||||||
/// socket, therefore you need to provide boot nodes if you want it to be connected to other nodes.
|
/// A builder to create a [`TestNode`].
|
||||||
/// The `storage_update_func` can be used to make adjustements to the runtime before the node
|
pub struct TestNodeBuilder {
|
||||||
/// starts.
|
para_id: ParaId,
|
||||||
pub async fn run_test_node(
|
|
||||||
task_executor: TaskExecutor,
|
task_executor: TaskExecutor,
|
||||||
key: Sr25519Keyring,
|
key: Sr25519Keyring,
|
||||||
parachain_storage_update_func: impl Fn(),
|
collator_key: Option<CollatorPair>,
|
||||||
relay_chain_storage_update_func: impl Fn(),
|
parachain_nodes: Vec<MultiaddrWithPeerId>,
|
||||||
parachain_boot_nodes: Vec<MultiaddrWithPeerId>,
|
parachain_nodes_exclusive: bool,
|
||||||
relay_chain_boot_nodes: Vec<MultiaddrWithPeerId>,
|
relay_chain_nodes: Vec<MultiaddrWithPeerId>,
|
||||||
para_id: ParaId,
|
}
|
||||||
is_collator: bool,
|
|
||||||
) -> CumulusTestNode {
|
impl TestNodeBuilder {
|
||||||
let collator_key = CollatorPair::generate().0;
|
/// Create a new instance of `Self`.
|
||||||
let parachain_config = node_config(
|
///
|
||||||
parachain_storage_update_func,
|
/// `para_id` - The parachain id this node is running for.
|
||||||
task_executor.clone(),
|
/// `task_executor` - The task executor to use.
|
||||||
|
/// `key` - The key that will be used to generate the name and that will be passed as `dev_seed`.
|
||||||
|
pub fn new(para_id: ParaId, task_executor: TaskExecutor, key: Sr25519Keyring) -> Self {
|
||||||
|
TestNodeBuilder {
|
||||||
key,
|
key,
|
||||||
parachain_boot_nodes,
|
|
||||||
para_id,
|
para_id,
|
||||||
is_collator,
|
task_executor,
|
||||||
|
collator_key: None,
|
||||||
|
parachain_nodes: Vec::new(),
|
||||||
|
parachain_nodes_exclusive: false,
|
||||||
|
relay_chain_nodes: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enable collator for this node.
|
||||||
|
pub fn enable_collator(mut self) -> Self {
|
||||||
|
let collator_key = CollatorPair::generate().0;
|
||||||
|
self.collator_key = Some(collator_key);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Instruct the node to exclusively connect to registered parachain nodes.
|
||||||
|
///
|
||||||
|
/// Parachain nodes can be registered using [`Self::connect_to_parachain_node`] and
|
||||||
|
/// [`Self::connect_to_parachain_nodes`].
|
||||||
|
pub fn exclusively_connect_to_registered_parachain_nodes(mut self) -> Self {
|
||||||
|
self.parachain_nodes_exclusive = true;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Make the node connect to the given parachain node.
|
||||||
|
///
|
||||||
|
/// By default the node will not be connected to any node or will be able to discover any other
|
||||||
|
/// node.
|
||||||
|
pub fn connect_to_parachain_node(mut self, node: &TestNode) -> Self {
|
||||||
|
self.parachain_nodes.push(node.addr.clone());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Make the node connect to the given parachain nodes.
|
||||||
|
///
|
||||||
|
/// By default the node will not be connected to any node or will be able to discover any other
|
||||||
|
/// node.
|
||||||
|
pub fn connect_to_parachain_nodes<'a>(
|
||||||
|
mut self,
|
||||||
|
nodes: impl Iterator<Item = &'a TestNode>,
|
||||||
|
) -> Self {
|
||||||
|
self.parachain_nodes.extend(nodes.map(|n| n.addr.clone()));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Make the node connect to the given relay chain node.
|
||||||
|
///
|
||||||
|
/// By default the node will not be connected to any node or will be able to discover any other
|
||||||
|
/// node.
|
||||||
|
pub fn connect_to_relay_chain_node(
|
||||||
|
mut self,
|
||||||
|
node: &polkadot_test_service::PolkadotTestNode,
|
||||||
|
) -> Self {
|
||||||
|
self.relay_chain_nodes.push(node.addr.clone());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Make the node connect to the given relay chain nodes.
|
||||||
|
///
|
||||||
|
/// By default the node will not be connected to any node or will be able to discover any other
|
||||||
|
/// node.
|
||||||
|
pub fn connect_to_relay_chain_nodes<'a>(
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Build the [`TestNode`].
|
||||||
|
pub async fn build(self) -> TestNode {
|
||||||
|
let parachain_config = node_config(
|
||||||
|
|| (),
|
||||||
|
self.task_executor.clone(),
|
||||||
|
self.key.clone(),
|
||||||
|
self.parachain_nodes,
|
||||||
|
self.parachain_nodes_exclusive,
|
||||||
|
self.para_id,
|
||||||
|
self.collator_key.is_some(),
|
||||||
)
|
)
|
||||||
.expect("could not generate Configuration");
|
.expect("could not generate Configuration");
|
||||||
let mut relay_chain_config = polkadot_test_service::node_config(
|
let mut relay_chain_config = polkadot_test_service::node_config(
|
||||||
relay_chain_storage_update_func,
|
|| (),
|
||||||
task_executor.clone(),
|
self.task_executor,
|
||||||
key,
|
self.key,
|
||||||
relay_chain_boot_nodes,
|
self.relay_chain_nodes,
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -322,10 +405,9 @@ pub async fn run_test_node(
|
|||||||
let multiaddr = parachain_config.network.listen_addresses[0].clone();
|
let multiaddr = parachain_config.network.listen_addresses[0].clone();
|
||||||
let (task_manager, client, network, rpc_handlers) = start_node_impl(
|
let (task_manager, client, network, rpc_handlers) = start_node_impl(
|
||||||
parachain_config,
|
parachain_config,
|
||||||
collator_key,
|
self.collator_key,
|
||||||
relay_chain_config,
|
relay_chain_config,
|
||||||
para_id,
|
self.para_id,
|
||||||
is_collator,
|
|
||||||
|_| Default::default(),
|
|_| Default::default(),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
@@ -334,7 +416,7 @@ pub async fn run_test_node(
|
|||||||
let peer_id = network.local_peer_id().clone();
|
let peer_id = network.local_peer_id().clone();
|
||||||
let addr = MultiaddrWithPeerId { multiaddr, peer_id };
|
let addr = MultiaddrWithPeerId { multiaddr, peer_id };
|
||||||
|
|
||||||
CumulusTestNode {
|
TestNode {
|
||||||
task_manager,
|
task_manager,
|
||||||
client,
|
client,
|
||||||
network,
|
network,
|
||||||
@@ -342,15 +424,20 @@ pub async fn run_test_node(
|
|||||||
rpc_handlers,
|
rpc_handlers,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Create a Cumulus `Configuration`. By default an in-memory socket will be used, therefore you
|
/// Create a Cumulus `Configuration`.
|
||||||
/// need to provide boot nodes if you want the future node to be connected to other nodes. The
|
///
|
||||||
/// `storage_update_func` can be used to make adjustments to the runtime before the node starts.
|
/// By default an in-memory socket will be used, therefore you need to provide nodes if you want the
|
||||||
|
/// node to be connected to other nodes. If `nodes_exclusive` is `true`, the node will only connect
|
||||||
|
/// to the given `nodes` and not to any other node. The `storage_update_func` can be used to make
|
||||||
|
/// adjustments to the runtime genesis.
|
||||||
pub fn node_config(
|
pub fn node_config(
|
||||||
storage_update_func: impl Fn(),
|
storage_update_func: impl Fn(),
|
||||||
task_executor: TaskExecutor,
|
task_executor: TaskExecutor,
|
||||||
key: Sr25519Keyring,
|
key: Sr25519Keyring,
|
||||||
boot_nodes: Vec<MultiaddrWithPeerId>,
|
nodes: Vec<MultiaddrWithPeerId>,
|
||||||
|
nodes_exlusive: bool,
|
||||||
para_id: ParaId,
|
para_id: ParaId,
|
||||||
is_collator: bool,
|
is_collator: bool,
|
||||||
) -> Result<Configuration, ServiceError> {
|
) -> Result<Configuration, ServiceError> {
|
||||||
@@ -379,7 +466,13 @@ pub fn node_config(
|
|||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
network_config.boot_nodes = boot_nodes;
|
if nodes_exlusive {
|
||||||
|
network_config.default_peers_set.reserved_nodes = nodes;
|
||||||
|
network_config.default_peers_set.non_reserved_mode =
|
||||||
|
sc_network::config::NonReservedPeerMode::Deny;
|
||||||
|
} else {
|
||||||
|
network_config.boot_nodes = nodes;
|
||||||
|
}
|
||||||
|
|
||||||
network_config.allow_non_globals_in_dht = true;
|
network_config.allow_non_globals_in_dht = true;
|
||||||
|
|
||||||
@@ -445,7 +538,7 @@ pub fn node_config(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CumulusTestNode {
|
impl TestNode {
|
||||||
/// Wait for `count` blocks to be imported in the node and then exit. This function will not
|
/// Wait for `count` blocks to be imported in the node and then exit. This function will not
|
||||||
/// return if no blocks are ever created, thus you should restrict the maximum amount of time of
|
/// return if no blocks are ever created, thus you should restrict the maximum amount of time of
|
||||||
/// the test execution.
|
/// the test execution.
|
||||||
|
|||||||
@@ -15,10 +15,9 @@
|
|||||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use cumulus_primitives_core::ParaId;
|
use cumulus_primitives_core::ParaId;
|
||||||
use cumulus_test_service::initial_head_data;
|
use cumulus_test_service::{initial_head_data, Keyring::*};
|
||||||
use futures::join;
|
use futures::join;
|
||||||
use sc_service::TaskExecutor;
|
use sc_service::TaskExecutor;
|
||||||
use substrate_test_runtime_client::AccountKeyring::*;
|
|
||||||
|
|
||||||
#[substrate_test_utils::test]
|
#[substrate_test_utils::test]
|
||||||
async fn test_collating_and_non_collator_mode_catching_up(task_executor: TaskExecutor) {
|
async fn test_collating_and_non_collator_mode_catching_up(task_executor: TaskExecutor) {
|
||||||
@@ -53,31 +52,21 @@ async fn test_collating_and_non_collator_mode_catching_up(task_executor: TaskExe
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// run cumulus charlie (a parachain collator)
|
// run cumulus charlie (a parachain collator)
|
||||||
let charlie = cumulus_test_service::run_test_node(
|
let charlie =
|
||||||
task_executor.clone(),
|
cumulus_test_service::TestNodeBuilder::new(para_id, task_executor.clone(), Charlie)
|
||||||
Charlie,
|
.enable_collator()
|
||||||
|| {},
|
.connect_to_relay_chain_nodes(vec![&alice, &bob])
|
||||||
|| {},
|
.build()
|
||||||
vec![],
|
|
||||||
vec![alice.addr.clone(), bob.addr.clone()],
|
|
||||||
para_id,
|
|
||||||
true,
|
|
||||||
)
|
|
||||||
.await;
|
.await;
|
||||||
charlie.wait_for_blocks(5).await;
|
charlie.wait_for_blocks(5).await;
|
||||||
|
|
||||||
// run cumulus dave (a parachain full node) and wait for it to sync some blocks
|
// run cumulus dave (a parachain full node) and wait for it to sync some blocks
|
||||||
let dave = cumulus_test_service::run_test_node(
|
let dave = cumulus_test_service::TestNodeBuilder::new(para_id, task_executor.clone(), Dave)
|
||||||
task_executor.clone(),
|
.connect_to_parachain_node(&charlie)
|
||||||
Dave,
|
.connect_to_relay_chain_nodes(vec![&alice, &bob])
|
||||||
|| {},
|
.build()
|
||||||
|| {},
|
|
||||||
vec![charlie.addr.clone()],
|
|
||||||
vec![alice.addr.clone(), bob.addr.clone()],
|
|
||||||
para_id,
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
dave.wait_for_blocks(7).await;
|
dave.wait_for_blocks(7).await;
|
||||||
|
|
||||||
join!(
|
join!(
|
||||||
|
|||||||
Reference in New Issue
Block a user