1
1
use crate :: { AsyncBlockSourceResult , BlockHeaderData , BlockSource , BlockSourceError , ChainTip , Poll } ;
2
2
3
+ use bitcoin:: blockdata:: block:: Block ;
4
+ use bitcoin:: hash_types:: BlockHash ;
5
+
3
6
use std:: ops:: DerefMut ;
4
7
5
8
pub struct ChainPoller < ' a , B : DerefMut < Target =dyn BlockSource + ' a > + Sized + Sync + Send > {
@@ -13,7 +16,6 @@ impl<'a, B: DerefMut<Target=dyn BlockSource + 'a> + Sized + Sync + Send> ChainPo
13
16
}
14
17
15
18
impl < ' b , B : DerefMut < Target =dyn BlockSource + ' b > + Sized + Sync + Send > Poll < ' b , B > for ChainPoller < ' b , B > {
16
-
17
19
fn poll_chain_tip < ' a > ( & ' a mut self , best_chain_tip : BlockHeaderData ) ->
18
20
AsyncBlockSourceResult < ' a , ( ChainTip , & ' a mut B :: Target ) >
19
21
where ' b : ' a {
@@ -59,7 +61,6 @@ impl<'a, B: DerefMut<Target=dyn BlockSource + 'a> + Sized + Sync + Send> Multipl
59
61
}
60
62
61
63
impl < ' b , B : DerefMut < Target =dyn BlockSource + ' b > + Sized + Sync + Send > Poll < ' b , B > for MultipleChainPoller < ' b , B > {
62
-
63
64
fn poll_chain_tip < ' a > ( & ' a mut self , best_chain_tip : BlockHeaderData ) ->
64
65
AsyncBlockSourceResult < ' a , ( ChainTip , & ' a mut B :: Target ) >
65
66
where ' b : ' a {
@@ -102,6 +103,144 @@ impl<'b, B: DerefMut<Target=dyn BlockSource + 'b> + Sized + Sync + Send> Poll<'b
102
103
}
103
104
}
104
105
106
+ pub struct ChainMultiplexer < ' b , B : DerefMut < Target =dyn BlockSource + ' b > + Sized + Sync + Send > {
107
+ block_sources : Vec < ( B , BlockSourceError ) > ,
108
+ backup_block_sources : Vec < ( B , BlockSourceError ) > ,
109
+ best_block_source : usize ,
110
+ }
111
+
112
+ impl < ' b , B : DerefMut < Target =dyn BlockSource + ' b > + Sized + Sync + Send > ChainMultiplexer < ' b , B > {
113
+ pub fn new ( mut block_sources : Vec < B > , mut backup_block_sources : Vec < B > ) -> Self {
114
+ assert ! ( !block_sources. is_empty( ) ) ;
115
+ let block_sources = block_sources. drain ( ..) . map ( |block_source| {
116
+ ( block_source, BlockSourceError :: Transient )
117
+ } ) . collect ( ) ;
118
+
119
+ let backup_block_sources = backup_block_sources. drain ( ..) . map ( |block_source| {
120
+ ( block_source, BlockSourceError :: Transient )
121
+ } ) . collect ( ) ;
122
+
123
+ Self { block_sources, backup_block_sources, best_block_source : 0 }
124
+ }
125
+
126
+ fn best_and_backup_block_sources ( & mut self ) -> Vec < & mut ( B , BlockSourceError ) > {
127
+ let best_block_source = self . block_sources . get_mut ( self . best_block_source ) . unwrap ( ) ;
128
+ let backup_block_sources = self . backup_block_sources . iter_mut ( ) ;
129
+ std:: iter:: once ( best_block_source)
130
+ . chain ( backup_block_sources)
131
+ . filter ( |( _, e) | e == & BlockSourceError :: Transient )
132
+ . collect ( )
133
+ }
134
+ }
135
+
136
+ impl < ' b , B : ' b + DerefMut < Target =dyn BlockSource + ' b > + Sized + Sync + Send > Poll < ' b , B > for ChainMultiplexer < ' b , B > {
137
+ fn poll_chain_tip < ' a > ( & ' a mut self , best_chain_tip : BlockHeaderData ) ->
138
+ AsyncBlockSourceResult < ' a , ( ChainTip , & ' a mut B :: Target ) >
139
+ where ' b : ' a {
140
+ Box :: pin ( async move {
141
+ let mut heaviest_chain_tip = best_chain_tip;
142
+ let mut best_result = Err ( BlockSourceError :: Persistent ) ;
143
+ for ( i, ( block_source, error) ) in self . block_sources . iter_mut ( ) . enumerate ( ) {
144
+ if let BlockSourceError :: Persistent = error {
145
+ continue ;
146
+ }
147
+
148
+ let result = match block_source. get_best_block ( ) . await {
149
+ Err ( e) => Err ( e) ,
150
+ Ok ( ( block_hash, height) ) => {
151
+ if block_hash == heaviest_chain_tip. header . block_hash ( ) {
152
+ Ok ( ChainTip :: Common )
153
+ } else {
154
+ match block_source. get_header ( & block_hash, height) . await {
155
+ Err ( e) => Err ( e) ,
156
+ Ok ( chain_tip) => {
157
+ crate :: stateless_check_header ( & chain_tip. header ) ?;
158
+ if chain_tip. header . block_hash ( ) != block_hash {
159
+ Err ( BlockSourceError :: Persistent )
160
+ } else if chain_tip. chainwork <= heaviest_chain_tip. chainwork {
161
+ Ok ( ChainTip :: Worse ( block_hash, chain_tip) )
162
+ } else {
163
+ Ok ( ChainTip :: Better ( block_hash, chain_tip) )
164
+ }
165
+ } ,
166
+ }
167
+ }
168
+ } ,
169
+ } ;
170
+
171
+ match result {
172
+ Err ( BlockSourceError :: Persistent ) => {
173
+ * error = BlockSourceError :: Persistent ;
174
+ } ,
175
+ Err ( BlockSourceError :: Transient ) => {
176
+ if best_result. is_err ( ) {
177
+ best_result = result;
178
+ }
179
+ } ,
180
+ Ok ( ChainTip :: Common ) => {
181
+ if let Ok ( ChainTip :: Better ( _, _) ) = best_result { } else {
182
+ best_result = result;
183
+ }
184
+ } ,
185
+ Ok ( ChainTip :: Better ( _, header) ) => {
186
+ self . best_block_source = i;
187
+ best_result = result;
188
+ heaviest_chain_tip = header;
189
+ } ,
190
+ Ok ( ChainTip :: Worse ( _, _) ) => {
191
+ if best_result. is_err ( ) {
192
+ best_result = result;
193
+ }
194
+ } ,
195
+ }
196
+ }
197
+
198
+ best_result. map ( move |chain_tip| ( chain_tip, self as & mut dyn BlockSource ) )
199
+ } )
200
+ }
201
+ }
202
+
203
+ impl < ' b , B : DerefMut < Target =dyn BlockSource + ' b > + Sized + Sync + Send > BlockSource for ChainMultiplexer < ' b , B > {
204
+ fn get_header < ' a > ( & ' a mut self , header_hash : & ' a BlockHash , height : Option < u32 > ) -> AsyncBlockSourceResult < ' a , BlockHeaderData > {
205
+ Box :: pin ( async move {
206
+ for ( block_source, error) in self . best_and_backup_block_sources ( ) {
207
+ let result = block_source. get_header ( header_hash, height) . await ;
208
+ match result {
209
+ Err ( e) => * error = e,
210
+ Ok ( _) => return result,
211
+ }
212
+ }
213
+ Err ( BlockSourceError :: Persistent )
214
+ } )
215
+ }
216
+
217
+ fn get_block < ' a > ( & ' a mut self , header_hash : & ' a BlockHash ) -> AsyncBlockSourceResult < ' a , Block > {
218
+ Box :: pin ( async move {
219
+ for ( block_source, error) in self . best_and_backup_block_sources ( ) {
220
+ let result = block_source. get_block ( header_hash) . await ;
221
+ match result {
222
+ Err ( e) => * error = e,
223
+ Ok ( _) => return result,
224
+ }
225
+ }
226
+ Err ( BlockSourceError :: Persistent )
227
+ } )
228
+ }
229
+
230
+ fn get_best_block < ' a > ( & ' a mut self ) -> AsyncBlockSourceResult < ' a , ( BlockHash , Option < u32 > ) > {
231
+ Box :: pin ( async move {
232
+ for ( block_source, error) in self . best_and_backup_block_sources ( ) {
233
+ let result = block_source. get_best_block ( ) . await ;
234
+ match result {
235
+ Err ( e) => * error = e,
236
+ Ok ( _) => return result,
237
+ }
238
+ }
239
+ Err ( BlockSourceError :: Persistent )
240
+ } )
241
+ }
242
+ }
243
+
105
244
#[ cfg( test) ]
106
245
mod tests {
107
246
use crate :: * ;
0 commit comments