1 use crate::{AsyncBlockSourceResult, BlockHeaderData, BlockSourceError, BlockSourceResult};
3 use bitcoin::blockdata::block::Block;
4 use bitcoin::hash_types::BlockHash;
5 use bitcoin::network::constants::Network;
7 /// The `Poll` trait defines behavior for polling block sources for a chain tip and retrieving
8 /// related chain data. It serves as an adapter for `BlockSource`.
10 /// Returns a chain tip in terms of its relationship to the provided chain tip.
11 fn poll_chain_tip<'a>(&'a mut self, best_known_chain_tip: ValidatedBlockHeader) ->
12 AsyncBlockSourceResult<'a, ChainTip>;
14 /// Returns the header that preceded the given header in the chain.
15 fn look_up_previous_header<'a>(&'a mut self, header: &'a ValidatedBlockHeader) ->
16 AsyncBlockSourceResult<'a, ValidatedBlockHeader>;
18 /// Returns the block associated with the given header.
19 fn fetch_block<'a>(&'a mut self, header: &'a ValidatedBlockHeader) ->
20 AsyncBlockSourceResult<'a, ValidatedBlock>;
23 /// A chain tip relative to another chain tip in terms of block hash and chainwork.
24 #[derive(Clone, Debug, PartialEq)]
26 /// A chain tip with the same hash as another chain's tip.
29 /// A chain tip with more chainwork than another chain's tip.
30 Better(ValidatedBlockHeader),
32 /// A chain tip with less or equal chainwork than another chain's tip. In either case, the
33 /// hashes of each tip will be different.
34 Worse(ValidatedBlockHeader),
37 /// The `Validate` trait defines behavior for validating chain data.
39 /// The validated data wrapper which can be dereferenced to obtain the validated data.
40 type T: std::ops::Deref<Target = Self>;
42 /// Validates the chain data against the given block hash and any criteria needed to ensure that
43 /// it is internally consistent.
44 fn validate(self, block_hash: BlockHash) -> BlockSourceResult<Self::T>;
47 impl Validate for BlockHeaderData {
48 type T = ValidatedBlockHeader;
50 fn validate(self, block_hash: BlockHash) -> BlockSourceResult<Self::T> {
52 .validate_pow(&self.header.target())
53 .or_else(|e| Err(BlockSourceError::persistent(e)))?;
55 if self.header.block_hash() != block_hash {
56 return Err(BlockSourceError::persistent("invalid block hash"));
59 Ok(ValidatedBlockHeader { block_hash, inner: self })
63 impl Validate for Block {
64 type T = ValidatedBlock;
66 fn validate(self, block_hash: BlockHash) -> BlockSourceResult<Self::T> {
68 .validate_pow(&self.header.target())
69 .or_else(|e| Err(BlockSourceError::persistent(e)))?;
71 if self.block_hash() != block_hash {
72 return Err(BlockSourceError::persistent("invalid block hash"));
75 if !self.check_merkle_root() {
76 return Err(BlockSourceError::persistent("invalid merkle root"));
79 if !self.check_witness_commitment() {
80 return Err(BlockSourceError::persistent("invalid witness commitment"));
83 Ok(ValidatedBlock { block_hash, inner: self })
87 /// A block header with validated proof of work and corresponding block hash.
88 #[derive(Clone, Copy, Debug, PartialEq)]
89 pub struct ValidatedBlockHeader {
90 block_hash: BlockHash,
91 inner: BlockHeaderData,
94 impl std::ops::Deref for ValidatedBlockHeader {
95 type Target = BlockHeaderData;
97 fn deref(&self) -> &Self::Target {
102 impl ValidatedBlockHeader {
103 /// Checks that the header correctly builds on previous_header: the claimed work differential
104 /// matches the actual PoW and the difficulty transition is possible, i.e., within 4x.
105 fn check_builds_on(&self, previous_header: &ValidatedBlockHeader, network: Network) -> BlockSourceResult<()> {
106 if self.header.prev_blockhash != previous_header.block_hash {
107 return Err(BlockSourceError::persistent("invalid previous block hash"));
110 if self.height != previous_header.height + 1 {
111 return Err(BlockSourceError::persistent("invalid block height"));
114 let work = self.header.work();
115 if self.chainwork != previous_header.chainwork + work {
116 return Err(BlockSourceError::persistent("invalid chainwork"));
119 if let Network::Bitcoin = network {
120 if self.height % 2016 == 0 {
121 let previous_work = previous_header.header.work();
122 if work > (previous_work << 2) || work < (previous_work >> 2) {
123 return Err(BlockSourceError::persistent("invalid difficulty transition"))
125 } else if self.header.bits != previous_header.header.bits {
126 return Err(BlockSourceError::persistent("invalid difficulty"))
134 /// A block with validated data against its transaction list and corresponding block hash.
135 pub struct ValidatedBlock {
136 block_hash: BlockHash,
140 impl std::ops::Deref for ValidatedBlock {
143 fn deref(&self) -> &Self::Target {