@@ -4,7 +4,7 @@ use crate::sync::network_context::{
4
4
LookupRequestResult , PeerGroup , ReqId , RpcRequestSendError , SendErrorProcessor ,
5
5
SyncNetworkContext ,
6
6
} ;
7
- use beacon_chain:: BeaconChainTypes ;
7
+ use beacon_chain:: { BeaconChainTypes , BlockProcessStatus } ;
8
8
use derivative:: Derivative ;
9
9
use lighthouse_network:: service:: api_types:: Id ;
10
10
use rand:: seq:: IteratorRandom ;
@@ -62,8 +62,7 @@ pub enum LookupRequestError {
62
62
pub struct SingleBlockLookup < T : BeaconChainTypes > {
63
63
pub id : Id ,
64
64
pub block_request_state : BlockRequestState < T :: EthSpec > ,
65
- pub blob_request_state : BlobRequestState < T :: EthSpec > ,
66
- pub custody_request_state : CustodyRequestState < T :: EthSpec > ,
65
+ pub component_requests : ComponentRequests < T :: EthSpec > ,
67
66
/// Peers that claim to have imported this set of block components
68
67
#[ derivative( Debug ( format_with = "fmt_peer_set_as_len" ) ) ]
69
68
peers : HashSet < PeerId > ,
@@ -72,6 +71,16 @@ pub struct SingleBlockLookup<T: BeaconChainTypes> {
72
71
created : Instant ,
73
72
}
74
73
74
+ #[ derive( Debug ) ]
75
+ pub ( crate ) enum ComponentRequests < E : EthSpec > {
76
+ WaitingForBlock ,
77
+ ActiveBlobRequest ( BlobRequestState < E > , usize ) ,
78
+ ActiveCustodyRequest ( CustodyRequestState < E > ) ,
79
+ // When printing in debug this state display the reason why it's not needed
80
+ #[ allow( dead_code) ]
81
+ NotNeeded ( & ' static str ) ,
82
+ }
83
+
75
84
impl < T : BeaconChainTypes > SingleBlockLookup < T > {
76
85
pub fn new (
77
86
requested_block_root : Hash256 ,
@@ -82,8 +91,7 @@ impl<T: BeaconChainTypes> SingleBlockLookup<T> {
82
91
Self {
83
92
id,
84
93
block_request_state : BlockRequestState :: new ( requested_block_root) ,
85
- blob_request_state : BlobRequestState :: new ( requested_block_root) ,
86
- custody_request_state : CustodyRequestState :: new ( requested_block_root) ,
94
+ component_requests : ComponentRequests :: WaitingForBlock ,
87
95
peers : HashSet :: from_iter ( peers. iter ( ) . copied ( ) ) ,
88
96
block_root : requested_block_root,
89
97
awaiting_parent,
@@ -150,16 +158,28 @@ impl<T: BeaconChainTypes> SingleBlockLookup<T> {
150
158
/// Returns true if the block has already been downloaded.
151
159
pub fn all_components_processed ( & self ) -> bool {
152
160
self . block_request_state . state . is_processed ( )
153
- && self . blob_request_state . state . is_processed ( )
154
- && self . custody_request_state . state . is_processed ( )
161
+ && match & self . component_requests {
162
+ ComponentRequests :: WaitingForBlock => false ,
163
+ ComponentRequests :: ActiveBlobRequest ( request, _) => request. state . is_processed ( ) ,
164
+ ComponentRequests :: ActiveCustodyRequest ( request) => request. state . is_processed ( ) ,
165
+ ComponentRequests :: NotNeeded { .. } => true ,
166
+ }
155
167
}
156
168
157
169
/// Returns true if this request is expecting some event to make progress
158
170
pub fn is_awaiting_event ( & self ) -> bool {
159
171
self . awaiting_parent . is_some ( )
160
172
|| self . block_request_state . state . is_awaiting_event ( )
161
- || self . blob_request_state . state . is_awaiting_event ( )
162
- || self . custody_request_state . state . is_awaiting_event ( )
173
+ || match & self . component_requests {
174
+ ComponentRequests :: WaitingForBlock => true ,
175
+ ComponentRequests :: ActiveBlobRequest ( request, _) => {
176
+ request. state . is_awaiting_event ( )
177
+ }
178
+ ComponentRequests :: ActiveCustodyRequest ( request) => {
179
+ request. state . is_awaiting_event ( )
180
+ }
181
+ ComponentRequests :: NotNeeded { .. } => false ,
182
+ }
163
183
}
164
184
165
185
/// Makes progress on all requests of this lookup. Any error is not recoverable and must result
@@ -169,9 +189,66 @@ impl<T: BeaconChainTypes> SingleBlockLookup<T> {
169
189
cx : & mut SyncNetworkContext < T > ,
170
190
) -> Result < LookupResult , LookupRequestError > {
171
191
// TODO: Check what's necessary to download, specially for blobs
172
- self . continue_request :: < BlockRequestState < T :: EthSpec > > ( cx) ?;
173
- self . continue_request :: < BlobRequestState < T :: EthSpec > > ( cx) ?;
174
- self . continue_request :: < CustodyRequestState < T :: EthSpec > > ( cx) ?;
192
+ self . continue_request :: < BlockRequestState < T :: EthSpec > > ( cx, 0 ) ?;
193
+
194
+ if let ComponentRequests :: WaitingForBlock = self . component_requests {
195
+ let downloaded_block = self
196
+ . block_request_state
197
+ . state
198
+ . peek_downloaded_data ( )
199
+ . cloned ( ) ;
200
+
201
+ if let Some ( block) = downloaded_block. or_else ( || {
202
+ // If the block is already being processed or fully validated, retrieve how many blobs
203
+ // it expects. Consider any stage of the block. If the block root has been validated, we
204
+ // can assert that this is the correct value of `blob_kzg_commitments_count`.
205
+ match cx. chain . get_block_process_status ( & self . block_root ) {
206
+ BlockProcessStatus :: Unknown => None ,
207
+ BlockProcessStatus :: NotValidated ( block)
208
+ | BlockProcessStatus :: ExecutionValidated ( block) => Some ( block. clone ( ) ) ,
209
+ }
210
+ } ) {
211
+ let expected_blobs = block. num_expected_blobs ( ) ;
212
+ let block_epoch = block. slot ( ) . epoch ( T :: EthSpec :: slots_per_epoch ( ) ) ;
213
+ if expected_blobs == 0 {
214
+ self . component_requests = ComponentRequests :: NotNeeded ( "no data" ) ;
215
+ }
216
+ if cx. chain . should_fetch_blobs ( block_epoch) {
217
+ self . component_requests = ComponentRequests :: ActiveBlobRequest (
218
+ BlobRequestState :: new ( self . block_root ) ,
219
+ expected_blobs,
220
+ ) ;
221
+ } else if cx. chain . should_fetch_custody_columns ( block_epoch) {
222
+ self . component_requests = ComponentRequests :: ActiveCustodyRequest (
223
+ CustodyRequestState :: new ( self . block_root ) ,
224
+ ) ;
225
+ } else {
226
+ self . component_requests = ComponentRequests :: NotNeeded ( "outside da window" ) ;
227
+ }
228
+ } else {
229
+ // Wait to download the block before downloading blobs. Then we can be sure that the
230
+ // block has data, so there's no need to do "blind" requests for all possible blobs and
231
+ // latter handle the case where if the peer sent no blobs, penalize.
232
+ //
233
+ // Lookup sync event safety: Reaching this code means that a block is not in any pre-import
234
+ // cache nor in the request state of this lookup. Therefore, the block must either: (1) not
235
+ // be downloaded yet or (2) the block is already imported into the fork-choice.
236
+ // In case (1) the lookup must either successfully download the block or get dropped.
237
+ // In case (2) the block will be downloaded, processed, reach `DuplicateFullyImported`
238
+ // and get dropped as completed.
239
+ }
240
+ }
241
+
242
+ match & self . component_requests {
243
+ ComponentRequests :: WaitingForBlock => { } // do nothing
244
+ ComponentRequests :: ActiveBlobRequest ( _, expected_blobs) => {
245
+ self . continue_request :: < BlobRequestState < T :: EthSpec > > ( cx, * expected_blobs) ?
246
+ }
247
+ ComponentRequests :: ActiveCustodyRequest ( _) => {
248
+ self . continue_request :: < CustodyRequestState < T :: EthSpec > > ( cx, 0 ) ?
249
+ }
250
+ ComponentRequests :: NotNeeded { .. } => { } // do nothing
251
+ }
175
252
176
253
// If all components of this lookup are already processed, there will be no future events
177
254
// that can make progress so it must be dropped. Consider the lookup completed.
@@ -187,15 +264,12 @@ impl<T: BeaconChainTypes> SingleBlockLookup<T> {
187
264
fn continue_request < R : RequestState < T > > (
188
265
& mut self ,
189
266
cx : & mut SyncNetworkContext < T > ,
267
+ expected_blobs : usize ,
190
268
) -> Result < ( ) , LookupRequestError > {
191
269
let id = self . id ;
192
270
let awaiting_parent = self . awaiting_parent . is_some ( ) ;
193
- let downloaded_block = self
194
- . block_request_state
195
- . state
196
- . peek_downloaded_data ( )
197
- . cloned ( ) ;
198
- let request = R :: request_state_mut ( self ) ;
271
+ let request =
272
+ R :: request_state_mut ( self ) . map_err ( |e| LookupRequestError :: BadState ( e. to_owned ( ) ) ) ?;
199
273
200
274
// Attempt to progress awaiting downloads
201
275
if request. get_state ( ) . is_awaiting_download ( ) {
@@ -214,13 +288,16 @@ impl<T: BeaconChainTypes> SingleBlockLookup<T> {
214
288
// not receive any new peers for some time it will be dropped. If it receives a new
215
289
// peer it must attempt to make progress.
216
290
R :: request_state_mut ( self )
291
+ . map_err ( |e| LookupRequestError :: BadState ( e. to_owned ( ) ) ) ?
217
292
. get_state_mut ( )
218
293
. update_awaiting_download_status ( "no peers" ) ;
219
294
return Ok ( ( ) ) ;
220
295
} ;
221
296
222
- let request = R :: request_state_mut ( self ) ;
223
- match request. make_request ( id, peer_id, downloaded_block, cx) ? {
297
+ let request = R :: request_state_mut ( self )
298
+ . map_err ( |e| LookupRequestError :: BadState ( e. to_owned ( ) ) ) ?;
299
+
300
+ match request. make_request ( id, peer_id, expected_blobs, cx) ? {
224
301
LookupRequestResult :: RequestSent ( req_id) => {
225
302
// Lookup sync event safety: If make_request returns `RequestSent`, we are
226
303
// guaranteed that `BlockLookups::on_download_response` will be called exactly
0 commit comments