1 use std::convert::TryInto;
4 use bitcoin::{BlockHash, TxOut};
5 use bitcoin::blockdata::block::Block;
6 use bitcoin::hashes::Hash;
8 use lightning::chain::AccessError;
9 use lightning_block_sync::BlockSource;
10 use lightning_block_sync::http::BinaryResponse;
11 use lightning_block_sync::rest::RestClient;
15 pub(crate) struct ChainVerifier {
16 rest_client: Arc<RestClient>,
19 struct RestBinaryResponse(Vec<u8>);
22 pub(crate) fn new() -> Self {
23 let rest_client = RestClient::new(config::bitcoin_rest_endpoint()).unwrap();
25 rest_client: Arc::new(rest_client),
29 fn retrieve_block(&self, block_height: u32) -> Result<Block, AccessError> {
30 let rest_client = self.rest_client.clone();
31 tokio::task::block_in_place(move || { tokio::runtime::Handle::current().block_on(async move {
32 let block_hash_result = rest_client.request_resource::<BinaryResponse, RestBinaryResponse>(&format!("blockhashbyheight/{}.bin", block_height)).await;
33 let block_hash: Vec<u8> = block_hash_result.map_err(|error| {
34 eprintln!("Could't find block hash at height {}: {}", block_height, error.to_string());
35 AccessError::UnknownChain
37 let block_hash = BlockHash::from_slice(&block_hash).unwrap();
39 let block_result = rest_client.get_block(&block_hash).await;
40 let block = block_result.map_err(|error| {
41 eprintln!("Couldn't retrieve block {}: {:?} ({})", block_height, error, block_hash);
42 AccessError::UnknownChain
49 impl chain::Access for ChainVerifier {
50 fn get_utxo(&self, _genesis_hash: &BlockHash, short_channel_id: u64) -> Result<TxOut, AccessError> {
51 let block_height = (short_channel_id >> 5 * 8) as u32; // block height is most significant three bytes
52 let transaction_index = ((short_channel_id >> 2 * 8) & 0xffffff) as u32;
53 let output_index = (short_channel_id & 0xffff) as u16;
55 let block = self.retrieve_block(block_height)?;
56 let transaction = block.txdata.get(transaction_index as usize).ok_or_else(|| {
57 eprintln!("Transaction index {} out of bounds in block {} ({})", transaction_index, block_height, block.block_hash().to_string());
58 AccessError::UnknownTx
60 let output = transaction.output.get(output_index as usize).ok_or_else(|| {
61 eprintln!("Output index {} out of bounds in transaction {}", output_index, transaction.txid().to_string());
62 AccessError::UnknownTx
68 impl TryInto<RestBinaryResponse> for BinaryResponse {
69 type Error = std::io::Error;
71 fn try_into(self) -> Result<RestBinaryResponse, Self::Error> {
72 Ok(RestBinaryResponse(self.0))