Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,687 changes: 997 additions & 690 deletions Cargo.lock

Large diffs are not rendered by default.

293 changes: 147 additions & 146 deletions Cargo.toml

Large diffs are not rendered by default.

7 changes: 6 additions & 1 deletion client/consensus/nimbus-consensus/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,17 @@ sp-runtime = { workspace = true }
sp-version = { workspace = true }
sp-trie = { workspace = true }
sp-state-machine = { workspace = true }
sp-externalities = { workspace = true }
sc-basic-authorship = { workspace = true }
sc-block-builder = { workspace = true }
sc-transaction-pool-api = { workspace = true }
substrate-prometheus-endpoint = { workspace = true }
anyhow = { workspace = true }
thiserror = { workspace = true }

# Cumulus dependencies
cumulus-client-collator = { workspace = true }
cumulus-client-consensus-common = { workspace = true }
cumulus-client-consensus-proposer = { workspace = true }
cumulus-client-parachain-inherent = { workspace = true }
cumulus-primitives-core = { workspace = true }
cumulus-primitives-parachain-inherent = { workspace = true }
Expand Down
38 changes: 27 additions & 11 deletions client/consensus/nimbus-consensus/src/collator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@
// You should have received a copy of the GNU General Public License
// along with Moonkit. If not, see <http://www.gnu.org/licenses/>.

use crate::ProposerInterface;
use cumulus_client_collator::service::ServiceInterface as CollatorServiceInterface;
use cumulus_client_consensus_common::{ParachainBlockImportMarker, ParachainCandidate};
use cumulus_client_consensus_proposer::ProposerInterface;
use cumulus_client_parachain_inherent::{ParachainInherentData, ParachainInherentDataProvider};
use cumulus_primitives_core::{
relay_chain::Hash as PHash, DigestItem, ParachainBlockData, PersistedValidationData,
Expand Down Expand Up @@ -124,6 +124,17 @@ where
collator_peer_id: PeerId,
cidp_context: CIDPContext,
) -> Result<(ParachainInherentData, InherentData), Box<dyn Error + Send + Sync + 'static>> {
// stable2603 introduced `RelayProofRequest` (cumulus_primitives_core)
// which wraps a typed list of relay-chain storage keys; previously the
// API took a raw `Vec<Vec<u8>>` of top-level keys. We faithfully
// translate every key as `RelayStorageKey::Top` since the call sites
// only ever passed top-level keys.
let relay_proof_request = cumulus_primitives_core::RelayProofRequest {
keys: additional_relay_state_keys
.into_iter()
.map(cumulus_primitives_core::RelayStorageKey::Top)
.collect(),
};
let paras_inherent_data = ParachainInherentDataProvider::create_at(
relay_parent,
&self.relay_client,
Expand All @@ -132,7 +143,7 @@ where
relay_parent_descendants
.map(RelayParentData::into_inherent_descendant_list)
.unwrap_or_default(),
additional_relay_state_keys,
relay_proof_request,
collator_peer_id,
)
.await;
Expand Down Expand Up @@ -202,7 +213,16 @@ where
)];
logs.extend(additional_pre_digest.into().unwrap_or_default());

let maybe_proposal = self
// Caller now owns the proof recorder and the runtime extensions; see
// paritytech/polkadot-sdk#9947. Register `ProofSizeExt` so the runtime
// can observe its own PoV growth during block production.
let storage_proof_recorder = sp_api::ProofRecorder::<Block>::default();
let mut extra_extensions = sp_externalities::Extensions::new();
extra_extensions.register(sp_trie::proof_size_extension::ProofSizeExt::new(
storage_proof_recorder.clone(),
));

let proposal = self
.proposer
.propose(
&parent_header,
Expand All @@ -211,14 +231,13 @@ where
Digest { logs },
proposal_duration,
Some(max_pov_size),
Some(storage_proof_recorder.clone()),
extra_extensions,
)
.await
.map_err(|e| Box::new(e) as Box<dyn Error + Send>)?;

let proposal = match maybe_proposal {
None => return Ok(None),
Some(p) => p,
};
let proof = storage_proof_recorder.drain_storage_proof();

let sealed_importable = seal::<_, P>(
proposal.block,
Expand All @@ -242,10 +261,7 @@ where
.map_err(|e| Box::new(e) as Box<dyn Error + Send>)
.await?;

Ok(Some(ParachainCandidate {
block,
proof: proposal.proof,
}))
Ok(Some(ParachainCandidate { block, proof }))
}

