]> git.bitcoin.ninja Git - rust-lightning/blob - lightning/src/routing/utxo.rs
Forward gossip messages which were verified asynchronously
[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         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);
155         }
156
157         /// Resolves this future against the given `graph` and with the given `result`.
158         ///
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);
168                         }
169                 }
170         }
171
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();
177
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];
184                         }
185
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,
189                         };
190
191                         pending_checks.lookup_completed(announcement_msg, &Arc::downgrade(&self.state));
192
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())
198                 };
199
200                 let mut res = [None, None, None, None, None];
201                 let mut res_idx = 0;
202
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
206                 // with them.
207                 let resolver = UtxoResolver(result);
208                 match announcement {
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,
213                                         });
214                                         res_idx += 1;
215                                 }
216                         },
217                         ChannelAnnouncement::Unsigned(msg) => {
218                                 let _ = graph.update_channel_from_unsigned_announcement(&msg, &Some(&resolver));
219                         },
220                 }
221
222                 for announce in core::iter::once(node_a).chain(core::iter::once(node_b)) {
223                         match announce {
224                                 Some(NodeAnnouncement::Full(signed_msg)) => {
225                                         if graph.update_node_from_announcement(&signed_msg).is_ok() {
226                                                 res[res_idx] = Some(MessageSendEvent::BroadcastNodeAnnouncement {
227                                                         msg: signed_msg,
228                                                 });
229                                                 res_idx += 1;
230                                         }
231                                 },
232                                 Some(NodeAnnouncement::Unsigned(msg)) => {
233                                         let _ = graph.update_node_from_unsigned_announcement(&msg);
234                                 },
235                                 None => {},
236                         }
237                 }
238
239                 for update in core::iter::once(update_a).chain(core::iter::once(update_b)) {
240                         match update {
241                                 Some(ChannelUpdate::Full(signed_msg)) => {
242                                         if graph.update_channel(&signed_msg).is_ok() {
243                                                 res[res_idx] = Some(MessageSendEvent::BroadcastChannelUpdate {
244                                                         msg: signed_msg,
245                                                 });
246                                                 res_idx += 1;
247                                         }
248                                 },
249                                 Some(ChannelUpdate::Unsigned(msg)) => {
250                                         let _ = graph.update_channel_unsigned(&msg);
251                                 },
252                                 None => {},
253                         }
254                 }
255
256                 res
257         }
258 }
259
260 struct PendingChecksContext {
261         channels: HashMap<u64, Weak<Mutex<UtxoMessages>>>,
262         nodes: HashMap<NodeId, Vec<Weak<Mutex<UtxoMessages>>>>,
263 }
264
265 impl PendingChecksContext {
266         fn lookup_completed(&mut self,
267                 msg: &msgs::UnsignedChannelAnnouncement, completed_state: &Weak<Mutex<UtxoMessages>>
268         ) {
269                 if let hash_map::Entry::Occupied(e) = self.channels.entry(msg.short_channel_id) {
270                         if Weak::ptr_eq(e.get(), &completed_state) {
271                                 e.remove();
272                         }
273                 }
274
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(); }
278                 }
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(); }
282                 }
283         }
284 }
285
286 /// A set of messages which are pending UTXO lookups for processing.
287 pub(super) struct PendingChecks {
288         internal: Mutex<PendingChecksContext>,
289 }
290
291 impl PendingChecks {
292         pub(super) fn new() -> Self {
293                 PendingChecks { internal: Mutex::new(PendingChecksContext {
294                         channels: HashMap::new(), nodes: HashMap::new(),
295                 }) }
296         }
297
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()) {
307                                 Some(msgs_ref) => {
308                                         let mut messages = msgs_ref.lock().unwrap();
309                                         let latest_update = if is_from_a {
310                                                         &mut messages.latest_channel_update_a
311                                                 } else {
312                                                         &mut messages.latest_channel_update_b
313                                                 };
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()) });
322                                         }
323                                         return Err(LightningError {
324                                                 err: "Awaiting channel_announcement validation to accept channel_update".to_owned(),
325                                                 action: ErrorAction::IgnoreAndLog(Level::Gossip),
326                                         });
327                                 },
328                                 None => { e.remove(); },
329                         }
330                 }
331                 Ok(())
332         }
333
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) {
344                                         Some(chan_mtx) => {
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
350                                                                 } else {
351                                                                         &mut chan_msgs.latest_node_announce_b
352                                                                 };
353                                                         if latest_announce.is_none() ||
354                                                                 latest_announce.as_ref().unwrap().timestamp() < msg.timestamp
355                                                         {
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()) });
364                                                         }
365                                                         found_at_least_one_chan = true;
366                                                         true
367                                                 } else {
368                                                         debug_assert!(false, "channel_announce is set before struct is added to node map");
369                                                         false
370                                                 }
371                                         },
372                                         None => false,
373                                 }
374                         });
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),
380                                 });
381                         }
382                 }
383                 Ok(())
384         }
385
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,
400                                                         None => {
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);
406                                                                 false
407                                                         },
408                                                 };
409                                                 if pending_matches {
410                                                         return Err(LightningError {
411                                                                 err: "Channel announcement is already being checked".to_owned(),
412                                                                 action: ErrorAction::IgnoreDuplicateGossip,
413                                                         });
414                                                 } else {
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 {
421                                                                 *e.get_mut() = item;
422                                                         }
423                                                 }
424                                         },
425                                         None => {
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 {
429                                                         *e.get_mut() = item;
430                                                 } else { e.remove(); }
431                                         },
432                                 }
433                         },
434                         hash_map::Entry::Vacant(v) => {
435                                 if let Some(item) = replacement { v.insert(item); }
436                         },
437                 }
438                 Ok(())
439         }
440
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| {
446                         match 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
455                                                 });
456                                         }
457                                         Ok(Some(value))
458                                 },
459                                 Err(UtxoLookupError::UnknownChain) => {
460                                         Err(LightningError {
461                                                 err: format!("Channel announced on an unknown chain ({})",
462                                                         msg.chain_hash.encode().to_hex()),
463                                                 action: ErrorAction::IgnoreError
464                                         })
465                                 },
466                                 Err(UtxoLookupError::UnknownTx) => {
467                                         Err(LightningError {
468                                                 err: "Channel announced without corresponding UTXO entry".to_owned(),
469                                                 action: ErrorAction::IgnoreError
470                                         })
471                                 },
472                         }
473                 };
474
475                 Self::check_replace_previous_entry(msg, full_msg, None,
476                         &mut self.internal.lock().unwrap().channels)?;
477
478                 match utxo_lookup {
479                         &None => {
480                                 // Tentatively accept, potentially exposing us to DoS attacks
481                                 Ok(None)
482                         },
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.
492                                                         handle_result(res)
493                                                 } else {
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));
503                                                         Err(LightningError {
504                                                                 err: "Channel being checked async".to_owned(),
505                                                                 action: ErrorAction::IgnoreAndLog(Level::Gossip),
506                                                         })
507                                                 }
508                                         },
509                                 }
510                         }
511                 }
512         }
513 }