2
2
//! current UTXO set. This module defines an implementation of the LDK API required to do so
3
3
//! against a [`BlockSource`] which implements a few additional methods for accessing the UTXO set.
4
4
5
- use crate :: { AsyncBlockSourceResult , BlockData , BlockSource } ;
5
+ use crate :: { AsyncBlockSourceResult , BlockData , BlockSource , BlockSourceError } ;
6
6
7
7
use bitcoin:: blockdata:: block:: Block ;
8
8
use bitcoin:: blockdata:: transaction:: { TxOut , OutPoint } ;
@@ -22,6 +22,8 @@ use std::sync::{Arc, Mutex};
22
22
use std:: collections:: VecDeque ;
23
23
use std:: future:: Future ;
24
24
use std:: ops:: Deref ;
25
+ use std:: pin:: Pin ;
26
+ use std:: task:: Poll ;
25
27
26
28
/// A trait which extends [`BlockSource`] and can be queried to fetch the block at a given height
27
29
/// 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 {
62
64
}
63
65
}
64
66
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
+
65
126
/// A struct which wraps a [`UtxoSource`] and a few LDK objects and implements the LDK
66
127
/// [`UtxoLookup`] trait.
67
128
///
@@ -156,8 +217,20 @@ impl<S: FutureSpawner,
156
217
}
157
218
}
158
219
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
160
223
. 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
+ }
161
234
let block_data = source. get_block ( & block_hash) . await
162
235
. map_err ( |_| UtxoLookupError :: UnknownTx ) ?;
163
236
let block = match block_data {
0 commit comments