ckb_verification/
genesis_verifier.rs

1use crate::{
2    error::CellbaseError, BlockErrorKind, BlockVerifier, EpochError, NumberError, UnclesError,
3    UnknownParentError,
4};
5use ckb_chain_spec::{calculate_block_reward, consensus::Consensus};
6use ckb_dao_utils::genesis_dao_data_with_satoshi_gift;
7use ckb_error::Error;
8use ckb_types::{core::BlockView, packed::CellInput};
9use ckb_verification_traits::Verifier;
10
11/// The genesis verification
12///
13/// BlockVerifier is not applicable to genesis, genesis have particular rules,
14/// It's not limited by block size. Its previous hash is zero hash, and it has no uncles.
15#[derive(Clone)]
16pub struct GenesisVerifier {}
17
18impl GenesisVerifier {
19    /// Create new GenesisVerifier
20    pub fn new() -> Self {
21        GenesisVerifier {}
22    }
23}
24
25impl Default for GenesisVerifier {
26    fn default() -> Self {
27        Self::new()
28    }
29}
30
31impl Verifier for GenesisVerifier {
32    type Target = Consensus;
33
34    fn verify(&self, consensus: &Self::Target) -> Result<(), Error> {
35        NumberVerifier::verify(consensus.genesis_block())?;
36        EpochVerifier::verify(consensus.genesis_block())?;
37        ParentHashVerifier::verify(consensus.genesis_block())?;
38        CellbaseVerifier::verify(consensus.genesis_block())?;
39        UnclesVerifier::verify(consensus.genesis_block())?;
40        DAOVerifier::new(consensus).verify(consensus.genesis_block())?;
41        BlockVerifier::new(consensus).verify(consensus.genesis_block())
42    }
43}
44
45#[derive(Clone)]
46pub struct NumberVerifier {}
47
48impl NumberVerifier {
49    pub fn verify(block: &BlockView) -> Result<(), Error> {
50        if block.header().number() != 0 {
51            return Err((NumberError {
52                expected: 0,
53                actual: block.header().number(),
54            })
55            .into());
56        }
57        Ok(())
58    }
59}
60
61#[derive(Clone)]
62pub struct EpochVerifier {}
63
64impl EpochVerifier {
65    pub fn verify(block: &BlockView) -> Result<(), Error> {
66        if block.header().epoch().number() != 0 {
67            return Err((EpochError::NumberMismatch {
68                expected: 0,
69                actual: block.header().epoch().number(),
70            })
71            .into());
72        }
73        Ok(())
74    }
75}
76
77#[derive(Clone)]
78pub struct ParentHashVerifier {}
79
80impl ParentHashVerifier {
81    pub fn verify(block: &BlockView) -> Result<(), Error> {
82        if block.parent_hash().raw_data()[..] != [0u8; 32][..] {
83            return Err((UnknownParentError {
84                parent_hash: block.parent_hash(),
85            })
86            .into());
87        }
88        Ok(())
89    }
90}
91
92#[derive(Clone)]
93pub struct UnclesVerifier {}
94
95impl UnclesVerifier {
96    pub fn verify(block: &BlockView) -> Result<(), Error> {
97        if !block.uncles().hashes().is_empty() {
98            return Err((UnclesError::OverCount {
99                max: 0,
100                actual: block.uncles().hashes().len() as u32,
101            })
102            .into());
103        }
104        Ok(())
105    }
106}
107
108#[derive(Clone)]
109pub struct DAOVerifier<'a> {
110    consensus: &'a Consensus,
111}
112
113impl<'a> DAOVerifier<'a> {
114    pub fn new(consensus: &'a Consensus) -> Self {
115        DAOVerifier { consensus }
116    }
117
118    pub fn verify(&self, block: &BlockView) -> Result<(), Error> {
119        let txs = block.transactions();
120        let epoch_length = self.consensus.genesis_epoch_ext.length();
121        let primary_issuance =
122            calculate_block_reward(self.consensus.initial_primary_epoch_reward, epoch_length);
123        let secondary_issuance =
124            calculate_block_reward(self.consensus.secondary_epoch_reward, epoch_length);
125        let dao = genesis_dao_data_with_satoshi_gift(
126            txs.iter().collect::<Vec<_>>(),
127            &self.consensus.satoshi_pubkey_hash,
128            self.consensus.satoshi_cell_occupied_ratio,
129            primary_issuance,
130            secondary_issuance,
131        )?;
132        if dao != block.header().dao() {
133            return Err((BlockErrorKind::InvalidDAO).into());
134        }
135        Ok(())
136    }
137}
138
139#[derive(Clone)]
140pub struct CellbaseVerifier {}
141
142impl CellbaseVerifier {
143    pub fn verify(block: &BlockView) -> Result<(), Error> {
144        let cellbase_len = block
145            .transactions()
146            .iter()
147            .filter(|tx| tx.is_cellbase())
148            .count();
149
150        // empty checked, block must contain cellbase
151        if cellbase_len != 1 {
152            return Err((CellbaseError::InvalidQuantity).into());
153        }
154
155        let cellbase_transaction = &block.transactions()[0];
156
157        if !cellbase_transaction.is_cellbase() {
158            return Err((CellbaseError::InvalidPosition).into());
159        }
160
161        // cellbase outputs/outputs_data len must be equalized
162        if cellbase_transaction.outputs().len() != cellbase_transaction.outputs_data().len() {
163            return Err((CellbaseError::InvalidOutputQuantity).into());
164        }
165
166        let cellbase_input = &cellbase_transaction
167            .inputs()
168            .get(0)
169            .expect("cellbase should have input");
170        if cellbase_input != &CellInput::new_cellbase_input(block.header().number()) {
171            return Err((CellbaseError::InvalidInput).into());
172        }
173
174        Ok(())
175    }
176}