ab_farmer/
plotter.rs

1//! Plotter abstraction
2//!
3//! Plotter is abstracted away to support different implementations. Originally it was just CPU, but
4//! eventually abstract network-attached, GPU and hybrid plotters became an option as well. Having a
5//! trait with async API representing plotting functionality allows composition of different
6//! implementations without the rest of the farmer being aware of implementation details.
7
8pub mod cpu;
9pub mod gpu;
10pub mod pool;
11
12use ab_core_primitives::ed25519::Ed25519PublicKey;
13use ab_core_primitives::sectors::SectorIndex;
14use ab_farmer_components::FarmerProtocolInfo;
15use ab_farmer_components::plotting::PlottedSector;
16use async_trait::async_trait;
17use bytes::Bytes;
18use futures::Stream;
19use futures::channel::mpsc;
20use std::fmt;
21use std::pin::Pin;
22use std::sync::Arc;
23use std::time::Duration;
24
25/// Sector plotting progress
26pub enum SectorPlottingProgress {
27    /// Downloading sector pieces
28    Downloading,
29    /// Downloaded sector pieces
30    Downloaded(Duration),
31    /// Encoding sector pieces
32    Encoding,
33    /// Encoded sector pieces
34    Encoded(Duration),
35    /// Finished plotting
36    Finished {
37        /// Information about the plotted sector
38        plotted_sector: PlottedSector,
39        /// How much time it took to plot a sector
40        time: Duration,
41        /// Stream of all plotted sector bytes
42        sector: Pin<Box<dyn Stream<Item = Result<Bytes, String>> + Send + Sync>>,
43    },
44    /// Plotting failed
45    Error {
46        /// Error message
47        error: String,
48    },
49}
50
51impl fmt::Debug for SectorPlottingProgress {
52    #[inline]
53    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54        match self {
55            SectorPlottingProgress::Downloading => fmt::Formatter::write_str(f, "Downloading"),
56            SectorPlottingProgress::Downloaded(time) => {
57                f.debug_tuple_field1_finish("Downloaded", &time)
58            }
59            SectorPlottingProgress::Encoding => fmt::Formatter::write_str(f, "Encoding"),
60            SectorPlottingProgress::Encoded(time) => f.debug_tuple_field1_finish("Encoded", &time),
61            SectorPlottingProgress::Finished {
62                plotted_sector,
63                time,
64                sector: _,
65            } => f.debug_struct_field3_finish(
66                "Finished",
67                "plotted_sector",
68                plotted_sector,
69                "time",
70                time,
71                "sector",
72                &"<stream>",
73            ),
74            SectorPlottingProgress::Error { error } => {
75                f.debug_struct_field1_finish("Error", "error", &error)
76            }
77        }
78    }
79}
80
81/// Abstract plotter implementation
82#[async_trait]
83pub trait Plotter: fmt::Debug {
84    /// Whether plotter has free capacity to encode more sectors
85    async fn has_free_capacity(&self) -> Result<bool, String>;
86
87    /// Plot one sector, sending sector plotting events via the provided stream.
88    ///
89    /// Future returns once plotting is successfully scheduled (for backpressure purposes).
90    async fn plot_sector(
91        &self,
92        public_key: Ed25519PublicKey,
93        sector_index: SectorIndex,
94        farmer_protocol_info: FarmerProtocolInfo,
95        pieces_in_sector: u16,
96        replotting: bool,
97        progress_sender: mpsc::Sender<SectorPlottingProgress>,
98    );
99
100    /// Try to plot one sector, sending sector plotting events via the provided stream.
101    ///
102    /// Returns `true` if plotting started successfully and `false` if there is no capacity to start
103    /// plotting immediately.
104    async fn try_plot_sector(
105        &self,
106        public_key: Ed25519PublicKey,
107        sector_index: SectorIndex,
108        farmer_protocol_info: FarmerProtocolInfo,
109        pieces_in_sector: u16,
110        replotting: bool,
111        progress_sender: mpsc::Sender<SectorPlottingProgress>,
112    ) -> bool;
113}
114
115#[async_trait]
116impl<P> Plotter for Arc<P>
117where
118    P: Plotter + Send + Sync,
119{
120    #[inline]
121    async fn has_free_capacity(&self) -> Result<bool, String> {
122        self.as_ref().has_free_capacity().await
123    }
124
125    #[inline]
126    async fn plot_sector(
127        &self,
128        public_key: Ed25519PublicKey,
129        sector_index: SectorIndex,
130        farmer_protocol_info: FarmerProtocolInfo,
131        pieces_in_sector: u16,
132        replotting: bool,
133        progress_sender: mpsc::Sender<SectorPlottingProgress>,
134    ) {
135        self.as_ref()
136            .plot_sector(
137                public_key,
138                sector_index,
139                farmer_protocol_info,
140                pieces_in_sector,
141                replotting,
142                progress_sender,
143            )
144            .await
145    }
146
147    #[inline]
148    async fn try_plot_sector(
149        &self,
150        public_key: Ed25519PublicKey,
151        sector_index: SectorIndex,
152        farmer_protocol_info: FarmerProtocolInfo,
153        pieces_in_sector: u16,
154        replotting: bool,
155        progress_sender: mpsc::Sender<SectorPlottingProgress>,
156    ) -> bool {
157        self.as_ref()
158            .try_plot_sector(
159                public_key,
160                sector_index,
161                farmer_protocol_info,
162                pieces_in_sector,
163                replotting,
164                progress_sender,
165            )
166            .await
167    }
168}