From 189c1fbe2c85cad9ae391b2ffe921e30f7d77dbc Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Mon, 5 Jun 2023 17:22:36 +0000 Subject: [PATCH] Fail UTXO lookups if the block doesn't have five confirmations The BOLT spec mandates that channels not be announced until they have at least six confirmations. This is important to enforce not because we particularly care about any specific DoS concerns, but because if we do not we may have to handle reorgs of channel funding transactions which change their SCID or have conflicting SCIDs. --- lightning-block-sync/src/gossip.rs | 77 +++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 2 deletions(-) diff --git a/lightning-block-sync/src/gossip.rs b/lightning-block-sync/src/gossip.rs index 4e66c0ce9..37f426851 100644 --- a/lightning-block-sync/src/gossip.rs +++ b/lightning-block-sync/src/gossip.rs @@ -2,7 +2,7 @@ //! current UTXO set. This module defines an implementation of the LDK API required to do so //! against a [`BlockSource`] which implements a few additional methods for accessing the UTXO set. -use crate::{AsyncBlockSourceResult, BlockData, BlockSource}; +use crate::{AsyncBlockSourceResult, BlockData, BlockSource, BlockSourceError}; use bitcoin::blockdata::block::Block; use bitcoin::blockdata::transaction::{TxOut, OutPoint}; @@ -22,6 +22,8 @@ use std::sync::{Arc, Mutex}; use std::collections::VecDeque; use std::future::Future; use std::ops::Deref; +use std::pin::Pin; +use std::task::Poll; /// A trait which extends [`BlockSource`] and can be queried to fetch the block at a given height /// as well as whether a given output is unspent (i.e. a member of the current UTXO set). @@ -62,6 +64,65 @@ impl FutureSpawner for TokioSpawner { } } +/// A trivial future which joins two other futures and polls them at the same time, returning only +/// once both complete. +pub(crate) struct Joiner< + A: Future), BlockSourceError>> + Unpin, + B: Future> + Unpin, +> { + pub a: A, + pub b: B, + a_res: Option<(BlockHash, Option)>, + b_res: Option, +} + +impl< + A: Future), BlockSourceError>> + Unpin, + B: Future> + Unpin, +> Joiner { + fn new(a: A, b: B) -> Self { Self { a, b, a_res: None, b_res: None } } +} + +impl< + A: Future), BlockSourceError>> + Unpin, + B: Future> + Unpin, +> Future for Joiner { + type Output = Result<((BlockHash, Option), BlockHash), BlockSourceError>; + fn poll(mut self: Pin<&mut Self>, ctx: &mut core::task::Context<'_>) -> Poll { + if self.a_res.is_none() { + match Pin::new(&mut self.a).poll(ctx) { + Poll::Ready(res) => { + if let Ok(ok) = res { + self.a_res = Some(ok); + } else { + return Poll::Ready(Err(res.unwrap_err())); + } + }, + Poll::Pending => {}, + } + } + if self.b_res.is_none() { + match Pin::new(&mut self.b).poll(ctx) { + Poll::Ready(res) => { + if let Ok(ok) = res { + self.b_res = Some(ok); + } else { + return Poll::Ready(Err(res.unwrap_err())); + } + + }, + Poll::Pending => {}, + } + } + if let Some(b_res) = self.b_res { + if let Some(a_res) = self.a_res { + return Poll::Ready(Ok((a_res, b_res))) + } + } + Poll::Pending + } +} + /// A struct which wraps a [`UtxoSource`] and a few LDK objects and implements the LDK /// [`UtxoLookup`] trait. /// @@ -156,8 +217,20 @@ impl tip_height { + return Err(UtxoLookupError::UnknownTx); + } + } let block_data = source.get_block(&block_hash).await .map_err(|_| UtxoLookupError::UnknownTx)?; let block = match block_data { -- 2.39.5