fuel_core_consensus_module/
block_verifier.rs

1//! The module provides the functionality that verifies the blocks and headers based
2//! on the used consensus.
3
4use crate::block_verifier::config::Config;
5use anyhow::ensure;
6use fuel_core_poa::ports::Database as PoAVerifierDatabase;
7use fuel_core_storage::transactional::AtomicView;
8use fuel_core_types::{
9    blockchain::{
10        block::Block,
11        consensus::Consensus,
12        header::BlockHeader,
13        primitives::DaBlockHeight,
14        SealedBlockHeader,
15    },
16    fuel_types::{
17        BlockHeight,
18        Bytes32,
19    },
20    tai64::Tai64,
21};
22
23pub mod config;
24
25#[cfg(test)]
26mod tests;
27
28/// Verifier is responsible for validation of the blocks and headers.
29pub struct Verifier<V> {
30    config: Config,
31    view_provider: V,
32}
33
34impl<V> Verifier<V> {
35    /// Creates a new instance of the verifier.
36    pub fn new(config: Config, view_provider: V) -> Self {
37        Self {
38            config,
39            view_provider,
40        }
41    }
42}
43
44impl<V> Verifier<V>
45where
46    V: AtomicView,
47    V::LatestView: PoAVerifierDatabase,
48{
49    /// Verifies **all** fields of the block based on used consensus to produce a block.
50    ///
51    /// Return an error if the verification failed, otherwise `Ok(())`.
52    pub fn verify_block_fields(
53        &self,
54        consensus: &Consensus,
55        block: &Block,
56    ) -> anyhow::Result<()> {
57        match consensus {
58            Consensus::Genesis(_) => {
59                let expected_genesis_height = self.config.block_height;
60                let expected_genesis_da_height = self.config.da_block_height;
61                verify_genesis_block_fields(
62                    expected_genesis_height,
63                    expected_genesis_da_height,
64                    block.header(),
65                )
66            }
67            Consensus::PoA(_) => {
68                let view = self.view_provider.latest_view()?;
69                fuel_core_poa::verifier::verify_block_fields(&view, block)
70            }
71            _ => Err(anyhow::anyhow!("Unsupported consensus: {:?}", consensus)),
72        }
73    }
74
75    /// Verifies the consensus of the block header.
76    pub fn verify_consensus(&self, header: &SealedBlockHeader) -> bool {
77        let SealedBlockHeader {
78            entity: header,
79            consensus,
80        } = header;
81        match consensus {
82            Consensus::Genesis(_) => true,
83            Consensus::PoA(consensus) => fuel_core_poa::verifier::verify_consensus(
84                &self.config.consensus,
85                header,
86                consensus,
87            ),
88            _ => false,
89        }
90    }
91}
92
93fn verify_genesis_block_fields(
94    expected_genesis_height: BlockHeight,
95    expected_genesis_da_height: DaBlockHeight,
96    header: &BlockHeader,
97) -> anyhow::Result<()> {
98    let actual_genesis_height = *header.height();
99
100    ensure!(
101        header.prev_root() == &Bytes32::zeroed(),
102        "The genesis previous root should be zeroed"
103    );
104    ensure!(
105        header.time() == Tai64::UNIX_EPOCH,
106        "The genesis time should be unix epoch time"
107    );
108    ensure!(
109        header.da_height == expected_genesis_da_height,
110        "The genesis `da_height` is not as expected"
111    );
112    ensure!(
113        expected_genesis_height == actual_genesis_height,
114        "The genesis height is not as expected"
115    );
116    Ok(())
117}