ckb_verification/
block_verifier.rs

1use crate::{
2    BlockErrorKind, CellbaseError, transaction_verifier::NonContextualTransactionVerifier,
3};
4use ckb_chain_spec::consensus::Consensus;
5use ckb_constant::consensus::ENABLED_SCRIPT_HASH_TYPE;
6use ckb_error::Error;
7use ckb_types::{
8    core::{BlockView, ScriptHashType},
9    packed::{CellInput, CellbaseWitness},
10    prelude::*,
11};
12use ckb_verification_traits::Verifier;
13use std::collections::HashSet;
14
15/// Block verifier that are independent of context.
16///
17/// Contains:
18/// - [`CellbaseVerifier`](./struct.CellbaseVerifier.html)
19/// - [`BlockBytesVerifier`](./struct.BlockBytesVerifier.html)
20/// - [`BlockExtensionVerifier`](./struct.BlockExtensionVerifier.html)
21/// - [`BlockProposalsLimitVerifier`](./struct.BlockProposalsLimitVerifier.html)
22/// - [`DuplicateVerifier`](./struct.DuplicateVerifier.html)
23/// - [`MerkleRootVerifier`](./struct.MerkleRootVerifier.html)
24#[derive(Clone)]
25pub struct BlockVerifier<'a> {
26    consensus: &'a Consensus,
27}
28
29impl<'a> BlockVerifier<'a> {
30    /// Constructs a BlockVerifier
31    pub fn new(consensus: &'a Consensus) -> Self {
32        BlockVerifier { consensus }
33    }
34}
35
36impl<'a> Verifier for BlockVerifier<'a> {
37    type Target = BlockView;
38
39    fn verify(&self, target: &BlockView) -> Result<(), Error> {
40        let max_block_proposals_limit = self.consensus.max_block_proposals_limit();
41        let max_block_bytes = self.consensus.max_block_bytes();
42        BlockProposalsLimitVerifier::new(max_block_proposals_limit).verify(target)?;
43        BlockBytesVerifier::new(max_block_bytes).verify(target)?;
44        CellbaseVerifier::new().verify(target)?;
45        DuplicateVerifier::new().verify(target)?;
46        MerkleRootVerifier::new().verify(target)
47    }
48}
49
50/// Cellbase verifier
51///
52/// First transaction must be cellbase, the rest must not be.
53/// Cellbase outputs/outputs_data len must le 1, and outputs len must equal to outputs_data len.
54/// Cellbase output data must be empty
55/// Cellbase output type_ must be empty
56/// Cellbase has only one dummy input. The input's `since` field must be equal to the block number.
57#[derive(Clone)]
58pub struct CellbaseVerifier {}
59
60impl CellbaseVerifier {
61    /// Constructs a CellbaseVerifier
62    pub fn new() -> Self {
63        CellbaseVerifier {}
64    }
65
66    pub fn verify(&self, block: &BlockView) -> Result<(), Error> {
67        if block.is_genesis() {
68            return Ok(());
69        }
70
71        let cellbase_len = block
72            .transactions()
73            .iter()
74            .filter(|tx| tx.is_cellbase())
75            .count();
76
77        // check cellbase count, block must contain ONLY one cellbase
78        if cellbase_len != 1 {
79            return Err((CellbaseError::InvalidQuantity).into());
80        }
81
82        let cellbase_transaction = &block.transactions()[0];
83
84        if !cellbase_transaction.is_cellbase() {
85            return Err((CellbaseError::InvalidPosition).into());
86        }
87
88        // cellbase outputs/outputs_data len must le 1, and outputs len must equal to outputs_data len
89        if cellbase_transaction.outputs().len() > 1
90            || cellbase_transaction.outputs_data().len() > 1
91            || cellbase_transaction.outputs().len() != cellbase_transaction.outputs_data().len()
92        {
93            return Err((CellbaseError::InvalidOutputQuantity).into());
94        }
95
96        // cellbase output data must be empty
97        if !cellbase_transaction
98            .outputs_data()
99            .get(0)
100            .map(|data| data.is_empty())
101            .unwrap_or(true)
102        {
103            return Err((CellbaseError::InvalidOutputData).into());
104        }
105
106        if cellbase_transaction
107            .witnesses()
108            .get(0)
109            .and_then(|witness| {
110                CellbaseWitness::from_slice(&witness.raw_data())
111                    .ok()
112                    .and_then(|cellbase_witness| {
113                        ScriptHashType::try_from(cellbase_witness.lock().hash_type())
114                            .ok()
115                            .and_then(|hash_type| {
116                                let val: u8 = hash_type.into();
117                                ENABLED_SCRIPT_HASH_TYPE.contains(&val).then_some(())
118                            })
119                    })
120            })
121            .is_none()
122        {
123            return Err((CellbaseError::InvalidWitness).into());
124        }
125
126        // cellbase output type_ must be empty
127        if cellbase_transaction
128            .outputs()
129            .into_iter()
130            .any(|output| output.type_().is_some())
131        {
132            return Err((CellbaseError::InvalidTypeScript).into());
133        }
134
135        for output in cellbase_transaction.outputs() {
136            if let Ok(hash_type) = TryInto::<ScriptHashType>::try_into(output.lock().hash_type()) {
137                let val: u8 = hash_type.into();
138                if !ENABLED_SCRIPT_HASH_TYPE.contains(&val) {
139                    return Err((CellbaseError::InvalidOutputLock).into());
140                }
141            } else {
142                return Err((CellbaseError::InvalidOutputLock).into());
143            }
144        }
145
146        let cellbase_input = &cellbase_transaction
147            .inputs()
148            .get(0)
149            .expect("cellbase should have input");
150        if cellbase_input != &CellInput::new_cellbase_input(block.header().number()) {
151            return Err((CellbaseError::InvalidInput).into());
152        }
153
154        Ok(())
155    }
156}
157
158/// DuplicateVerifier
159///
160/// Verifying that a block does not contain any duplicate transactions or
161/// proposals.
162#[derive(Clone)]
163pub struct DuplicateVerifier {}
164
165impl DuplicateVerifier {
166    pub fn new() -> Self {
167        DuplicateVerifier {}
168    }
169
170    pub fn verify(&self, block: &BlockView) -> Result<(), Error> {
171        let mut seen = HashSet::with_capacity(block.transactions().len());
172        if !block.transactions().iter().all(|tx| seen.insert(tx.hash())) {
173            return Err((BlockErrorKind::CommitTransactionDuplicate).into());
174        }
175
176        let mut seen = HashSet::with_capacity(block.data().proposals().len());
177        if !block
178            .data()
179            .proposals()
180            .into_iter()
181            .all(|id| seen.insert(id))
182        {
183            return Err((BlockErrorKind::ProposalTransactionDuplicate).into());
184        }
185        Ok(())
186    }
187}
188
189/// MerkleRootVerifier
190///
191/// Check the merkle root
192#[derive(Clone, Default)]
193pub struct MerkleRootVerifier {}
194
195impl MerkleRootVerifier {
196    pub fn new() -> Self {
197        MerkleRootVerifier::default()
198    }
199
200    pub fn verify(&self, block: &BlockView) -> Result<(), Error> {
201        if block.transactions_root() != block.calc_transactions_root() {
202            return Err(BlockErrorKind::TransactionsRoot.into());
203        }
204
205        if block.proposals_hash() != block.calc_proposals_hash() {
206            return Err(BlockErrorKind::ProposalTransactionsHash.into());
207        }
208
209        Ok(())
210    }
211}
212
213/// BlockProposalsLimitVerifier.
214///
215/// Check block proposal limit.
216#[derive(Clone)]
217pub struct BlockProposalsLimitVerifier {
218    block_proposals_limit: u64,
219}
220
221impl BlockProposalsLimitVerifier {
222    pub fn new(block_proposals_limit: u64) -> Self {
223        BlockProposalsLimitVerifier {
224            block_proposals_limit,
225        }
226    }
227
228    pub fn verify(&self, block: &BlockView) -> Result<(), Error> {
229        let proposals_len = block.data().proposals().len() as u64;
230        if proposals_len <= self.block_proposals_limit {
231            Ok(())
232        } else {
233            Err(BlockErrorKind::ExceededMaximumProposalsLimit.into())
234        }
235    }
236}
237
238/// BlockBytesVerifier.
239///
240/// Check block size limit.
241#[derive(Clone)]
242pub struct BlockBytesVerifier {
243    block_bytes_limit: u64,
244}
245
246impl BlockBytesVerifier {
247    pub fn new(block_bytes_limit: u64) -> Self {
248        BlockBytesVerifier { block_bytes_limit }
249    }
250
251    pub fn verify(&self, block: &BlockView) -> Result<(), Error> {
252        // Skip bytes limit on genesis block
253        if block.is_genesis() {
254            return Ok(());
255        }
256        let block_bytes = block.data().serialized_size_without_uncle_proposals() as u64;
257        if block_bytes <= self.block_bytes_limit {
258            Ok(())
259        } else {
260            Err(BlockErrorKind::ExceededMaximumBlockBytes.into())
261        }
262    }
263}
264
265/// Context-independent verification checks for block transactions
266///
267/// Basic checks that don't depend on any context
268/// See [`NonContextualTransactionVerifier`](./struct.NonContextualBlockTxsVerifier.html)
269pub struct NonContextualBlockTxsVerifier<'a> {
270    consensus: &'a Consensus,
271}
272
273impl<'a> NonContextualBlockTxsVerifier<'a> {
274    /// Creates a new NonContextualBlockTxsVerifier
275    pub fn new(consensus: &'a Consensus) -> Self {
276        NonContextualBlockTxsVerifier { consensus }
277    }
278
279    /// Perform context-independent verification checks for block transactions
280    pub fn verify(&self, block: &BlockView) -> Result<Vec<()>, Error> {
281        block
282            .transactions()
283            .iter()
284            .map(|tx| NonContextualTransactionVerifier::new(tx, self.consensus).verify())
285            .collect()
286    }
287}