@@ -27,7 +27,7 @@ use celestia_types::nmt::Namespace;
27
27
use celestia_types:: row:: Row ;
28
28
use celestia_types:: sample:: Sample ;
29
29
use celestia_types:: { fraud_proof:: BadEncodingFraudProof , hash:: Hash } ;
30
- use celestia_types:: { ExtendedHeader , FraudProof , Height } ;
30
+ use celestia_types:: { ExtendedHeader , FraudProof } ;
31
31
use cid:: Cid ;
32
32
use futures:: StreamExt ;
33
33
use libp2p:: {
@@ -165,7 +165,6 @@ impl From<oneshot::error::RecvError> for P2pError {
165
165
#[ derive( Debug ) ]
166
166
pub struct P2p {
167
167
cmd_tx : mpsc:: Sender < P2pCmd > ,
168
- header_sub_watcher : watch:: Receiver < Option < ExtendedHeader > > ,
169
168
peer_tracker_info_watcher : watch:: Receiver < PeerTrackerInfo > ,
170
169
local_peer_id : PeerId ,
171
170
}
@@ -209,6 +208,8 @@ pub(crate) enum P2pCmd {
209
208
} ,
210
209
InitHeaderSub {
211
210
head : Box < ExtendedHeader > ,
211
+ /// Any valid headers received by header-sub will be send to this channel.
212
+ channel : mpsc:: Sender < ExtendedHeader > ,
212
213
} ,
213
214
SetPeerTrust {
214
215
peer_id : PeerId ,
@@ -221,6 +222,9 @@ pub(crate) enum P2pCmd {
221
222
GetNetworkCompromisedToken {
222
223
respond_to : oneshot:: Sender < CancellationToken > ,
223
224
} ,
225
+ GetNetworkHead {
226
+ respond_to : oneshot:: Sender < Option < ExtendedHeader > > ,
227
+ } ,
224
228
}
225
229
226
230
impl P2p {
@@ -234,21 +238,18 @@ impl P2p {
234
238
235
239
let local_peer_id = PeerId :: from ( args. local_keypair . public ( ) ) ;
236
240
237
- let ( cmd_tx, cmd_rx) = mpsc:: channel ( 16 ) ;
238
- let ( header_sub_tx, header_sub_rx) = watch:: channel ( None ) ;
239
-
240
241
let peer_tracker = Arc :: new ( PeerTracker :: new ( args. event_pub . clone ( ) ) ) ;
241
242
let peer_tracker_info_watcher = peer_tracker. info_watcher ( ) ;
242
243
243
- let mut worker = Worker :: new ( args, cmd_rx, header_sub_tx, peer_tracker) ?;
244
+ let ( cmd_tx, cmd_rx) = mpsc:: channel ( 16 ) ;
245
+ let mut worker = Worker :: new ( args, cmd_rx, peer_tracker) ?;
244
246
245
247
spawn ( async move {
246
248
worker. run ( ) . await ;
247
249
} ) ;
248
250
249
251
Ok ( P2p {
250
252
cmd_tx,
251
- header_sub_watcher : header_sub_rx,
252
253
peer_tracker_info_watcher,
253
254
local_peer_id,
254
255
} )
@@ -258,20 +259,18 @@ impl P2p {
258
259
#[ cfg( any( test, feature = "test-utils" ) ) ]
259
260
pub fn mocked ( ) -> ( Self , crate :: test_utils:: MockP2pHandle ) {
260
261
let ( cmd_tx, cmd_rx) = mpsc:: channel ( 16 ) ;
261
- let ( header_sub_tx, header_sub_rx) = watch:: channel ( None ) ;
262
262
let ( peer_tracker_tx, peer_tracker_rx) = watch:: channel ( PeerTrackerInfo :: default ( ) ) ;
263
263
264
264
let p2p = P2p {
265
265
cmd_tx : cmd_tx. clone ( ) ,
266
- header_sub_watcher : header_sub_rx,
267
266
peer_tracker_info_watcher : peer_tracker_rx,
268
267
local_peer_id : PeerId :: random ( ) ,
269
268
} ;
270
269
271
270
let handle = crate :: test_utils:: MockP2pHandle {
272
271
cmd_tx,
273
272
cmd_rx,
274
- header_sub_tx,
273
+ header_sub_tx : None ,
275
274
peer_tracker_tx,
276
275
} ;
277
276
@@ -296,11 +295,6 @@ impl P2p {
296
295
. map_err ( |_| P2pError :: WorkerDied )
297
296
}
298
297
299
- /// Watcher for the latest verified network head headers announced on `header-sub`.
300
- pub fn header_sub_watcher ( & self ) -> watch:: Receiver < Option < ExtendedHeader > > {
301
- self . header_sub_watcher . clone ( )
302
- }
303
-
304
298
/// Watcher for the current [`PeerTrackerInfo`].
305
299
pub fn peer_tracker_info_watcher ( & self ) -> watch:: Receiver < PeerTrackerInfo > {
306
300
self . peer_tracker_info_watcher . clone ( )
@@ -312,9 +306,14 @@ impl P2p {
312
306
}
313
307
314
308
/// Initializes `header-sub` protocol with a given `subjective_head`.
315
- pub async fn init_header_sub ( & self , head : ExtendedHeader ) -> Result < ( ) > {
309
+ pub async fn init_header_sub (
310
+ & self ,
311
+ head : ExtendedHeader ,
312
+ channel : mpsc:: Sender < ExtendedHeader > ,
313
+ ) -> Result < ( ) > {
316
314
self . send_command ( P2pCmd :: InitHeaderSub {
317
315
head : Box :: new ( head) ,
316
+ channel,
318
317
} )
319
318
. await
320
319
}
@@ -545,6 +544,16 @@ impl P2p {
545
544
546
545
Ok ( rx. await ?)
547
546
}
547
+
548
+ /// Get the latest header announced in the network.
549
+ pub async fn get_network_head ( & self ) -> Result < Option < ExtendedHeader > > {
550
+ let ( tx, rx) = oneshot:: channel ( ) ;
551
+
552
+ self . send_command ( P2pCmd :: GetNetworkHead { respond_to : tx } )
553
+ . await ?;
554
+
555
+ Ok ( rx. await ?)
556
+ }
548
557
}
549
558
550
559
/// Our network behaviour.
@@ -573,12 +582,17 @@ where
573
582
bad_encoding_fraud_sub_topic : TopicHash ,
574
583
cmd_rx : mpsc:: Receiver < P2pCmd > ,
575
584
peer_tracker : Arc < PeerTracker > ,
576
- header_sub_watcher : watch :: Sender < Option < ExtendedHeader > > ,
585
+ header_sub_state : Option < HeaderSubState > ,
577
586
bitswap_queries : HashMap < beetswap:: QueryId , OneshotResultSender < Vec < u8 > , P2pError > > ,
578
587
network_compromised_token : CancellationToken ,
579
588
store : Arc < S > ,
580
589
}
581
590
591
+ struct HeaderSubState {
592
+ known_head : ExtendedHeader ,
593
+ channel : mpsc:: Sender < ExtendedHeader > ,
594
+ }
595
+
582
596
impl < B , S > Worker < B , S >
583
597
where
584
598
B : Blockstore ,
@@ -587,7 +601,6 @@ where
587
601
fn new (
588
602
args : P2pArgs < B , S > ,
589
603
cmd_rx : mpsc:: Receiver < P2pCmd > ,
590
- header_sub_watcher : watch:: Sender < Option < ExtendedHeader > > ,
591
604
peer_tracker : Arc < PeerTracker > ,
592
605
) -> Result < Self , P2pError > {
593
606
let local_peer_id = PeerId :: from ( args. local_keypair . public ( ) ) ;
@@ -649,7 +662,7 @@ where
649
662
bad_encoding_fraud_sub_topic : bad_encoding_fraud_sub_topic. hash ( ) ,
650
663
header_sub_topic_hash : header_sub_topic. hash ( ) ,
651
664
peer_tracker,
652
- header_sub_watcher ,
665
+ header_sub_state : None ,
653
666
bitswap_queries : HashMap :: new ( ) ,
654
667
network_compromised_token : CancellationToken :: new ( ) ,
655
668
store : args. store ,
@@ -771,8 +784,8 @@ where
771
784
P2pCmd :: ConnectedPeers { respond_to } => {
772
785
respond_to. maybe_send ( self . peer_tracker . connected_peers ( ) ) ;
773
786
}
774
- P2pCmd :: InitHeaderSub { head } => {
775
- self . on_init_header_sub ( * head) ;
787
+ P2pCmd :: InitHeaderSub { head, channel } => {
788
+ self . on_init_header_sub ( * head, channel ) ;
776
789
}
777
790
P2pCmd :: SetPeerTrust {
778
791
peer_id,
@@ -786,7 +799,14 @@ where
786
799
self . on_get_shwap_cid ( cid, respond_to) ;
787
800
}
788
801
P2pCmd :: GetNetworkCompromisedToken { respond_to } => {
789
- respond_to. maybe_send ( self . network_compromised_token . child_token ( ) )
802
+ respond_to. maybe_send ( self . network_compromised_token . child_token ( ) ) ;
803
+ }
804
+ P2pCmd :: GetNetworkHead { respond_to } => {
805
+ let head = self
806
+ . header_sub_state
807
+ . as_ref ( )
808
+ . map ( |state| state. known_head . clone ( ) ) ;
809
+ respond_to. maybe_send ( head) ;
790
810
}
791
811
}
792
812
@@ -836,7 +856,7 @@ where
836
856
} ;
837
857
838
858
let acceptance = if message. topic == self . header_sub_topic_hash {
839
- self . on_header_sub_message ( & message. data [ ..] ) . await
859
+ self . on_header_sub_message ( & message. data [ ..] )
840
860
} else if message. topic == self . bad_encoding_fraud_sub_topic {
841
861
self . on_bad_encoding_fraud_sub_message ( & message. data [ ..] , & peer)
842
862
. await
@@ -961,41 +981,41 @@ where
961
981
}
962
982
963
983
#[ instrument( skip_all, fields( header = %head) ) ]
964
- fn on_init_header_sub ( & mut self , head : ExtendedHeader ) {
965
- self . header_sub_watcher . send_replace ( Some ( head) ) ;
984
+ fn on_init_header_sub ( & mut self , head : ExtendedHeader , channel : mpsc:: Sender < ExtendedHeader > ) {
985
+ self . header_sub_state = Some ( HeaderSubState {
986
+ known_head : head,
987
+ channel,
988
+ } ) ;
966
989
trace ! ( "HeaderSub initialized" ) ;
967
990
}
968
991
969
992
#[ instrument( skip_all) ]
970
- async fn on_header_sub_message ( & mut self , data : & [ u8 ] ) -> gossipsub:: MessageAcceptance {
993
+ fn on_header_sub_message ( & mut self , data : & [ u8 ] ) -> gossipsub:: MessageAcceptance {
971
994
let Ok ( header) = ExtendedHeader :: decode_and_validate ( data) else {
972
995
trace ! ( "Malformed or invalid header from header-sub" ) ;
973
996
return gossipsub:: MessageAcceptance :: Reject ;
974
997
} ;
975
998
976
999
trace ! ( "Received header from header-sub ({header})" ) ;
977
1000
978
- let updated = self . header_sub_watcher . send_if_modified ( move |state| {
979
- let Some ( known_header) = state else {
980
- debug ! ( "HeaderSub not initialized yet" ) ;
981
- return false ;
982
- } ;
1001
+ let Some ( ref mut state) = self . header_sub_state else {
1002
+ debug ! ( "header-sub not initialized yet" ) ;
1003
+ return gossipsub:: MessageAcceptance :: Ignore ;
1004
+ } ;
983
1005
984
- if known_header . verify ( & header) . is_err ( ) {
985
- trace ! ( "Failed to verify HeaderSub header. Ignoring {header}" ) ;
986
- return false ;
987
- }
1006
+ if state . known_head . verify ( & header) . is_err ( ) {
1007
+ trace ! ( "Failed to verify HeaderSub header. Ignoring {header}" ) ;
1008
+ return gossipsub :: MessageAcceptance :: Ignore ;
1009
+ }
988
1010
989
- debug ! ( "New header from header-sub ({header})" ) ;
990
- * state = Some ( header) ;
991
- true
992
- } ) ;
1011
+ trace ! ( "New header from header-sub ({header})" ) ;
993
1012
994
- if updated {
995
- gossipsub:: MessageAcceptance :: Accept
996
- } else {
997
- gossipsub:: MessageAcceptance :: Ignore
998
- }
1013
+ state. known_head = header. clone ( ) ;
1014
+ // We intentionally do not `send().await` to avoid blocking `P2p`
1015
+ // in case `Syncer` enters some weird state.
1016
+ let _ = state. channel . try_send ( header) ;
1017
+
1018
+ gossipsub:: MessageAcceptance :: Accept
999
1019
}
1000
1020
1001
1021
#[ instrument( skip_all) ]
@@ -1011,15 +1031,15 @@ where
1011
1031
} ;
1012
1032
1013
1033
let height = befp. height ( ) . value ( ) ;
1014
- let current_height =
1015
- if let Some ( network_height ) = network_head_height ( & self . header_sub_watcher ) {
1016
- network_height . value ( )
1017
- } else if let Ok ( local_head) = self . store . get_head ( ) . await {
1018
- local_head. height ( ) . value ( )
1019
- } else {
1020
- // we aren't tracking the network and have uninitialized store
1021
- return gossipsub:: MessageAcceptance :: Ignore ;
1022
- } ;
1034
+
1035
+ let current_height = if let Some ( ref header_sub_state ) = self . header_sub_state {
1036
+ header_sub_state . known_head . height ( ) . value ( )
1037
+ } else if let Ok ( local_head) = self . store . get_head ( ) . await {
1038
+ local_head. height ( ) . value ( )
1039
+ } else {
1040
+ // we aren't tracking the network and have uninitialized store
1041
+ return gossipsub:: MessageAcceptance :: Ignore ;
1042
+ } ;
1023
1043
1024
1044
if height > current_height + FRAUD_PROOF_HEAD_HEIGHT_THRESHOLD {
1025
1045
// does this threshold make any sense if we're gonna ignore it anyway
@@ -1156,7 +1176,3 @@ where
1156
1176
. client_set_send_dont_have ( false )
1157
1177
. build ( ) )
1158
1178
}
1159
-
1160
- fn network_head_height ( watcher : & watch:: Sender < Option < ExtendedHeader > > ) -> Option < Height > {
1161
- watcher. borrow ( ) . as_ref ( ) . map ( |header| header. height ( ) )
1162
- }
0 commit comments