da9c65c3b12a605c385fd566fe4cf0a505df4b35
[rust-lightning] / lightning / src / routing / utxo.rs
1 // This file is Copyright its original authors, visible in version control
2 // history.
3 //
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
8 // licenses.
9
10 //! This module contains traits for LDK to access UTXOs to check gossip data is correct.
11 //!
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.
15
16 use bitcoin::{BlockHash, TxOut};
17 use bitcoin::hashes::hex::ToHex;
18
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;
25
26 use crate::prelude::*;
27
28 use alloc::sync::{Arc, Weak};
29 use crate::sync::Mutex;
30 use core::ops::Deref;
31
32 /// An error when accessing the chain via [`UtxoLookup`].
33 #[derive(Clone, Debug)]
34 pub enum UtxoLookupError {
35         /// The requested chain is unknown.
36         UnknownChain,
37
38         /// The requested transaction doesn't exist or hasn't confirmed.
39         UnknownTx,
40 }
41
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`
44 /// variant.
45 pub enum UtxoResult {
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.
51         ///
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.
56         Async(UtxoFuture),
57 }
58
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
63         /// is unknown.
64         ///
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;
67 }
68
69 enum ChannelAnnouncement {
70         Full(msgs::ChannelAnnouncement),
71         Unsigned(msgs::UnsignedChannelAnnouncement),
72 }
73 impl ChannelAnnouncement {
74         fn node_id_1(&self) -> &NodeId {
75                 match self {
76                         ChannelAnnouncement::Full(msg) => &msg.contents.node_id_1,
77                         ChannelAnnouncement::Unsigned(msg) => &msg.node_id_1,
78                 }
79         }
80 }
81
82 enum NodeAnnouncement {
83         Full(msgs::NodeAnnouncement),
84         Unsigned(msgs::UnsignedNodeAnnouncement),
85 }
86 impl NodeAnnouncement {
87         fn timestamp(&self) -> u32 {
88                 match self {
89                         NodeAnnouncement::Full(msg) => msg.contents.timestamp,
90                         NodeAnnouncement::Unsigned(msg) => msg.timestamp,
91                 }
92         }
93 }
94
95 enum ChannelUpdate {
96         Full(msgs::ChannelUpdate),
97         Unsigned(msgs::UnsignedChannelUpdate),
98 }
99 impl ChannelUpdate {
100         fn timestamp(&self) -> u32 {
101                 match self {
102                         ChannelUpdate::Full(msg) => msg.contents.timestamp,
103                         ChannelUpdate::Unsigned(msg) => msg.timestamp,
104                 }
105         }
106 }
107
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>,
115 }
116
117 /// Represents a future resolution of a [`UtxoLookup::get_utxo`] query resolving async.
118 ///
119 /// See [`UtxoResult::Async`] and [`UtxoFuture::resolve`] for more info.
120 #[derive(Clone)]
121 pub struct UtxoFuture {
122         state: Arc<Mutex<UtxoMessages>>,
123 }
124
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())
131         }
132 }
133
134 impl UtxoFuture {
135         /// Builds a new future for later resolution.
136         pub fn new() -> Self {
137                 Self { state: Arc::new(Mutex::new(UtxoMessages {
138                         complete: None,
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,
144                 }))}
145         }
146
147         /// Resolves this future against the given `graph` and with the given `result`.
148         ///
149         /// This is identical to calling [`UtxoFuture::resolve`] with a dummy `gossip`, disabling
150         /// forwarding the validated gossip message onwards to peers.
151         ///
152         /// Because this may cause the [`NetworkGraph`]'s [`processing_queue_high`] to flip, in order
153         /// to allow us to interact with peers again, you should call [`PeerManager::process_events`]
154         /// after this.
155         ///
156         /// [`processing_queue_high`]: crate::ln::msgs::RoutingMessageHandler::processing_queue_high
157         /// [`PeerManager::process_events`]: crate::ln::peer_handler::PeerManager::process_events
158         pub fn resolve_without_forwarding<L: Deref>(&self,
159                 graph: &NetworkGraph<L>, result: Result<TxOut, UtxoLookupError>)
160         where L::Target: Logger {
161                 self.do_resolve(graph, result);
162         }
163
164         /// Resolves this future against the given `graph` and with the given `result`.
165         ///
166         /// The given `gossip` is used to broadcast any validated messages onwards to all peers which
167         /// have available buffer space.
168         ///
169         /// Because this may cause the [`NetworkGraph`]'s [`processing_queue_high`] to flip, in order
170         /// to allow us to interact with peers again, you should call [`PeerManager::process_events`]
171         /// after this.
172         ///
173         /// [`processing_queue_high`]: crate::ln::msgs::RoutingMessageHandler::processing_queue_high
174         /// [`PeerManager::process_events`]: crate::ln::peer_handler::PeerManager::process_events
175         pub fn resolve<L: Deref, G: Deref<Target=NetworkGraph<L>>, U: Deref, GS: Deref<Target = P2PGossipSync<G, U, L>>>(&self,
176                 graph: &NetworkGraph<L>, gossip: GS, result: Result<TxOut, UtxoLookupError>
177         ) where L::Target: Logger, U::Target: UtxoLookup {
178                 let mut res = self.do_resolve(graph, result);
179                 for msg_opt in res.iter_mut() {
180                         if let Some(msg) = msg_opt.take() {
181                                 gossip.forward_gossip_msg(msg);
182                         }
183                 }
184         }
185
186         fn do_resolve<L: Deref>(&self, graph: &NetworkGraph<L>, result: Result<TxOut, UtxoLookupError>)
187         -> [Option<MessageSendEvent>; 5] where L::Target: Logger {
188                 let (announcement, node_a, node_b, update_a, update_b) = {
189                         let mut pending_checks = graph.pending_checks.internal.lock().unwrap();
190                         let mut async_messages = self.state.lock().unwrap();
191
192                         if async_messages.channel_announce.is_none() {
193                                 // We raced returning to `check_channel_announcement` which hasn't updated
194                                 // `channel_announce` yet. That's okay, we can set the `complete` field which it will
195                                 // check once it gets control again.
196                                 async_messages.complete = Some(result);
197                                 return [None, None, None, None, None];
198                         }
199
200                         let announcement_msg = match async_messages.channel_announce.as_ref().unwrap() {
201                                 ChannelAnnouncement::Full(signed_msg) => &signed_msg.contents,
202                                 ChannelAnnouncement::Unsigned(msg) => &msg,
203                         };
204
205                         pending_checks.lookup_completed(announcement_msg, &Arc::downgrade(&self.state));
206
207                         (async_messages.channel_announce.take().unwrap(),
208                                 async_messages.latest_node_announce_a.take(),
209                                 async_messages.latest_node_announce_b.take(),
210                                 async_messages.latest_channel_update_a.take(),
211                                 async_messages.latest_channel_update_b.take())
212                 };
213
214                 let mut res = [None, None, None, None, None];
215                 let mut res_idx = 0;
216
217                 // Now that we've updated our internal state, pass the pending messages back through the
218                 // network graph with a different `UtxoLookup` which will resolve immediately.
219                 // Note that we ignore errors as we don't disconnect peers anyway, so there's nothing to do
220                 // with them.
221                 let resolver = UtxoResolver(result);
222                 match announcement {
223                         ChannelAnnouncement::Full(signed_msg) => {
224                                 if graph.update_channel_from_announcement(&signed_msg, &Some(&resolver)).is_ok() {
225                                         res[res_idx] = Some(MessageSendEvent::BroadcastChannelAnnouncement {
226                                                 msg: signed_msg, update_msg: None,
227                                         });
228                                         res_idx += 1;
229                                 }
230                         },
231                         ChannelAnnouncement::Unsigned(msg) => {
232                                 let _ = graph.update_channel_from_unsigned_announcement(&msg, &Some(&resolver));
233                         },
234                 }
235
236                 for announce in core::iter::once(node_a).chain(core::iter::once(node_b)) {
237                         match announce {
238                                 Some(NodeAnnouncement::Full(signed_msg)) => {
239                                         if graph.update_node_from_announcement(&signed_msg).is_ok() {
240                                                 res[res_idx] = Some(MessageSendEvent::BroadcastNodeAnnouncement {
241                                                         msg: signed_msg,
242                                                 });
243                                                 res_idx += 1;
244                                         }
245                                 },
246                                 Some(NodeAnnouncement::Unsigned(msg)) => {
247                                         let _ = graph.update_node_from_unsigned_announcement(&msg);
248                                 },
249                                 None => {},
250                         }
251                 }
252
253                 for update in core::iter::once(update_a).chain(core::iter::once(update_b)) {
254                         match update {
255                                 Some(ChannelUpdate::Full(signed_msg)) => {
256                                         if graph.update_channel(&signed_msg).is_ok() {
257                                                 res[res_idx] = Some(MessageSendEvent::BroadcastChannelUpdate {
258                                                         msg: signed_msg,
259                                                 });
260                                                 res_idx += 1;
261                                         }
262                                 },
263                                 Some(ChannelUpdate::Unsigned(msg)) => {
264                                         let _ = graph.update_channel_unsigned(&msg);
265                                 },
266                                 None => {},
267                         }
268                 }
269
270                 res
271         }
272 }
273
274 struct PendingChecksContext {
275         channels: HashMap<u64, Weak<Mutex<UtxoMessages>>>,
276         nodes: HashMap<NodeId, Vec<Weak<Mutex<UtxoMessages>>>>,
277 }
278
279 impl PendingChecksContext {
280         fn lookup_completed(&mut self,
281                 msg: &msgs::UnsignedChannelAnnouncement, completed_state: &Weak<Mutex<UtxoMessages>>
282         ) {
283                 if let hash_map::Entry::Occupied(e) = self.channels.entry(msg.short_channel_id) {
284                         if Weak::ptr_eq(e.get(), &completed_state) {
285                                 e.remove();
286                         }
287                 }
288
289                 if let hash_map::Entry::Occupied(mut e) = self.nodes.entry(msg.node_id_1) {
290                         e.get_mut().retain(|elem| !Weak::ptr_eq(&elem, &completed_state));
291                         if e.get().is_empty() { e.remove(); }
292                 }
293                 if let hash_map::Entry::Occupied(mut e) = self.nodes.entry(msg.node_id_2) {
294                         e.get_mut().retain(|elem| !Weak::ptr_eq(&elem, &completed_state));
295                         if e.get().is_empty() { e.remove(); }
296                 }
297         }
298 }
299
300 /// A set of messages which are pending UTXO lookups for processing.
301 pub(super) struct PendingChecks {
302         internal: Mutex<PendingChecksContext>,
303 }
304
305 impl PendingChecks {
306         pub(super) fn new() -> Self {
307                 PendingChecks { internal: Mutex::new(PendingChecksContext {
308                         channels: HashMap::new(), nodes: HashMap::new(),
309                 }) }
310         }
311
312         /// Checks if there is a pending `channel_update` UTXO validation for the given channel,
313         /// and, if so, stores the channel message for handling later and returns an `Err`.
314         pub(super) fn check_hold_pending_channel_update(
315                 &self, msg: &msgs::UnsignedChannelUpdate, full_msg: Option<&msgs::ChannelUpdate>
316         ) -> Result<(), LightningError> {
317                 let mut pending_checks = self.internal.lock().unwrap();
318                 if let hash_map::Entry::Occupied(e) = pending_checks.channels.entry(msg.short_channel_id) {
319                         let is_from_a = (msg.flags & 1) == 1;
320                         match Weak::upgrade(e.get()) {
321                                 Some(msgs_ref) => {
322                                         let mut messages = msgs_ref.lock().unwrap();
323                                         let latest_update = if is_from_a {
324                                                         &mut messages.latest_channel_update_a
325                                                 } else {
326                                                         &mut messages.latest_channel_update_b
327                                                 };
328                                         if latest_update.is_none() || latest_update.as_ref().unwrap().timestamp() < msg.timestamp {
329                                                 // If the messages we got has a higher timestamp, just blindly assume the
330                                                 // signatures on the new message are correct and drop the old message. This
331                                                 // may cause us to end up dropping valid `channel_update`s if a peer is
332                                                 // malicious, but we should get the correct ones when the node updates them.
333                                                 *latest_update = Some(
334                                                         if let Some(msg) = full_msg { ChannelUpdate::Full(msg.clone()) }
335                                                         else { ChannelUpdate::Unsigned(msg.clone()) });
336                                         }
337                                         return Err(LightningError {
338                                                 err: "Awaiting channel_announcement validation to accept channel_update".to_owned(),
339                                                 action: ErrorAction::IgnoreAndLog(Level::Gossip),
340                                         });
341                                 },
342                                 None => { e.remove(); },
343                         }
344                 }
345                 Ok(())
346         }
347
348         /// Checks if there is a pending `node_announcement` UTXO validation for a channel with the
349         /// given node and, if so, stores the channel message for handling later and returns an `Err`.
350         pub(super) fn check_hold_pending_node_announcement(
351                 &self, msg: &msgs::UnsignedNodeAnnouncement, full_msg: Option<&msgs::NodeAnnouncement>
352         ) -> Result<(), LightningError> {
353                 let mut pending_checks = self.internal.lock().unwrap();
354                 if let hash_map::Entry::Occupied(mut e) = pending_checks.nodes.entry(msg.node_id) {
355                         let mut found_at_least_one_chan = false;
356                         e.get_mut().retain(|node_msgs| {
357                                 match Weak::upgrade(&node_msgs) {
358                                         Some(chan_mtx) => {
359                                                 let mut chan_msgs = chan_mtx.lock().unwrap();
360                                                 if let Some(chan_announce) = &chan_msgs.channel_announce {
361                                                         let latest_announce =
362                                                                 if *chan_announce.node_id_1() == msg.node_id {
363                                                                         &mut chan_msgs.latest_node_announce_a
364                                                                 } else {
365                                                                         &mut chan_msgs.latest_node_announce_b
366                                                                 };
367                                                         if latest_announce.is_none() ||
368                                                                 latest_announce.as_ref().unwrap().timestamp() < msg.timestamp
369                                                         {
370                                                                 // If the messages we got has a higher timestamp, just blindly
371                                                                 // assume the signatures on the new message are correct and drop
372                                                                 // the old message. This may cause us to end up dropping valid
373                                                                 // `node_announcement`s if a peer is malicious, but we should get
374                                                                 // the correct ones when the node updates them.
375                                                                 *latest_announce = Some(
376                                                                         if let Some(msg) = full_msg { NodeAnnouncement::Full(msg.clone()) }
377                                                                         else { NodeAnnouncement::Unsigned(msg.clone()) });
378                                                         }
379                                                         found_at_least_one_chan = true;
380                                                         true
381                                                 } else {
382                                                         debug_assert!(false, "channel_announce is set before struct is added to node map");
383                                                         false
384                                                 }
385                                         },
386                                         None => false,
387                                 }
388                         });
389                         if e.get().is_empty() { e.remove(); }
390                         if found_at_least_one_chan {
391                                 return Err(LightningError {
392                                         err: "Awaiting channel_announcement validation to accept node_announcement".to_owned(),
393                                         action: ErrorAction::IgnoreAndLog(Level::Gossip),
394                                 });
395                         }
396                 }
397                 Ok(())
398         }
399
400         fn check_replace_previous_entry(msg: &msgs::UnsignedChannelAnnouncement,
401                 full_msg: Option<&msgs::ChannelAnnouncement>, replacement: Option<Weak<Mutex<UtxoMessages>>>,
402                 pending_channels: &mut HashMap<u64, Weak<Mutex<UtxoMessages>>>
403         ) -> Result<(), msgs::LightningError> {
404                 match pending_channels.entry(msg.short_channel_id) {
405                         hash_map::Entry::Occupied(mut e) => {
406                                 // There's already a pending lookup for the given SCID. Check if the messages
407                                 // are the same and, if so, return immediately (don't bother spawning another
408                                 // lookup if we haven't gotten that far yet).
409                                 match Weak::upgrade(&e.get()) {
410                                         Some(pending_msgs) => {
411                                                 let pending_matches = match &pending_msgs.lock().unwrap().channel_announce {
412                                                         Some(ChannelAnnouncement::Full(pending_msg)) => Some(pending_msg) == full_msg,
413                                                         Some(ChannelAnnouncement::Unsigned(pending_msg)) => pending_msg == msg,
414                                                         None => {
415                                                                 // This shouldn't actually be reachable. We set the
416                                                                 // `channel_announce` field under the same lock as setting the
417                                                                 // channel map entry. Still, we can just treat it as
418                                                                 // non-matching and let the new request fly.
419                                                                 debug_assert!(false);
420                                                                 false
421                                                         },
422                                                 };
423                                                 if pending_matches {
424                                                         return Err(LightningError {
425                                                                 err: "Channel announcement is already being checked".to_owned(),
426                                                                 action: ErrorAction::IgnoreDuplicateGossip,
427                                                         });
428                                                 } else {
429                                                         // The earlier lookup is a different message. If we have another
430                                                         // request in-flight now replace the original.
431                                                         // Note that in the replace case whether to replace is somewhat
432                                                         // arbitrary - both results will be handled, we're just updating the
433                                                         // value that will be compared to future lookups with the same SCID.
434                                                         if let Some(item) = replacement {
435                                                                 *e.get_mut() = item;
436                                                         }
437                                                 }
438                                         },
439                                         None => {
440                                                 // The earlier lookup already resolved. We can't be sure its the same
441                                                 // so just remove/replace it and move on.
442                                                 if let Some(item) = replacement {
443                                                         *e.get_mut() = item;
444                                                 } else { e.remove(); }
445                                         },
446                                 }
447                         },
448                         hash_map::Entry::Vacant(v) => {
449                                 if let Some(item) = replacement { v.insert(item); }
450                         },
451                 }
452                 Ok(())
453         }
454
455         pub(super) fn check_channel_announcement<U: Deref>(&self,
456                 utxo_lookup: &Option<U>, msg: &msgs::UnsignedChannelAnnouncement,
457                 full_msg: Option<&msgs::ChannelAnnouncement>
458         ) -> Result<Option<u64>, msgs::LightningError> where U::Target: UtxoLookup {
459                 let handle_result = |res| {
460                         match res {
461                                 Ok(TxOut { value, script_pubkey }) => {
462                                         let expected_script =
463                                                 make_funding_redeemscript_from_slices(msg.bitcoin_key_1.as_slice(), msg.bitcoin_key_2.as_slice()).to_v0_p2wsh();
464                                         if script_pubkey != expected_script {
465                                                 return Err(LightningError{
466                                                         err: format!("Channel announcement key ({}) didn't match on-chain script ({})",
467                                                                 expected_script.to_hex(), script_pubkey.to_hex()),
468                                                         action: ErrorAction::IgnoreError
469                                                 });
470                                         }
471                                         Ok(Some(value))
472                                 },
473                                 Err(UtxoLookupError::UnknownChain) => {
474                                         Err(LightningError {
475                                                 err: format!("Channel announced on an unknown chain ({})",
476                                                         msg.chain_hash.encode().to_hex()),
477                                                 action: ErrorAction::IgnoreError
478                                         })
479                                 },
480                                 Err(UtxoLookupError::UnknownTx) => {
481                                         Err(LightningError {
482                                                 err: "Channel announced without corresponding UTXO entry".to_owned(),
483                                                 action: ErrorAction::IgnoreError
484                                         })
485                                 },
486                         }
487                 };
488
489                 Self::check_replace_previous_entry(msg, full_msg, None,
490                         &mut self.internal.lock().unwrap().channels)?;
491
492                 match utxo_lookup {
493                         &None => {
494                                 // Tentatively accept, potentially exposing us to DoS attacks
495                                 Ok(None)
496                         },
497                         &Some(ref utxo_lookup) => {
498                                 match utxo_lookup.get_utxo(&msg.chain_hash, msg.short_channel_id) {
499                                         UtxoResult::Sync(res) => handle_result(res),
500                                         UtxoResult::Async(future) => {
501                                                 let mut pending_checks = self.internal.lock().unwrap();
502                                                 let mut async_messages = future.state.lock().unwrap();
503                                                 if let Some(res) = async_messages.complete.take() {
504                                                         // In the unlikely event the future resolved before we managed to get it,
505                                                         // handle the result in-line.
506                                                         handle_result(res)
507                                                 } else {
508                                                         Self::check_replace_previous_entry(msg, full_msg,
509                                                                 Some(Arc::downgrade(&future.state)), &mut pending_checks.channels)?;
510                                                         async_messages.channel_announce = Some(
511                                                                 if let Some(msg) = full_msg { ChannelAnnouncement::Full(msg.clone()) }
512                                                                 else { ChannelAnnouncement::Unsigned(msg.clone()) });
513                                                         pending_checks.nodes.entry(msg.node_id_1)
514                                                                 .or_insert(Vec::new()).push(Arc::downgrade(&future.state));
515                                                         pending_checks.nodes.entry(msg.node_id_2)
516                                                                 .or_insert(Vec::new()).push(Arc::downgrade(&future.state));
517                                                         Err(LightningError {
518                                                                 err: "Channel being checked async".to_owned(),
519                                                                 action: ErrorAction::IgnoreAndLog(Level::Gossip),
520                                                         })
521                                                 }
522                                         },
523                                 }
524                         }
525                 }
526         }
527
528         /// The maximum number of pending gossip checks before [`Self::too_many_checks_pending`]
529         /// returns `true`. Note that this isn't a strict upper-bound on the number of checks pending -
530         /// each peer may, at a minimum, read one more socket buffer worth of `channel_announcement`s
531         /// which we'll have to process. With a socket buffer of 4KB and a minimum
532         /// `channel_announcement` size of, roughly, 429 bytes, this may leave us with `10*our peer
533         /// count` messages to process beyond this limit. Because we'll probably have a few peers,
534         /// there's no reason for this constant to be materially less than 30 or so, and 32 in-flight
535         /// checks should be more than enough for decent parallelism.
536         const MAX_PENDING_LOOKUPS: usize = 32;
537
538         /// Returns true if there are a large number of async checks pending and future
539         /// `channel_announcement` messages should be delayed. Note that this is only a hint and
540         /// messages already in-flight may still have to be handled for various reasons.
541         pub(super) fn too_many_checks_pending(&self) -> bool {
542                 let mut pending_checks = self.internal.lock().unwrap();
543                 if pending_checks.channels.len() > Self::MAX_PENDING_LOOKUPS {
544                         // If we have many channel checks pending, ensure we don't have any dangling checks
545                         // (i.e. checks where the user told us they'd call back but drop'd the `AccessFuture`
546                         // instead) before we commit to applying backpressure.
547                         pending_checks.channels.retain(|_, chan| {
548                                 Weak::upgrade(&chan).is_some()
549                         });
550                         pending_checks.nodes.retain(|_, channels| {
551                                 channels.retain(|chan| Weak::upgrade(&chan).is_some());
552                                 !channels.is_empty()
553                         });
554                         pending_checks.channels.len() > Self::MAX_PENDING_LOOKUPS
555                 } else {
556                         false
557                 }
558         }
559 }