,
}
impl Default for NaiveEquivocationDefender {
fn default() -> Self {
NaiveEquivocationDefender { cache: LruMap::new(ByLength::new(LRU_WINDOW)) }
}
}
impl NaiveEquivocationDefender {
// return `true` if equivocation is beyond the limit.
fn insert_and_check(&mut self, slot: Slot) -> bool {
let val = self
.cache
.get_or_insert(*slot, || 0)
.expect("insertion with ByLength limiter always succeeds; qed");
if *val == EQUIVOCATION_LIMIT {
true
} else {
*val += 1;
false
}
}
}
struct Verifier {
client: Arc,
create_inherent_data_providers: CIDP,
slot_duration: SlotDuration,
defender: NaiveEquivocationDefender,
telemetry: Option,
_phantom: std::marker::PhantomData (Block, P)>,
}
#[async_trait::async_trait]
impl VerifierT for Verifier
where
P: Pair,
P::Signature: Codec,
P::Public: Codec + Debug,
Block: BlockT,
Client: ProvideRuntimeApi + Send + Sync,
>::Api: BlockBuilderApi + AuraApi,
CIDP: CreateInherentDataProviders,
{
async fn verify(
&mut self,
mut block_params: BlockImportParams,
) -> Result, String> {
// Skip checks that include execution, if being told so, or when importing only state.
//
// This is done for example when gap syncing and it is expected that the block after the gap
// was checked/chosen properly, e.g. by warp syncing to this block using a finality proof.
if block_params.state_action.skip_execution_checks() || block_params.with_state() {
return Ok(block_params)
}
let post_hash = block_params.header.hash();
let parent_hash = *block_params.header.parent_hash();
// check seal and update pre-hash/post-hash
{
let authorities = aura_internal::fetch_authorities(self.client.as_ref(), parent_hash)
.map_err(|e| {
format!("Could not fetch authorities at {:?}: {}", parent_hash, e)
})?;
let slot_now = slot_now(self.slot_duration);
let res = aura_internal::check_header_slot_and_seal::(
slot_now,
block_params.header,
&authorities,
);
match res {
Ok((pre_header, slot, seal_digest)) => {
telemetry!(
self.telemetry;
CONSENSUS_TRACE;
"aura.checked_and_importing";
"pre_header" => ?pre_header,
);
block_params.header = pre_header;
block_params.post_digests.push(seal_digest);
block_params.fork_choice = Some(ForkChoiceStrategy::LongestChain);
block_params.post_hash = Some(post_hash);
// Check for and reject egregious amounts of equivocations.
if self.defender.insert_and_check(slot) {
return Err(format!(
"Rejecting block {:?} due to excessive equivocations at slot",
post_hash,
))
}
},
Err(aura_internal::SealVerificationError::Deferred(hdr, slot)) => {
telemetry!(
self.telemetry;
CONSENSUS_DEBUG;
"aura.header_too_far_in_future";
"hash" => ?post_hash,
"a" => ?hdr,
"b" => ?slot,
);
return Err(format!(
"Rejecting block ({:?}) from future slot {:?}",
post_hash, slot
))
},
Err(e) =>
return Err(format!(
"Rejecting block ({:?}) with invalid seal ({:?})",
post_hash, e
)),
}
}
// check inherents.
if let Some(body) = block_params.body.clone() {
let block = Block::new(block_params.header.clone(), body);
let create_inherent_data_providers = self
.create_inherent_data_providers
.create_inherent_data_providers(parent_hash, ())
.await
.map_err(|e| format!("Could not create inherent data {:?}", e))?;
let inherent_data = create_inherent_data_providers
.create_inherent_data()
.await
.map_err(|e| format!("Could not create inherent data {:?}", e))?;
let inherent_res = self
.client
.runtime_api()
.check_inherents(parent_hash, block, inherent_data)
.map_err(|e| format!("Unable to check block inherents {:?}", e))?;
if !inherent_res.ok() {
for (i, e) in inherent_res.into_errors() {
match create_inherent_data_providers.try_handle_error(&i, &e).await {
Some(res) => res.map_err(|e| format!("Inherent Error {:?}", e))?,
None =>
return Err(format!(
"Unknown inherent error, source {:?}",
String::from_utf8_lossy(&i[..])
)),
}
}
}
}
Ok(block_params)
}
}
fn slot_now(slot_duration: SlotDuration) -> Slot {
let timestamp = sp_timestamp::InherentDataProvider::from_system_time().timestamp();
Slot::from_timestamp(timestamp, slot_duration)
}
/// Start an import queue for a Cumulus node which checks blocks' seals and inherent data.
///
/// Pass in only inherent data providers which don't include aura or parachain consensus inherents,
/// e.g. things like timestamp and custom inherents for the runtime.
///
/// The others are generated explicitly internally.
///
/// This should only be used for runtimes where the runtime does not check all inherents and
/// seals in `execute_block` (see )
pub fn fully_verifying_import_queue(
client: Arc,
block_import: I,
create_inherent_data_providers: CIDP,
slot_duration: SlotDuration,
spawner: &impl sp_core::traits::SpawnEssentialNamed,
registry: Option<&substrate_prometheus_endpoint::Registry>,
telemetry: Option,
) -> BasicQueue
where
P: Pair + 'static,
P::Signature: Codec,
P::Public: Codec + Debug,
I: BlockImport
+ ParachainBlockImportMarker
+ Send
+ Sync
+ 'static,
Client: ProvideRuntimeApi + Send + Sync + 'static,
>::Api: BlockBuilderApi + AuraApi,
CIDP: CreateInherentDataProviders + 'static,
{
let verifier = Verifier:: {
client,
create_inherent_data_providers,
defender: NaiveEquivocationDefender::default(),
slot_duration,
telemetry,
_phantom: std::marker::PhantomData,
};
BasicQueue::new(verifier, Box::new(block_import), None, spawner, registry)
}