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