]> git.bitcoin.ninja Git - rust-lightning/blob - lightning-block-sync/src/gossip.rs
Implement the `UtxoSource` interface for REST/RPC clients
[rust-lightning] / lightning-block-sync / src / gossip.rs
1 //! When fetching gossip from peers, lightning nodes need to validate that gossip against the
2 //! current UTXO set. This module defines an implementation of the LDK API required to do so
3 //! against a [`BlockSource`] which implements a few additional methods for accessing the UTXO set.
4
5 use crate::{AsyncBlockSourceResult, BlockData, BlockSource};
6
7 use bitcoin::blockdata::transaction::{TxOut, OutPoint};
8 use bitcoin::hash_types::BlockHash;
9
10 use lightning::sign::NodeSigner;
11
12 use lightning::ln::peer_handler::{CustomMessageHandler, PeerManager, SocketDescriptor};
13 use lightning::ln::msgs::{ChannelMessageHandler, OnionMessageHandler};
14
15 use lightning::routing::gossip::{NetworkGraph, P2PGossipSync};
16 use lightning::routing::utxo::{UtxoFuture, UtxoLookup, UtxoResult, UtxoLookupError};
17
18 use lightning::util::logger::Logger;
19
20 use std::sync::Arc;
21 use std::future::Future;
22 use std::ops::Deref;
23
24 /// A trait which extends [`BlockSource`] and can be queried to fetch the block at a given height
25 /// as well as whether a given output is unspent (i.e. a member of the current UTXO set).
26 ///
27 /// Note that while this is implementable for a [`BlockSource`] which returns filtered block data
28 /// (i.e. [`BlockData::HeaderOnly`] for [`BlockSource::get_block`] requests), such an
29 /// implementation will reject all gossip as it is not fully able to verify the UTXOs referenced.
30 ///
31 /// For efficiency, an implementation may consider caching some set of blocks, as many redundant
32 /// calls may be made.
33 pub trait UtxoSource : BlockSource + 'static {
34         /// Fetches the block hash of the block at the given height.
35         ///
36         /// This will, in turn, be passed to to [`BlockSource::get_block`] to fetch the block needed
37         /// for gossip validation.
38         fn get_block_hash_by_height<'a>(&'a self, block_height: u32) -> AsyncBlockSourceResult<'a, BlockHash>;
39
40         /// Returns true if the given output has *not* been spent, i.e. is a member of the current UTXO
41         /// set.
42         fn is_output_unspent<'a>(&'a self, outpoint: OutPoint) -> AsyncBlockSourceResult<'a, bool>;
43 }
44
45 /// A generic trait which is able to spawn futures in the background.
46 ///
47 /// If the `tokio` feature is enabled, this is implemented on `TokioSpawner` struct which
48 /// delegates to `tokio::spawn()`.
49 pub trait FutureSpawner : Send + Sync + 'static {
50         /// Spawns the given future as a background task.
51         ///
52         /// This method MUST NOT block on the given future immediately.
53         fn spawn<T: Future<Output = ()> + Send + 'static>(&self, future: T);
54 }
55
56 #[cfg(feature = "tokio")]
57 /// A trivial [`FutureSpawner`] which delegates to `tokio::spawn`.
58 pub struct TokioSpawner;
59 #[cfg(feature = "tokio")]
60 impl FutureSpawner for TokioSpawner {
61         fn spawn<T: Future<Output = ()> + Send + 'static>(&self, future: T) {
62                 tokio::spawn(future);
63         }
64 }
65
66 /// A struct which wraps a [`UtxoSource`] and a few LDK objects and implements the LDK
67 /// [`UtxoLookup`] trait.
68 ///
69 /// Note that if you're using this against a Bitcoin Core REST or RPC server, you likely wish to
70 /// increase the `rpcworkqueue` setting in Bitcoin Core as LDK attempts to parallelize requests (a
71 /// value of 1024 should more than suffice), and ensure you have sufficient file descriptors
72 /// available on both Bitcoin Core and your LDK application for each request to hold its own
73 /// connection.
74 pub struct GossipVerifier<S: FutureSpawner,
75         Blocks: Deref + Send + Sync + 'static + Clone,
76         L: Deref + Send + Sync + 'static,
77         Descriptor: SocketDescriptor + Send + Sync + 'static,
78         CM: Deref + Send + Sync + 'static,
79         OM: Deref + Send + Sync + 'static,
80         CMH: Deref + Send + Sync + 'static,
81         NS: Deref + Send + Sync + 'static,
82 > where
83         Blocks::Target: UtxoSource,
84         L::Target: Logger,
85         CM::Target: ChannelMessageHandler,
86         OM::Target: OnionMessageHandler,
87         CMH::Target: CustomMessageHandler,
88         NS::Target: NodeSigner,
89 {
90         source: Blocks,
91         peer_manager: Arc<PeerManager<Descriptor, CM, Arc<P2PGossipSync<Arc<NetworkGraph<L>>, Self, L>>, OM, L, CMH, NS>>,
92         gossiper: Arc<P2PGossipSync<Arc<NetworkGraph<L>>, Self, L>>,
93         spawn: S,
94 }
95
96 impl<S: FutureSpawner,
97         Blocks: Deref + Send + Sync + Clone,
98         L: Deref + Send + Sync,
99         Descriptor: SocketDescriptor + Send + Sync,
100         CM: Deref + Send + Sync,
101         OM: Deref + Send + Sync,
102         CMH: Deref + Send + Sync,
103         NS: Deref + Send + Sync,
104 > GossipVerifier<S, Blocks, L, Descriptor, CM, OM, CMH, NS> where
105         Blocks::Target: UtxoSource,
106         L::Target: Logger,
107         CM::Target: ChannelMessageHandler,
108         OM::Target: OnionMessageHandler,
109         CMH::Target: CustomMessageHandler,
110         NS::Target: NodeSigner,
111 {
112         /// Constructs a new [`GossipVerifier`].
113         ///
114         /// This is expected to be given to a [`P2PGossipSync`] (initially constructed with `None` for
115         /// the UTXO lookup) via [`P2PGossipSync::add_utxo_lookup`].
116         pub fn new(source: Blocks, spawn: S, gossiper: Arc<P2PGossipSync<Arc<NetworkGraph<L>>, Self, L>>, peer_manager: Arc<PeerManager<Descriptor, CM, Arc<P2PGossipSync<Arc<NetworkGraph<L>>, Self, L>>, OM, L, CMH, NS>>) -> Self {
117                 Self { source, spawn, gossiper, peer_manager }
118         }
119
120         async fn retrieve_utxo(source: Blocks, short_channel_id: u64) -> Result<TxOut, UtxoLookupError> {
121                 let block_height = (short_channel_id >> 5 * 8) as u32; // block height is most significant three bytes
122                 let transaction_index = ((short_channel_id >> 2 * 8) & 0xffffff) as u32;
123                 let output_index = (short_channel_id & 0xffff) as u16;
124
125                 let block_hash = source.get_block_hash_by_height(block_height).await
126                         .map_err(|_| UtxoLookupError::UnknownTx)?;
127                 let block_data = source.get_block(&block_hash).await
128                         .map_err(|_| UtxoLookupError::UnknownTx)?;
129                 let mut block = match block_data {
130                         BlockData::HeaderOnly(_) => return Err(UtxoLookupError::UnknownTx),
131                         BlockData::FullBlock(block) => block,
132                 };
133                 if transaction_index as usize >= block.txdata.len() {
134                         return Err(UtxoLookupError::UnknownTx);
135                 }
136                 let mut transaction = block.txdata.swap_remove(transaction_index as usize);
137                 if output_index as usize >= transaction.output.len() {
138                         return Err(UtxoLookupError::UnknownTx);
139                 }
140                 let outpoint_unspent =
141                         source.is_output_unspent(OutPoint::new(transaction.txid(), output_index.into())).await
142                                 .map_err(|_| UtxoLookupError::UnknownTx)?;
143                 if outpoint_unspent {
144                         Ok(transaction.output.swap_remove(output_index as usize))
145                 } else {
146                         Err(UtxoLookupError::UnknownTx)
147                 }
148         }
149 }
150
151 impl<S: FutureSpawner,
152         Blocks: Deref + Send + Sync + Clone,
153         L: Deref + Send + Sync,
154         Descriptor: SocketDescriptor + Send + Sync,
155         CM: Deref + Send + Sync,
156         OM: Deref + Send + Sync,
157         CMH: Deref + Send + Sync,
158         NS: Deref + Send + Sync,
159 > Deref for GossipVerifier<S, Blocks, L, Descriptor, CM, OM, CMH, NS> where
160         Blocks::Target: UtxoSource,
161         L::Target: Logger,
162         CM::Target: ChannelMessageHandler,
163         OM::Target: OnionMessageHandler,
164         CMH::Target: CustomMessageHandler,
165         NS::Target: NodeSigner,
166 {
167         type Target = Self;
168         fn deref(&self) -> &Self { self }
169 }
170
171
172 impl<S: FutureSpawner,
173         Blocks: Deref + Send + Sync + Clone,
174         L: Deref + Send + Sync,
175         Descriptor: SocketDescriptor + Send + Sync,
176         CM: Deref + Send + Sync,
177         OM: Deref + Send + Sync,
178         CMH: Deref + Send + Sync,
179         NS: Deref + Send + Sync,
180 > UtxoLookup for GossipVerifier<S, Blocks, L, Descriptor, CM, OM, CMH, NS> where
181         Blocks::Target: UtxoSource,
182         L::Target: Logger,
183         CM::Target: ChannelMessageHandler,
184         OM::Target: OnionMessageHandler,
185         CMH::Target: CustomMessageHandler,
186         NS::Target: NodeSigner,
187 {
188         fn get_utxo(&self, _genesis_hash: &BlockHash, short_channel_id: u64) -> UtxoResult {
189                 let res = UtxoFuture::new();
190                 let fut = res.clone();
191                 let source = self.source.clone();
192                 let gossiper = Arc::clone(&self.gossiper);
193                 let pm = Arc::clone(&self.peer_manager);
194                 self.spawn.spawn(async move {
195                         let res = Self::retrieve_utxo(source, short_channel_id).await;
196                         fut.resolve(gossiper.network_graph(), &*gossiper, res);
197                         pm.process_events();
198                 });
199                 UtxoResult::Async(res)
200         }
201 }