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