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.
5 use crate::{AsyncBlockSourceResult, BlockData, BlockSource};
7 use bitcoin::blockdata::transaction::{TxOut, OutPoint};
8 use bitcoin::hash_types::BlockHash;
10 use lightning::sign::NodeSigner;
12 use lightning::ln::peer_handler::{CustomMessageHandler, PeerManager, SocketDescriptor};
13 use lightning::ln::msgs::{ChannelMessageHandler, OnionMessageHandler};
15 use lightning::routing::gossip::{NetworkGraph, P2PGossipSync};
16 use lightning::routing::utxo::{UtxoFuture, UtxoLookup, UtxoResult, UtxoLookupError};
18 use lightning::util::logger::Logger;
21 use std::future::Future;
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).
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.
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.
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>;
40 /// Returns true if the given output has *not* been spent, i.e. is a member of the current UTXO
42 fn is_output_unspent<'a>(&'a self, outpoint: OutPoint) -> AsyncBlockSourceResult<'a, bool>;
45 /// A generic trait which is able to spawn futures in the background.
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.
52 /// This method MUST NOT block on the given future immediately.
53 fn spawn<T: Future<Output = ()> + Send + 'static>(&self, future: T);
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) {
66 /// A struct which wraps a [`UtxoSource`] and a few LDK objects and implements the LDK
67 /// [`UtxoLookup`] trait.
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
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,
83 Blocks::Target: UtxoSource,
85 CM::Target: ChannelMessageHandler,
86 OM::Target: OnionMessageHandler,
87 CMH::Target: CustomMessageHandler,
88 NS::Target: NodeSigner,
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>>,
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,
107 CM::Target: ChannelMessageHandler,
108 OM::Target: OnionMessageHandler,
109 CMH::Target: CustomMessageHandler,
110 NS::Target: NodeSigner,
112 /// Constructs a new [`GossipVerifier`].
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 }
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;
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,
133 if transaction_index as usize >= block.txdata.len() {
134 return Err(UtxoLookupError::UnknownTx);
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);
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))
146 Err(UtxoLookupError::UnknownTx)
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,
162 CM::Target: ChannelMessageHandler,
163 OM::Target: OnionMessageHandler,
164 CMH::Target: CustomMessageHandler,
165 NS::Target: NodeSigner,
168 fn deref(&self) -> &Self { self }
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,
183 CM::Target: ChannelMessageHandler,
184 OM::Target: OnionMessageHandler,
185 CMH::Target: CustomMessageHandler,
186 NS::Target: NodeSigner,
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);
199 UtxoResult::Async(res)