Skip to content

Commit 673a9b7

Browse files
nazar-pcJay Pan
authored andcommitted
Block import and verification refactoring (paritytech#4844)
A few refactorings to block import and block verification that should not be controversial. Block verification before block import is stateless by design as described in https://substrate.stackexchange.com/a/1322/25 and the fact that it wasn't yet I consider to be a bug. Some code that requires it had to use `Mutex`, but I do not expect it to have a measurable performance impact. Similarly with block import checking whether block preconditions should not be an exclusive operation, there is nothing fundamentally wrong with checking a few competing blocks whose parent blocks exist at the same time (and even import them concurrently later, though IIRC this is not yet implemented either). They were originally a part of paritytech#4842 and upstreaming will help us to reduce the size of the patch we need to apply on top of upstream code at Subspace every time we upgrade. There are no new features introduced here, just refactoring to get rid of unnecessary requirements.
1 parent c0dbeac commit 673a9b7

22 files changed

Lines changed: 244 additions & 168 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cumulus/client/consensus/aura/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ workspace = true
1313
async-trait = { workspace = true }
1414
codec = { features = ["derive"], workspace = true, default-features = true }
1515
futures = { workspace = true }
16+
parking_lot = { workspace = true }
1617
tracing = { workspace = true, default-features = true }
1718
schnellru = { workspace = true }
1819

cumulus/client/consensus/aura/src/equivocation_import_queue.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
/// should be thrown out and which ones should be kept.
2222
use codec::Codec;
2323
use cumulus_client_consensus_common::ParachainBlockImportMarker;
24+
use parking_lot::Mutex;
2425
use schnellru::{ByLength, LruMap};
2526

2627
use sc_consensus::{
@@ -70,7 +71,7 @@ impl NaiveEquivocationDefender {
7071
struct Verifier<P, Client, Block, CIDP> {
7172
client: Arc<Client>,
7273
create_inherent_data_providers: CIDP,
73-
defender: NaiveEquivocationDefender,
74+
defender: Mutex<NaiveEquivocationDefender>,
7475
telemetry: Option<TelemetryHandle>,
7576
_phantom: std::marker::PhantomData<fn() -> (Block, P)>,
7677
}
@@ -88,7 +89,7 @@ where
8889
CIDP: CreateInherentDataProviders<Block, ()>,
8990
{
9091
async fn verify(
91-
&mut self,
92+
&self,
9293
mut block_params: BlockImportParams<Block>,
9394
) -> Result<BlockImportParams<Block>, String> {
9495
// Skip checks that include execution, if being told so, or when importing only state.
@@ -137,7 +138,7 @@ where
137138
block_params.post_hash = Some(post_hash);
138139

139140
// Check for and reject egregious amounts of equivocations.
140-
if self.defender.insert_and_check(slot) {
141+
if self.defender.lock().insert_and_check(slot) {
141142
return Err(format!(
142143
"Rejecting block {:?} due to excessive equivocations at slot",
143144
post_hash,
@@ -243,7 +244,7 @@ where
243244
let verifier = Verifier::<P, _, _, _> {
244245
client,
245246
create_inherent_data_providers,
246-
defender: NaiveEquivocationDefender::default(),
247+
defender: Mutex::new(NaiveEquivocationDefender::default()),
247248
telemetry,
248249
_phantom: std::marker::PhantomData,
249250
};

cumulus/client/consensus/common/src/import_queue.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ pub struct VerifyNothing;
5050
#[async_trait::async_trait]
5151
impl<Block: BlockT> Verifier<Block> for VerifyNothing {
5252
async fn verify(
53-
&mut self,
53+
&self,
5454
params: BlockImportParams<Block>,
5555
) -> Result<BlockImportParams<Block>, String> {
5656
Ok(params)

cumulus/client/consensus/common/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,13 +172,13 @@ impl<Block: BlockT, I: Clone, BE> Clone for ParachainBlockImport<Block, I, BE> {
172172
impl<Block, BI, BE> BlockImport<Block> for ParachainBlockImport<Block, BI, BE>
173173
where
174174
Block: BlockT,
175-
BI: BlockImport<Block> + Send,
175+
BI: BlockImport<Block> + Send + Sync,
176176
BE: Backend<Block>,
177177
{
178178
type Error = BI::Error;
179179

180180
async fn check_block(
181-
&mut self,
181+
&self,
182182
block: sc_consensus::BlockCheckParams<Block>,
183183
) -> Result<sc_consensus::ImportResult, Self::Error> {
184184
self.inner.check_block(block).await

cumulus/client/consensus/relay-chain/src/import_queue.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ where
5252
CIDP: CreateInherentDataProviders<Block, ()>,
5353
{
5454
async fn verify(
55-
&mut self,
55+
&self,
5656
mut block_params: BlockImportParams<Block>,
5757
) -> Result<BlockImportParams<Block>, String> {
5858
block_params.fork_choice = Some(sc_consensus::ForkChoiceStrategy::Custom(

cumulus/polkadot-parachain/src/service.rs

Lines changed: 36 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -498,43 +498,26 @@ pub async fn start_shell_node<Net: NetworkBackend<Block, Hash>>(
498498
.await
499499
}
500500

501-
enum BuildOnAccess<R> {
502-
Uninitialized(Option<Box<dyn FnOnce() -> R + Send + Sync>>),
503-
Initialized(R),
504-
}
505-
506-
impl<R> BuildOnAccess<R> {
507-
fn get_mut(&mut self) -> &mut R {
508-
loop {
509-
match self {
510-
Self::Uninitialized(f) => {
511-
*self = Self::Initialized((f.take().unwrap())());
512-
},
513-
Self::Initialized(ref mut r) => return r,
514-
}
515-
}
516-
}
517-
}
518-
519501
struct Verifier<Client, AuraId> {
520502
client: Arc<Client>,
521-
aura_verifier: BuildOnAccess<Box<dyn VerifierT<Block>>>,
503+
aura_verifier: Box<dyn VerifierT<Block>>,
522504
relay_chain_verifier: Box<dyn VerifierT<Block>>,
523505
_phantom: PhantomData<AuraId>,
524506
}
525507

526508
#[async_trait::async_trait]
527-
impl<Client, AuraId: AuraIdT> VerifierT<Block> for Verifier<Client, AuraId>
509+
impl<Client, AuraId> VerifierT<Block> for Verifier<Client, AuraId>
528510
where
529-
Client: sp_api::ProvideRuntimeApi<Block> + Send + Sync,
511+
Client: ProvideRuntimeApi<Block> + Send + Sync,
530512
Client::Api: AuraRuntimeApi<Block, AuraId>,
513+
AuraId: AuraIdT + Sync,
531514
{
532515
async fn verify(
533-
&mut self,
516+
&self,
534517
block_import: BlockImportParams<Block>,
535518
) -> Result<BlockImportParams<Block>, String> {
536519
if self.client.runtime_api().has_aura_api(*block_import.header.parent_hash()) {
537-
self.aura_verifier.get_mut().verify(block_import).await
520+
self.aura_verifier.verify(block_import).await
538521
} else {
539522
self.relay_chain_verifier.verify(block_import).await
540523
}
@@ -543,7 +526,7 @@ where
543526

544527
/// Build the import queue for parachain runtimes that started with relay chain consensus and
545528
/// switched to aura.
546-
pub fn build_relay_to_aura_import_queue<RuntimeApi, AuraId: AuraIdT>(
529+
pub fn build_relay_to_aura_import_queue<RuntimeApi, AuraId>(
547530
client: Arc<ParachainClient<RuntimeApi>>,
548531
block_import: ParachainBlockImport<RuntimeApi>,
549532
config: &Configuration,
@@ -553,46 +536,43 @@ pub fn build_relay_to_aura_import_queue<RuntimeApi, AuraId: AuraIdT>(
553536
where
554537
RuntimeApi: ConstructNodeRuntimeApi<Block, ParachainClient<RuntimeApi>>,
555538
RuntimeApi::RuntimeApi: AuraRuntimeApi<Block, AuraId>,
539+
AuraId: AuraIdT + Sync,
556540
{
557541
let verifier_client = client.clone();
558542

559-
let aura_verifier = move || {
560-
Box::new(cumulus_client_consensus_aura::build_verifier::<
561-
<AuraId as AppCrypto>::Pair,
562-
_,
563-
_,
564-
_,
565-
>(cumulus_client_consensus_aura::BuildVerifierParams {
566-
client: verifier_client.clone(),
567-
create_inherent_data_providers: move |parent_hash, _| {
568-
let cidp_client = verifier_client.clone();
569-
async move {
570-
let slot_duration = cumulus_client_consensus_aura::slot_duration_at(
571-
&*cidp_client,
572-
parent_hash,
573-
)?;
574-
let timestamp = sp_timestamp::InherentDataProvider::from_system_time();
575-
576-
let slot =
577-
sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration(
578-
*timestamp,
579-
slot_duration,
580-
);
581-
582-
Ok((slot, timestamp))
583-
}
584-
},
585-
telemetry: telemetry_handle,
586-
})) as Box<_>
587-
};
543+
let aura_verifier = cumulus_client_consensus_aura::build_verifier::<
544+
<AuraId as AppCrypto>::Pair,
545+
_,
546+
_,
547+
_,
548+
>(cumulus_client_consensus_aura::BuildVerifierParams {
549+
client: verifier_client.clone(),
550+
create_inherent_data_providers: move |parent_hash, _| {
551+
let cidp_client = verifier_client.clone();
552+
async move {
553+
let slot_duration =
554+
cumulus_client_consensus_aura::slot_duration_at(&*cidp_client, parent_hash)?;
555+
let timestamp = sp_timestamp::InherentDataProvider::from_system_time();
556+
557+
let slot =
558+
sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration(
559+
*timestamp,
560+
slot_duration,
561+
);
562+
563+
Ok((slot, timestamp))
564+
}
565+
},
566+
telemetry: telemetry_handle,
567+
});
588568

589569
let relay_chain_verifier =
590570
Box::new(RelayChainVerifier::new(client.clone(), |_, _| async { Ok(()) })) as Box<_>;
591571

592572
let verifier = Verifier {
593573
client,
594574
relay_chain_verifier,
595-
aura_verifier: BuildOnAccess::Uninitialized(Some(Box::new(aura_verifier))),
575+
aura_verifier: Box::new(aura_verifier),
596576
_phantom: PhantomData,
597577
};
598578

@@ -632,7 +612,7 @@ pub async fn start_generic_aura_lookahead_node<Net: NetworkBackend<Block, Hash>>
632612
///
633613
/// Uses the lookahead collator to support async backing.
634614
#[sc_tracing::logging::prefix_logs_with("Parachain")]
635-
pub async fn start_asset_hub_lookahead_node<RuntimeApi, AuraId: AuraIdT, Net>(
615+
pub async fn start_asset_hub_lookahead_node<RuntimeApi, AuraId, Net>(
636616
parachain_config: Configuration,
637617
polkadot_config: Configuration,
638618
collator_options: CollatorOptions,
@@ -644,6 +624,7 @@ where
644624
RuntimeApi::RuntimeApi: AuraRuntimeApi<Block, AuraId>
645625
+ pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi<Block, Balance>
646626
+ substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Nonce>,
627+
AuraId: AuraIdT + Sync,
647628
Net: NetworkBackend<Block, Hash>,
648629
{
649630
start_node_impl::<RuntimeApi, _, _, _, Net>(

prdoc/pr_4844.prdoc

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
title: Make `Verifier::verify` and `BlockImport::check_block` use `&self` instead of `&mut self`
2+
3+
doc:
4+
- audience: Node Dev
5+
description: |
6+
`Verifier::verify` and `BlockImport::check_block` were refactored to use `&self` instead of `&mut self`
7+
because there is no fundamental requirement for those operations to be exclusive in nature.
8+
9+
crates:
10+
- name: sc-consensus
11+
bump: major
12+
validate: false
13+
- name: sc-consensus-aura
14+
bump: major
15+
- name: sc-consensus-babe
16+
bump: major
17+
- name: sc-consensus-beefy
18+
bump: major
19+
- name: sc-consensus-grandpa
20+
bump: major
21+
- name: sc-consensus-manual-seal
22+
bump: major
23+
- name: sc-consensus-pow
24+
bump: major
25+
- name: sc-service
26+
bump: major
27+
- name: cumulus-client-consensus-common
28+
bump: major
29+
- name: cumulus-client-consensus-aura
30+
bump: major
31+
- name: cumulus-client-consensus-relay-chain
32+
bump: major
33+
- name: polkadot-parachain-bin
34+
validate: false

substrate/client/consensus/aura/src/import_queue.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ where
174174
CIDP::InherentDataProviders: InherentDataProviderExt + Send + Sync,
175175
{
176176
async fn verify(
177-
&mut self,
177+
&self,
178178
mut block: BlockImportParams<B>,
179179
) -> Result<BlockImportParams<B>, String> {
180180
// Skip checks that include execution, if being told so or when importing only state.

substrate/client/consensus/babe/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1128,7 +1128,7 @@ where
11281128
CIDP::InherentDataProviders: InherentDataProviderExt + Send + Sync,
11291129
{
11301130
async fn verify(
1131-
&mut self,
1131+
&self,
11321132
mut block: BlockImportParams<Block>,
11331133
) -> Result<BlockImportParams<Block>, String> {
11341134
trace!(
@@ -1681,7 +1681,7 @@ where
16811681
}
16821682

16831683
async fn check_block(
1684-
&mut self,
1684+
&self,
16851685
block: BlockCheckParams<Block>,
16861686
) -> Result<ImportResult, Self::Error> {
16871687
self.inner.check_block(block).await.map_err(Into::into)

0 commit comments

Comments
 (0)