ckb_verification/
header_verifier.rs

1use crate::{
2    BlockVersionError, EpochError, NumberError, PowError, TimestampError, UnknownParentError,
3    ALLOWED_FUTURE_BLOCKTIME,
4};
5use ckb_chain_spec::consensus::Consensus;
6use ckb_error::Error;
7use ckb_pow::PowEngine;
8use ckb_systemtime::unix_time_as_millis;
9use ckb_traits::HeaderFieldsProvider;
10use ckb_types::core::{BlockNumber, EpochNumberWithFraction, HeaderView};
11use ckb_verification_traits::Verifier;
12
13/// Context-dependent verification checks for block header
14///
15/// By "context", only mean the previous block headers here.
16pub struct HeaderVerifier<'a, DL> {
17    data_loader: &'a DL,
18    consensus: &'a Consensus,
19}
20
21impl<'a, DL: HeaderFieldsProvider> HeaderVerifier<'a, DL> {
22    /// Crate new HeaderVerifier
23    pub fn new(data_loader: &'a DL, consensus: &'a Consensus) -> Self {
24        HeaderVerifier {
25            consensus,
26            data_loader,
27        }
28    }
29}
30
31impl<'a, DL: HeaderFieldsProvider> Verifier for HeaderVerifier<'a, DL> {
32    type Target = HeaderView;
33    fn verify(&self, header: &Self::Target) -> Result<(), Error> {
34        VersionVerifier::new(header, self.consensus).verify()?;
35        // POW check first
36        PowVerifier::new(header, self.consensus.pow_engine().as_ref()).verify()?;
37        let parent_fields = self
38            .data_loader
39            .get_header_fields(&header.parent_hash())
40            .ok_or_else(|| UnknownParentError {
41                parent_hash: header.parent_hash(),
42            })?;
43        NumberVerifier::new(parent_fields.number, header).verify()?;
44        EpochVerifier::new(parent_fields.epoch, header).verify()?;
45        TimestampVerifier::new(
46            self.data_loader,
47            header,
48            self.consensus.median_time_block_count(),
49        )
50        .verify()?;
51        Ok(())
52    }
53}
54
55pub struct VersionVerifier<'a> {
56    header: &'a HeaderView,
57    consensus: &'a Consensus,
58}
59
60impl<'a> VersionVerifier<'a> {
61    pub fn new(header: &'a HeaderView, consensus: &'a Consensus) -> Self {
62        VersionVerifier { header, consensus }
63    }
64
65    pub fn verify(&self) -> Result<(), Error> {
66        if !self
67            .consensus
68            .hardfork_switch
69            .ckb2023
70            .is_remove_header_version_reservation_rule_enabled(self.header.epoch().number())
71            && self.header.version() != self.consensus.block_version()
72        {
73            return Err(BlockVersionError {
74                expected: self.consensus.block_version(),
75                actual: self.header.version(),
76            }
77            .into());
78        }
79        Ok(())
80    }
81}
82
83pub struct TimestampVerifier<'a, DL> {
84    header: &'a HeaderView,
85    data_loader: &'a DL,
86    median_block_count: usize,
87    now: u64,
88}
89
90impl<'a, DL: HeaderFieldsProvider> TimestampVerifier<'a, DL> {
91    pub fn new(data_loader: &'a DL, header: &'a HeaderView, median_block_count: usize) -> Self {
92        TimestampVerifier {
93            data_loader,
94            header,
95            median_block_count,
96            now: unix_time_as_millis(),
97        }
98    }
99
100    pub fn verify(&self) -> Result<(), Error> {
101        // skip genesis block
102        if self.header.is_genesis() {
103            return Ok(());
104        }
105
106        let min = self.data_loader.block_median_time(
107            &self.header.data().raw().parent_hash(),
108            self.median_block_count,
109        );
110        if self.header.timestamp() <= min {
111            return Err(TimestampError::BlockTimeTooOld {
112                min,
113                actual: self.header.timestamp(),
114            }
115            .into());
116        }
117        let max = self.now + ALLOWED_FUTURE_BLOCKTIME;
118        if self.header.timestamp() > max {
119            return Err(TimestampError::BlockTimeTooNew {
120                max,
121                actual: self.header.timestamp(),
122            }
123            .into());
124        }
125        Ok(())
126    }
127}
128
129/// Checks if the block number of the given header matches the expected number,
130/// which is the parent block's number + 1.
131pub struct NumberVerifier<'a> {
132    parent: BlockNumber,
133    header: &'a HeaderView,
134}
135
136impl<'a> NumberVerifier<'a> {
137    pub fn new(parent: BlockNumber, header: &'a HeaderView) -> Self {
138        NumberVerifier { parent, header }
139    }
140
141    pub fn verify(&self) -> Result<(), Error> {
142        if self.header.number() != self.parent + 1 {
143            return Err(NumberError {
144                expected: self.parent + 1,
145                actual: self.header.number(),
146            }
147            .into());
148        }
149        Ok(())
150    }
151}
152
153pub struct EpochVerifier<'a> {
154    parent: EpochNumberWithFraction,
155    header: &'a HeaderView,
156}
157
158impl<'a> EpochVerifier<'a> {
159    pub fn new(parent: EpochNumberWithFraction, header: &'a HeaderView) -> Self {
160        EpochVerifier { parent, header }
161    }
162
163    pub fn verify(&self) -> Result<(), Error> {
164        if !self.header.epoch().is_well_formed() {
165            return Err(EpochError::Malformed {
166                value: self.header.epoch(),
167            }
168            .into());
169        }
170        if !self.parent.is_genesis() && !self.header.epoch().is_successor_of(self.parent) {
171            return Err(EpochError::NonContinuous {
172                current: self.header.epoch(),
173                parent: self.parent,
174            }
175            .into());
176        }
177        Ok(())
178    }
179}
180
181pub struct PowVerifier<'a> {
182    header: &'a HeaderView,
183    pow: &'a dyn PowEngine,
184}
185
186impl<'a> PowVerifier<'a> {
187    pub fn new(header: &'a HeaderView, pow: &'a dyn PowEngine) -> Self {
188        PowVerifier { header, pow }
189    }
190
191    pub fn verify(&self) -> Result<(), Error> {
192        if self.pow.verify(&self.header.data()) {
193            Ok(())
194        } else {
195            Err(PowError::InvalidNonce.into())
196        }
197    }
198}