22//! current UTXO set. This module defines an implementation of the LDK API required to do so
33//! against a [`BlockSource`] which implements a few additional methods for accessing the UTXO set.
44
5- use crate :: { AsyncBlockSourceResult , BlockData , BlockSource } ;
5+ use crate :: { AsyncBlockSourceResult , BlockData , BlockSource , BlockSourceError } ;
66
77use bitcoin:: blockdata:: block:: Block ;
88use bitcoin:: blockdata:: transaction:: { TxOut , OutPoint } ;
@@ -22,6 +22,8 @@ use std::sync::{Arc, Mutex};
2222use std:: collections:: VecDeque ;
2323use std:: future:: Future ;
2424use std:: ops:: Deref ;
25+ use std:: pin:: Pin ;
26+ use std:: task:: Poll ;
2527
2628/// A trait which extends [`BlockSource`] and can be queried to fetch the block at a given height
2729/// 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 {
6264 }
6365}
6466
67+ /// A trivial future which joins two other futures and polls them at the same time, returning only
68+ /// once both complete.
69+ pub ( crate ) struct Joiner <
70+ A : Future < Output =Result < ( BlockHash , Option < u32 > ) , BlockSourceError > > + Unpin ,
71+ B : Future < Output =Result < BlockHash , BlockSourceError > > + Unpin ,
72+ > {
73+ pub a : A ,
74+ pub b : B ,
75+ a_res : Option < ( BlockHash , Option < u32 > ) > ,
76+ b_res : Option < BlockHash > ,
77+ }
78+
79+ impl <
80+ A : Future < Output =Result < ( BlockHash , Option < u32 > ) , BlockSourceError > > + Unpin ,
81+ B : Future < Output =Result < BlockHash , BlockSourceError > > + Unpin ,
82+ > Joiner < A , B > {
83+ fn new ( a : A , b : B ) -> Self { Self { a, b, a_res : None , b_res : None } }
84+ }
85+
86+ impl <
87+ A : Future < Output =Result < ( BlockHash , Option < u32 > ) , BlockSourceError > > + Unpin ,
88+ B : Future < Output =Result < BlockHash , BlockSourceError > > + Unpin ,
89+ > Future for Joiner < A , B > {
90+ type Output = Result < ( ( BlockHash , Option < u32 > ) , BlockHash ) , BlockSourceError > ;
91+ fn poll ( mut self : Pin < & mut Self > , ctx : & mut core:: task:: Context < ' _ > ) -> Poll < Self :: Output > {
92+ if self . a_res . is_none ( ) {
93+ match Pin :: new ( & mut self . a ) . poll ( ctx) {
94+ Poll :: Ready ( res) => {
95+ if let Ok ( ok) = res {
96+ self . a_res = Some ( ok) ;
97+ } else {
98+ return Poll :: Ready ( Err ( res. unwrap_err ( ) ) ) ;
99+ }
100+ } ,
101+ Poll :: Pending => { } ,
102+ }
103+ }
104+ if self . b_res . is_none ( ) {
105+ match Pin :: new ( & mut self . b ) . poll ( ctx) {
106+ Poll :: Ready ( res) => {
107+ if let Ok ( ok) = res {
108+ self . b_res = Some ( ok) ;
109+ } else {
110+ return Poll :: Ready ( Err ( res. unwrap_err ( ) ) ) ;
111+ }
112+
113+ } ,
114+ Poll :: Pending => { } ,
115+ }
116+ }
117+ if let Some ( b_res) = self . b_res {
118+ if let Some ( a_res) = self . a_res {
119+ return Poll :: Ready ( Ok ( ( a_res, b_res) ) )
120+ }
121+ }
122+ Poll :: Pending
123+ }
124+ }
125+
65126/// A struct which wraps a [`UtxoSource`] and a few LDK objects and implements the LDK
66127/// [`UtxoLookup`] trait.
67128///
@@ -156,8 +217,20 @@ impl<S: FutureSpawner,
156217 }
157218 }
158219
159- let block_hash = source. get_block_hash_by_height ( block_height) . await
220+ let ( ( _, tip_height_opt) , block_hash) =
221+ Joiner :: new ( source. get_best_block ( ) , source. get_block_hash_by_height ( block_height) )
222+ . await
160223 . map_err ( |_| UtxoLookupError :: UnknownTx ) ?;
224+ if let Some ( tip_height) = tip_height_opt {
225+ // If the block doesn't yet have five confirmations, error out.
226+ //
227+ // The BOLT spec requires nodes wait for six confirmations before announcing a
228+ // channel, and we give them one block of headroom in case we're delayed seeing a
229+ // block.
230+ if block_height + 5 > tip_height {
231+ return Err ( UtxoLookupError :: UnknownTx ) ;
232+ }
233+ }
161234 let block_data = source. get_block ( & block_hash) . await
162235 . map_err ( |_| UtxoLookupError :: UnknownTx ) ?;
163236 let block = match block_data {
0 commit comments