/// Propose, seal, import a block and packaging it into a collation.
Expand Down
52 changes: 18 additions & 34 deletions client/consensus/nimbus-consensus/src/collators.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ pub mod slot_based;
use crate::{collator::SlotClaim, *};
use async_backing_primitives::Slot;
use async_backing_primitives::UnincludedSegmentApi;
use cumulus_client_consensus_common::{ParentSearchParams, PotentialParent};
use cumulus_client_consensus_common::ParentSearchParams;
use cumulus_primitives_core::{
relay_chain::{Header as RelayHeader, OccupiedCoreAssumption, ValidationCodeHash},
ParaId,
Expand All @@ -51,15 +51,6 @@ use sp_runtime::{
use sp_timestamp::Timestamp;
use std::convert::TryInto;

// This is an arbitrary value which is likely guaranteed to exceed any reasonable
// limit, as it would correspond to 30 non-included blocks.
//
// Since we only search for parent blocks which have already been imported,
// we can guarantee that all imported blocks respect the unincluded segment
// rules specified by the parachain's runtime and thus will never be too deep. This is just an extra
// sanity check.
const PARENT_SEARCH_DEPTH: usize = 30;

pub(crate) fn seal_header<Block>(
header: &Block::Header,
keystore: &dyn Keystore,
Expand Down Expand Up @@ -240,15 +231,14 @@ async fn scheduling_lookahead(
}
}

/// Use [`cumulus_client_consensus_common::find_potential_parents`] to find parachain blocks that
/// we can build on. Once a list of potential parents is retrieved, return the last one of the
/// longest chain.
/// Use [`cumulus_client_consensus_common::find_parent_for_building`] to find the best parachain
/// block to build on. Returns the included block header alongside the best parent header.
async fn find_parent<Block>(
relay_parent: RelayHash,
para_id: ParaId,
para_backend: &impl sc_client_api::Backend<Block>,
relay_client: &impl RelayChainInterface,
) -> Option<(<Block as BlockT>::Header, PotentialParent<Block>)>
) -> Option<(<Block as BlockT>::Header, <Block as BlockT>::Header)>
where
Block: BlockT,
{
Expand All @@ -259,40 +249,34 @@ where
.await
.unwrap_or(polkadot_primitives::DEFAULT_SCHEDULING_LOOKAHEAD)
.saturating_sub(1) as usize,
max_depth: PARENT_SEARCH_DEPTH,
ignore_alternative_branches: true,
};

let potential_parents = cumulus_client_consensus_common::find_potential_parents::<Block>(
match cumulus_client_consensus_common::find_parent_for_building::<Block>(
parent_search_params,
para_backend,
relay_client,
)
.await;

let potential_parents = match potential_parents {
.await
{
Ok(Some(result)) => Some((result.included_header, result.best_parent_header)),
Ok(None) => {
tracing::warn!(
target: crate::LOG_TARGET,
?relay_parent,
"Could not find parent to build upon.",
);
None
}
Err(e) => {
tracing::error!(
target: crate::LOG_TARGET,
?relay_parent,
err = ?e,
"Could not fetch potential parents to build upon"
);

return None;
None
}
Ok(x) => x,
};

let included_block = potential_parents
.iter()
.find(|x| x.depth == 0)?
.header
.clone();
potential_parents
.into_iter()
.max_by_key(|a| a.depth)
.map(|parent| (included_block, parent))
}
}

/// Helper for managing pre-connections to backing groups.
Expand Down
1 change: 0 additions & 1 deletion client/consensus/nimbus-consensus/src/collators/basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
use crate::*;
use cumulus_client_collator::service::ServiceInterface as CollatorServiceInterface;
use cumulus_client_consensus_common::{self as consensus_common, ParachainBlockImportMarker};
use cumulus_client_consensus_proposer::ProposerInterface;
use cumulus_primitives_core::{
relay_chain::{BlockId as RBlockId, Hash as PHash, ValidationCode},
CollectCollationInfo, ParaId, PersistedValidationData,
Expand Down
62 changes: 29 additions & 33 deletions client/consensus/nimbus-consensus/src/collators/lookahead.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ use cumulus_client_consensus_common::{
self as consensus_common, load_abridged_host_configuration, ParachainBlockImportMarker,
ParentSearchParams,
};
use cumulus_client_consensus_proposer::ProposerInterface;
use cumulus_primitives_core::{
relay_chain::{AsyncBackingParams, CoreIndex, Hash as PHash},
CollectCollationInfo, ParaId,
Expand All @@ -43,6 +42,7 @@ use sp_core::Encode;
use sp_inherents::CreateInherentDataProviders;
use sp_keystore::KeystorePtr;
use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
use sp_runtime::Saturating;
use std::{sync::Arc, time::Duration};

/// Parameters for [`run`].
Expand Down Expand Up @@ -122,14 +122,6 @@ where
CHP: consensus_common::ValidationCodeHashProvider<Block::Hash> + Send + 'static,
DP: DigestsProvider<NimbusId, <Block as BlockT>::Hash> + Send + Sync + 'static,
{
// This is an arbitrary value which is likely guaranteed to exceed any reasonable
// limit, as it would correspond to 10 non-included blocks.
//
// Since we only search for parent blocks which have already been imported,
// we can guarantee that all imported blocks respect the unincluded segment
// rules specified by the parachain's runtime and thus will never be too deep.
const PARENT_SEARCH_DEPTH: usize = 10;

async move {
cumulus_client_collator::initialize_collator_subsystems(
&mut params.overseer_handle,
Expand Down Expand Up @@ -273,9 +265,13 @@ where
}
};

// Search potential parents to build upon
let mut potential_parents =
match cumulus_client_consensus_common::find_potential_parents::<Block>(
// Find the best parent to build upon. The new
// `find_parent_for_building` returns the included block plus the
// deepest descendant that fits within the ancestry lookback (the
// stable2603 replacement for the old `find_potential_parents`
// + manual depth filtering).
let (included_header, initial_parent_header) =
match cumulus_client_consensus_common::find_parent_for_building::<Block>(
ParentSearchParams {
relay_parent,
para_id: params.para_id,
Expand All @@ -284,8 +280,6 @@ where
&params.relay_client,
)
.await,
max_depth: PARENT_SEARCH_DEPTH,
ignore_alternative_branches: true,
},
&*params.para_backend,
&params.relay_client,
Expand All @@ -302,39 +296,37 @@ where

continue;
}
Ok(potential_parents) => potential_parents,
Ok(None) => {
tracing::debug!(
target: crate::LOG_TARGET,
?relay_parent,
"No parent found to build upon; skipping slot.",
);
continue;
}
Ok(Some(result)) => (result.included_header, result.best_parent_header),
};

// Search the first potential parent parablock that is already included in the relay
let included_block = match potential_parents.iter().find(|x| x.depth == 0) {
None => continue, // also serves as an `is_empty` check.
Some(b) => b.hash,
};
let included_block = included_header.hash();

// At this point, we found a potential parent parablock that is already included in the relay.
//
// Sort by depth, ascending, to choose the longest chain. If the longest chain has space,
// build upon that. Otherwise, don't build at all.
potential_parents.sort_by_key(|a| a.depth);
let initial_parent = match potential_parents.pop() {
None => continue,
Some(initial_parent) => initial_parent,
};
// Distance from included block to best parent (unincluded segment length).
let initial_parent_depth =
(*initial_parent_header.number()).saturating_sub(*included_header.number());

// Build in a loop until not allowed. Note that the selected collators can change
// at any block, so we need to re-claim our slot every time.
// This needs to change to support elastic scaling, but for continuously
// scheduled chains this ensures that the backlog will grow steadily.
let mut parent_hash = initial_parent.hash;
let mut parent_header = initial_parent.header;
let mut parent_hash = initial_parent_header.hash();
let mut parent_header = initial_parent_header;
let overseer_handle = &mut params.overseer_handle;

// Proactively connect to backing groups. This is especially important for single
// collator setups where we always own the slot and thus would never trigger
// pre-connection through the normal code path.
connection_helper.update(slot_now).await;

for n_built in 0..2 {
for n_built in 0..2u32 {
// Ask to the runtime if we are authorized to create a new parablock on top of this parent.
// (This will claim the slot internally)
let para_client = &*params.para_client;
Expand All @@ -358,7 +350,7 @@ where
target: crate::LOG_TARGET,
?slot_now,
?relay_parent,
unincluded_segment_len = initial_parent.depth + n_built,
unincluded_segment_len = ?initial_parent_depth.saturating_add(n_built.into()),
"Slot claimed. Building"
);

Expand Down Expand Up @@ -475,6 +467,10 @@ where
validation_code_hash,
result_sender: None,
core_index,
// `None` keeps V2 candidate-descriptor semantics
// (the relay parent is used as the scheduling
// parent). Set to `Some(hash)` to opt into V3.
scheduling_parent: None,
},
),
"SubmitCollation",
Expand Down
Loading
Loading