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