1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
use crate::chain_params::ChainParams;
use crate::verification::HeaderVerifier;
use sc_client_api::{AuxStore, HeaderBackend};
use sc_consensus::{BlockImportParams, Verifier};
use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
use sp_runtime::SaturatedConversion;
use std::sync::Arc;
use subcoin_primitives::{extract_bitcoin_block_hash, extract_bitcoin_block_header};

/// Verifier used by the Substrate import queue.
///
/// Verifies the blocks received from the Substrate networking.
pub struct SubstrateImportQueueVerifier<Block, Client> {
    client: Arc<Client>,
    btc_header_verifier: HeaderVerifier<Block, Client>,
}

impl<Block, Client> SubstrateImportQueueVerifier<Block, Client> {
    /// Constructs a new instance of [`SubstrateImportQueueVerifier`].
    pub fn new(client: Arc<Client>, network: bitcoin::Network) -> Self {
        Self {
            client: client.clone(),
            btc_header_verifier: HeaderVerifier::new(client, ChainParams::new(network)),
        }
    }
}

#[async_trait::async_trait]
impl<Block, Client> Verifier<Block> for SubstrateImportQueueVerifier<Block, Client>
where
    Block: BlockT,
    Client: HeaderBackend<Block> + AuxStore,
{
    async fn verify(
        &self,
        mut block_import_params: BlockImportParams<Block>,
    ) -> Result<BlockImportParams<Block>, String> {
        let substrate_header = &block_import_params.header;

        let btc_header = extract_bitcoin_block_header::<Block>(substrate_header)
            .map_err(|err| format!("Failed to extract bitcoin header: {err:?}"))?;

        self.btc_header_verifier
            .verify(&btc_header)
            .map_err(|err| format!("Invalid bitcoin header: {err:?}"))?;

        let (chain_work, fork_choice) = crate::block_import::calculate_chain_work_and_fork_choice(
            &self.client,
            &btc_header,
            (*substrate_header.number()).saturated_into::<u32>(),
        )
        .map_err(|err| format!("Failed to calculate cumulative work: {err:?}"))?;

        block_import_params.fork_choice = Some(fork_choice);

        let bitcoin_block_hash = extract_bitcoin_block_hash::<Block>(substrate_header)
            .map_err(|err| format!("Failed to extract bitcoin block hash: {err:?}"))?;

        let substrate_block_hash = substrate_header.hash();

        crate::block_import::write_aux_storage::<Block>(
            &mut block_import_params,
            bitcoin_block_hash,
            substrate_block_hash,
            chain_work,
        );

        Ok(block_import_params)
    }
}