Skip to main content

ab_node_rpc_server/
lib.rs

1//! RPC API for the farmer
2
3// TODO: Ed25519 uses SHA-512, whose `sha3` target feature intrinsics (enabled on macOS on aarch64)
4//  are not supported by Miri: https://github.com/rust-lang/miri/issues/3172
5#[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/// Top-level error type for the RPC handler
61#[derive(Debug, thiserror::Error)]
62pub enum FarmerRpcApiError {
63    /// Solution was ignored
64    #[error("Solution was ignored for slot {slot}")]
65    SolutionWasIgnored {
66        /// Slot number
67        slot: SlotNumber,
68    },
69    /// Super segment headers length exceeded the limit
70    #[error(
71        "Super segment headers length exceeded the limit: \
72        {actual}/{MAX_SUPER_SEGMENT_HEADERS_PER_REQUEST}"
73    )]
74    SuperSegmentHeadersLengthExceeded {
75        /// Requested number of super segment headers/indices
76        actual: usize,
77    },
78    /// Failed to recreate segment
79    #[error("Failed to recreate segment: {0}")]
80    FailedToRecreateSegment(#[from] RecreateSegmentError),
81    /// Blocking task join error
82    #[error("Blocking task join error: {0}")]
83    BlockingTaskJoinError(#[from] JoinError),
84    /// Invalid block seal
85    #[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
91        pre_seal_hash: Blake3Hash,
92        /// Public key hash of the seal
93        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/// Provides rpc methods for interacting with the farmer
116#[rpc(server)]
117pub trait FarmerRpcApi {
118    /// Get metadata necessary for farmer operation
119    #[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    /// Slot info subscription
129    #[subscription(
130        name = "subscribeSlotInfo" => "slot_info",
131        unsubscribe = "unsubscribeSlotInfo",
132        item = SlotInfo,
133    )]
134    async fn subscribe_slot_info(&self) -> SubscriptionResult;
135
136    /// Sign block subscription
137    #[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    /// New super segment header subscription
148    #[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    /// Public key hash that seals for the current pre-seal hash must be created with
187    current_public_key_hash: Blake3Hash,
188    senders: Vec<oneshot::Sender<OwnedBlockHeaderSeal>>,
189}
190
191impl BlockSignatureSenders {
192    /// Send a seal for the current pre-seal hash to one of the senders.
193    ///
194    /// Seals for other pre-seal hashes are ignored with a warning. A seal of another public key or
195    /// with an invalid signature results in an error, and the senders are kept for a valid seal.
196    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/// Temporary in-memory cache of the last archived segment
272#[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/// Farmer RPC configuration
291#[derive(Debug)]
292pub struct FarmerRpcConfig<BCI, CSS> {
293    /// IP and port (TCP) on which to listen for farmer RPC requests
294    pub listen_on: SocketAddr,
295    /// Genesis beacon chain block
296    pub genesis_block: OwnedBeaconChainBlock,
297    /// Consensus constants
298    pub consensus_constants: ConsensusConstants,
299    /// Max pieces in a sector
300    pub max_pieces_in_sector: u16,
301    /// New slot notifications
302    pub new_slot_notification_receiver: mpsc::Receiver<NewSlotNotification>,
303    /// Block sealing notifications
304    pub block_sealing_notification_receiver: mpsc::Receiver<BlockSealNotification>,
305    /// Super segment notifications
306    pub new_super_segment_notification_receiver: mpsc::Receiver<SuperSegment>,
307    /// Shard membership updates
308    pub shard_membership_updates_sender: mpsc::Sender<Vec<FarmerShardMembershipInfo>>,
309    /// DSN bootstrap nodes
310    pub dsn_bootstrap_nodes: Vec<Multiaddr>,
311    /// Beacon chain info
312    pub beacon_chain_info: BCI,
313    /// Chain sync status
314    pub chain_sync_status: CSS,
315    /// Erasure coding instance
316    pub erasure_coding: ErasureCoding,
317}
318
319/// Worker that drives RPC server tasks
320#[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    /// Creates a new farmer RPC worker
346    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    /// Drive RPC server tasks
410    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        // Also send periodic updates in addition to the subscription response
416        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        // Store solution sender so that we can retrieve it when solution comes from
471        // the farmer
472        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        // This will be sent to the farmer
480        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                        // Remove closed receivers
496                        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        // Store signature sender so that we can retrieve it when a solution comes from the farmer
521        {
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        // This will be sent to the farmer
534        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                        // Remove closed receivers
547                        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        // This will be sent to the farmer
563        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/// Implements the [`FarmerRpcApiServer`] trait for a farmer to connect to
591#[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    // Note: this RPC uses the cached archived segment, which is only updated by archived segments
787    // subscriptions
788    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            // TODO: There will be a need for chain info instances of all live shards to re-derive
878            //  segments here, but there is just a beacon chain here for now
879            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            // TODO: This is a workaround for https://github.com/paritytech/jsonrpsee/issues/1617
929            //  and should be replaced with cleanup on disconnection once that issue is resolved
930            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}