1 // This file is Copyright its original authors, visible in version control
4 // This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
5 // or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
7 // You may not use this file except in accordance with one or both of these
10 //! This module contains traits for LDK to access UTXOs to check gossip data is correct.
12 //! When lightning nodes gossip channel information, they resist DoS attacks by checking that each
13 //! channel matches a UTXO on-chain, requiring at least some marginal on-chain transacting in
14 //! order to announce a channel. This module handles that checking.
16 use bitcoin::{BlockHash, TxOut};
17 use bitcoin::hashes::hex::ToHex;
19 use crate::ln::chan_utils::make_funding_redeemscript_from_slices;
20 use crate::ln::msgs::{self, LightningError, ErrorAction};
21 use crate::routing::gossip::{NetworkGraph, NodeId, P2PGossipSync};
22 use crate::util::events::MessageSendEvent;
23 use crate::util::logger::{Level, Logger};
24 use crate::util::ser::Writeable;
26 use crate::prelude::*;
28 use alloc::sync::{Arc, Weak};
29 use crate::sync::Mutex;
32 /// An error when accessing the chain via [`UtxoLookup`].
33 #[derive(Clone, Debug)]
34 pub enum UtxoLookupError {
35 /// The requested chain is unknown.
38 /// The requested transaction doesn't exist or hasn't confirmed.
42 /// The result of a [`UtxoLookup::get_utxo`] call. A call may resolve either synchronously,
43 /// returning the `Sync` variant, or asynchronously, returning an [`UtxoFuture`] in the `Async`
46 /// A result which was resolved synchronously. It either includes a [`TxOut`] for the output
47 /// requested or a [`UtxoLookupError`].
48 Sync(Result<TxOut, UtxoLookupError>),
49 /// A result which will be resolved asynchronously. It includes a [`UtxoFuture`], a `clone` of
50 /// which you must keep locally and call [`UtxoFuture::resolve`] on once the lookup completes.
52 /// Note that in order to avoid runaway memory usage, the number of parallel checks is limited,
53 /// but only fairly loosely. Because a pending checks block all message processing, leaving
54 /// checks pending for an extended time may cause DoS of other functions. It is recommended you
55 /// keep a tight timeout on lookups, on the order of a few seconds.
59 /// The `UtxoLookup` trait defines behavior for accessing on-chain UTXOs.
60 pub trait UtxoLookup {
61 /// Returns the transaction output of a funding transaction encoded by [`short_channel_id`].
62 /// Returns an error if `genesis_hash` is for a different chain or if such a transaction output
65 /// [`short_channel_id`]: https://github.com/lightning/bolts/blob/master/07-routing-gossip.md#definition-of-short_channel_id
66 fn get_utxo(&self, genesis_hash: &BlockHash, short_channel_id: u64) -> UtxoResult;
69 enum ChannelAnnouncement {
70 Full(msgs::ChannelAnnouncement),
71 Unsigned(msgs::UnsignedChannelAnnouncement),
73 impl ChannelAnnouncement {
74 fn node_id_1(&self) -> &NodeId {
76 ChannelAnnouncement::Full(msg) => &msg.contents.node_id_1,
77 ChannelAnnouncement::Unsigned(msg) => &msg.node_id_1,
82 enum NodeAnnouncement {
83 Full(msgs::NodeAnnouncement),
84 Unsigned(msgs::UnsignedNodeAnnouncement),
86 impl NodeAnnouncement {
87 fn timestamp(&self) -> u32 {
89 NodeAnnouncement::Full(msg) => msg.contents.timestamp,
90 NodeAnnouncement::Unsigned(msg) => msg.timestamp,
96 Full(msgs::ChannelUpdate),
97 Unsigned(msgs::UnsignedChannelUpdate),
100 fn timestamp(&self) -> u32 {
102 ChannelUpdate::Full(msg) => msg.contents.timestamp,
103 ChannelUpdate::Unsigned(msg) => msg.timestamp,
108 struct UtxoMessages {
109 complete: Option<Result<TxOut, UtxoLookupError>>,
110 channel_announce: Option<ChannelAnnouncement>,
111 latest_node_announce_a: Option<NodeAnnouncement>,
112 latest_node_announce_b: Option<NodeAnnouncement>,
113 latest_channel_update_a: Option<ChannelUpdate>,
114 latest_channel_update_b: Option<ChannelUpdate>,
117 /// Represents a future resolution of a [`UtxoLookup::get_utxo`] query resolving async.
119 /// See [`UtxoResult::Async`] and [`UtxoFuture::resolve`] for more info.
121 pub struct UtxoFuture {
122 state: Arc<Mutex<UtxoMessages>>,
125 /// A trivial implementation of [`UtxoLookup`] which is used to call back into the network graph
126 /// once we have a concrete resolution of a request.
127 struct UtxoResolver(Result<TxOut, UtxoLookupError>);
128 impl UtxoLookup for UtxoResolver {
129 fn get_utxo(&self, _genesis_hash: &BlockHash, _short_channel_id: u64) -> UtxoResult {
130 UtxoResult::Sync(self.0.clone())
135 /// Builds a new future for later resolution.
136 pub fn new() -> Self {
137 Self { state: Arc::new(Mutex::new(UtxoMessages {
139 channel_announce: None,
140 latest_node_announce_a: None,
141 latest_node_announce_b: None,
142 latest_channel_update_a: None,
143 latest_channel_update_b: None,
147 /// Resolves this future against the given `graph` and with the given `result`.
149 /// This is identical to calling [`UtxoFuture::resolve`] with a dummy `gossip`, disabling
150 /// forwarding the validated gossip message onwards to peers.
151 pub fn resolve_without_forwarding<L: Deref>(&self,
152 graph: &NetworkGraph<L>, result: Result<TxOut, UtxoLookupError>)
153 where L::Target: Logger {
154 self.do_resolve(graph, result);
157 /// Resolves this future against the given `graph` and with the given `result`.
159 /// The given `gossip` is used to broadcast any validated messages onwards to all peers which
160 /// have available buffer space.
161 pub fn resolve<L: Deref, G: Deref<Target=NetworkGraph<L>>, U: Deref, GS: Deref<Target = P2PGossipSync<G, U, L>>>(&self,
162 graph: &NetworkGraph<L>, gossip: GS, result: Result<TxOut, UtxoLookupError>
163 ) where L::Target: Logger, U::Target: UtxoLookup {
164 let mut res = self.do_resolve(graph, result);
165 for msg_opt in res.iter_mut() {
166 if let Some(msg) = msg_opt.take() {
167 gossip.forward_gossip_msg(msg);
172 fn do_resolve<L: Deref>(&self, graph: &NetworkGraph<L>, result: Result<TxOut, UtxoLookupError>)
173 -> [Option<MessageSendEvent>; 5] where L::Target: Logger {
174 let (announcement, node_a, node_b, update_a, update_b) = {
175 let mut pending_checks = graph.pending_checks.internal.lock().unwrap();
176 let mut async_messages = self.state.lock().unwrap();
178 if async_messages.channel_announce.is_none() {
179 // We raced returning to `check_channel_announcement` which hasn't updated
180 // `channel_announce` yet. That's okay, we can set the `complete` field which it will
181 // check once it gets control again.
182 async_messages.complete = Some(result);
183 return [None, None, None, None, None];
186 let announcement_msg = match async_messages.channel_announce.as_ref().unwrap() {
187 ChannelAnnouncement::Full(signed_msg) => &signed_msg.contents,
188 ChannelAnnouncement::Unsigned(msg) => &msg,
191 pending_checks.lookup_completed(announcement_msg, &Arc::downgrade(&self.state));
193 (async_messages.channel_announce.take().unwrap(),
194 async_messages.latest_node_announce_a.take(),
195 async_messages.latest_node_announce_b.take(),
196 async_messages.latest_channel_update_a.take(),
197 async_messages.latest_channel_update_b.take())
200 let mut res = [None, None, None, None, None];
203 // Now that we've updated our internal state, pass the pending messages back through the
204 // network graph with a different `UtxoLookup` which will resolve immediately.
205 // Note that we ignore errors as we don't disconnect peers anyway, so there's nothing to do
207 let resolver = UtxoResolver(result);
209 ChannelAnnouncement::Full(signed_msg) => {
210 if graph.update_channel_from_announcement(&signed_msg, &Some(&resolver)).is_ok() {
211 res[res_idx] = Some(MessageSendEvent::BroadcastChannelAnnouncement {
212 msg: signed_msg, update_msg: None,
217 ChannelAnnouncement::Unsigned(msg) => {
218 let _ = graph.update_channel_from_unsigned_announcement(&msg, &Some(&resolver));
222 for announce in core::iter::once(node_a).chain(core::iter::once(node_b)) {
224 Some(NodeAnnouncement::Full(signed_msg)) => {
225 if graph.update_node_from_announcement(&signed_msg).is_ok() {
226 res[res_idx] = Some(MessageSendEvent::BroadcastNodeAnnouncement {
232 Some(NodeAnnouncement::Unsigned(msg)) => {
233 let _ = graph.update_node_from_unsigned_announcement(&msg);
239 for update in core::iter::once(update_a).chain(core::iter::once(update_b)) {
241 Some(ChannelUpdate::Full(signed_msg)) => {
242 if graph.update_channel(&signed_msg).is_ok() {
243 res[res_idx] = Some(MessageSendEvent::BroadcastChannelUpdate {
249 Some(ChannelUpdate::Unsigned(msg)) => {
250 let _ = graph.update_channel_unsigned(&msg);
260 struct PendingChecksContext {
261 channels: HashMap<u64, Weak<Mutex<UtxoMessages>>>,
262 nodes: HashMap<NodeId, Vec<Weak<Mutex<UtxoMessages>>>>,
265 impl PendingChecksContext {
266 fn lookup_completed(&mut self,
267 msg: &msgs::UnsignedChannelAnnouncement, completed_state: &Weak<Mutex<UtxoMessages>>
269 if let hash_map::Entry::Occupied(e) = self.channels.entry(msg.short_channel_id) {
270 if Weak::ptr_eq(e.get(), &completed_state) {
275 if let hash_map::Entry::Occupied(mut e) = self.nodes.entry(msg.node_id_1) {
276 e.get_mut().retain(|elem| !Weak::ptr_eq(&elem, &completed_state));
277 if e.get().is_empty() { e.remove(); }
279 if let hash_map::Entry::Occupied(mut e) = self.nodes.entry(msg.node_id_2) {
280 e.get_mut().retain(|elem| !Weak::ptr_eq(&elem, &completed_state));
281 if e.get().is_empty() { e.remove(); }
286 /// A set of messages which are pending UTXO lookups for processing.
287 pub(super) struct PendingChecks {
288 internal: Mutex<PendingChecksContext>,
292 pub(super) fn new() -> Self {
293 PendingChecks { internal: Mutex::new(PendingChecksContext {
294 channels: HashMap::new(), nodes: HashMap::new(),
298 /// Checks if there is a pending `channel_update` UTXO validation for the given channel,
299 /// and, if so, stores the channel message for handling later and returns an `Err`.
300 pub(super) fn check_hold_pending_channel_update(
301 &self, msg: &msgs::UnsignedChannelUpdate, full_msg: Option<&msgs::ChannelUpdate>
302 ) -> Result<(), LightningError> {
303 let mut pending_checks = self.internal.lock().unwrap();
304 if let hash_map::Entry::Occupied(e) = pending_checks.channels.entry(msg.short_channel_id) {
305 let is_from_a = (msg.flags & 1) == 1;
306 match Weak::upgrade(e.get()) {
308 let mut messages = msgs_ref.lock().unwrap();
309 let latest_update = if is_from_a {
310 &mut messages.latest_channel_update_a
312 &mut messages.latest_channel_update_b
314 if latest_update.is_none() || latest_update.as_ref().unwrap().timestamp() < msg.timestamp {
315 // If the messages we got has a higher timestamp, just blindly assume the
316 // signatures on the new message are correct and drop the old message. This
317 // may cause us to end up dropping valid `channel_update`s if a peer is
318 // malicious, but we should get the correct ones when the node updates them.
319 *latest_update = Some(
320 if let Some(msg) = full_msg { ChannelUpdate::Full(msg.clone()) }
321 else { ChannelUpdate::Unsigned(msg.clone()) });
323 return Err(LightningError {
324 err: "Awaiting channel_announcement validation to accept channel_update".to_owned(),
325 action: ErrorAction::IgnoreAndLog(Level::Gossip),
328 None => { e.remove(); },
334 /// Checks if there is a pending `node_announcement` UTXO validation for a channel with the
335 /// given node and, if so, stores the channel message for handling later and returns an `Err`.
336 pub(super) fn check_hold_pending_node_announcement(
337 &self, msg: &msgs::UnsignedNodeAnnouncement, full_msg: Option<&msgs::NodeAnnouncement>
338 ) -> Result<(), LightningError> {
339 let mut pending_checks = self.internal.lock().unwrap();
340 if let hash_map::Entry::Occupied(mut e) = pending_checks.nodes.entry(msg.node_id) {
341 let mut found_at_least_one_chan = false;
342 e.get_mut().retain(|node_msgs| {
343 match Weak::upgrade(&node_msgs) {
345 let mut chan_msgs = chan_mtx.lock().unwrap();
346 if let Some(chan_announce) = &chan_msgs.channel_announce {
347 let latest_announce =
348 if *chan_announce.node_id_1() == msg.node_id {
349 &mut chan_msgs.latest_node_announce_a
351 &mut chan_msgs.latest_node_announce_b
353 if latest_announce.is_none() ||
354 latest_announce.as_ref().unwrap().timestamp() < msg.timestamp
356 // If the messages we got has a higher timestamp, just blindly
357 // assume the signatures on the new message are correct and drop
358 // the old message. This may cause us to end up dropping valid
359 // `node_announcement`s if a peer is malicious, but we should get
360 // the correct ones when the node updates them.
361 *latest_announce = Some(
362 if let Some(msg) = full_msg { NodeAnnouncement::Full(msg.clone()) }
363 else { NodeAnnouncement::Unsigned(msg.clone()) });
365 found_at_least_one_chan = true;
368 debug_assert!(false, "channel_announce is set before struct is added to node map");
375 if e.get().is_empty() { e.remove(); }
376 if found_at_least_one_chan {
377 return Err(LightningError {
378 err: "Awaiting channel_announcement validation to accept node_announcement".to_owned(),
379 action: ErrorAction::IgnoreAndLog(Level::Gossip),
386 fn check_replace_previous_entry(msg: &msgs::UnsignedChannelAnnouncement,
387 full_msg: Option<&msgs::ChannelAnnouncement>, replacement: Option<Weak<Mutex<UtxoMessages>>>,
388 pending_channels: &mut HashMap<u64, Weak<Mutex<UtxoMessages>>>
389 ) -> Result<(), msgs::LightningError> {
390 match pending_channels.entry(msg.short_channel_id) {
391 hash_map::Entry::Occupied(mut e) => {
392 // There's already a pending lookup for the given SCID. Check if the messages
393 // are the same and, if so, return immediately (don't bother spawning another
394 // lookup if we haven't gotten that far yet).
395 match Weak::upgrade(&e.get()) {
396 Some(pending_msgs) => {
397 let pending_matches = match &pending_msgs.lock().unwrap().channel_announce {
398 Some(ChannelAnnouncement::Full(pending_msg)) => Some(pending_msg) == full_msg,
399 Some(ChannelAnnouncement::Unsigned(pending_msg)) => pending_msg == msg,
401 // This shouldn't actually be reachable. We set the
402 // `channel_announce` field under the same lock as setting the
403 // channel map entry. Still, we can just treat it as
404 // non-matching and let the new request fly.
405 debug_assert!(false);
410 return Err(LightningError {
411 err: "Channel announcement is already being checked".to_owned(),
412 action: ErrorAction::IgnoreDuplicateGossip,
415 // The earlier lookup is a different message. If we have another
416 // request in-flight now replace the original.
417 // Note that in the replace case whether to replace is somewhat
418 // arbitrary - both results will be handled, we're just updating the
419 // value that will be compared to future lookups with the same SCID.
420 if let Some(item) = replacement {
426 // The earlier lookup already resolved. We can't be sure its the same
427 // so just remove/replace it and move on.
428 if let Some(item) = replacement {
430 } else { e.remove(); }
434 hash_map::Entry::Vacant(v) => {
435 if let Some(item) = replacement { v.insert(item); }
441 pub(super) fn check_channel_announcement<U: Deref>(&self,
442 utxo_lookup: &Option<U>, msg: &msgs::UnsignedChannelAnnouncement,
443 full_msg: Option<&msgs::ChannelAnnouncement>
444 ) -> Result<Option<u64>, msgs::LightningError> where U::Target: UtxoLookup {
445 let handle_result = |res| {
447 Ok(TxOut { value, script_pubkey }) => {
448 let expected_script =
449 make_funding_redeemscript_from_slices(msg.bitcoin_key_1.as_slice(), msg.bitcoin_key_2.as_slice()).to_v0_p2wsh();
450 if script_pubkey != expected_script {
451 return Err(LightningError{
452 err: format!("Channel announcement key ({}) didn't match on-chain script ({})",
453 expected_script.to_hex(), script_pubkey.to_hex()),
454 action: ErrorAction::IgnoreError
459 Err(UtxoLookupError::UnknownChain) => {
461 err: format!("Channel announced on an unknown chain ({})",
462 msg.chain_hash.encode().to_hex()),
463 action: ErrorAction::IgnoreError
466 Err(UtxoLookupError::UnknownTx) => {
468 err: "Channel announced without corresponding UTXO entry".to_owned(),
469 action: ErrorAction::IgnoreError
475 Self::check_replace_previous_entry(msg, full_msg, None,
476 &mut self.internal.lock().unwrap().channels)?;
480 // Tentatively accept, potentially exposing us to DoS attacks
483 &Some(ref utxo_lookup) => {
484 match utxo_lookup.get_utxo(&msg.chain_hash, msg.short_channel_id) {
485 UtxoResult::Sync(res) => handle_result(res),
486 UtxoResult::Async(future) => {
487 let mut pending_checks = self.internal.lock().unwrap();
488 let mut async_messages = future.state.lock().unwrap();
489 if let Some(res) = async_messages.complete.take() {
490 // In the unlikely event the future resolved before we managed to get it,
491 // handle the result in-line.
494 Self::check_replace_previous_entry(msg, full_msg,
495 Some(Arc::downgrade(&future.state)), &mut pending_checks.channels)?;
496 async_messages.channel_announce = Some(
497 if let Some(msg) = full_msg { ChannelAnnouncement::Full(msg.clone()) }
498 else { ChannelAnnouncement::Unsigned(msg.clone()) });
499 pending_checks.nodes.entry(msg.node_id_1)
500 .or_insert(Vec::new()).push(Arc::downgrade(&future.state));
501 pending_checks.nodes.entry(msg.node_id_2)
502 .or_insert(Vec::new()).push(Arc::downgrade(&future.state));
504 err: "Channel being checked async".to_owned(),
505 action: ErrorAction::IgnoreAndLog(Level::Gossip),