@@ -10,7 +10,7 @@ use std::{
10
10
collections:: hash_map:: Entry , collections:: HashMap , marker:: PhantomData , sync:: Arc ,
11
11
time:: Duration ,
12
12
} ;
13
- use types:: { data_column_sidecar:: ColumnIndex , DataColumnSidecar , Hash256 , Slot } ;
13
+ use types:: { data_column_sidecar:: ColumnIndex , DataColumnSidecar , EthSpec , Hash256 , Slot } ;
14
14
15
15
pub type SamplingResult = Result < ( ) , SamplingError > ;
16
16
@@ -48,6 +48,12 @@ impl<T: BeaconChainTypes> Sampling<T> {
48
48
self . requests . values ( ) . map ( |r| r. block_root ) . collect ( )
49
49
}
50
50
51
+ /// Create a new sampling request for a known block
52
+ ///
53
+ /// ### Returns
54
+ ///
55
+ /// - `Some`: Request completed, won't make more progress. Expect requester to act on the result.
56
+ /// - `None`: Request still active, requester should do no action
51
57
pub fn on_new_sample_request (
52
58
& mut self ,
53
59
block_root : Hash256 ,
@@ -81,6 +87,13 @@ impl<T: BeaconChainTypes> Sampling<T> {
81
87
. map ( |result| ( requester, result) )
82
88
}
83
89
90
+ /// Insert a downloaded column into an active sampling request. Then make progress on the
91
+ /// entire request.
92
+ ///
93
+ /// ### Returns
94
+ ///
95
+ /// - `Some`: Request completed, won't make more progress. Expect requester to act on the result.
96
+ /// - `None`: Request still active, requester should do no action
84
97
pub fn on_sample_downloaded (
85
98
& mut self ,
86
99
id : SamplingId ,
@@ -98,6 +111,13 @@ impl<T: BeaconChainTypes> Sampling<T> {
98
111
self . handle_sampling_result ( result, & id. id )
99
112
}
100
113
114
+ /// Insert a downloaded column into an active sampling request. Then make progress on the
115
+ /// entire request.
116
+ ///
117
+ /// ### Returns
118
+ ///
119
+ /// - `Some`: Request completed, won't make more progress. Expect requester to act on the result.
120
+ /// - `None`: Request still active, requester should do no action
101
121
pub fn on_sample_verified (
102
122
& mut self ,
103
123
id : SamplingId ,
@@ -114,14 +134,17 @@ impl<T: BeaconChainTypes> Sampling<T> {
114
134
self . handle_sampling_result ( result, & id. id )
115
135
}
116
136
137
+ /// Converts a result from the internal format of `ActiveSamplingRequest` (error first to use ?
138
+ /// conveniently), to an Option first format to use an `if let Some() { act on result }` pattern
139
+ /// in the sync manager.
117
140
fn handle_sampling_result (
118
141
& mut self ,
119
142
result : Result < Option < ( ) > , SamplingError > ,
120
143
id : & SamplingRequester ,
121
144
) -> Option < SamplingResult > {
122
145
let result = result. transpose ( ) ;
123
146
if result. is_some ( ) {
124
- debug ! ( self . log, "Removed sampling request" ; "id" => ?id) ;
147
+ debug ! ( self . log, "Remove completed sampling request" ; "id" => ?id, "result" => ?result ) ;
125
148
self . requests . remove ( id) ;
126
149
}
127
150
result
@@ -146,6 +169,7 @@ pub enum SamplingError {
146
169
ProcessorUnavailable ,
147
170
TooManyFailures ,
148
171
BadState ( String ) ,
172
+ ColumnIndexOutOfBounds ,
149
173
}
150
174
151
175
/// Required success index by current failures, with p_target=5.00E-06
@@ -170,7 +194,8 @@ impl<T: BeaconChainTypes> ActiveSamplingRequest<T> {
170
194
log : slog:: Logger ,
171
195
) -> Self {
172
196
// Select ahead of time the full list of to-sample columns
173
- let mut column_shuffle = ( 0 ..64 ) . collect :: < Vec < ColumnIndex > > ( ) ;
197
+ let mut column_shuffle = ( 0 ..<T :: EthSpec as EthSpec >:: number_of_columns ( ) as ColumnIndex )
198
+ . collect :: < Vec < ColumnIndex > > ( ) ;
174
199
let mut rng = thread_rng ( ) ;
175
200
column_shuffle. shuffle ( & mut rng) ;
176
201
@@ -189,9 +214,15 @@ impl<T: BeaconChainTypes> ActiveSamplingRequest<T> {
189
214
}
190
215
}
191
216
192
- // TODO: When is a fork and only a subset of your peers know about a block, sampling should only
193
- // be queried on the peers on that fork. Should this case be handled? How to handle it?
194
- fn on_sample_downloaded (
217
+ /// Insert a downloaded column into an active sampling request. Then make progress on the
218
+ /// entire request.
219
+ ///
220
+ /// ### Returns
221
+ ///
222
+ /// - `Err`: Sampling request has failed and will be dropped
223
+ /// - `Ok(Some)`: Sampling request has successfully completed and will be dropped
224
+ /// - `Ok(None)`: Sampling request still active
225
+ pub ( crate ) fn on_sample_downloaded (
195
226
& mut self ,
196
227
_peer_id : PeerId ,
197
228
column_index : ColumnIndex ,
@@ -258,6 +289,14 @@ impl<T: BeaconChainTypes> ActiveSamplingRequest<T> {
258
289
self . continue_sampling ( cx)
259
290
}
260
291
292
+ /// Insert a column verification result into an active sampling request. Then make progress
293
+ /// on the entire request.
294
+ ///
295
+ /// ### Returns
296
+ ///
297
+ /// - `Err`: Sampling request has failed and will be dropped
298
+ /// - `Ok(Some)`: Sampling request has successfully completed and will be dropped
299
+ /// - `Ok(None)`: Sampling request still active
261
300
pub ( crate ) fn on_sample_verified (
262
301
& mut self ,
263
302
column_index : ColumnIndex ,
@@ -301,7 +340,7 @@ impl<T: BeaconChainTypes> ActiveSamplingRequest<T> {
301
340
self . continue_sampling ( cx)
302
341
}
303
342
304
- fn continue_sampling (
343
+ pub ( crate ) fn continue_sampling (
305
344
& mut self ,
306
345
cx : & mut SyncNetworkContext < T > ,
307
346
) -> Result < Option < ( ) > , SamplingError > {
@@ -337,8 +376,11 @@ impl<T: BeaconChainTypes> ActiveSamplingRequest<T> {
337
376
// First, attempt to progress sampling by requesting more columns, so that request failures
338
377
// are accounted for below.
339
378
for idx in 0 ..* required_successes {
340
- // Re-request columns
341
- let column_index = self . column_shuffle [ idx] ;
379
+ // Re-request columns. Note: out of bounds error should never happen, inputs are hardcoded
380
+ let column_index = * self
381
+ . column_shuffle
382
+ . get ( idx)
383
+ . ok_or ( SamplingError :: ColumnIndexOutOfBounds ) ?;
342
384
let request = self
343
385
. column_requests
344
386
. entry ( column_index)
@@ -431,6 +473,8 @@ mod request {
431
473
Status :: Verified => return Ok ( false ) , // Already completed
432
474
}
433
475
476
+ // TODO: When is a fork and only a subset of your peers know about a block, sampling should only
477
+ // be queried on the peers on that fork. Should this case be handled? How to handle it?
434
478
let peer_ids = cx. get_custodial_peers (
435
479
block_slot. epoch ( <T :: EthSpec as EthSpec >:: slots_per_epoch ( ) ) ,
436
480
self . column_index ,
0 commit comments