Skip to main content

ab_farmer/cluster/
farmer.rs

1//! Farming cluster farmer
2//!
3//! Farmer is responsible for maintaining farms, doing audits and generating proofs when solution is
4//! found in one of the plots.
5//!
6//! This module exposes some data structures for NATS communication, custom farm implementation
7//! designed to work with cluster farmer and a service function to drive the backend part
8//! of the farmer.
9
10use crate::cluster::controller::ClusterControllerFarmerIdentifyBroadcast;
11use crate::cluster::nats_client::{
12    GenericBroadcast, GenericRequest, GenericStreamRequest, NatsClient,
13};
14use crate::farm::{
15    Farm, FarmError, FarmId, FarmingNotification, HandlerFn, HandlerId, PieceReader,
16    PlottedSectors, SectorUpdate,
17};
18use crate::utils::AsyncJoinOnDrop;
19use ab_core_primitives::pieces::{Piece, PieceOffset};
20use ab_core_primitives::sectors::SectorIndex;
21use ab_farmer_components::plotting::PlottedSector;
22use ab_farmer_rpc_primitives::SolutionResponse;
23use anyhow::anyhow;
24use async_trait::async_trait;
25use derive_more::{Display, From};
26use event_listener_primitives::Bag;
27use futures::channel::mpsc;
28use futures::stream::FuturesUnordered;
29use futures::{FutureExt, Stream, StreamExt, select, stream};
30use parity_scale_codec::{Decode, Encode, EncodeLike, Input, Output};
31use std::future::Future;
32use std::pin::{Pin, pin};
33use std::sync::Arc as StdArc;
34use std::time::{Duration, Instant};
35use tokio::time::MissedTickBehavior;
36use tracing::{Instrument, debug, error, info_span, trace, warn};
37use triomphe::Arc;
38use ulid::Ulid;
39
40const BROADCAST_NOTIFICATIONS_BUFFER: usize = 1000;
41const MIN_FARMER_IDENTIFICATION_INTERVAL: Duration = Duration::from_secs(1);
42
43type Handler<A> = Bag<HandlerFn<A>, A>;
44
45/// An identifier for a cluster farmer, can be used for in logs, thread names, etc.
46#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Display, From)]
47pub struct ClusterFarmerId(Ulid);
48
49impl Encode for ClusterFarmerId {
50    #[inline]
51    fn size_hint(&self) -> usize {
52        Encode::size_hint(&self.0.0)
53    }
54
55    #[inline]
56    fn encode_to<O>(&self, dest: &mut O)
57    where
58        O: Output + ?Sized,
59    {
60        Encode::encode_to(&self.0.0, dest);
61    }
62}
63
64impl EncodeLike for ClusterFarmerId {}
65
66impl Decode for ClusterFarmerId {
67    #[inline]
68    fn decode<I>(input: &mut I) -> Result<Self, parity_scale_codec::Error>
69    where
70        I: Input,
71    {
72        u128::decode(input)
73            .map(|ulid| Self(Ulid(ulid)))
74            .map_err(|e| e.chain("Could not decode `ClusterFarmerId.0.0`"))
75    }
76}
77
78#[expect(
79    clippy::new_without_default,
80    reason = "Default has different semantics"
81)]
82impl ClusterFarmerId {
83    /// Create a new cluster farmer ID
84    pub fn new() -> Self {
85        Self(Ulid::generate())
86    }
87}
88
89/// Broadcast with cluster farmer id for identification
90#[derive(Debug, Clone, Encode, Decode)]
91pub struct ClusterFarmerIdentifyBroadcast {
92    /// Cluster farmer ID
93    pub farmer_id: ClusterFarmerId,
94}
95
96impl GenericBroadcast for ClusterFarmerIdentifyBroadcast {
97    /// `*` here stands for cluster farmer ID
98    const SUBJECT: &'static str = "ab.farmer.*.farmer-identify";
99}
100
101/// Request farm details from farmer
102#[derive(Debug, Clone, Encode, Decode)]
103pub struct ClusterFarmerFarmDetailsRequest;
104
105impl GenericStreamRequest for ClusterFarmerFarmDetailsRequest {
106    /// `*` here stands for cluster farmer ID
107    const SUBJECT: &'static str = "ab.farmer.*.farm.details";
108    type Response = ClusterFarmerFarmDetails;
109}
110
111/// Farm details
112#[derive(Debug, Clone, Encode, Decode)]
113pub struct ClusterFarmerFarmDetails {
114    /// Farm ID
115    pub farm_id: FarmId,
116    /// Total number of sectors in the farm
117    pub total_sectors_count: u16,
118}
119
120/// Broadcast with sector updates by farmers
121#[derive(Debug, Clone, Encode, Decode)]
122struct ClusterFarmerSectorUpdateBroadcast {
123    /// Farm ID
124    farm_id: FarmId,
125    /// Sector index
126    sector_index: SectorIndex,
127    /// Sector update
128    sector_update: SectorUpdate,
129}
130
131impl GenericBroadcast for ClusterFarmerSectorUpdateBroadcast {
132    /// `*` here stands for single farm ID
133    const SUBJECT: &'static str = "ab.farmer.*.sector-update";
134}
135
136/// Broadcast with farming notifications by farmers
137#[derive(Debug, Clone, Encode, Decode)]
138struct ClusterFarmerFarmingNotificationBroadcast {
139    /// Farm ID
140    farm_id: FarmId,
141    /// Farming notification
142    farming_notification: FarmingNotification,
143}
144
145impl GenericBroadcast for ClusterFarmerFarmingNotificationBroadcast {
146    /// `*` here stands for single farm ID
147    const SUBJECT: &'static str = "ab.farmer.*.farming-notification";
148}
149
150/// Broadcast with solutions by farmers
151#[derive(Debug, Clone, Encode, Decode)]
152struct ClusterFarmerSolutionBroadcast {
153    /// Farm ID
154    farm_id: FarmId,
155    /// Solution response
156    solution_response: SolutionResponse,
157}
158
159impl GenericBroadcast for ClusterFarmerSolutionBroadcast {
160    /// `*` here stands for single farm ID
161    const SUBJECT: &'static str = "ab.farmer.*.solution-response";
162}
163
164/// Read piece from farm
165#[derive(Debug, Clone, Encode, Decode)]
166struct ClusterFarmerReadPieceRequest {
167    sector_index: SectorIndex,
168    piece_offset: PieceOffset,
169}
170
171impl GenericRequest for ClusterFarmerReadPieceRequest {
172    /// `*` here stands for single farm ID
173    const SUBJECT: &'static str = "ab.farmer.*.farm.read-piece";
174    type Response = Result<Option<Piece>, String>;
175}
176
177/// Request plotted sectors from farmer
178#[derive(Debug, Clone, Encode, Decode)]
179struct ClusterFarmerPlottedSectorsRequest;
180
181impl GenericStreamRequest for ClusterFarmerPlottedSectorsRequest {
182    /// `*` here stands for single farm ID
183    const SUBJECT: &'static str = "ab.farmer.*.farm.plotted-sectors";
184    type Response = Result<PlottedSector, String>;
185}
186
187#[derive(Debug)]
188struct ClusterPlottedSectors {
189    farm_id_string: String,
190    nats_client: NatsClient,
191}
192
193#[async_trait]
194impl PlottedSectors for ClusterPlottedSectors {
195    async fn get(
196        &self,
197    ) -> Result<
198        Box<dyn Stream<Item = Result<PlottedSector, FarmError>> + Unpin + Send + '_>,
199        FarmError,
200    > {
201        Ok(Box::new(
202            self.nats_client
203                .stream_request(
204                    &ClusterFarmerPlottedSectorsRequest,
205                    Some(&self.farm_id_string),
206                )
207                .await?
208                .map(|response| response.map_err(FarmError::from)),
209        ))
210    }
211}
212
213#[derive(Debug)]
214struct ClusterPieceReader {
215    farm_id_string: String,
216    nats_client: NatsClient,
217}
218
219#[async_trait]
220impl PieceReader for ClusterPieceReader {
221    async fn read_piece(
222        &self,
223        sector_index: SectorIndex,
224        piece_offset: PieceOffset,
225    ) -> Result<Option<Piece>, FarmError> {
226        Ok(self
227            .nats_client
228            .request(
229                &ClusterFarmerReadPieceRequest {
230                    sector_index,
231                    piece_offset,
232                },
233                Some(&self.farm_id_string),
234            )
235            .await??)
236    }
237}
238
239#[derive(Default, Debug)]
240struct Handlers {
241    sector_update: Handler<(SectorIndex, SectorUpdate)>,
242    farming_notification: Handler<FarmingNotification>,
243    solution: Handler<SolutionResponse>,
244}
245
246/// Cluster farm implementation
247#[derive(Debug)]
248pub struct ClusterFarm {
249    farm_id: FarmId,
250    farm_id_string: String,
251    total_sectors_count: u16,
252    nats_client: NatsClient,
253    handlers: Arc<Handlers>,
254    background_tasks: AsyncJoinOnDrop<()>,
255}
256
257#[async_trait(?Send)]
258impl Farm for ClusterFarm {
259    fn id(&self) -> &FarmId {
260        &self.farm_id
261    }
262
263    fn total_sectors_count(&self) -> u16 {
264        self.total_sectors_count
265    }
266
267    fn plotted_sectors(&self) -> StdArc<dyn PlottedSectors + 'static> {
268        StdArc::new(ClusterPlottedSectors {
269            farm_id_string: self.farm_id_string.clone(),
270            nats_client: self.nats_client.clone(),
271        })
272    }
273
274    fn piece_reader(&self) -> StdArc<dyn PieceReader + 'static> {
275        StdArc::new(ClusterPieceReader {
276            farm_id_string: self.farm_id_string.clone(),
277            nats_client: self.nats_client.clone(),
278        })
279    }
280
281    fn on_sector_update(
282        &self,
283        callback: HandlerFn<(SectorIndex, SectorUpdate)>,
284    ) -> Box<dyn HandlerId> {
285        Box::new(self.handlers.sector_update.add(callback))
286    }
287
288    fn on_farming_notification(
289        &self,
290        callback: HandlerFn<FarmingNotification>,
291    ) -> Box<dyn HandlerId> {
292        Box::new(self.handlers.farming_notification.add(callback))
293    }
294
295    fn on_solution(&self, callback: HandlerFn<SolutionResponse>) -> Box<dyn HandlerId> {
296        Box::new(self.handlers.solution.add(callback))
297    }
298
299    fn run(self: Box<Self>) -> Pin<Box<dyn Future<Output = anyhow::Result<()>> + Send>> {
300        Box::pin((*self).run())
301    }
302}
303
304impl ClusterFarm {
305    /// Create a new instance using information from previously received
306    /// [`ClusterFarmerIdentifyBroadcast`]
307    pub async fn new(
308        farm_id: FarmId,
309        total_sectors_count: u16,
310        nats_client: NatsClient,
311    ) -> anyhow::Result<Self> {
312        let farm_id_string = farm_id.to_string();
313
314        let sector_updates_subscription = nats_client
315            .subscribe_to_broadcasts::<ClusterFarmerSectorUpdateBroadcast>(
316                Some(&farm_id_string),
317                None,
318            )
319            .await
320            .map_err(|error| anyhow!("Failed to subscribe to sector updates broadcast: {error}"))?;
321        let farming_notifications_subscription = nats_client
322            .subscribe_to_broadcasts::<ClusterFarmerFarmingNotificationBroadcast>(
323                Some(&farm_id_string),
324                None,
325            )
326            .await
327            .map_err(|error| {
328                anyhow!("Failed to subscribe to farming notifications broadcast: {error}")
329            })?;
330        let solution_subscription = nats_client
331            .subscribe_to_broadcasts::<ClusterFarmerSolutionBroadcast>(Some(&farm_id_string), None)
332            .await
333            .map_err(|error| {
334                anyhow!("Failed to subscribe to solution responses broadcast: {error}")
335            })?;
336
337        let handlers = Arc::<Handlers>::default();
338        // Run background tasks and fire corresponding notifications
339        let background_tasks = {
340            let handlers = Arc::clone(&handlers);
341
342            async move {
343                let mut sector_updates_subscription = pin!(sector_updates_subscription);
344                let mut farming_notifications_subscription =
345                    pin!(farming_notifications_subscription);
346                let mut solution_subscription = pin!(solution_subscription);
347
348                let sector_updates_fut = async {
349                    #[expect(
350                        clippy::rest_pattern_accessible_field,
351                        reason = "Do not need other fields"
352                    )]
353                    while let Some(ClusterFarmerSectorUpdateBroadcast {
354                        sector_index,
355                        sector_update,
356                        ..
357                    }) = sector_updates_subscription.next().await
358                    {
359                        handlers
360                            .sector_update
361                            .call_simple(&(sector_index, sector_update));
362                    }
363                };
364                let farming_notifications_fut = async {
365                    #[expect(
366                        clippy::rest_pattern_accessible_field,
367                        reason = "Do not need other fields"
368                    )]
369                    while let Some(ClusterFarmerFarmingNotificationBroadcast {
370                        farming_notification,
371                        ..
372                    }) = farming_notifications_subscription.next().await
373                    {
374                        handlers
375                            .farming_notification
376                            .call_simple(&farming_notification);
377                    }
378                };
379                let solutions_fut = async {
380                    #[expect(
381                        clippy::rest_pattern_accessible_field,
382                        reason = "Do not need other fields"
383                    )]
384                    while let Some(ClusterFarmerSolutionBroadcast {
385                        solution_response, ..
386                    }) = solution_subscription.next().await
387                    {
388                        handlers.solution.call_simple(&solution_response);
389                    }
390                };
391
392                select! {
393                    () = sector_updates_fut.fuse() => {}
394                    () = farming_notifications_fut.fuse() => {}
395                    () = solutions_fut.fuse() => {}
396                }
397            }
398        };
399
400        Ok(Self {
401            farm_id,
402            farm_id_string,
403            total_sectors_count,
404            nats_client,
405            handlers,
406            background_tasks: AsyncJoinOnDrop::new(tokio::spawn(background_tasks), true),
407        })
408    }
409
410    /// Run and wait for background tasks to exit or return an error
411    pub async fn run(self) -> anyhow::Result<()> {
412        Ok(self.background_tasks.await?)
413    }
414}
415
416#[derive(Debug)]
417struct FarmDetails {
418    farm_id: FarmId,
419    farm_id_string: String,
420    total_sectors_count: u16,
421    piece_reader: StdArc<dyn PieceReader + 'static>,
422    plotted_sectors: StdArc<dyn PlottedSectors + 'static>,
423    _background_tasks: Option<AsyncJoinOnDrop<()>>,
424}
425
426/// Create farmer service for specified farms that will be processing incoming requests and send
427/// periodic identify notifications.
428///
429/// Implementation is using concurrency with multiple tokio tasks, but can be started multiple times
430/// per controller instance in order to parallelize more work across threads if needed.
431pub fn farmer_service<F>(
432    nats_client: NatsClient,
433    farms: &[F],
434    identification_broadcast_interval: Duration,
435    primary_instance: bool,
436) -> impl Future<Output = anyhow::Result<()>> + Send + 'static
437where
438    F: Farm,
439{
440    let farmer_id = ClusterFarmerId::new();
441    let farmer_id_string = farmer_id.to_string();
442
443    // For each farm start forwarding notifications as broadcast messages and create farm details
444    // that can be used to respond to incoming requests
445    let farms_details = farms
446        .iter()
447        .map(|farm| {
448            let farm_id = *farm.id();
449            let nats_client = nats_client.clone();
450
451            let background_tasks = if primary_instance {
452                let (sector_updates_sender, mut sector_updates_receiver) =
453                    mpsc::channel(BROADCAST_NOTIFICATIONS_BUFFER);
454                let (farming_notifications_sender, mut farming_notifications_receiver) =
455                    mpsc::channel(BROADCAST_NOTIFICATIONS_BUFFER);
456                let (solutions_sender, mut solutions_receiver) =
457                    mpsc::channel(BROADCAST_NOTIFICATIONS_BUFFER);
458
459                let sector_updates_handler_id =
460                    farm.on_sector_update(StdArc::new(move |(sector_index, sector_update)| {
461                        if let Err(error) = sector_updates_sender.clone().try_send(
462                            ClusterFarmerSectorUpdateBroadcast {
463                                farm_id,
464                                sector_index: *sector_index,
465                                sector_update: sector_update.clone(),
466                            },
467                        ) {
468                            warn!(%farm_id, %error, "Failed to send sector update notification");
469                        }
470                    }));
471
472                let farming_notifications_handler_id =
473                    farm.on_farming_notification(StdArc::new(move |farming_notification| {
474                        if let Err(error) = farming_notifications_sender.clone().try_send(
475                            ClusterFarmerFarmingNotificationBroadcast {
476                                farm_id,
477                                farming_notification: farming_notification.clone(),
478                            },
479                        ) {
480                            warn!(%farm_id, %error, "Failed to send farming notification");
481                        }
482                    }));
483
484                let solutions_handler_id =
485                    farm.on_solution(StdArc::new(move |solution_response| {
486                        if let Err(error) =
487                            solutions_sender
488                                .clone()
489                                .try_send(ClusterFarmerSolutionBroadcast {
490                                    farm_id,
491                                    solution_response: solution_response.clone(),
492                                })
493                        {
494                            warn!(%farm_id, %error, "Failed to send solution notification");
495                        }
496                    }));
497
498                Some(AsyncJoinOnDrop::new(
499                    tokio::spawn(async move {
500                        let farm_id_string = farm_id.to_string();
501
502                        let sector_updates_fut = async {
503                            while let Some(broadcast) = sector_updates_receiver.next().await {
504                                if let Err(error) =
505                                    nats_client.broadcast(&broadcast, &farm_id_string).await
506                                {
507                                    warn!(%farm_id, %error, "Failed to broadcast sector update");
508                                }
509                            }
510                        };
511                        let farming_notifications_fut = async {
512                            while let Some(broadcast) = farming_notifications_receiver.next().await
513                            {
514                                if let Err(error) =
515                                    nats_client.broadcast(&broadcast, &farm_id_string).await
516                                {
517                                    warn!(
518                                        %farm_id,
519                                        %error,
520                                        "Failed to broadcast farming notification"
521                                    );
522                                }
523                            }
524                        };
525                        let solutions_fut = async {
526                            while let Some(broadcast) = solutions_receiver.next().await {
527                                if let Err(error) =
528                                    nats_client.broadcast(&broadcast, &farm_id_string).await
529                                {
530                                    warn!(%farm_id, %error, "Failed to broadcast solution");
531                                }
532                            }
533                        };
534
535                        select! {
536                            () = sector_updates_fut.fuse() => {}
537                            () = farming_notifications_fut.fuse() => {}
538                            () = solutions_fut.fuse() => {}
539                        }
540
541                        drop(sector_updates_handler_id);
542                        drop(farming_notifications_handler_id);
543                        drop(solutions_handler_id);
544                    }),
545                    true,
546                ))
547            } else {
548                None
549            };
550
551            FarmDetails {
552                farm_id,
553                farm_id_string: farm_id.to_string(),
554                total_sectors_count: farm.total_sectors_count(),
555                piece_reader: farm.piece_reader(),
556                plotted_sectors: farm.plotted_sectors(),
557                _background_tasks: background_tasks,
558            }
559        })
560        .collect::<Vec<_>>();
561
562    async move {
563        if primary_instance {
564            select! {
565                result = identify_responder(
566                    &nats_client,
567                    farmer_id,
568                    &farmer_id_string,
569                    identification_broadcast_interval
570                ).fuse() => {
571                    result
572                },
573                result = farms_details_responder(
574                    &nats_client,
575                    &farmer_id_string,
576                    &farms_details
577                ).fuse() => {
578                    result
579                },
580                result = plotted_sectors_responder(&nats_client, &farms_details).fuse() => {
581                    result
582                },
583                result = read_piece_responder(&nats_client, &farms_details).fuse() => {
584                    result
585                },
586            }
587        } else {
588            select! {
589                result = plotted_sectors_responder(&nats_client, &farms_details).fuse() => {
590                    result
591                },
592                result = read_piece_responder(&nats_client, &farms_details).fuse() => {
593                    result
594                },
595            }
596        }
597    }
598}
599
600/// Listen for farmer identification broadcast from controller and publish identification
601/// broadcast in response, also send periodic notifications reminding that farm exists
602async fn identify_responder(
603    nats_client: &NatsClient,
604    farmer_id: ClusterFarmerId,
605    farmer_id_string: &str,
606    identification_broadcast_interval: Duration,
607) -> anyhow::Result<()> {
608    let mut subscription = nats_client
609        .subscribe_to_broadcasts::<ClusterControllerFarmerIdentifyBroadcast>(None, None)
610        .await
611        .map_err(|error| {
612            anyhow!("Failed to subscribe to farmer identify broadcast requests: {error}")
613        })?
614        .fuse();
615
616    // Also send periodic updates in addition to the subscription response
617    let mut interval = tokio::time::interval(identification_broadcast_interval);
618    interval.set_missed_tick_behavior(MissedTickBehavior::Delay);
619
620    let mut last_identification = Instant::now();
621
622    loop {
623        select! {
624            maybe_message = subscription.next() => {
625                let Some(message) = maybe_message else {
626                    debug!("Identify broadcast stream ended");
627                    break;
628                };
629
630                trace!(?message, "Farmer received identify broadcast message");
631
632                if last_identification.elapsed() < MIN_FARMER_IDENTIFICATION_INTERVAL {
633                    // Skip too frequent identification requests
634                    continue;
635                }
636
637                last_identification = Instant::now();
638                send_identify_broadcast(nats_client, farmer_id, farmer_id_string).await;
639                interval.reset();
640            }
641            _ = interval.tick().fuse() => {
642                last_identification = Instant::now();
643                trace!("Farmer self-identification");
644
645                send_identify_broadcast(nats_client, farmer_id, farmer_id_string).await;
646            }
647        }
648    }
649
650    Ok(())
651}
652
653async fn send_identify_broadcast(
654    nats_client: &NatsClient,
655    farmer_id: ClusterFarmerId,
656    farmer_id_string: &str,
657) {
658    if let Err(error) = nats_client
659        .broadcast(&new_identify_message(farmer_id), farmer_id_string)
660        .await
661    {
662        warn!(%farmer_id, %error, "Failed to send farmer identify notification");
663    }
664}
665
666fn new_identify_message(farmer_id: ClusterFarmerId) -> ClusterFarmerIdentifyBroadcast {
667    ClusterFarmerIdentifyBroadcast { farmer_id }
668}
669
670async fn farms_details_responder(
671    nats_client: &NatsClient,
672    farmer_id_string: &str,
673    farms_details: &[FarmDetails],
674) -> anyhow::Result<()> {
675    nats_client
676        .stream_request_responder(
677            Some(farmer_id_string),
678            Some(farmer_id_string.to_string()),
679            |_request: ClusterFarmerFarmDetailsRequest| async {
680                Some(stream::iter(farms_details.iter().map(|farm_details| {
681                    ClusterFarmerFarmDetails {
682                        farm_id: farm_details.farm_id,
683                        total_sectors_count: farm_details.total_sectors_count,
684                    }
685                })))
686            },
687        )
688        .await
689}
690
691async fn plotted_sectors_responder(
692    nats_client: &NatsClient,
693    farms_details: &[FarmDetails],
694) -> anyhow::Result<()> {
695    farms_details
696        .iter()
697        .map(|farm_details| async move {
698            nats_client
699                .stream_request_responder::<_, _, Pin<Box<dyn Stream<Item = _> + Send>>, _>(
700                    Some(&farm_details.farm_id_string),
701                    Some(farm_details.farm_id_string.clone()),
702                    |_request: ClusterFarmerPlottedSectorsRequest| async move {
703                        Some(match farm_details.plotted_sectors.get().await {
704                            Ok(plotted_sectors) => {
705                                Box::pin(plotted_sectors.map(|maybe_plotted_sector| {
706                                    maybe_plotted_sector.map_err(|error| error.to_string())
707                                })) as _
708                            }
709                            Err(error) => {
710                                error!(
711                                    %error,
712                                    farm_id = %farm_details.farm_id,
713                                    "Failed to get plotted sectors"
714                                );
715
716                                Box::pin(stream::once(async move {
717                                    Err(format!("Failed to get plotted sectors: {error}"))
718                                })) as _
719                            }
720                        })
721                    },
722                )
723                .instrument(info_span!("", cache_id = %farm_details.farm_id))
724                .await
725        })
726        .collect::<FuturesUnordered<_>>()
727        .next()
728        .await
729        .ok_or_else(|| anyhow!("No farms"))?
730}
731
732async fn read_piece_responder(
733    nats_client: &NatsClient,
734    farms_details: &[FarmDetails],
735) -> anyhow::Result<()> {
736    farms_details
737        .iter()
738        .map(|farm_details| async move {
739            nats_client
740                .request_responder(
741                    Some(farm_details.farm_id_string.as_str()),
742                    Some(farm_details.farm_id_string.clone()),
743                    |request: ClusterFarmerReadPieceRequest| async move {
744                        Some(
745                            farm_details
746                                .piece_reader
747                                .read_piece(request.sector_index, request.piece_offset)
748                                .await
749                                .map_err(|error| error.to_string()),
750                        )
751                    },
752                )
753                .instrument(info_span!("", cache_id = %farm_details.farm_id))
754                .await
755        })
756        .collect::<FuturesUnordered<_>>()
757        .next()
758        .await
759        .ok_or_else(|| anyhow!("No farms"))?
760}