@@ -16,16 +16,21 @@ use beacon_chain::{BeaconChain, BeaconChainTypes, BlockProcessStatus, EngineStat
16
16
use fnv:: FnvHashMap ;
17
17
use lighthouse_network:: rpc:: methods:: BlobsByRangeRequest ;
18
18
use lighthouse_network:: rpc:: { BlocksByRangeRequest , GoodbyeReason , RPCError } ;
19
- use lighthouse_network:: service:: api_types:: { AppRequestId , Id , SingleLookupReqId , SyncRequestId } ;
19
+ use lighthouse_network:: service:: api_types:: {
20
+ AppRequestId , DataColumnsByRootRequestId , Id , SingleLookupReqId , SyncRequestId ,
21
+ } ;
20
22
use lighthouse_network:: { Client , NetworkGlobals , PeerAction , PeerId , ReportSource , Request } ;
21
23
pub use requests:: LookupVerifyError ;
24
+ use requests:: { ActiveDataColumnsByRootRequest , DataColumnsByRootSingleBlockRequest } ;
22
25
use slog:: { debug, error, trace, warn} ;
23
26
use std:: collections:: hash_map:: Entry ;
24
27
use std:: sync:: Arc ;
25
28
use std:: time:: Duration ;
26
29
use tokio:: sync:: mpsc;
27
30
use types:: blob_sidecar:: FixedBlobSidecarList ;
28
- use types:: { BlobSidecar , DataColumnSidecarList , EthSpec , Hash256 , SignedBeaconBlock } ;
31
+ use types:: {
32
+ BlobSidecar , DataColumnSidecar , DataColumnSidecarList , EthSpec , Hash256 , SignedBeaconBlock ,
33
+ } ;
29
34
30
35
mod requests;
31
36
@@ -96,10 +101,10 @@ impl From<LookupVerifyError> for RpcResponseError {
96
101
/// Sequential ID that uniquely identifies ReqResp outgoing requests
97
102
pub type ReqId = u32 ;
98
103
99
- pub enum LookupRequestResult {
104
+ pub enum LookupRequestResult < I = ReqId > {
100
105
/// A request is sent. Sync MUST receive an event from the network in the future for either:
101
106
/// completed response or failed request
102
- RequestSent ( ReqId ) ,
107
+ RequestSent ( I ) ,
103
108
/// No request is sent, and no further action is necessary to consider this request completed
104
109
NoRequestNeeded ,
105
110
/// No request is sent, but the request is not completed. Sync MUST receive some future event
@@ -123,6 +128,10 @@ pub struct SyncNetworkContext<T: BeaconChainTypes> {
123
128
/// A mapping of active BlobsByRoot requests, including both current slot and parent lookups.
124
129
blobs_by_root_requests : FnvHashMap < SingleLookupReqId , ActiveBlobsByRootRequest < T :: EthSpec > > ,
125
130
131
+ /// A mapping of active DataColumnsByRoot requests
132
+ data_columns_by_root_requests :
133
+ FnvHashMap < DataColumnsByRootRequestId , ActiveDataColumnsByRootRequest < T :: EthSpec > > ,
134
+
126
135
/// BlocksByRange requests paired with BlobsByRange
127
136
range_blocks_and_blobs_requests :
128
137
FnvHashMap < Id , ( RangeRequestId , BlocksAndBlobsRequestInfo < T :: EthSpec > ) > ,
@@ -171,6 +180,7 @@ impl<T: BeaconChainTypes> SyncNetworkContext<T> {
171
180
request_id : 1 ,
172
181
blocks_by_root_requests : <_ >:: default ( ) ,
173
182
blobs_by_root_requests : <_ >:: default ( ) ,
183
+ data_columns_by_root_requests : <_ >:: default ( ) ,
174
184
range_blocks_and_blobs_requests : FnvHashMap :: default ( ) ,
175
185
network_beacon_processor,
176
186
chain,
@@ -211,10 +221,21 @@ impl<T: BeaconChainTypes> SyncNetworkContext<T> {
211
221
None
212
222
}
213
223
} ) ;
224
+ let failed_data_column_by_root_ids =
225
+ self . data_columns_by_root_requests
226
+ . iter ( )
227
+ . filter_map ( |( req_id, request) | {
228
+ if request. peer_id == * peer_id {
229
+ Some ( SyncRequestId :: DataColumnsByRoot ( * req_id, request. requester ) )
230
+ } else {
231
+ None
232
+ }
233
+ } ) ;
214
234
215
235
failed_range_ids
216
236
. chain ( failed_block_ids)
217
237
. chain ( failed_blob_ids)
238
+ . chain ( failed_data_column_by_root_ids)
218
239
. collect ( )
219
240
}
220
241
@@ -529,6 +550,43 @@ impl<T: BeaconChainTypes> SyncNetworkContext<T> {
529
550
Ok ( LookupRequestResult :: RequestSent ( req_id) )
530
551
}
531
552
553
+ /// Request to send a single `data_columns_by_root` request to the network.
554
+ pub fn data_column_lookup_request (
555
+ & mut self ,
556
+ requester : SingleLookupReqId ,
557
+ peer_id : PeerId ,
558
+ request : DataColumnsByRootSingleBlockRequest ,
559
+ ) -> Result < LookupRequestResult < DataColumnsByRootRequestId > , & ' static str > {
560
+ let req_id = DataColumnsByRootRequestId ( self . next_id ( ) ) ;
561
+ debug ! (
562
+ self . log,
563
+ "Sending DataColumnsByRoot Request" ;
564
+ "method" => "DataColumnsByRoot" ,
565
+ "block_root" => ?request. block_root,
566
+ "indices" => ?request. indices,
567
+ "peer" => %peer_id,
568
+ "requester" => ?requester,
569
+ "req_id" => %req_id,
570
+ ) ;
571
+
572
+ self . send_network_msg ( NetworkMessage :: SendRequest {
573
+ peer_id,
574
+ request : Request :: DataColumnsByRoot ( request. clone ( ) . into_request ( & self . chain . spec ) ) ,
575
+ request_id : AppRequestId :: Sync ( SyncRequestId :: DataColumnsByRoot ( req_id, requester) ) ,
576
+ } ) ?;
577
+
578
+ self . data_columns_by_root_requests . insert (
579
+ req_id,
580
+ ActiveDataColumnsByRootRequest :: new ( request, peer_id, requester) ,
581
+ ) ;
582
+
583
+ Ok ( LookupRequestResult :: RequestSent ( req_id) )
584
+ }
585
+
586
+ /// Request to fetch all needed custody columns of a specific block. This function may not send
587
+ /// any request to the network if no columns have to be fetched based on the import state of the
588
+ /// node. A custody request is a "super request" that may trigger 0 or more `data_columns_by_root`
589
+ /// requests.
532
590
pub fn custody_lookup_request (
533
591
& mut self ,
534
592
lookup_id : SingleLookupId ,
@@ -707,14 +765,14 @@ impl<T: BeaconChainTypes> SyncNetworkContext<T> {
707
765
& mut self ,
708
766
request_id : SingleLookupReqId ,
709
767
peer_id : PeerId ,
710
- block : RpcEvent < Arc < SignedBeaconBlock < T :: EthSpec > > > ,
768
+ rpc_event : RpcEvent < Arc < SignedBeaconBlock < T :: EthSpec > > > ,
711
769
) -> Option < RpcResponseResult < Arc < SignedBeaconBlock < T :: EthSpec > > > > {
712
770
let Entry :: Occupied ( mut request) = self . blocks_by_root_requests . entry ( request_id) else {
713
771
metrics:: inc_counter_vec ( & metrics:: SYNC_UNKNOWN_NETWORK_REQUESTS , & [ "blocks_by_root" ] ) ;
714
772
return None ;
715
773
} ;
716
774
717
- let resp = match block {
775
+ let resp = match rpc_event {
718
776
RpcEvent :: Response ( block, seen_timestamp) => {
719
777
match request. get_mut ( ) . add_response ( block) {
720
778
Ok ( block) => Ok ( ( block, seen_timestamp) ) ,
@@ -745,14 +803,14 @@ impl<T: BeaconChainTypes> SyncNetworkContext<T> {
745
803
& mut self ,
746
804
request_id : SingleLookupReqId ,
747
805
peer_id : PeerId ,
748
- blob : RpcEvent < Arc < BlobSidecar < T :: EthSpec > > > ,
806
+ rpc_event : RpcEvent < Arc < BlobSidecar < T :: EthSpec > > > ,
749
807
) -> Option < RpcResponseResult < FixedBlobSidecarList < T :: EthSpec > > > {
750
808
let Entry :: Occupied ( mut request) = self . blobs_by_root_requests . entry ( request_id) else {
751
809
metrics:: inc_counter_vec ( & metrics:: SYNC_UNKNOWN_NETWORK_REQUESTS , & [ "blobs_by_root" ] ) ;
752
810
return None ;
753
811
} ;
754
812
755
- let resp = match blob {
813
+ let resp = match rpc_event {
756
814
RpcEvent :: Response ( blob, seen_timestamp) => {
757
815
let request = request. get_mut ( ) ;
758
816
match request. add_response ( blob) {
@@ -791,6 +849,54 @@ impl<T: BeaconChainTypes> SyncNetworkContext<T> {
791
849
}
792
850
}
793
851
852
+ #[ allow( clippy:: type_complexity) ]
853
+ pub fn on_data_columns_by_root_response (
854
+ & mut self ,
855
+ id : DataColumnsByRootRequestId ,
856
+ peer_id : PeerId ,
857
+ rpc_event : RpcEvent < Arc < DataColumnSidecar < T :: EthSpec > > > ,
858
+ ) -> Option < RpcResponseResult < Vec < Arc < DataColumnSidecar < T :: EthSpec > > > > > {
859
+ let Entry :: Occupied ( mut request) = self . data_columns_by_root_requests . entry ( id) else {
860
+ return None ;
861
+ } ;
862
+
863
+ let resp = match rpc_event {
864
+ RpcEvent :: Response ( data_column, seen_timestamp) => {
865
+ let request = request. get_mut ( ) ;
866
+ match request. add_response ( data_column) {
867
+ Ok ( Some ( data_columns) ) => Ok ( ( data_columns, seen_timestamp) ) ,
868
+ Ok ( None ) => return None ,
869
+ Err ( e) => Err ( ( e. into ( ) , request. resolve ( ) ) ) ,
870
+ }
871
+ }
872
+ RpcEvent :: StreamTermination => match request. remove ( ) . terminate ( ) {
873
+ Ok ( _) => return None ,
874
+ // (err, false = not resolved) because terminate returns Ok() if resolved
875
+ Err ( e) => Err ( ( e. into ( ) , false ) ) ,
876
+ } ,
877
+ RpcEvent :: RPCError ( e) => Err ( ( e. into ( ) , request. remove ( ) . resolve ( ) ) ) ,
878
+ } ;
879
+
880
+ match resp {
881
+ Ok ( resp) => Some ( Ok ( resp) ) ,
882
+ // Track if this request has already returned some value downstream. Ensure that
883
+ // downstream code only receives a single Result per request. If the serving peer does
884
+ // multiple penalizable actions per request, downscore and return None. This allows to
885
+ // catch if a peer is returning more columns than requested or if the excess blobs are
886
+ // invalid.
887
+ Err ( ( e, resolved) ) => {
888
+ if let RpcResponseError :: VerifyError ( e) = & e {
889
+ self . report_peer ( peer_id, PeerAction :: LowToleranceError , e. into ( ) ) ;
890
+ }
891
+ if resolved {
892
+ None
893
+ } else {
894
+ Some ( Err ( e) )
895
+ }
896
+ }
897
+ }
898
+ }
899
+
794
900
pub fn send_block_for_processing (
795
901
& self ,
796
902
id : Id ,
@@ -900,7 +1006,7 @@ fn to_fixed_blob_sidecar_list<E: EthSpec>(
900
1006
let index = blob. index as usize ;
901
1007
* fixed_list
902
1008
. get_mut ( index)
903
- . ok_or ( LookupVerifyError :: UnrequestedBlobIndex ( index as u64 ) ) ? = Some ( blob)
1009
+ . ok_or ( LookupVerifyError :: UnrequestedIndex ( index as u64 ) ) ? = Some ( blob)
904
1010
}
905
1011
Ok ( fixed_list)
906
1012
}
0 commit comments