ckb_verification/
block_verifier.rs

1use 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/// Block verifier that are independent of context.
15///
16/// Contains:
17/// - [`CellbaseVerifier`](./struct.CellbaseVerifier.html)
18/// - [`BlockBytesVerifier`](./struct.BlockBytesVerifier.html)
19/// - [`BlockExtensionVerifier`](./struct.BlockExtensionVerifier.html)
20/// - [`BlockProposalsLimitVerifier`](./struct.BlockProposalsLimitVerifier.html)
21/// - [`DuplicateVerifier`](./struct.DuplicateVerifier.html)
22/// - [`MerkleRootVerifier`](./struct.MerkleRootVerifier.html)
23#[derive(Clone)]
24pub struct BlockVerifier<'a> {
25    consensus: &'a Consensus,
26}
27
28impl<'a> BlockVerifier<'a> {
29    /// Constructs a BlockVerifier
30    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/// Cellbase verifier
50///
51/// First transaction must be cellbase, the rest must not be.
52/// Cellbase outputs/outputs_data len must le 1, and outputs len must equal to outputs_data len.
53/// Cellbase output data must be empty
54/// Cellbase output type_ must be empty
55/// Cellbase has only one dummy input. The input's `since` field must be equal to the block number.
56#[derive(Clone)]
57pub struct CellbaseVerifier {}
58
59impl CellbaseVerifier {
60    /// Constructs a CellbaseVerifier
61    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        // check cellbase count, block must contain ONLY one cellbase
77        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        // cellbase outputs/outputs_data len must le 1, and outputs len must equal to outputs_data len
88        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        // cellbase output data must be empty
96        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        // cellbase output type_ must be empty
121        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/// DuplicateVerifier
142///
143/// Verifying that a block does not contain any duplicate transactions or
144/// proposals.
145#[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/// MerkleRootVerifier
173///
174/// Check the merkle root
175#[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/// BlockProposalsLimitVerifier.
197///
198/// Check block proposal limit.
199#[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/// BlockBytesVerifier.
222///
223/// Check block size limit.
224#[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        // Skip bytes limit on genesis block
236        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
248/// Context-independent verification checks for block transactions
249///
250/// Basic checks that don't depend on any context
251/// See [`NonContextualTransactionVerifier`](./struct.NonContextualBlockTxsVerifier.html)
252pub struct NonContextualBlockTxsVerifier<'a> {
253    consensus: &'a Consensus,
254}
255
256impl<'a> NonContextualBlockTxsVerifier<'a> {
257    /// Creates a new NonContextualBlockTxsVerifier
258    pub fn new(consensus: &'a Consensus) -> Self {
259        NonContextualBlockTxsVerifier { consensus }
260    }
261
262    /// Perform context-independent verification checks for block transactions
263    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}