use alloy_primitives::{BlockNumber, B256}; use reth_provider::{BlockNumReader, ProviderError}; use std::cmp::Ordering; /// Errors that can occur in Hl consensus #[derive(Debug, thiserror::Error)] pub enum HlConsensusErr { /// Error from the provider #[error(transparent)] Provider(#[from] ProviderError), /// Head block hash not found #[error("Head block hash not found")] HeadHashNotFound, } /// Hl consensus implementation pub struct HlConsensus
{ /// The provider for reading block information pub provider: P, } impl
HlConsensus
where
P: BlockNumReader + Clone,
{
/// Determines the head block hash according to Hl consensus rules:
/// 1. Follow the highest block number
/// 2. For same height blocks, pick the one with lower hash
pub(crate) fn canonical_head(
&self,
hash: B256,
number: BlockNumber,
) -> Result<(B256, B256), HlConsensusErr> {
let current_head = self.provider.best_block_number()?;
let current_hash = self
.provider
.block_hash(current_head)?
.ok_or(HlConsensusErr::HeadHashNotFound)?;
match number.cmp(¤t_head) {
Ordering::Greater => Ok((hash, current_hash)),
Ordering::Equal => Ok((hash.min(current_hash), current_hash)),
Ordering::Less => Ok((current_hash, current_hash)),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloy_primitives::hex;
use reth_chainspec::ChainInfo;
use reth_provider::BlockHashReader;
use std::collections::HashMap;
#[derive(Clone)]
struct MockProvider {
blocks: HashMap