Remove unnecessary Arcs in verifier.rs
[rapid-gossip-sync-server] / src / verifier.rs
1 use std::convert::TryInto;
2
3 use bitcoin::{BlockHash, TxOut};
4 use bitcoin::blockdata::block::Block;
5 use bitcoin::hashes::Hash;
6 use lightning::chain;
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;
11
12 use crate::config;
13
14 pub(crate) struct ChainVerifier {
15         rest_client: RestClient,
16 }
17
18 struct RestBinaryResponse(Vec<u8>);
19
20 impl ChainVerifier {
21         pub(crate) fn new() -> Self {
22                 ChainVerifier {
23                         rest_client: RestClient::new(config::bitcoin_rest_endpoint()).unwrap(),
24                 }
25         }
26
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
35                         })?.0;
36                         let block_hash = BlockHash::from_slice(&block_hash).unwrap();
37
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
42                         })?;
43                         Ok(block)
44                 }) })
45         }
46 }
47
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;
53
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
58                 })?;
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
62                 })?;
63                 Ok(output.clone())
64         }
65 }
66
67 impl TryInto<RestBinaryResponse> for BinaryResponse {
68         type Error = std::io::Error;
69
70         fn try_into(self) -> Result<RestBinaryResponse, Self::Error> {
71                 Ok(RestBinaryResponse(self.0))
72         }
73 }