1#[cfg(all(test, not(all(miri, target_feature = "sha3"))))]
6mod tests;
7
8use ab_archiving::archiver::NewArchivedSegment;
9use ab_client_api::{BeaconChainInfo, ChainSyncStatus};
10use ab_client_archiving::recreate::{
11 RecreateSegmentError, RecreateSegmentSuperSegmentDetails, recreate_genesis_segment,
12 recreate_segment,
13};
14use ab_client_block_authoring::slot_worker::{
15 BlockSealNotification, NewSlotInfo, NewSlotNotification,
16};
17use ab_client_consensus_common::ConsensusConstants;
18use ab_core_primitives::block::header::OwnedBlockHeaderSeal;
19use ab_core_primitives::block::owned::OwnedBeaconChainBlock;
20use ab_core_primitives::hashes::Blake3Hash;
21use ab_core_primitives::pieces::{Piece, PieceIndex};
22use ab_core_primitives::pot::SlotNumber;
23use ab_core_primitives::segments::{
24 HistorySize, LocalSegmentIndex, SegmentIndex, SuperSegment, SuperSegmentHeader,
25 SuperSegmentIndex, SuperSegmentRoot,
26};
27use ab_core_primitives::shard::ShardIndex;
28use ab_core_primitives::solutions::Solution;
29use ab_erasure_coding::ErasureCoding;
30use ab_farmer_components::FarmerProtocolInfo;
31use ab_farmer_rpc_primitives::{
32 BlockSealInfo, BlockSealResponse, FarmerAppInfo, FarmerShardMembershipInfo,
33 MAX_SUPER_SEGMENT_HEADERS_PER_REQUEST, SHARD_MEMBERSHIP_EXPIRATION, SlotInfo, SolutionResponse,
34};
35use ab_networking::libp2p::Multiaddr;
36use async_lock::Mutex as AsyncMutex;
37use futures::channel::{mpsc, oneshot};
38use futures::{FutureExt, SinkExt, StreamExt, select};
39use jsonrpsee::core::{SubscriptionResult, async_trait};
40use jsonrpsee::proc_macros::rpc;
41use jsonrpsee::server::{Server, ServerConfig};
42use jsonrpsee::tokio::task::{JoinError, spawn_blocking};
43use jsonrpsee::tokio::time::MissedTickBehavior;
44use jsonrpsee::types::{ErrorObject, ErrorObjectOwned};
45use jsonrpsee::{
46 ConnectionId, Extensions, PendingSubscriptionSink, SubscriptionSink, TrySendError,
47};
48use parking_lot::Mutex;
49use schnellru::{ByLength, LruMap};
50use std::collections::{HashMap, VecDeque};
51use std::io;
52use std::net::SocketAddr;
53use std::time::{Duration, Instant};
54use tracing::{error, info, warn};
55use triomphe::Arc;
56
57const CACHED_SUPER_SEGMENTS_CAPACITY: usize = 5;
58const CACHED_ARCHIVED_SEGMENT_TIMEOUT: Duration = Duration::from_mins(1);
59
60#[derive(Debug, thiserror::Error)]
62pub enum FarmerRpcApiError {
63 #[error("Solution was ignored for slot {slot}")]
65 SolutionWasIgnored {
66 slot: SlotNumber,
68 },
69 #[error(
71 "Super segment headers length exceeded the limit: \
72 {actual}/{MAX_SUPER_SEGMENT_HEADERS_PER_REQUEST}"
73 )]
74 SuperSegmentHeadersLengthExceeded {
75 actual: usize,
77 },
78 #[error("Failed to recreate segment: {0}")]
80 FailedToRecreateSegment(#[from] RecreateSegmentError),
81 #[error("Blocking task join error: {0}")]
83 BlockingTaskJoinError(#[from] JoinError),
84 #[error(
86 "Invalid block seal for pre-seal hash {pre_seal_hash} and public key hash \
87 {public_key_hash}"
88 )]
89 InvalidBlockSeal {
90 pre_seal_hash: Blake3Hash,
92 public_key_hash: Blake3Hash,
94 },
95}
96
97impl From<FarmerRpcApiError> for ErrorObjectOwned {
98 fn from(error: FarmerRpcApiError) -> Self {
99 #[expect(
100 clippy::rest_pattern_accessible_field,
101 reason = "Only extracting error code"
102 )]
103 let code = match &error {
104 FarmerRpcApiError::SolutionWasIgnored { .. } => 0,
105 FarmerRpcApiError::SuperSegmentHeadersLengthExceeded { .. } => 1,
106 FarmerRpcApiError::FailedToRecreateSegment(_) => 2,
107 FarmerRpcApiError::BlockingTaskJoinError(_) => 3,
108 FarmerRpcApiError::InvalidBlockSeal { .. } => 4,
109 };
110
111 ErrorObject::owned(code, error.to_string(), None::<()>)
112 }
113}
114
115#[rpc(server)]
117pub trait FarmerRpcApi {
118 #[method(name = "getFarmerAppInfo")]
120 fn get_farmer_app_info(&self) -> Result<FarmerAppInfo, FarmerRpcApiError>;
121
122 #[method(name = "submitSolutionResponse")]
123 fn submit_solution_response(
124 &self,
125 solution_response: SolutionResponse,
126 ) -> Result<(), FarmerRpcApiError>;
127
128 #[subscription(
130 name = "subscribeSlotInfo" => "slot_info",
131 unsubscribe = "unsubscribeSlotInfo",
132 item = SlotInfo,
133 )]
134 async fn subscribe_slot_info(&self) -> SubscriptionResult;
135
136 #[subscription(
138 name = "subscribeBlockSealing" => "block_seal",
139 unsubscribe = "unsubscribeBlockSealing",
140 item = BlockSealInfo,
141 )]
142 async fn subscribe_block_seal(&self) -> SubscriptionResult;
143
144 #[method(name = "submitBlockSeal")]
145 fn submit_block_seal(&self, block_seal: BlockSealResponse) -> Result<(), FarmerRpcApiError>;
146
147 #[subscription(
149 name = "subscribeNewSuperSegmentHeader" => "new_super_segment_header",
150 unsubscribe = "unsubscribeNewSuperSegmentHeader",
151 item = SuperSegmentHeader,
152 )]
153 async fn subscribe_new_super_segment_header(&self) -> SubscriptionResult;
154
155 #[method(name = "superSegmentHeaders")]
156 async fn super_segment_headers(
157 &self,
158 super_segment_indices: Vec<SuperSegmentIndex>,
159 ) -> Result<Vec<Option<SuperSegmentHeader>>, FarmerRpcApiError>;
160
161 #[method(name = "lastSuperSegmentHeaders")]
162 async fn last_super_segment_headers(
163 &self,
164 limit: u32,
165 ) -> Result<Vec<Option<SuperSegmentHeader>>, FarmerRpcApiError>;
166
167 #[method(name = "superSegmentRootForSegmentIndex")]
168 async fn super_segment_root_for_segment_index(
169 &self,
170 segment_index: SegmentIndex,
171 ) -> Result<Option<SuperSegmentRoot>, FarmerRpcApiError>;
172
173 #[method(name = "piece")]
174 async fn piece(&self, piece_index: PieceIndex) -> Result<Option<Piece>, FarmerRpcApiError>;
175
176 #[method(name = "updateShardMembershipInfo", with_extensions)]
177 async fn update_shard_membership_info(
178 &self,
179 info: Vec<FarmerShardMembershipInfo>,
180 ) -> Result<(), FarmerRpcApiError>;
181}
182
183#[derive(Debug, Default)]
184struct BlockSignatureSenders {
185 current_pre_seal_hash: Blake3Hash,
186 current_public_key_hash: Blake3Hash,
188 senders: Vec<oneshot::Sender<OwnedBlockHeaderSeal>>,
189}
190
191impl BlockSignatureSenders {
192 fn submit_seal(&mut self, block_seal: BlockSealResponse) -> Result<(), FarmerRpcApiError> {
197 let BlockSealResponse {
198 pre_seal_hash,
199 seal,
200 } = block_seal;
201
202 if self.current_pre_seal_hash != pre_seal_hash {
203 warn!(
204 %pre_seal_hash,
205 current_pre_seal_hash = %self.current_pre_seal_hash,
206 "Received block seal for unexpected pre-seal hash"
207 );
208
209 return Ok(());
210 }
211
212 let public_key_hash = seal.as_ref().public_key_hash();
213 if public_key_hash != self.current_public_key_hash
214 || !seal.as_ref().is_seal_valid(&pre_seal_hash)
215 {
216 warn!(
217 %pre_seal_hash,
218 %public_key_hash,
219 expected_public_key_hash = %self.current_public_key_hash,
220 "Received invalid block seal"
221 );
222
223 return Err(FarmerRpcApiError::InvalidBlockSeal {
224 pre_seal_hash,
225 public_key_hash,
226 });
227 }
228
229 if let Some(sender) = self.senders.pop() {
230 let _: Result<(), _> = sender.send(seal);
231 }
232
233 Ok(())
234 }
235}
236
237#[derive(Debug)]
238struct CachedSuperSegments {
239 super_segments: VecDeque<SuperSegment>,
240}
241
242impl Default for CachedSuperSegments {
243 fn default() -> Self {
244 Self {
245 super_segments: VecDeque::with_capacity(CACHED_SUPER_SEGMENTS_CAPACITY),
246 }
247 }
248}
249
250impl CachedSuperSegments {
251 fn get_for_segment_index(&self, segment_index: SegmentIndex) -> Option<&SuperSegment> {
252 self.super_segments.iter().find(|super_segment| {
253 let max_segment_index = super_segment.header.max_segment_index.as_inner();
254 let first_segment_index = max_segment_index
255 - SegmentIndex::from(u64::from(super_segment.header.num_segments))
256 + SegmentIndex::ONE;
257
258 (first_segment_index..=max_segment_index).contains(&segment_index)
259 })
260 }
261
262 fn add(&mut self, super_segment: SuperSegment) {
263 if self.super_segments.len() == CACHED_SUPER_SEGMENTS_CAPACITY {
264 self.super_segments.pop_front();
265 }
266
267 self.super_segments.push_back(super_segment);
268 }
269}
270
271#[derive(Debug)]
273struct CachedArchivedSegment {
274 segment_index: SegmentIndex,
275 segment: NewArchivedSegment,
276 last_used_at: Instant,
277}
278
279#[derive(Debug)]
280struct ShardMembershipConnectionsState {
281 last_update: Instant,
282 info: Vec<FarmerShardMembershipInfo>,
283}
284
285#[derive(Debug, Default)]
286struct ShardMembershipConnections {
287 connections: HashMap<ConnectionId, ShardMembershipConnectionsState>,
288}
289
290#[derive(Debug)]
292pub struct FarmerRpcConfig<BCI, CSS> {
293 pub listen_on: SocketAddr,
295 pub genesis_block: OwnedBeaconChainBlock,
297 pub consensus_constants: ConsensusConstants,
299 pub max_pieces_in_sector: u16,
301 pub new_slot_notification_receiver: mpsc::Receiver<NewSlotNotification>,
303 pub block_sealing_notification_receiver: mpsc::Receiver<BlockSealNotification>,
305 pub new_super_segment_notification_receiver: mpsc::Receiver<SuperSegment>,
307 pub shard_membership_updates_sender: mpsc::Sender<Vec<FarmerShardMembershipInfo>>,
309 pub dsn_bootstrap_nodes: Vec<Multiaddr>,
311 pub beacon_chain_info: BCI,
313 pub chain_sync_status: CSS,
315 pub erasure_coding: ErasureCoding,
317}
318
319#[derive(Debug)]
321pub struct FarmerRpcWorker<BCI, CSS>
322where
323 BCI: BeaconChainInfo,
324 CSS: ChainSyncStatus,
325{
326 server: Option<Server>,
327 rpc: Option<FarmerRpc<BCI, CSS>>,
328 new_slot_notification_receiver: mpsc::Receiver<NewSlotNotification>,
329 block_sealing_notification_receiver: mpsc::Receiver<BlockSealNotification>,
330 new_super_segment_notification_receiver: mpsc::Receiver<SuperSegment>,
331 solution_response_senders: Arc<Mutex<LruMap<SlotNumber, mpsc::Sender<Solution>>>>,
332 block_sealing_senders: Arc<Mutex<BlockSignatureSenders>>,
333 slot_info_subscriptions: Arc<Mutex<Vec<SubscriptionSink>>>,
334 block_sealing_subscriptions: Arc<Mutex<Vec<SubscriptionSink>>>,
335 new_super_segment_header_subscriptions: Arc<Mutex<Vec<SubscriptionSink>>>,
336 cached_archived_segment: Arc<AsyncMutex<Option<CachedArchivedSegment>>>,
337 cached_super_segments: Arc<Mutex<CachedSuperSegments>>,
338}
339
340impl<BCI, CSS> FarmerRpcWorker<BCI, CSS>
341where
342 BCI: BeaconChainInfo,
343 CSS: ChainSyncStatus,
344{
345 pub async fn new(config: FarmerRpcConfig<BCI, CSS>) -> io::Result<Self> {
347 let server = Server::builder()
348 .set_config(ServerConfig::builder().ws_only().build())
349 .build(config.listen_on)
350 .await?;
351
352 let address = server.local_addr()?;
353 info!(%address, "Started farmer RPC server");
354
355 let block_authoring_delay = u64::from(config.consensus_constants.block_authoring_delay);
356 let block_authoring_delay = usize::try_from(block_authoring_delay)
357 .expect("Block authoring delay will never exceed usize on any platform; qed");
358 let solution_response_senders_capacity = u32::try_from(block_authoring_delay)
359 .expect("Always a tiny constant in the protocol; qed");
360
361 let slot_info_subscriptions = Arc::default();
362 let block_sealing_subscriptions = Arc::default();
363
364 let solution_response_senders = Arc::new(Mutex::new(LruMap::new(ByLength::new(
365 solution_response_senders_capacity,
366 ))));
367 let block_sealing_senders = Arc::default();
368 let new_super_segment_header_subscriptions = Arc::default();
369 let cached_archived_segment = Arc::default();
370 let cached_super_segments = Arc::default();
371
372 let rpc = FarmerRpc {
373 genesis_block: config.genesis_block,
374 solution_response_senders: Arc::clone(&solution_response_senders),
375 block_sealing_senders: Arc::clone(&block_sealing_senders),
376 dsn_bootstrap_nodes: config.dsn_bootstrap_nodes,
377 beacon_chain_info: config.beacon_chain_info,
378 chain_sync_status: config.chain_sync_status,
379 consensus_constants: config.consensus_constants,
380 max_pieces_in_sector: config.max_pieces_in_sector,
381 slot_info_subscriptions: Arc::clone(&slot_info_subscriptions),
382 block_sealing_subscriptions: Arc::clone(&block_sealing_subscriptions),
383 new_super_segment_header_subscriptions: Arc::clone(
384 &new_super_segment_header_subscriptions,
385 ),
386 cached_archived_segment: Arc::clone(&cached_archived_segment),
387 cached_super_segments: Arc::clone(&cached_super_segments),
388 shard_membership_connections: Arc::default(),
389 shard_membership_updates_sender: config.shard_membership_updates_sender,
390 erasure_coding: config.erasure_coding,
391 };
392
393 Ok(Self {
394 server: Some(server),
395 rpc: Some(rpc),
396 new_slot_notification_receiver: config.new_slot_notification_receiver,
397 block_sealing_notification_receiver: config.block_sealing_notification_receiver,
398 new_super_segment_notification_receiver: config.new_super_segment_notification_receiver,
399 solution_response_senders,
400 block_sealing_senders,
401 slot_info_subscriptions,
402 block_sealing_subscriptions,
403 new_super_segment_header_subscriptions,
404 cached_archived_segment,
405 cached_super_segments,
406 })
407 }
408
409 pub async fn run(mut self) {
411 let server = self.server.take().expect("Called only once from here; qed");
412 let rpc = self.rpc.take().expect("Called only once from here; qed");
413 let mut server_fut = server.start(rpc.into_rpc()).stopped().boxed().fuse();
414
415 let mut archived_segment_cache_cleanup_interval =
417 tokio::time::interval(CACHED_ARCHIVED_SEGMENT_TIMEOUT);
418 archived_segment_cache_cleanup_interval.set_missed_tick_behavior(MissedTickBehavior::Delay);
419
420 loop {
421 select! {
422 () = server_fut => {}
423 maybe_new_slot_notification = self.new_slot_notification_receiver.next() => {
424 let Some(new_slot_notification) = maybe_new_slot_notification else {
425 break;
426 };
427
428 self.handle_new_slot_notification(new_slot_notification);
429 }
430 maybe_block_sealing_notification = self.block_sealing_notification_receiver.next() => {
431 let Some(block_sealing_notification) = maybe_block_sealing_notification else {
432 break;
433 };
434
435 self.handle_block_sealing_notification(block_sealing_notification);
436 }
437 maybe_new_super_segment = self.new_super_segment_notification_receiver.next() => {
438 let Some(new_super_segment) = maybe_new_super_segment else {
439 break;
440 };
441
442 self.handle_new_super_segment(new_super_segment);
443 }
444 _ = archived_segment_cache_cleanup_interval.tick().fuse() => {
445 if let Some(mut maybe_cached_archived_segment) = self.cached_archived_segment.try_lock()
446 && let Some(cached_archived_segment) = maybe_cached_archived_segment.as_ref()
447 && cached_archived_segment.last_used_at.elapsed() >= CACHED_ARCHIVED_SEGMENT_TIMEOUT
448 {
449 maybe_cached_archived_segment.take();
450 }
451 }
452 }
453 }
454 }
455
456 fn handle_new_slot_notification(&mut self, new_slot_notification: NewSlotNotification) {
457 let NewSlotNotification {
458 new_slot_info,
459 solution_sender,
460 } = new_slot_notification;
461
462 let NewSlotInfo {
463 slot,
464 proof_of_time,
465 solution_range,
466 shard_membership_entropy,
467 num_shards,
468 } = new_slot_info;
469
470 let mut solution_response_senders = self.solution_response_senders.lock();
473 if solution_response_senders.peek(&slot).is_none() {
474 solution_response_senders.insert(slot, solution_sender);
475 }
476
477 let global_challenge = proof_of_time.derive_global_challenge(slot);
478
479 let slot_info = SlotInfo {
481 slot,
482 global_challenge,
483 solution_range: solution_range.to_leaf_shard(num_shards),
484 shard_membership_entropy,
485 num_shards,
486 };
487 let slot_info = serde_json::value::to_raw_value(&slot_info)
488 .expect("Serialization of slot info never fails; qed");
489
490 self.slot_info_subscriptions.lock().retain_mut(|sink| {
491 match sink.try_send(slot_info.clone()) {
492 Ok(()) => true,
493 Err(error) => match error {
494 TrySendError::Closed(_) => {
495 false
497 }
498 TrySendError::Full(_) => {
499 warn!(
500 subscription_id = ?sink.subscription_id(),
501 "Slot info receiver is too slow, dropping notification"
502 );
503 true
504 }
505 },
506 }
507 });
508 }
509
510 fn handle_block_sealing_notification(
511 &mut self,
512 block_sealing_notification: BlockSealNotification,
513 ) {
514 let BlockSealNotification {
515 pre_seal_hash,
516 public_key_hash,
517 seal_sender,
518 } = block_sealing_notification;
519
520 {
522 let mut block_sealing_senders = self.block_sealing_senders.lock();
523
524 if block_sealing_senders.current_pre_seal_hash != pre_seal_hash {
525 block_sealing_senders.current_pre_seal_hash = pre_seal_hash;
526 block_sealing_senders.current_public_key_hash = public_key_hash;
527 block_sealing_senders.senders.clear();
528 }
529
530 block_sealing_senders.senders.push(seal_sender);
531 }
532
533 let block_seal_info = BlockSealInfo {
535 pre_seal_hash,
536 public_key_hash,
537 };
538 let block_seal_info = serde_json::value::to_raw_value(&block_seal_info)
539 .expect("Serialization of block seal info never fails; qed");
540
541 self.block_sealing_subscriptions.lock().retain_mut(|sink| {
542 match sink.try_send(block_seal_info.clone()) {
543 Ok(()) => true,
544 Err(error) => match error {
545 TrySendError::Closed(_) => {
546 false
548 }
549 TrySendError::Full(_) => {
550 warn!(
551 subscription_id = ?sink.subscription_id(),
552 "Block seal info receiver is too slow, dropping notification"
553 );
554 true
555 }
556 },
557 }
558 });
559 }
560
561 fn handle_new_super_segment(&mut self, super_segment: SuperSegment) {
562 let super_segment_header = serde_json::value::to_raw_value(&super_segment.header)
564 .expect("Serialization of super segment info never fails; qed");
565
566 self.cached_super_segments.lock().add(super_segment);
567
568 self.new_super_segment_header_subscriptions
569 .lock()
570 .retain_mut(|sink| {
571 let subscription_id = sink.subscription_id();
572
573 match sink.try_send(super_segment_header.clone()) {
574 Ok(()) => true,
575 Err(error) => match error {
576 TrySendError::Closed(_) => false,
577 TrySendError::Full(_) => {
578 warn!(
579 ?subscription_id,
580 "Super segment receiver is too slow, dropping notification"
581 );
582 true
583 }
584 },
585 }
586 });
587 }
588}
589
590#[derive(Debug)]
592struct FarmerRpc<BCI, CSS>
593where
594 BCI: BeaconChainInfo,
595 CSS: ChainSyncStatus,
596{
597 genesis_block: OwnedBeaconChainBlock,
598 solution_response_senders: Arc<Mutex<LruMap<SlotNumber, mpsc::Sender<Solution>>>>,
599 block_sealing_senders: Arc<Mutex<BlockSignatureSenders>>,
600 dsn_bootstrap_nodes: Vec<Multiaddr>,
601 beacon_chain_info: BCI,
602 chain_sync_status: CSS,
603 consensus_constants: ConsensusConstants,
604 max_pieces_in_sector: u16,
605 slot_info_subscriptions: Arc<Mutex<Vec<SubscriptionSink>>>,
606 block_sealing_subscriptions: Arc<Mutex<Vec<SubscriptionSink>>>,
607 new_super_segment_header_subscriptions: Arc<Mutex<Vec<SubscriptionSink>>>,
608 cached_archived_segment: Arc<AsyncMutex<Option<CachedArchivedSegment>>>,
609 cached_super_segments: Arc<Mutex<CachedSuperSegments>>,
610 shard_membership_connections: Arc<Mutex<ShardMembershipConnections>>,
611 shard_membership_updates_sender: mpsc::Sender<Vec<FarmerShardMembershipInfo>>,
612 erasure_coding: ErasureCoding,
613}
614
615#[async_trait]
616impl<BCI, CSS> FarmerRpcApiServer for FarmerRpc<BCI, CSS>
617where
618 BCI: BeaconChainInfo,
619 CSS: ChainSyncStatus,
620{
621 fn get_farmer_app_info(&self) -> Result<FarmerAppInfo, FarmerRpcApiError> {
622 let max_segment_index = self
623 .beacon_chain_info
624 .last_super_segment_header()
625 .map_or(SegmentIndex::ZERO, |super_segment_header| {
626 super_segment_header.max_segment_index.as_inner()
627 });
628
629 let consensus_constants = &self.consensus_constants;
630 let protocol_info = FarmerProtocolInfo {
631 history_size: HistorySize::from(max_segment_index),
632 max_pieces_in_sector: self.max_pieces_in_sector,
633 recent_segments: consensus_constants.recent_segments,
634 recent_history_fraction: consensus_constants.recent_history_fraction,
635 min_sector_lifetime: consensus_constants.min_sector_lifetime,
636 };
637
638 let farmer_app_info = FarmerAppInfo {
639 genesis_root: *self.genesis_block.header.header().root(),
640 dsn_bootstrap_nodes: self.dsn_bootstrap_nodes.clone(),
641 syncing: self.chain_sync_status.is_syncing(),
642 farming_timeout: consensus_constants
643 .slot_duration
644 .as_duration()
645 .mul_f64(u64::from(consensus_constants.block_authoring_delay) as f64),
646 protocol_info,
647 };
648
649 Ok(farmer_app_info)
650 }
651
652 fn submit_solution_response(
653 &self,
654 solution_response: SolutionResponse,
655 ) -> Result<(), FarmerRpcApiError> {
656 let slot = solution_response.slot_number;
657 let public_key_hash = solution_response.solution.public_key_hash;
658 let sector_index = solution_response.solution.sector_index;
659 let mut solution_response_senders = self.solution_response_senders.lock();
660
661 let success = solution_response_senders
662 .peek_mut(&slot)
663 .and_then(|sender| sender.try_send(solution_response.solution).ok())
664 .is_some();
665
666 if !success {
667 warn!(
668 %slot,
669 %sector_index,
670 %public_key_hash,
671 "Solution was ignored, likely because farmer was too slow"
672 );
673
674 return Err(FarmerRpcApiError::SolutionWasIgnored { slot });
675 }
676
677 Ok(())
678 }
679
680 async fn subscribe_slot_info(
681 &self,
682 subscription_sink: PendingSubscriptionSink,
683 ) -> SubscriptionResult {
684 let subscription = subscription_sink.accept().await?;
685 self.slot_info_subscriptions.lock().push(subscription);
686
687 Ok(())
688 }
689
690 async fn subscribe_block_seal(
691 &self,
692 subscription_sink: PendingSubscriptionSink,
693 ) -> SubscriptionResult {
694 let subscription = subscription_sink.accept().await?;
695 self.block_sealing_subscriptions.lock().push(subscription);
696
697 Ok(())
698 }
699
700 fn submit_block_seal(&self, block_seal: BlockSealResponse) -> Result<(), FarmerRpcApiError> {
701 self.block_sealing_senders.lock().submit_seal(block_seal)
702 }
703
704 async fn subscribe_new_super_segment_header(
705 &self,
706 subscription_sink: PendingSubscriptionSink,
707 ) -> SubscriptionResult {
708 let subscription = subscription_sink.accept().await?;
709 self.new_super_segment_header_subscriptions
710 .lock()
711 .push(subscription);
712
713 Ok(())
714 }
715
716 async fn super_segment_headers(
717 &self,
718 super_segment_indices: Vec<SuperSegmentIndex>,
719 ) -> Result<Vec<Option<SuperSegmentHeader>>, FarmerRpcApiError> {
720 if super_segment_indices.len() > MAX_SUPER_SEGMENT_HEADERS_PER_REQUEST {
721 error!(
722 "`super_segment_indices` length exceed the limit: {} ",
723 super_segment_indices.len()
724 );
725
726 return Err(FarmerRpcApiError::SuperSegmentHeadersLengthExceeded {
727 actual: super_segment_indices.len(),
728 });
729 }
730
731 Ok(super_segment_indices
732 .into_iter()
733 .map(|super_segment_index| {
734 self.beacon_chain_info
735 .get_super_segment_header(super_segment_index)
736 })
737 .collect())
738 }
739
740 async fn last_super_segment_headers(
741 &self,
742 limit: u32,
743 ) -> Result<Vec<Option<SuperSegmentHeader>>, FarmerRpcApiError> {
744 if limit as usize > MAX_SUPER_SEGMENT_HEADERS_PER_REQUEST {
745 error!(
746 "Request limit ({}) exceed the server limit: {} ",
747 limit, MAX_SUPER_SEGMENT_HEADERS_PER_REQUEST
748 );
749
750 return Err(FarmerRpcApiError::SuperSegmentHeadersLengthExceeded {
751 actual: limit as usize,
752 });
753 }
754
755 let last_super_segment_index = self
756 .beacon_chain_info
757 .last_super_segment_header()
758 .map_or(SuperSegmentIndex::ZERO, |super_segment_header| {
759 super_segment_header.index.as_inner()
760 });
761
762 let mut last_super_segment_headers = (SuperSegmentIndex::ZERO..=last_super_segment_index)
763 .rev()
764 .take(limit as usize)
765 .map(|super_segment_index| {
766 self.beacon_chain_info
767 .get_super_segment_header(super_segment_index)
768 })
769 .collect::<Vec<_>>();
770
771 last_super_segment_headers.reverse();
772
773 Ok(last_super_segment_headers)
774 }
775
776 async fn super_segment_root_for_segment_index(
777 &self,
778 segment_index: SegmentIndex,
779 ) -> Result<Option<SuperSegmentRoot>, FarmerRpcApiError> {
780 Ok(self
781 .beacon_chain_info
782 .get_super_segment_header_for_segment_index(segment_index)
783 .map(|super_segment_header| super_segment_header.root))
784 }
785
786 async fn piece(&self, piece_index: PieceIndex) -> Result<Option<Piece>, FarmerRpcApiError> {
789 let segment_index = piece_index.segment_index();
790 let cached_archived_segment = &mut *self.cached_archived_segment.lock().await;
791
792 if let Some(cached_archived_segment) = cached_archived_segment
793 && cached_archived_segment.segment_index == segment_index
794 {
795 cached_archived_segment.last_used_at = Instant::now();
796
797 return Ok(cached_archived_segment
798 .segment
799 .pieces
800 .pieces()
801 .nth(usize::from(piece_index.position())));
802 }
803
804 if segment_index == SegmentIndex::ZERO {
805 let segment = spawn_blocking({
806 let genesis_block = self.genesis_block.clone();
807 let erasure_coding = self.erasure_coding.clone();
808
809 move || recreate_genesis_segment(&genesis_block, erasure_coding)
810 })
811 .await?;
812 let cached_archived_segment = cached_archived_segment.insert(CachedArchivedSegment {
813 segment_index: SegmentIndex::ZERO,
814 segment,
815 last_used_at: Instant::now(),
816 });
817
818 return Ok(cached_archived_segment
819 .segment
820 .pieces
821 .pieces()
822 .nth(usize::from(piece_index.position())));
823 }
824
825 let (super_segment_index, shard_segment_root_with_position, segment_proof) = {
826 let cached_super_segments = self.cached_super_segments.lock();
827 let Some(super_segment) = cached_super_segments.get_for_segment_index(segment_index)
828 else {
829 return Ok(None);
830 };
831
832 let Some(shard_segment_root_with_position) = super_segment
833 .segment_roots
834 .iter()
835 .nth_back(u64::from(
836 super_segment.header.max_segment_index.as_inner() - segment_index,
837 ) as usize)
838 .copied()
839 else {
840 error!(
841 %piece_index,
842 %segment_index,
843 super_segment_header = ?super_segment.header,
844 "Failed to find segment index inside super segment, this should never happen"
845 );
846 return Ok(None);
847 };
848
849 let segment_position = shard_segment_root_with_position.segment_position;
850
851 let Some(segment_proof) = super_segment.proof_for_segment(segment_position) else {
852 error!(
853 %piece_index,
854 %segment_index,
855 %segment_position,
856 super_segment_header = ?super_segment.header,
857 "Failed to get segment proof for segment position, this should never happen"
858 );
859
860 return Ok(None);
861 };
862
863 (
864 super_segment.header.index.as_inner(),
865 shard_segment_root_with_position,
866 segment_proof,
867 )
868 };
869
870 let recreate_segment_super_segment_details = RecreateSegmentSuperSegmentDetails {
871 super_segment_index,
872 segment_position: shard_segment_root_with_position.segment_position,
873 segment_proof,
874 };
875
876 if shard_segment_root_with_position.shard_index != ShardIndex::BEACON_CHAIN {
877 unimplemented!("Shard segments for non-beacon chain shards are not supported yet");
880 }
881
882 let last_archived_segment = shard_segment_root_with_position
883 .local_segment_index
884 .checked_sub(LocalSegmentIndex::ONE)
885 .and_then(|last_segment_index| {
886 self.beacon_chain_info
887 .get_segment_header(last_segment_index)
888 });
889
890 let maybe_segment = recreate_segment(
891 last_archived_segment,
892 &self.beacon_chain_info,
893 self.erasure_coding.clone(),
894 &recreate_segment_super_segment_details,
895 |_| Vec::new(),
896 )
897 .await?;
898
899 let Some(segment) = maybe_segment else {
900 return Ok(None);
901 };
902
903 let cached_archived_segment = cached_archived_segment.insert(CachedArchivedSegment {
904 segment_index,
905 segment,
906 last_used_at: Instant::now(),
907 });
908
909 Ok(cached_archived_segment
910 .segment
911 .pieces
912 .pieces()
913 .nth(usize::from(piece_index.position())))
914 }
915
916 async fn update_shard_membership_info(
917 &self,
918 ext: &Extensions,
919 info: Vec<FarmerShardMembershipInfo>,
920 ) -> Result<(), FarmerRpcApiError> {
921 let connection_id = ext
922 .get::<ConnectionId>()
923 .expect("`ConnectionId` is always present; qed");
924
925 let shard_membership = {
926 let mut shard_membership_connections = self.shard_membership_connections.lock();
927
928 shard_membership_connections
931 .connections
932 .retain(|_connection_id, state| {
933 state.last_update.elapsed() < SHARD_MEMBERSHIP_EXPIRATION
934 });
935
936 shard_membership_connections.connections.insert(
937 *connection_id,
938 ShardMembershipConnectionsState {
939 last_update: Instant::now(),
940 info,
941 },
942 );
943
944 shard_membership_connections
945 .connections
946 .values()
947 .flat_map(|state| state.info.clone())
948 .collect::<Vec<_>>()
949 };
950
951 if let Err(error) = self
952 .shard_membership_updates_sender
953 .clone()
954 .send(shard_membership)
955 .await
956 {
957 warn!(%error, "Failed to send shard membership update");
958 }
959
960 Ok(())
961 }
962}