Repository: paritytech/substrate
File: client/consensus/babe/src/lib.rs (Rust)

Code before:
	let height_limit = notification.header.number().saturating_sub(
		notification.tree_route.len().saturated_into::<NumberFor<Block>>() + One::one(),
	);
	for head in notification.stale_heads.iter() {
		let mut hash = *head;
		// Insert stale blocks hashes until canonical chain is not reached.
		// Soon or late we should hit an element already present within the `aux_keys` set.
		while aux_keys.insert(aux_schema::block_weight_key(hash)) {
			match client.header_metadata(hash) {
				Ok(meta) => {
					// This should never happen and must be considered a bug.
					if meta.number <= height_limit {
						warn!(target: "babe", "unexpected canonical chain state or malformed finality notification");
						break
					}
					hash = meta.parent;
				},
				Err(err) => {
					warn!(target: "babe", "header lookup fail while cleaning data for block {}: {}", head.to_string(), err.to_string());
					break
				},
			}
		}
	}

	aux_keys.into_iter().map(|val| (val, None)).collect()
}

async fn answer_requests<B: BlockT, C>(
	mut request_rx: Receiver<BabeRequest<B>>,
	config: Config,
	client: Arc<C>,
	epoch_changes: SharedEpochChanges<B, Epoch>,
) where
	C: ProvideRuntimeApi<B>
		+ ProvideUncles<B>
		+ BlockchainEvents<B>
		+ HeaderBackend<B>
		+ HeaderMetadata<B, Error = ClientError>
		+ Send
		+ Sync
		+ 'static,
{
	while let Some(request) = request_rx.next().await {
		match request {
			BabeRequest::EpochForChild(parent_hash, parent_number, slot_number, response) => {
				let lookup = || {
					let epoch_changes = epoch_changes.shared_data();
					let epoch_descriptor = epoch_changes
						.epoch_descriptor_for_child_of(
							descendent_query(&*client),

Review comment (bug):
```suggestion
					hash = meta.parent;

					// If the parent is part of the canonical chain or there doesn't exist a block
					// hash for the parent number (bug?!), we can abort adding blocks.
					if meta.number <= height_limit && client
						.hash(meta.number.saturating_sub(1u32.into()))
						.ok()
						.flatten()
						.map_or(true, |h| h == hash)
					{
```
Not a *game-changer*, but maybe this could be a small potential optimization, i.e. query the client only if the *quick and dirty* check fails



Code after:
			// Ensure we don't prune latest finalized block.
			// This should not happen, but better be safe than sorry!
			.filter(|h| **h != notification.hash)
			.map(aux_schema::block_weight_key),
	);

	// Cleans data for stale branches.

	for head in notification.stale_heads.iter() {
		let mut hash = *head;
		// Insert stale blocks hashes until canonical chain is reached.
		// If we reach a block that is already part of the `aux_keys` we can stop the processing the
		// head.
		while aux_keys.insert(aux_schema::block_weight_key(hash)) {
			match client.header_metadata(hash) {
				Ok(meta) => {
					hash = meta.parent;

					// If the parent is part of the canonical chain or there doesn't exist a block
					// hash for the parent number (bug?!), we can abort adding blocks.
					if client
						.hash(meta.number.saturating_sub(1u32.into()))
						.ok()
						.flatten()
						.map_or(true, |h| h == hash)
					{
						break
					}
				},
				Err(err) => {
					warn!(
						target: "babe",
						"Header lookup fail while cleaning data for block {:?}: {}",
						hash,
						err,
					);
					break
				},
			}
		}
	}

	aux_keys.into_iter().map(|val| (val, None)).collect()
}

async fn answer_requests<B: BlockT, C>(
	mut request_rx: Receiver<BabeRequest<B>>,
	config: Config,
	client: Arc<C>,
	epoch_changes: SharedEpochChanges<B, Epoch>,
) where