ckb_verification/
genesis_verifier.rs1use 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#[derive(Clone)]
16pub struct GenesisVerifier {}
17
18impl GenesisVerifier {
19 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 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 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}