Skip to main content

ab_node_rpc_server/
lib.rs

1//! RPC API for the farmer
2
3use 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/// Top-level error type for the RPC handler
56#[derive(Debug, thiserror::Error)]
57pub enum FarmerRpcApiError {
58    /// Solution was ignored
59    #[error("Solution was ignored for slot {slot}")]
60    SolutionWasIgnored {
61        /// Slot number
62        slot: SlotNumber,
63    },
64    /// Super segment headers length exceeded the limit
65    #[error(
66        "Super segment headers length exceeded the limit: \
67        {actual}/{MAX_SUPER_SEGMENT_HEADERS_PER_REQUEST}"
68    )]
69    SuperSegmentHeadersLengthExceeded {
70        /// Requested number of super segment headers/indices
71        actual: usize,
72    },
73    /// Failed to recreate segment
74    #[error("Failed to recreate segment: {0}")]
75    FailedToRecreateSegment(#[from] RecreateSegmentError),
76    /// Blocking task join error
77    #[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/// Provides rpc methods for interacting with the farmer
99#[rpc(server)]
100pub trait FarmerRpcApi {
101    /// Get metadata necessary for farmer operation
102    #[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    /// Slot info subscription
112    #[subscription(
113        name = "subscribeSlotInfo" => "slot_info",
114        unsubscribe = "unsubscribeSlotInfo",
115        item = SlotInfo,
116    )]
117    async fn subscribe_slot_info(&self) -> SubscriptionResult;
118
119    /// Sign block subscription
120    #[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    /// New super segment header subscription
131    #[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/// Temporary in-memory cache of the last archived segment
207#[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/// Farmer RPC configuration
226#[derive(Debug)]
227pub struct FarmerRpcConfig<BCI, CSS> {
228    /// IP and port (TCP) on which to listen for farmer RPC requests
229    pub listen_on: SocketAddr,
230    /// Genesis beacon chain block
231    pub genesis_block: OwnedBeaconChainBlock,
232    /// Consensus constants
233    pub consensus_constants: ConsensusConstants,
234    /// Max pieces in a sector
235    pub max_pieces_in_sector: u16,
236    /// New slot notifications
237    pub new_slot_notification_receiver: mpsc::Receiver<NewSlotNotification>,
238    /// Block sealing notifications
239    pub block_sealing_notification_receiver: mpsc::Receiver<BlockSealNotification>,
240    /// Super segment notifications
241    pub new_super_segment_notification_receiver: mpsc::Receiver<SuperSegment>,
242    /// Shard membership updates
243    pub shard_membership_updates_sender: mpsc::Sender<Vec<FarmerShardMembershipInfo>>,
244    /// DSN bootstrap nodes
245    pub dsn_bootstrap_nodes: Vec<Multiaddr>,
246    /// Beacon chain info
247    pub beacon_chain_info: BCI,
248    /// Chain sync status
249    pub chain_sync_status: CSS,
250    /// Erasure coding instance
251    pub erasure_coding: ErasureCoding,
252}
253
254/// Worker that drives RPC server tasks
255#[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    /// Creates a new farmer RPC worker
281    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    /// Drive RPC server tasks
345    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        // Also send periodic updates in addition to the subscription response
351        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        // Store solution sender so that we can retrieve it when solution comes from
406        // the farmer
407        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        // This will be sent to the farmer
415        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                        // Remove closed receivers
431                        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        // Store signature sender so that we can retrieve it when a solution comes from the farmer
456        {
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        // This will be sent to the farmer
468        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                        // Remove closed receivers
481                        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        // This will be sent to the farmer
497        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/// Implements the [`FarmerRpcApiServer`] trait for a farmer to connect to
525#[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    // Note: this RPC uses the cached archived segment, which is only updated by archived segments
731    // subscriptions
732    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            // TODO: There will be a need for chain info instances of all live shards to re-derive
822            //  segments here, but there is just a beacon chain here for now
823            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            // TODO: This is a workaround for https://github.com/paritytech/jsonrpsee/issues/1617
873            //  and should be replaced with cleanup on disconnection once that issue is resolved
874            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}