::new(params)
};
let mut connection_helper = BackingGroupConnectionHelper::new(
params.keystore.clone(),
params.overseer_handle.clone(),
);
while let Some(relay_parent_header) = import_notifications.next().await {
let relay_parent = relay_parent_header.hash();
let Some(core_index) = claim_queue_at(relay_parent, &mut params.relay_client)
.await
.iter_claims_at_depth_for_para(0, params.para_id)
.next()
else {
tracing::trace!(
target: crate::LOG_TARGET,
?relay_parent,
?params.para_id,
"Para is not scheduled on any core, skipping import notification",
);
continue;
};
let max_pov_size = match params
.relay_client
.persisted_validation_data(
relay_parent,
params.para_id,
OccupiedCoreAssumption::Included,
)
.await
{
Ok(None) => continue,
Ok(Some(pvd)) => pvd.max_pov_size,
Err(err) => {
tracing::error!(target: crate::LOG_TARGET, ?err, "Failed to gather information from relay-client");
continue;
},
};
let (included_block, initial_parent) = match crate::collators::find_parent(
relay_parent,
params.para_id,
&*params.para_backend,
¶ms.relay_client,
)
.await
{
Some(value) => value,
None => continue,
};
let para_client = &*params.para_client;
let keystore = ¶ms.keystore;
let can_build_upon = |block_hash| {
let (slot_now, relay_slot, timestamp) = get_teyrchain_slot::<_, _, P::Public>(
para_client,
block_hash,
&relay_parent_header,
params.relay_chain_slot_duration,
)?;
Some(super::can_build_upon::<_, _, P>(
slot_now,
relay_slot,
timestamp,
block_hash,
included_block.hash(),
para_client,
&keystore,
))
};
// Build in a loop until not allowed. Note that the authorities can change
// at any block, so we need to re-claim our slot every time.
let mut parent_hash = initial_parent.hash;
let mut parent_header = initial_parent.header;
let overseer_handle = &mut params.overseer_handle;
// Do not try to build upon an unknown, pruned or bad block
if !collator.collator_service().check_block_status(parent_hash, &parent_header) {
continue;
}
// Trigger pre-conect to backing groups if necessary.
if let (Some((slot_now, _relay_slot, _timestamp)), Ok(authorities)) = (
get_teyrchain_slot::<_, _, P::Public>(
para_client,
parent_hash,
&relay_parent_header,
params.relay_chain_slot_duration,
),
para_client.runtime_api().authorities(parent_hash),
) {
connection_helper.update::(slot_now, &authorities).await;
}
// This needs to change to support elastic scaling, but for continuously
// scheduled chains this ensures that the backlog will grow steadily.
for n_built in 0..2 {
let slot_claim = match can_build_upon(parent_hash) {
Some(fut) => match fut.await {
None => break,
Some(c) => c,
},
None => break,
};
tracing::debug!(
target: crate::LOG_TARGET,
?relay_parent,
unincluded_segment_len = initial_parent.depth + n_built,
"Slot claimed. Building"
);
let validation_data = PersistedValidationData {
parent_head: parent_header.encode().into(),
relay_parent_number: *relay_parent_header.number(),
relay_parent_storage_root: *relay_parent_header.state_root(),
max_pov_size,
};
// Build and announce collations recursively until
// `can_build_upon` fails or building a collation fails.
let (teyrchain_inherent_data, other_inherent_data) = match collator
.create_inherent_data(
relay_parent,
&validation_data,
parent_hash,
slot_claim.timestamp(),
params.collator_peer_id,
)
.await
{
Err(err) => {
tracing::error!(target: crate::LOG_TARGET, ?err);
break;
},
Ok(x) => x,
};
let Some(validation_code_hash) =
params.code_hash_provider.code_hash_at(parent_hash)
else {
tracing::error!(target: crate::LOG_TARGET, ?parent_hash, "Could not fetch validation code hash");
break;
};
super::check_validation_code_or_log(
&validation_code_hash,
params.para_id,
¶ms.relay_client,
relay_parent,
)
.await;
let allowed_pov_size = if let Some(max_pov_percentage) = params.max_pov_percentage {
validation_data.max_pov_size * max_pov_percentage / 100
} else {
// Set the block limit to 85% of the maximum PoV size.
//
// Once https://github.com/pezkuwichain/pezkuwi-sdk/issues/193 issue is
// fixed, the reservation should be removed.
validation_data.max_pov_size * 85 / 100
} as usize;
match collator
.collate(
&parent_header,
&slot_claim,
None,
(teyrchain_inherent_data, other_inherent_data),
params.authoring_duration,
allowed_pov_size,
)
.await
{
Ok(Some((collation, block_data))) => {
let Some(new_block_header) =
block_data.blocks().first().map(|b| b.header().clone())
else {
tracing::error!(target: crate::LOG_TARGET, "Produced PoV doesn't contain any blocks");
break;
};
let new_block_hash = new_block_header.hash();
// Here we are assuming that the import logic protects against equivocations
// and provides sybil-resistance, as it should.
collator.collator_service().announce_block(new_block_hash, None);
if let Some(ref export_pov) = export_pov {
export_pov_to_path::(
export_pov.clone(),
collation.proof_of_validity.clone().into_compressed(),
new_block_hash,
*new_block_header.number(),
parent_header.clone(),
*relay_parent_header.state_root(),
*relay_parent_header.number(),
validation_data.max_pov_size,
);
}
// Send a submit-collation message to the collation generation subsystem,
// which then distributes this to validators.
//
// Here we are assuming that the leaf is imported, as we've gotten an
// import notification.
overseer_handle
.send_msg(
CollationGenerationMessage::SubmitCollation(
SubmitCollationParams {
relay_parent,
collation,
parent_head: parent_header.encode().into(),
validation_code_hash,
result_sender: None,
core_index,
},
),
"SubmitCollation",
)
.await;
parent_hash = new_block_hash;
parent_header = new_block_header;
},
Ok(None) => {
tracing::debug!(target: crate::LOG_TARGET, "No block proposal");
break;
},
Err(err) => {
tracing::error!(target: crate::LOG_TARGET, ?err);
break;
},
}
}
}
}
}