ckb_verification/
block_verifier.rs1use crate::{
2 transaction_verifier::NonContextualTransactionVerifier, BlockErrorKind, CellbaseError,
3};
4use ckb_chain_spec::consensus::Consensus;
5use ckb_error::Error;
6use ckb_types::{
7 core::{BlockView, ScriptHashType},
8 packed::{CellInput, CellbaseWitness},
9 prelude::*,
10};
11use ckb_verification_traits::Verifier;
12use std::collections::HashSet;
13
14#[derive(Clone)]
24pub struct BlockVerifier<'a> {
25 consensus: &'a Consensus,
26}
27
28impl<'a> BlockVerifier<'a> {
29 pub fn new(consensus: &'a Consensus) -> Self {
31 BlockVerifier { consensus }
32 }
33}
34
35impl<'a> Verifier for BlockVerifier<'a> {
36 type Target = BlockView;
37
38 fn verify(&self, target: &BlockView) -> Result<(), Error> {
39 let max_block_proposals_limit = self.consensus.max_block_proposals_limit();
40 let max_block_bytes = self.consensus.max_block_bytes();
41 BlockProposalsLimitVerifier::new(max_block_proposals_limit).verify(target)?;
42 BlockBytesVerifier::new(max_block_bytes).verify(target)?;
43 CellbaseVerifier::new().verify(target)?;
44 DuplicateVerifier::new().verify(target)?;
45 MerkleRootVerifier::new().verify(target)
46 }
47}
48
49#[derive(Clone)]
57pub struct CellbaseVerifier {}
58
59impl CellbaseVerifier {
60 pub fn new() -> Self {
62 CellbaseVerifier {}
63 }
64
65 pub fn verify(&self, block: &BlockView) -> Result<(), Error> {
66 if block.is_genesis() {
67 return Ok(());
68 }
69
70 let cellbase_len = block
71 .transactions()
72 .iter()
73 .filter(|tx| tx.is_cellbase())
74 .count();
75
76 if cellbase_len != 1 {
78 return Err((CellbaseError::InvalidQuantity).into());
79 }
80
81 let cellbase_transaction = &block.transactions()[0];
82
83 if !cellbase_transaction.is_cellbase() {
84 return Err((CellbaseError::InvalidPosition).into());
85 }
86
87 if cellbase_transaction.outputs().len() > 1
89 || cellbase_transaction.outputs_data().len() > 1
90 || cellbase_transaction.outputs().len() != cellbase_transaction.outputs_data().len()
91 {
92 return Err((CellbaseError::InvalidOutputQuantity).into());
93 }
94
95 if !cellbase_transaction
97 .outputs_data()
98 .get(0)
99 .map(|data| data.is_empty())
100 .unwrap_or(true)
101 {
102 return Err((CellbaseError::InvalidOutputData).into());
103 }
104
105 if cellbase_transaction
106 .witnesses()
107 .get(0)
108 .and_then(|witness| {
109 CellbaseWitness::from_slice(&witness.raw_data())
110 .ok()
111 .and_then(|cellbase_witness| {
112 ScriptHashType::try_from(cellbase_witness.lock().hash_type()).ok()
113 })
114 })
115 .is_none()
116 {
117 return Err((CellbaseError::InvalidWitness).into());
118 }
119
120 if cellbase_transaction
122 .outputs()
123 .into_iter()
124 .any(|output| output.type_().is_some())
125 {
126 return Err((CellbaseError::InvalidTypeScript).into());
127 }
128
129 let cellbase_input = &cellbase_transaction
130 .inputs()
131 .get(0)
132 .expect("cellbase should have input");
133 if cellbase_input != &CellInput::new_cellbase_input(block.header().number()) {
134 return Err((CellbaseError::InvalidInput).into());
135 }
136
137 Ok(())
138 }
139}
140
141#[derive(Clone)]
146pub struct DuplicateVerifier {}
147
148impl DuplicateVerifier {
149 pub fn new() -> Self {
150 DuplicateVerifier {}
151 }
152
153 pub fn verify(&self, block: &BlockView) -> Result<(), Error> {
154 let mut seen = HashSet::with_capacity(block.transactions().len());
155 if !block.transactions().iter().all(|tx| seen.insert(tx.hash())) {
156 return Err((BlockErrorKind::CommitTransactionDuplicate).into());
157 }
158
159 let mut seen = HashSet::with_capacity(block.data().proposals().len());
160 if !block
161 .data()
162 .proposals()
163 .into_iter()
164 .all(|id| seen.insert(id))
165 {
166 return Err((BlockErrorKind::ProposalTransactionDuplicate).into());
167 }
168 Ok(())
169 }
170}
171
172#[derive(Clone, Default)]
176pub struct MerkleRootVerifier {}
177
178impl MerkleRootVerifier {
179 pub fn new() -> Self {
180 MerkleRootVerifier::default()
181 }
182
183 pub fn verify(&self, block: &BlockView) -> Result<(), Error> {
184 if block.transactions_root() != block.calc_transactions_root() {
185 return Err(BlockErrorKind::TransactionsRoot.into());
186 }
187
188 if block.proposals_hash() != block.calc_proposals_hash() {
189 return Err(BlockErrorKind::ProposalTransactionsHash.into());
190 }
191
192 Ok(())
193 }
194}
195
196#[derive(Clone)]
200pub struct BlockProposalsLimitVerifier {
201 block_proposals_limit: u64,
202}
203
204impl BlockProposalsLimitVerifier {
205 pub fn new(block_proposals_limit: u64) -> Self {
206 BlockProposalsLimitVerifier {
207 block_proposals_limit,
208 }
209 }
210
211 pub fn verify(&self, block: &BlockView) -> Result<(), Error> {
212 let proposals_len = block.data().proposals().len() as u64;
213 if proposals_len <= self.block_proposals_limit {
214 Ok(())
215 } else {
216 Err(BlockErrorKind::ExceededMaximumProposalsLimit.into())
217 }
218 }
219}
220
221#[derive(Clone)]
225pub struct BlockBytesVerifier {
226 block_bytes_limit: u64,
227}
228
229impl BlockBytesVerifier {
230 pub fn new(block_bytes_limit: u64) -> Self {
231 BlockBytesVerifier { block_bytes_limit }
232 }
233
234 pub fn verify(&self, block: &BlockView) -> Result<(), Error> {
235 if block.is_genesis() {
237 return Ok(());
238 }
239 let block_bytes = block.data().serialized_size_without_uncle_proposals() as u64;
240 if block_bytes <= self.block_bytes_limit {
241 Ok(())
242 } else {
243 Err(BlockErrorKind::ExceededMaximumBlockBytes.into())
244 }
245 }
246}
247
248pub struct NonContextualBlockTxsVerifier<'a> {
253 consensus: &'a Consensus,
254}
255
256impl<'a> NonContextualBlockTxsVerifier<'a> {
257 pub fn new(consensus: &'a Consensus) -> Self {
259 NonContextualBlockTxsVerifier { consensus }
260 }
261
262 pub fn verify(&self, block: &BlockView) -> Result<Vec<()>, Error> {
264 block
265 .transactions()
266 .iter()
267 .map(|tx| NonContextualTransactionVerifier::new(tx, self.consensus).verify())
268 .collect()
269 }
270}