ckb_verification/
header_verifier.rs

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