1use crate::uncles_verifier::{UncleProvider, UnclesVerifier};
2use ckb_async_runtime::Handle;
3use ckb_chain_spec::{
4 consensus::{Consensus, ConsensusProvider},
5 versionbits::VersionbitsIndexer,
6};
7use ckb_dao::DaoCalculator;
8use ckb_dao_utils::DaoError;
9use ckb_error::{Error, InternalErrorKind};
10use ckb_logger::error_target;
11use ckb_merkle_mountain_range::MMRStore;
12use ckb_reward_calculator::RewardCalculator;
13use ckb_store::{ChainStore, data_loader_wrapper::AsDataLoader};
14use ckb_traits::HeaderProvider;
15use ckb_types::{
16 core::error::OutPointError,
17 core::{
18 BlockReward, BlockView, Capacity, Cycle, EpochExt, HeaderView, TransactionView,
19 cell::{HeaderChecker, ResolvedTransaction},
20 },
21 packed::{Byte32, CellOutput, HeaderDigest, Script},
22 prelude::*,
23 utilities::merkle_mountain_range::ChainRootMMR,
24};
25use ckb_verification::cache::{
26 TxVerificationCache, {CacheEntry, Completed},
27};
28use ckb_verification::{
29 BlockErrorKind, CellbaseError, CommitError, ContextualTransactionVerifier,
30 DaoScriptSizeVerifier, TimeRelativeTransactionVerifier, UnknownParentError,
31};
32use ckb_verification::{BlockTransactionsError, EpochError, TxVerifyEnv};
33use ckb_verification_traits::Switch;
34use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator};
35use std::collections::{HashMap, HashSet};
36use std::sync::Arc;
37use tokio::sync::{RwLock, oneshot};
38
39pub struct VerifyContext<CS> {
41 pub(crate) store: Arc<CS>,
42 pub(crate) consensus: Arc<Consensus>,
43}
44
45impl<CS> Clone for VerifyContext<CS> {
46 fn clone(&self) -> Self {
47 VerifyContext {
48 store: Arc::clone(&self.store),
49 consensus: Arc::clone(&self.consensus),
50 }
51 }
52}
53
54impl<CS: ChainStore + VersionbitsIndexer> VerifyContext<CS> {
55 pub fn new(store: Arc<CS>, consensus: Arc<Consensus>) -> Self {
57 VerifyContext { store, consensus }
58 }
59
60 fn finalize_block_reward(
61 &self,
62 parent: &HeaderView,
63 ) -> Result<(Script, BlockReward), DaoError> {
64 RewardCalculator::new(&self.consensus, self.store.as_ref()).block_reward_to_finalize(parent)
65 }
66}
67
68impl<CS: ChainStore> HeaderProvider for VerifyContext<CS> {
69 fn get_header(&self, hash: &Byte32) -> Option<HeaderView> {
70 self.store.get_block_header(hash)
71 }
72}
73
74impl<CS: ChainStore> HeaderChecker for VerifyContext<CS> {
75 fn check_valid(&self, block_hash: &Byte32) -> Result<(), OutPointError> {
76 if !self.store.is_main_chain(block_hash) {
77 return Err(OutPointError::InvalidHeader(block_hash.clone()));
78 }
79 self.store
80 .get_block_header(block_hash)
81 .ok_or_else(|| OutPointError::InvalidHeader(block_hash.clone()))?;
82 Ok(())
83 }
84}
85
86impl<CS: ChainStore> ConsensusProvider for VerifyContext<CS> {
87 fn get_consensus(&self) -> &Consensus {
88 &self.consensus
89 }
90}
91
92pub struct UncleVerifierContext<'a, 'b, CS> {
93 epoch: &'b EpochExt,
94 context: &'a VerifyContext<CS>,
95}
96
97impl<'a, 'b, CS: ChainStore> UncleVerifierContext<'a, 'b, CS> {
98 pub(crate) fn new(context: &'a VerifyContext<CS>, epoch: &'b EpochExt) -> Self {
99 UncleVerifierContext { epoch, context }
100 }
101}
102
103impl<'a, 'b, CS: ChainStore> UncleProvider for UncleVerifierContext<'a, 'b, CS> {
104 fn double_inclusion(&self, hash: &Byte32) -> bool {
105 self.context.store.get_block_number(hash).is_some() || self.context.store.is_uncle(hash)
106 }
107
108 fn descendant(&self, uncle: &HeaderView) -> bool {
109 let parent_hash = uncle.data().raw().parent_hash();
110 let uncle_number = uncle.number();
111 let store = &self.context.store;
112
113 if store.get_block_number(&parent_hash).is_some() {
114 return store
115 .get_block_header(&parent_hash)
116 .map(|parent| (parent.number() + 1) == uncle_number)
117 .unwrap_or(false);
118 }
119
120 if let Some(uncle_parent) = store.get_uncle_header(&parent_hash) {
121 return (uncle_parent.number() + 1) == uncle_number;
122 }
123
124 false
125 }
126
127 fn epoch(&self) -> &EpochExt {
128 self.epoch
129 }
130
131 fn consensus(&self) -> &Consensus {
132 &self.context.consensus
133 }
134}
135
136pub struct TwoPhaseCommitVerifier<'a, CS> {
137 context: &'a VerifyContext<CS>,
138 block: &'a BlockView,
139}
140
141impl<'a, CS: ChainStore + VersionbitsIndexer> TwoPhaseCommitVerifier<'a, CS> {
142 pub fn new(context: &'a VerifyContext<CS>, block: &'a BlockView) -> Self {
143 TwoPhaseCommitVerifier { context, block }
144 }
145
146 pub fn verify(&self) -> Result<(), Error> {
147 if self.block.is_genesis() {
148 return Ok(());
149 }
150 let block_number = self.block.header().number();
151 let proposal_window = self.context.consensus.tx_proposal_window();
152 let proposal_start = block_number.saturating_sub(proposal_window.farthest());
153 let mut proposal_end = block_number.saturating_sub(proposal_window.closest());
154
155 let mut block_hash = self
156 .context
157 .store
158 .get_block_hash(proposal_end)
159 .ok_or(CommitError::AncestorNotFound)?;
160
161 let mut proposal_txs_ids = HashSet::new();
162
163 while proposal_end >= proposal_start {
164 let header = self
165 .context
166 .store
167 .get_block_header(&block_hash)
168 .ok_or(CommitError::AncestorNotFound)?;
169 if header.is_genesis() {
170 break;
171 }
172
173 if let Some(ids) = self.context.store.get_block_proposal_txs_ids(&block_hash) {
174 proposal_txs_ids.extend(ids);
175 }
176 if let Some(uncles) = self.context.store.get_block_uncles(&block_hash) {
177 uncles
178 .data()
179 .into_iter()
180 .for_each(|uncle| proposal_txs_ids.extend(uncle.proposals()));
181 }
182
183 block_hash = header.data().raw().parent_hash();
184 proposal_end -= 1;
185 }
186
187 let committed_ids: HashSet<_> = self
188 .block
189 .transactions()
190 .iter()
191 .skip(1)
192 .map(TransactionView::proposal_short_id)
193 .collect();
194
195 if committed_ids.difference(&proposal_txs_ids).next().is_some() {
196 error_target!(
197 crate::LOG_TARGET,
198 "BlockView {} {}",
199 self.block.number(),
200 self.block.hash()
201 );
202 error_target!(crate::LOG_TARGET, "proposal_window {:?}", proposal_window);
203 error_target!(crate::LOG_TARGET, "Committed Ids:");
204 for committed_id in committed_ids.iter() {
205 error_target!(crate::LOG_TARGET, " {:?}", committed_id);
206 }
207 error_target!(crate::LOG_TARGET, "Proposal Txs Ids:");
208 for proposal_txs_id in proposal_txs_ids.iter() {
209 error_target!(crate::LOG_TARGET, " {:?}", proposal_txs_id);
210 }
211 return Err((CommitError::Invalid).into());
212 }
213 Ok(())
214 }
215}
216
217pub struct RewardVerifier<'a, 'b, CS> {
218 resolved: &'a [Arc<ResolvedTransaction>],
219 parent: &'b HeaderView,
220 context: &'a VerifyContext<CS>,
221}
222
223impl<'a, 'b, CS: ChainStore + VersionbitsIndexer> RewardVerifier<'a, 'b, CS> {
224 pub fn new(
225 context: &'a VerifyContext<CS>,
226 resolved: &'a [Arc<ResolvedTransaction>],
227 parent: &'b HeaderView,
228 ) -> Self {
229 RewardVerifier {
230 parent,
231 context,
232 resolved,
233 }
234 }
235
236 #[allow(clippy::int_plus_one)]
237 pub fn verify(&self) -> Result<(), Error> {
238 let cellbase = &self.resolved[0];
239 let no_finalization_target =
240 (self.parent.number() + 1) <= self.context.consensus.finalization_delay_length();
241
242 let (target_lock, block_reward) = self.context.finalize_block_reward(self.parent)?;
243 let output = CellOutput::new_builder()
244 .capacity(block_reward.total)
245 .lock(target_lock.clone())
246 .build();
247 let insufficient_reward_to_create_cell = output.is_lack_of_capacity(Capacity::zero())?;
248
249 if no_finalization_target || insufficient_reward_to_create_cell {
250 let ret = if cellbase.transaction.outputs().is_empty() {
251 Ok(())
252 } else {
253 Err((CellbaseError::InvalidRewardTarget).into())
254 };
255 return ret;
256 }
257
258 if !insufficient_reward_to_create_cell {
259 if cellbase.transaction.outputs_capacity()? != block_reward.total {
260 return Err((CellbaseError::InvalidRewardAmount).into());
261 }
262 if cellbase
263 .transaction
264 .outputs()
265 .get(0)
266 .expect("cellbase should have output")
267 .lock()
268 != target_lock
269 {
270 return Err((CellbaseError::InvalidRewardTarget).into());
271 }
272 }
273
274 Ok(())
275 }
276}
277
278struct DaoHeaderVerifier<'a, 'b, 'c, CS> {
279 context: &'a VerifyContext<CS>,
280 resolved: &'a [Arc<ResolvedTransaction>],
281 parent: &'b HeaderView,
282 header: &'c HeaderView,
283}
284
285impl<'a, 'b, 'c, CS: ChainStore + VersionbitsIndexer> DaoHeaderVerifier<'a, 'b, 'c, CS> {
286 pub fn new(
287 context: &'a VerifyContext<CS>,
288 resolved: &'a [Arc<ResolvedTransaction>],
289 parent: &'b HeaderView,
290 header: &'c HeaderView,
291 ) -> Self {
292 DaoHeaderVerifier {
293 context,
294 resolved,
295 parent,
296 header,
297 }
298 }
299
300 pub fn verify(&self) -> Result<(), Error> {
301 let dao = DaoCalculator::new(
302 &self.context.consensus,
303 &self.context.store.borrow_as_data_loader(),
304 )
305 .dao_field(self.resolved.iter().map(AsRef::as_ref), self.parent)
306 .map_err(|e| {
307 error_target!(
308 crate::LOG_TARGET,
309 "Error generating dao data for block {}: {:?}",
310 self.header.hash(),
311 e
312 );
313 e
314 })?;
315
316 if dao != self.header.dao() {
317 return Err((BlockErrorKind::InvalidDAO).into());
318 }
319 Ok(())
320 }
321}
322
323struct BlockTxsVerifier<'a, 'b, CS> {
324 context: VerifyContext<CS>,
325 header: HeaderView,
326 handle: &'a Handle,
327 txs_verify_cache: &'a Arc<RwLock<TxVerificationCache>>,
328 parent: &'b HeaderView,
329}
330
331impl<'a, 'b, CS: ChainStore + VersionbitsIndexer + 'static> BlockTxsVerifier<'a, 'b, CS> {
332 pub fn new(
333 context: VerifyContext<CS>,
334 header: HeaderView,
335 handle: &'a Handle,
336 txs_verify_cache: &'a Arc<RwLock<TxVerificationCache>>,
337 parent: &'b HeaderView,
338 ) -> Self {
339 BlockTxsVerifier {
340 context,
341 header,
342 handle,
343 txs_verify_cache,
344 parent,
345 }
346 }
347
348 fn fetched_cache(&self, rtxs: &'a [Arc<ResolvedTransaction>]) -> HashMap<Byte32, CacheEntry> {
349 let (sender, receiver) = oneshot::channel();
350 let txs_verify_cache = Arc::clone(self.txs_verify_cache);
351 let wtx_hashes: Vec<Byte32> = rtxs
352 .iter()
353 .skip(1)
354 .map(|rtx| rtx.transaction.witness_hash())
355 .collect();
356 self.handle.spawn(async move {
357 let guard = txs_verify_cache.read().await;
358 let ret = wtx_hashes
359 .into_iter()
360 .filter_map(|wtx_hash| {
361 guard
362 .peek(&wtx_hash)
363 .cloned()
364 .map(|value| (wtx_hash, value))
365 })
366 .collect();
367
368 if let Err(e) = sender.send(ret) {
369 error_target!(crate::LOG_TARGET, "TxsVerifier fetched_cache error {:?}", e);
370 };
371 });
372 self.handle
373 .block_on(receiver)
374 .expect("fetched cache no exception")
375 }
376
377 fn update_cache(&self, ret: Vec<(Byte32, Completed)>) {
378 let txs_verify_cache = Arc::clone(self.txs_verify_cache);
379 self.handle.spawn(async move {
380 let mut guard = txs_verify_cache.write().await;
381 for (k, v) in ret {
382 guard.put(k, v);
383 }
384 });
385 }
386
387 pub fn verify(
388 &self,
389 resolved: &'a [Arc<ResolvedTransaction>],
390 skip_script_verify: bool,
391 ) -> Result<(Cycle, Vec<Completed>), Error> {
392 let fetched_cache = if resolved.len() > 1 {
395 self.fetched_cache(resolved)
396 } else {
397 HashMap::new()
398 };
399
400 let tx_env = Arc::new(TxVerifyEnv::new_commit(&self.header));
401
402 let ret = resolved
404 .par_iter()
405 .enumerate()
406 .map(|(index, tx)| {
407 let wtx_hash = tx.transaction.witness_hash();
408
409 if let Some(completed) = fetched_cache.get(&wtx_hash) {
410 TimeRelativeTransactionVerifier::new(
411 Arc::clone(tx),
412 Arc::clone(&self.context.consensus),
413 self.context.store.as_data_loader(),
414 Arc::clone(&tx_env),
415 )
416 .verify()
417 .map_err(|error| {
418 BlockTransactionsError {
419 index: index as u32,
420 error,
421 }
422 .into()
423 })
424 .map(|_| (wtx_hash, *completed))
425 } else {
426 ContextualTransactionVerifier::new(
427 Arc::clone(tx),
428 Arc::clone(&self.context.consensus),
429 self.context.store.as_data_loader(),
430 Arc::clone(&tx_env),
431 )
432 .verify(
433 self.context.consensus.max_block_cycles(),
434 skip_script_verify,
435 )
436 .map_err(|error| {
437 BlockTransactionsError {
438 index: index as u32,
439 error,
440 }
441 .into()
442 })
443 .map(|completed| (wtx_hash, completed))
444 }.and_then(|result| {
445 if self.context.consensus.rfc0044_active(self.parent.epoch().number()) {
446 DaoScriptSizeVerifier::new(
447 Arc::clone(tx),
448 Arc::clone(&self.context.consensus),
449 self.context.store.as_data_loader(),
450 ).verify()?;
451 }
452 Ok(result)
453 })
454 })
455 .skip(1) .collect::<Result<Vec<(Byte32, Completed)>, Error>>()?;
457
458 let sum: Cycle = ret.iter().map(|(_, cache_entry)| cache_entry.cycles).sum();
459 let cache_entires = ret
460 .iter()
461 .map(|(_, completed)| completed)
462 .cloned()
463 .collect();
464 if !ret.is_empty() {
465 self.update_cache(ret);
466 }
467
468 if sum > self.context.consensus.max_block_cycles() {
469 Err(BlockErrorKind::ExceededMaximumCycles.into())
470 } else {
471 Ok((sum, cache_entires))
472 }
473 }
474}
475pub struct EpochVerifier<'a> {
479 epoch: &'a EpochExt,
480 block: &'a BlockView,
481}
482
483impl<'a> EpochVerifier<'a> {
484 pub fn new(epoch: &'a EpochExt, block: &'a BlockView) -> Self {
485 EpochVerifier { epoch, block }
486 }
487
488 pub fn verify(&self) -> Result<(), Error> {
489 let header = self.block.header();
490 let actual_epoch_with_fraction = header.epoch();
491 let block_number = header.number();
492 let epoch_with_fraction = self.epoch.number_with_fraction(block_number);
493 if actual_epoch_with_fraction != epoch_with_fraction {
494 return Err(EpochError::NumberMismatch {
495 expected: epoch_with_fraction.full_value(),
496 actual: actual_epoch_with_fraction.full_value(),
497 }
498 .into());
499 }
500 let actual_compact_target = header.compact_target();
501 if self.epoch.compact_target() != actual_compact_target {
502 return Err(EpochError::TargetMismatch {
503 expected: self.epoch.compact_target(),
504 actual: actual_compact_target,
505 }
506 .into());
507 }
508 Ok(())
509 }
510}
511
512#[derive(Clone)]
516pub struct BlockExtensionVerifier<'a, 'b, CS, MS> {
517 context: &'a VerifyContext<CS>,
518 chain_root_mmr: &'a ChainRootMMR<MS>,
519 parent: &'b HeaderView,
520}
521
522impl<'a, 'b, CS: ChainStore + VersionbitsIndexer, MS: MMRStore<HeaderDigest>>
523 BlockExtensionVerifier<'a, 'b, CS, MS>
524{
525 pub fn new(
526 context: &'a VerifyContext<CS>,
527 chain_root_mmr: &'a ChainRootMMR<MS>,
528 parent: &'b HeaderView,
529 ) -> Self {
530 BlockExtensionVerifier {
531 context,
532 chain_root_mmr,
533 parent,
534 }
535 }
536
537 pub fn verify(&self, block: &BlockView) -> Result<(), Error> {
538 let extra_fields_count = block.data().count_extra_fields();
539
540 let mmr_active = self
541 .context
542 .consensus
543 .rfc0044_active(self.parent.epoch().number());
544 match extra_fields_count {
545 0 => {
546 if mmr_active {
547 return Err(BlockErrorKind::NoBlockExtension.into());
548 }
549 }
550 1 => {
551 let extension = if let Some(data) = block.extension() {
552 data
553 } else {
554 return Err(BlockErrorKind::UnknownFields.into());
555 };
556 if extension.is_empty() {
557 return Err(BlockErrorKind::EmptyBlockExtension.into());
558 }
559 if extension.len() > 96 {
560 return Err(BlockErrorKind::ExceededMaximumBlockExtensionBytes.into());
561 }
562 if mmr_active {
563 if extension.len() < 32 {
564 return Err(BlockErrorKind::InvalidBlockExtension.into());
565 }
566
567 let chain_root = self
568 .chain_root_mmr
569 .get_root()
570 .map_err(|e| InternalErrorKind::MMR.other(e))?;
571 let actual_root_hash = chain_root.calc_mmr_hash();
572 let expected_root_hash =
573 Byte32::new_unchecked(extension.raw_data().slice(..32));
574 if actual_root_hash != expected_root_hash {
575 return Err(BlockErrorKind::InvalidChainRoot.into());
576 }
577 }
578 }
579 _ => {
580 return Err(BlockErrorKind::UnknownFields.into());
581 }
582 }
583
584 let actual_extra_hash = block.calc_extra_hash().extra_hash();
585 if actual_extra_hash != block.extra_hash() {
586 return Err(BlockErrorKind::InvalidExtraHash.into());
587 }
588 Ok(())
589 }
590}
591
592pub struct ContextualBlockVerifier<'a, CS, MS> {
602 context: VerifyContext<CS>,
603 switch: Switch,
604 handle: &'a Handle,
605 txs_verify_cache: Arc<RwLock<TxVerificationCache>>,
606 chain_root_mmr: &'a ChainRootMMR<MS>,
607}
608
609impl<'a, CS: ChainStore + VersionbitsIndexer + 'static, MS: MMRStore<HeaderDigest>>
610 ContextualBlockVerifier<'a, CS, MS>
611{
612 pub fn new(
614 context: VerifyContext<CS>,
615 handle: &'a Handle,
616 switch: Switch,
617 txs_verify_cache: Arc<RwLock<TxVerificationCache>>,
618 chain_root_mmr: &'a ChainRootMMR<MS>,
619 ) -> Self {
620 ContextualBlockVerifier {
621 context,
622 handle,
623 switch,
624 txs_verify_cache,
625 chain_root_mmr,
626 }
627 }
628
629 pub fn verify(
631 &'a self,
632 resolved: &'a [Arc<ResolvedTransaction>],
633 block: &'a BlockView,
634 ) -> Result<(Cycle, Vec<Completed>), Error> {
635 let parent_hash = block.data().header().raw().parent_hash();
636 let header = block.header();
637 let parent = self
638 .context
639 .store
640 .get_block_header(&parent_hash)
641 .ok_or_else(|| UnknownParentError {
642 parent_hash: parent_hash.clone(),
643 })?;
644
645 let epoch_ext = if block.is_genesis() {
646 self.context.consensus.genesis_epoch_ext().to_owned()
647 } else {
648 self.context
649 .consensus
650 .next_epoch_ext(&parent, &self.context.store.borrow_as_data_loader())
651 .ok_or_else(|| UnknownParentError {
652 parent_hash: parent.hash(),
653 })?
654 .epoch()
655 };
656
657 if !self.switch.disable_epoch() {
658 EpochVerifier::new(&epoch_ext, block).verify()?;
659 }
660
661 if !self.switch.disable_uncles() {
662 let uncle_verifier_context = UncleVerifierContext::new(&self.context, &epoch_ext);
663 UnclesVerifier::new(uncle_verifier_context, block).verify()?;
664 }
665
666 if !self.switch.disable_two_phase_commit() {
667 TwoPhaseCommitVerifier::new(&self.context, block).verify()?;
668 }
669
670 if !self.switch.disable_daoheader() {
671 DaoHeaderVerifier::new(&self.context, resolved, &parent, &block.header()).verify()?;
672 }
673
674 if !self.switch.disable_reward() {
675 RewardVerifier::new(&self.context, resolved, &parent).verify()?;
676 }
677
678 if !self.switch.disable_extension() {
679 BlockExtensionVerifier::new(&self.context, self.chain_root_mmr, &parent)
680 .verify(block)?;
681 }
682
683 let ret = BlockTxsVerifier::new(
684 self.context.clone(),
685 header,
686 self.handle,
687 &self.txs_verify_cache,
688 &parent,
689 )
690 .verify(resolved, self.switch.disable_script())?;
691 Ok(ret)
692 }
693}