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