1pub mod caches;
10pub mod farms;
11mod stream_map;
12
13use crate::cluster::cache::{ClusterCacheReadPieceRequest, ClusterCacheReadPiecesRequest};
14use crate::cluster::nats_client::{
15 GenericBroadcast, GenericNotification, GenericRequest, GenericStreamRequest, NatsClient,
16};
17use crate::farm::{PieceCacheId, PieceCacheOffset};
18use crate::farmer_cache::FarmerCache;
19use crate::node_client::NodeClient;
20use ab_core_primitives::pieces::{Piece, PieceIndex};
21use ab_core_primitives::segments::{
22 SegmentIndex, SuperSegmentHeader, SuperSegmentIndex, SuperSegmentRoot,
23};
24use ab_data_retrieval::piece_getter::PieceGetter;
25use ab_farmer_rpc_primitives::{
26 BlockSealInfo, BlockSealResponse, FarmerAppInfo, FarmerShardMembershipInfo, SlotInfo,
27 SolutionResponse,
28};
29use anyhow::anyhow;
30use async_nats::HeaderValue;
31use async_trait::async_trait;
32use futures::channel::mpsc;
33use futures::future::FusedFuture;
34use futures::stream::FuturesUnordered;
35use futures::{FutureExt, Stream, StreamExt, select, stream};
36use parity_scale_codec::{Decode, Encode};
37use parking_lot::Mutex;
38use rand::prelude::*;
39use std::collections::{HashMap, HashSet};
40use std::pin::Pin;
41use std::task::Poll;
42use tracing::{debug, error, trace, warn};
43use triomphe::Arc;
44
45const GLOBAL_CACHE_GROUP: &str = "_";
48
49#[derive(Debug, Copy, Clone, Encode, Decode)]
51pub struct ClusterControllerFarmerIdentifyBroadcast;
52
53impl GenericBroadcast for ClusterControllerFarmerIdentifyBroadcast {
54 const SUBJECT: &'static str = "ab.controller.farmer-identify";
55}
56
57#[derive(Debug, Copy, Clone, Encode, Decode)]
59pub struct ClusterControllerCacheIdentifyBroadcast;
60
61impl GenericBroadcast for ClusterControllerCacheIdentifyBroadcast {
62 const SUBJECT: &'static str = "ab.controller.*.cache-identify";
64}
65
66#[derive(Debug, Clone, Encode, Decode)]
68struct ClusterControllerSlotInfoBroadcast {
69 slot_info: SlotInfo,
70 instance: String,
71}
72
73impl GenericBroadcast for ClusterControllerSlotInfoBroadcast {
74 const SUBJECT: &'static str = "ab.controller.slot-info";
75
76 fn deterministic_message_id(&self) -> Option<HeaderValue> {
77 Some(
80 HeaderValue::try_from(format!("slot-info-{}", self.slot_info.slot))
81 .expect("No `\r` or `\n`; qed"),
82 )
83 }
84}
85
86#[derive(Debug, Clone, Encode, Decode)]
88struct ClusterControllerBlockSealingBroadcast {
89 block_sealing_info: BlockSealInfo,
90}
91
92impl GenericBroadcast for ClusterControllerBlockSealingBroadcast {
93 const SUBJECT: &'static str = "ab.controller.block-sealing-info";
94}
95
96#[derive(Debug, Clone, Encode, Decode)]
98struct ClusterControllerNewSuperSegmentHeaderBroadcast {
99 new_super_segment_header: SuperSegmentHeader,
100}
101
102impl GenericBroadcast for ClusterControllerNewSuperSegmentHeaderBroadcast {
103 const SUBJECT: &'static str = "ab.controller.new-super-segment-header";
104
105 fn deterministic_message_id(&self) -> Option<HeaderValue> {
106 Some(
109 HeaderValue::try_from(format!(
110 "new-super-segment-{}",
111 self.new_super_segment_header.index
112 ))
113 .expect("No `\r` or `\n`; qed"),
114 )
115 }
116}
117
118#[derive(Debug, Clone, Encode, Decode)]
120struct ClusterControllerSolutionNotification {
121 solution_response: SolutionResponse,
122}
123
124impl GenericNotification for ClusterControllerSolutionNotification {
125 const SUBJECT: &'static str = "ab.controller.*.solution";
126}
127
128#[derive(Debug, Clone, Encode, Decode)]
130struct ClusterControllerBlockSealNotification {
131 block_seal: BlockSealResponse,
132}
133
134impl GenericNotification for ClusterControllerBlockSealNotification {
135 const SUBJECT: &'static str = "ab.controller.block-seal";
136}
137
138#[derive(Debug, Clone, Encode, Decode)]
140struct ClusterControllerFarmerAppInfoRequest;
141
142impl GenericRequest for ClusterControllerFarmerAppInfoRequest {
143 const SUBJECT: &'static str = "ab.controller.farmer-app-info";
144 type Response = Result<FarmerAppInfo, String>;
145}
146
147#[derive(Debug, Clone, Encode, Decode)]
149struct ClusterControllerSuperSegmentHeadersRequest {
150 super_segment_indices: Vec<SuperSegmentIndex>,
151}
152
153impl GenericRequest for ClusterControllerSuperSegmentHeadersRequest {
154 const SUBJECT: &'static str = "ab.controller.super-segment-headers";
155 type Response = Vec<Option<SuperSegmentHeader>>;
156}
157
158#[derive(Debug, Clone, Encode, Decode)]
160struct ClusterControllerSuperSegmentRootForSegmentIndexRequest {
161 segment_index: SegmentIndex,
162}
163
164impl GenericRequest for ClusterControllerSuperSegmentRootForSegmentIndexRequest {
165 const SUBJECT: &'static str = "ab.controller.super-segment-root-for-segment-index";
166 type Response = Option<SuperSegmentRoot>;
167}
168
169#[derive(Debug, Clone, Encode, Decode)]
171struct ClusterControllerFindPieceInCacheRequest {
172 piece_index: PieceIndex,
173}
174
175impl GenericRequest for ClusterControllerFindPieceInCacheRequest {
176 const SUBJECT: &'static str = "ab.controller.*.find-piece-in-cache";
177 type Response = Option<(PieceCacheId, PieceCacheOffset)>;
178}
179
180#[derive(Debug, Clone, Encode, Decode)]
182struct ClusterControllerFindPiecesInCacheRequest {
183 piece_indices: Vec<PieceIndex>,
184}
185
186impl GenericStreamRequest for ClusterControllerFindPiecesInCacheRequest {
187 const SUBJECT: &'static str = "ab.controller.*.find-pieces-in-cache";
188 type Response = (PieceIndex, PieceCacheId, PieceCacheOffset);
190}
191
192#[derive(Debug, Clone, Encode, Decode)]
194struct ClusterControllerPieceRequest {
195 piece_index: PieceIndex,
196}
197
198impl GenericRequest for ClusterControllerPieceRequest {
199 const SUBJECT: &'static str = "ab.controller.piece";
200 type Response = Option<Piece>;
201}
202
203#[derive(Debug, Clone, Encode, Decode)]
205struct ClusterControllerPiecesRequest {
206 piece_indices: Vec<PieceIndex>,
207}
208
209impl GenericStreamRequest for ClusterControllerPiecesRequest {
210 const SUBJECT: &'static str = "ab.controller.pieces";
211 type Response = (PieceIndex, Piece);
213}
214
215#[derive(Debug, Clone)]
217pub struct ClusterPieceGetter {
218 nats_client: NatsClient,
219 cache_group: String,
220}
221
222#[async_trait]
223impl PieceGetter for ClusterPieceGetter {
224 async fn get_piece(&self, piece_index: PieceIndex) -> anyhow::Result<Option<Piece>> {
225 if let Some((piece_cache_id, piece_cache_offset)) = self
226 .nats_client
227 .request(
228 &ClusterControllerFindPieceInCacheRequest { piece_index },
229 Some(&self.cache_group),
230 )
231 .await?
232 {
233 trace!(
234 %piece_index,
235 %piece_cache_id,
236 %piece_cache_offset,
237 "Found piece in cache, retrieving"
238 );
239
240 match self
241 .nats_client
242 .request(
243 &ClusterCacheReadPieceRequest {
244 offset: piece_cache_offset,
245 },
246 Some(&piece_cache_id.to_string()),
247 )
248 .await
249 .map_err(|error| error.to_string())
250 .flatten()
251 {
252 Ok(Some((retrieved_piece_index, piece))) => {
253 if retrieved_piece_index == piece_index {
254 trace!(
255 %piece_index,
256 %piece_cache_id,
257 %piece_cache_offset,
258 "Retrieved piece from cache successfully"
259 );
260
261 return Ok(Some(piece));
262 }
263
264 trace!(
265 %piece_index,
266 %piece_cache_id,
267 %piece_cache_offset,
268 "Retrieving piece was replaced in cache during retrieval"
269 );
270 }
271 Ok(None) => {
272 trace!(
273 %piece_index,
274 %piece_cache_id,
275 %piece_cache_offset,
276 "Piece cache didn't have piece at offset"
277 );
278 }
279 Err(error) => {
280 debug!(
281 %piece_index,
282 %piece_cache_id,
283 %piece_cache_offset,
284 %error,
285 "Retrieving piece from cache failed"
286 );
287 }
288 }
289 } else {
290 trace!(%piece_index, "Piece not found in cache");
291 }
292
293 Ok(self
294 .nats_client
295 .request(&ClusterControllerPieceRequest { piece_index }, None)
296 .await?)
297 }
298
299 async fn get_pieces<'a>(
300 &'a self,
301 piece_indices: Vec<PieceIndex>,
302 ) -> anyhow::Result<
303 Box<dyn Stream<Item = (PieceIndex, anyhow::Result<Option<Piece>>)> + Send + Unpin + 'a>,
304 > {
305 let (tx, mut rx) = mpsc::unbounded();
306
307 let piece_indices_to_get =
308 Mutex::new(piece_indices.iter().copied().collect::<HashSet<_>>());
309
310 let mut cached_pieces_by_cache_id = HashMap::<PieceCacheId, Vec<PieceCacheOffset>>::new();
311
312 {
313 let mut cached_pieces = self
314 .nats_client
315 .stream_request(
316 &ClusterControllerFindPiecesInCacheRequest { piece_indices },
317 Some(&self.cache_group),
318 )
319 .await?;
320
321 while let Some((_piece_index, piece_cache_id, piece_cache_offset)) =
322 cached_pieces.next().await
323 {
324 cached_pieces_by_cache_id
325 .entry(piece_cache_id)
326 .or_default()
327 .push(piece_cache_offset);
328 }
329 }
330
331 let fut = async move {
332 let tx = &tx;
333
334 cached_pieces_by_cache_id
335 .into_iter()
336 .map(|(piece_cache_id, offsets)| {
337 let piece_indices_to_get = &piece_indices_to_get;
338
339 async move {
340 let mut pieces_stream = match self
341 .nats_client
342 .stream_request(
343 &ClusterCacheReadPiecesRequest { offsets },
344 Some(&piece_cache_id.to_string()),
345 )
346 .await
347 {
348 Ok(pieces) => pieces,
349 Err(error) => {
350 warn!(
351 %error,
352 %piece_cache_id,
353 "Failed to request pieces from cache"
354 );
355
356 return;
357 }
358 };
359
360 while let Some(piece_result) = pieces_stream.next().await {
361 let (piece_offset, maybe_piece) = match piece_result {
362 Ok(result) => result,
363 Err(error) => {
364 warn!(%error, "Failed to get piece from cache");
365 continue;
366 }
367 };
368
369 if let Some((piece_index, piece)) = maybe_piece {
370 piece_indices_to_get.lock().remove(&piece_index);
371
372 tx.unbounded_send((piece_index, Ok(Some(piece)))).expect(
373 "This future isn't polled after receiver is dropped; qed",
374 );
375 } else {
376 warn!(
377 %piece_cache_id,
378 %piece_offset,
379 "Failed to get piece from cache, it was missing or already gone"
380 );
381 }
382 }
383 }
384 })
385 .collect::<FuturesUnordered<_>>()
386 .for_each(|()| async {})
388 .await;
389
390 let mut piece_indices_to_get = piece_indices_to_get.into_inner();
391 if piece_indices_to_get.is_empty() {
392 return;
393 }
394
395 let mut pieces_from_controller = match self
396 .nats_client
397 .stream_request(
398 &ClusterControllerPiecesRequest {
399 piece_indices: piece_indices_to_get.iter().copied().collect(),
400 },
401 None,
402 )
403 .await
404 {
405 Ok(pieces_from_controller) => pieces_from_controller,
406 Err(error) => {
407 error!(%error, "Failed to get pieces from controller");
408
409 for piece_index in piece_indices_to_get {
410 tx.unbounded_send((
411 piece_index,
412 Err(anyhow::anyhow!("Failed to get piece from controller")),
413 ))
414 .expect("This future isn't polled after receiver is dropped; qed");
415 }
416 return;
417 }
418 };
419
420 while let Some((piece_index, piece)) = pieces_from_controller.next().await {
421 piece_indices_to_get.remove(&piece_index);
422 tx.unbounded_send((piece_index, Ok(Some(piece))))
423 .expect("This future isn't polled after receiver is dropped; qed");
424 }
425
426 for piece_index in piece_indices_to_get {
427 tx.unbounded_send((piece_index, Err(anyhow::anyhow!("Failed to get piece"))))
428 .expect("This future isn't polled after receiver is dropped; qed");
429 }
430 };
431 let mut fut = Box::pin(fut.fuse());
432
433 Ok(Box::new(stream::poll_fn(move |cx| {
435 if !fut.is_terminated() {
436 let _: Poll<()> = fut.poll_unpin(cx);
438 }
439
440 if let Poll::Ready(maybe_result) = rx.poll_next_unpin(cx) {
441 return Poll::Ready(maybe_result);
442 }
443
444 Poll::Pending
446 })))
447 }
448}
449
450impl ClusterPieceGetter {
451 #[inline]
453 pub fn new(nats_client: NatsClient, cache_group: Option<String>) -> Self {
454 Self {
455 nats_client,
456 cache_group: cache_group.unwrap_or_else(|| GLOBAL_CACHE_GROUP.to_string()),
457 }
458 }
459}
460
461#[derive(Debug, Clone)]
464pub struct ClusterNodeClient {
465 nats_client: NatsClient,
466 last_slot_info_instance: Arc<Mutex<String>>,
469}
470
471impl ClusterNodeClient {
472 pub fn new(nats_client: NatsClient) -> Self {
474 Self {
475 nats_client,
476 last_slot_info_instance: Arc::default(),
477 }
478 }
479}
480
481#[async_trait]
482impl NodeClient for ClusterNodeClient {
483 async fn farmer_app_info(&self) -> anyhow::Result<FarmerAppInfo> {
484 Ok(self
485 .nats_client
486 .request(&ClusterControllerFarmerAppInfoRequest, None)
487 .await?
488 .map_err(anyhow::Error::msg)?)
489 }
490
491 async fn subscribe_slot_info(
492 &self,
493 ) -> anyhow::Result<Pin<Box<dyn Stream<Item = SlotInfo> + Send + 'static>>> {
494 let subscription = self
495 .nats_client
496 .subscribe_to_broadcasts::<ClusterControllerSlotInfoBroadcast>(None, None)
497 .await?
498 .filter_map({
499 let mut last_slot_number = None;
500 let last_slot_info_instance = Arc::clone(&self.last_slot_info_instance);
501
502 move |broadcast| {
503 let slot_info = broadcast.slot_info;
504
505 let maybe_slot_info = if let Some(last_slot_number) = last_slot_number
506 && last_slot_number >= slot_info.slot
507 {
508 None
509 } else {
510 last_slot_number.replace(slot_info.slot);
511 *last_slot_info_instance.lock() = broadcast.instance;
512
513 Some(slot_info)
514 };
515
516 async move { maybe_slot_info }
517 }
518 });
519
520 Ok(Box::pin(subscription))
521 }
522
523 async fn submit_solution_response(
524 &self,
525 solution_response: SolutionResponse,
526 ) -> anyhow::Result<()> {
527 let last_slot_info_instance = self.last_slot_info_instance.lock().clone();
528 Ok(self
529 .nats_client
530 .notification(
531 &ClusterControllerSolutionNotification { solution_response },
532 Some(&last_slot_info_instance),
533 )
534 .await?)
535 }
536
537 async fn subscribe_block_sealing(
538 &self,
539 ) -> anyhow::Result<Pin<Box<dyn Stream<Item = BlockSealInfo> + Send + 'static>>> {
540 let subscription = self
541 .nats_client
542 .subscribe_to_broadcasts::<ClusterControllerBlockSealingBroadcast>(None, None)
543 .await?
544 .map(|broadcast| broadcast.block_sealing_info);
545
546 Ok(Box::pin(subscription))
547 }
548
549 async fn submit_block_seal(&self, block_seal: BlockSealResponse) -> anyhow::Result<()> {
550 Ok(self
551 .nats_client
552 .notification(&ClusterControllerBlockSealNotification { block_seal }, None)
553 .await?)
554 }
555
556 async fn subscribe_new_super_segment_headers(
557 &self,
558 ) -> anyhow::Result<Pin<Box<dyn Stream<Item = SuperSegmentHeader> + Send + 'static>>> {
559 let subscription = self
560 .nats_client
561 .subscribe_to_broadcasts::<ClusterControllerNewSuperSegmentHeaderBroadcast>(None, None)
562 .await?
563 .filter_map({
564 let mut last_super_segment_index = None;
565
566 move |broadcast| {
567 let new_super_segment_header = broadcast.new_super_segment_header;
568 let super_segment_index = new_super_segment_header.index.as_inner();
569
570 let maybe_super_segment_header = if let Some(last_super_segment_index) =
571 last_super_segment_index
572 && last_super_segment_index >= super_segment_index
573 {
574 None
575 } else {
576 last_super_segment_index.replace(super_segment_index);
577
578 Some(new_super_segment_header)
579 };
580
581 async move { maybe_super_segment_header }
582 }
583 });
584
585 Ok(Box::pin(subscription))
586 }
587
588 async fn super_segment_headers(
589 &self,
590 super_segment_indices: Vec<SuperSegmentIndex>,
591 ) -> anyhow::Result<Vec<Option<SuperSegmentHeader>>> {
592 Ok(self
593 .nats_client
594 .request(
595 &ClusterControllerSuperSegmentHeadersRequest {
596 super_segment_indices,
597 },
598 None,
599 )
600 .await?)
601 }
602
603 async fn super_segment_root_for_segment_index(
604 &self,
605 segment_index: SegmentIndex,
606 ) -> anyhow::Result<Option<SuperSegmentRoot>> {
607 Ok(self
608 .nats_client
609 .request(
610 &ClusterControllerSuperSegmentRootForSegmentIndexRequest { segment_index },
611 None,
612 )
613 .await?)
614 }
615
616 async fn piece(&self, piece_index: PieceIndex) -> anyhow::Result<Option<Piece>> {
617 Ok(self
618 .nats_client
619 .request(&ClusterControllerPieceRequest { piece_index }, None)
620 .await?)
621 }
622
623 async fn update_shard_membership_info(
624 &self,
625 _info: FarmerShardMembershipInfo,
626 ) -> anyhow::Result<()> {
627 Ok(())
629 }
630}
631
632pub async fn controller_service<NC, PG>(
638 nats_client: &NatsClient,
639 node_client: &NC,
640 piece_getter: &PG,
641 farmer_caches: &[(&str, &FarmerCache)],
642 instance: &str,
643 primary_instance: bool,
644) -> anyhow::Result<()>
645where
646 NC: NodeClient,
647 PG: PieceGetter + Sync,
648{
649 if primary_instance {
650 select! {
651 result = slot_info_broadcaster(nats_client, node_client, instance).fuse() => {
652 result
653 },
654 result = block_sealing_broadcaster(nats_client, node_client, instance).fuse() => {
655 result
656 },
657 result = new_super_segment_headers_broadcaster(nats_client, node_client, instance).fuse() => {
658 result
659 },
660 result = solution_response_forwarder(nats_client, node_client, instance).fuse() => {
661 result
662 },
663 result = block_seal_forwarder(nats_client, node_client, instance).fuse() => {
664 result
665 },
666 result = farmer_app_info_responder(nats_client, node_client).fuse() => {
667 result
668 },
669 result = super_segment_headers_responder(nats_client, node_client).fuse() => {
670 result
671 },
672 result = super_segment_root_for_segment_index_responder(nats_client, node_client).fuse() => {
673 result
674 },
675 result = find_piece_responder(nats_client, farmer_caches).fuse() => {
676 result
677 },
678 result = find_pieces_responder(nats_client, farmer_caches).fuse() => {
679 result
680 },
681 result = piece_responder(nats_client, piece_getter).fuse() => {
682 result
683 },
684 result = pieces_responder(nats_client, piece_getter).fuse() => {
685 result
686 },
687 }
688 } else {
689 select! {
690 result = farmer_app_info_responder(nats_client, node_client).fuse() => {
691 result
692 },
693 result = super_segment_headers_responder(nats_client, node_client).fuse() => {
694 result
695 },
696 result = super_segment_root_for_segment_index_responder(nats_client, node_client).fuse() => {
697 result
698 },
699 result = find_piece_responder(nats_client, farmer_caches).fuse() => {
700 result
701 },
702 result = find_pieces_responder(nats_client, farmer_caches).fuse() => {
703 result
704 },
705 result = piece_responder(nats_client, piece_getter).fuse() => {
706 result
707 },
708 result = pieces_responder(nats_client, piece_getter).fuse() => {
709 result
710 },
711 }
712 }
713}
714
715async fn slot_info_broadcaster<NC>(
716 nats_client: &NatsClient,
717 node_client: &NC,
718 instance: &str,
719) -> anyhow::Result<()>
720where
721 NC: NodeClient,
722{
723 let mut slot_info_notifications = node_client
724 .subscribe_slot_info()
725 .await
726 .map_err(|error| anyhow!("Failed to subscribe to slot info notifications: {error}"))?;
727
728 while let Some(slot_info) = slot_info_notifications.next().await {
729 debug!(?slot_info, "New slot");
730
731 let slot = slot_info.slot;
732
733 if let Err(error) = nats_client
734 .broadcast(
735 &ClusterControllerSlotInfoBroadcast {
736 slot_info,
737 instance: instance.to_string(),
738 },
739 instance,
740 )
741 .await
742 {
743 warn!(%slot, %error, "Failed to broadcast slot info");
744 }
745 }
746
747 Ok(())
748}
749
750async fn block_sealing_broadcaster<NC>(
751 nats_client: &NatsClient,
752 node_client: &NC,
753 instance: &str,
754) -> anyhow::Result<()>
755where
756 NC: NodeClient,
757{
758 let mut block_sealing_subscription = node_client
759 .subscribe_block_sealing()
760 .await
761 .map_err(|error| anyhow!("Failed to subscribe to block sealing notifications: {error}"))?;
762
763 while let Some(block_sealing_info) = block_sealing_subscription.next().await {
764 trace!(?block_sealing_info, "New block sealing notification");
765
766 if let Err(error) = nats_client
767 .broadcast(
768 &ClusterControllerBlockSealingBroadcast { block_sealing_info },
769 instance,
770 )
771 .await
772 {
773 warn!(%error, "Failed to broadcast block sealing info");
774 }
775 }
776
777 Ok(())
778}
779
780async fn new_super_segment_headers_broadcaster<NC>(
781 nats_client: &NatsClient,
782 node_client: &NC,
783 instance: &str,
784) -> anyhow::Result<()>
785where
786 NC: NodeClient,
787{
788 let mut new_super_segments_notifications = node_client
789 .subscribe_new_super_segment_headers()
790 .await
791 .map_err(|error| {
792 anyhow!("Failed to subscribe to new super segment header notifications: {error}")
793 })?;
794
795 while let Some(new_super_segment_header) = new_super_segments_notifications.next().await {
796 trace!(
797 ?new_super_segment_header,
798 "New archived new super segment header notification"
799 );
800
801 if let Err(error) = nats_client
802 .broadcast(
803 &ClusterControllerNewSuperSegmentHeaderBroadcast {
804 new_super_segment_header,
805 },
806 instance,
807 )
808 .await
809 {
810 warn!(%error, "Failed to broadcast new super segment header info");
811 }
812 }
813
814 Ok(())
815}
816
817async fn solution_response_forwarder<NC>(
818 nats_client: &NatsClient,
819 node_client: &NC,
820 instance: &str,
821) -> anyhow::Result<()>
822where
823 NC: NodeClient,
824{
825 let mut subscription = nats_client
826 .subscribe_to_notifications::<ClusterControllerSolutionNotification>(
827 Some(instance),
828 Some(instance.to_string()),
829 )
830 .await
831 .map_err(|error| anyhow!("Failed to subscribe to solution notifications: {error}"))?;
832
833 while let Some(notification) = subscription.next().await {
834 debug!(?notification, "Solution notification");
835
836 let slot = notification.solution_response.slot_number;
837 let public_key_hash = notification.solution_response.solution.public_key_hash;
838 let sector_index = notification.solution_response.solution.sector_index;
839
840 if let Err(error) = node_client
841 .submit_solution_response(notification.solution_response)
842 .await
843 {
844 warn!(
845 %error,
846 %slot,
847 %public_key_hash,
848 %sector_index,
849 "Failed to send solution response"
850 );
851 }
852 }
853
854 Ok(())
855}
856
857async fn block_seal_forwarder<NC>(
858 nats_client: &NatsClient,
859 node_client: &NC,
860 instance: &str,
861) -> anyhow::Result<()>
862where
863 NC: NodeClient,
864{
865 let mut subscription = nats_client
866 .subscribe_to_notifications::<ClusterControllerBlockSealNotification>(
867 None,
868 Some(instance.to_string()),
869 )
870 .await
871 .map_err(|error| anyhow!("Failed to subscribe to block seal notifications: {error}"))?;
872
873 while let Some(notification) = subscription.next().await {
874 debug!(?notification, "Block seal notification");
875
876 if let Err(error) = node_client.submit_block_seal(notification.block_seal).await {
877 warn!(%error, "Failed to send block seal");
878 }
879 }
880
881 Ok(())
882}
883
884async fn farmer_app_info_responder<NC>(
885 nats_client: &NatsClient,
886 node_client: &NC,
887) -> anyhow::Result<()>
888where
889 NC: NodeClient,
890{
891 nats_client
892 .request_responder(
893 None,
894 Some("ab.controller".to_string()),
895 |_: ClusterControllerFarmerAppInfoRequest| async move {
896 Some(
897 node_client
898 .farmer_app_info()
899 .await
900 .map_err(|error| error.to_string()),
901 )
902 },
903 )
904 .await
905}
906
907async fn super_segment_headers_responder<NC>(
908 nats_client: &NatsClient,
909 node_client: &NC,
910) -> anyhow::Result<()>
911where
912 NC: NodeClient,
913{
914 nats_client
915 .request_responder(
916 None,
917 Some("ab.controller".to_string()),
918 |ClusterControllerSuperSegmentHeadersRequest { super_segment_indices }| async move {
919 node_client
920 .super_segment_headers(super_segment_indices.clone())
921 .await
922 .inspect_err(|error| {
923 warn!(%error, ?super_segment_indices, "Failed to get super segment headers");
924 })
925 .ok()
926 },
927 )
928 .await
929}
930
931async fn super_segment_root_for_segment_index_responder<NC>(
932 nats_client: &NatsClient,
933 node_client: &NC,
934) -> anyhow::Result<()>
935where
936 NC: NodeClient,
937{
938 nats_client
939 .request_responder(
940 None,
941 Some("ab.controller".to_string()),
942 |ClusterControllerSuperSegmentRootForSegmentIndexRequest { segment_index }| async move {
943 node_client
944 .super_segment_root_for_segment_index(segment_index)
945 .await
946 .inspect_err(|error| {
947 warn!(
948 %error,
949 %segment_index,
950 "Failed to get super segment root for segment index"
951 );
952 })
953 .ok()
954 },
955 )
956 .await
957}
958
959async fn find_piece_responder(
960 nats_client: &NatsClient,
961 farmer_caches: &[(&str, &FarmerCache)],
962) -> anyhow::Result<()> {
963 futures::future::try_join(
964 farmer_caches
965 .iter()
966 .map(|(cache_group, farmer_cache)| {
967 nats_client.request_responder(
968 Some(cache_group),
969 Some("ab.controller".to_string()),
970 move |ClusterControllerFindPieceInCacheRequest { piece_index }| async move {
971 Some(farmer_cache.find_piece(piece_index).await)
972 },
973 )
974 })
975 .collect::<FuturesUnordered<_>>()
976 .next()
977 .map(|result| result.unwrap_or(Ok(()))),
978 nats_client.request_responder(
979 Some(GLOBAL_CACHE_GROUP),
980 Some("ab.controller".to_string()),
981 |ClusterControllerFindPieceInCacheRequest { piece_index }| async move {
982 let (_cache_group, farmer_cache) = farmer_caches.iter().choose(&mut rand::rng())?;
983 Some(farmer_cache.find_piece(piece_index).await)
984 },
985 ),
986 )
987 .await
988 .map(|((), ())| ())
989}
990
991async fn find_pieces_responder(
992 nats_client: &NatsClient,
993 farmer_caches: &[(&str, &FarmerCache)],
994) -> anyhow::Result<()> {
995 futures::future::try_join(
996 farmer_caches
997 .iter()
998 .map(|(cache_group, farmer_cache)| {
999 nats_client.stream_request_responder(
1000 Some(cache_group),
1001 Some("ab.controller".to_string()),
1002 move |ClusterControllerFindPiecesInCacheRequest { piece_indices }| async move {
1003 Some(stream::iter(farmer_cache.find_pieces(piece_indices).await))
1004 },
1005 )
1006 })
1007 .collect::<FuturesUnordered<_>>()
1008 .next()
1009 .map(|result| result.unwrap_or(Ok(()))),
1010 nats_client.stream_request_responder(
1011 Some(GLOBAL_CACHE_GROUP),
1012 Some("ab.controller".to_string()),
1013 |ClusterControllerFindPiecesInCacheRequest { piece_indices }| async move {
1014 let (_cache_group, farmer_cache) = farmer_caches.iter().choose(&mut rand::rng())?;
1015 Some(stream::iter(farmer_cache.find_pieces(piece_indices).await))
1016 },
1017 ),
1018 )
1019 .await
1020 .map(|((), ())| ())
1021}
1022
1023async fn piece_responder<PG>(nats_client: &NatsClient, piece_getter: &PG) -> anyhow::Result<()>
1024where
1025 PG: PieceGetter + Sync,
1026{
1027 nats_client
1028 .request_responder(
1029 None,
1030 Some("ab.controller".to_string()),
1031 |ClusterControllerPieceRequest { piece_index }| async move {
1032 piece_getter
1033 .get_piece(piece_index)
1034 .await
1035 .inspect_err(|error| warn!(%error, %piece_index, "Failed to get piece"))
1036 .ok()
1037 },
1038 )
1039 .await
1040}
1041
1042async fn pieces_responder<PG>(nats_client: &NatsClient, piece_getter: &PG) -> anyhow::Result<()>
1043where
1044 PG: PieceGetter + Sync,
1045{
1046 nats_client
1047 .stream_request_responder(
1048 None,
1049 Some("ab.controller".to_string()),
1050 |ClusterControllerPiecesRequest { piece_indices }| async move {
1051 piece_getter
1052 .get_pieces(piece_indices)
1053 .await
1054 .map(|stream| {
1055 Box::pin(stream.filter_map(
1056 |(piece_index, maybe_piece_result)| async move {
1057 match maybe_piece_result {
1058 Ok(Some(piece)) => Some((piece_index, piece)),
1059 Ok(None) => None,
1060 Err(error) => {
1061 warn!(%error, %piece_index, "Failed to get piece");
1062 None
1063 }
1064 }
1065 },
1066 ))
1067 })
1068 .inspect_err(|error| warn!(%error, "Failed to get pieces"))
1069 .ok()
1070 },
1071 )
1072 .await
1073}