ab_farmer_components/
lib.rs

1//! Components of the reference implementation of Subspace Farmer for Subspace Network Blockchain.
2//!
3//! These components are used to implement farmer itself, but can also be used independently if necessary.
4
5#![feature(
6    const_trait_impl,
7    exact_size_is_empty,
8    int_roundings,
9    iter_array_chunks,
10    iter_collect_into,
11    never_type,
12    new_zeroed_alloc,
13    portable_simd,
14    try_blocks
15)]
16#![expect(incomplete_features, reason = "generic_const_exprs")]
17// TODO: This feature is not actually used in this crate, but is added as a workaround for
18//  https://github.com/rust-lang/rust/issues/141492
19#![feature(generic_const_exprs)]
20#![warn(rust_2018_idioms, missing_debug_implementations, missing_docs)]
21
22pub mod auditing;
23pub mod file_ext;
24pub mod plotting;
25pub mod proving;
26pub mod reading;
27pub mod sector;
28mod segment_reconstruction;
29
30use crate::file_ext::FileExt;
31use ab_core_primitives::segments::HistorySize;
32use parity_scale_codec::{Decode, Encode};
33use serde::{Deserialize, Serialize};
34use std::fs::File;
35use std::future::Future;
36use std::io;
37
38/// Enum to encapsulate the selection between [`ReadAtSync`] and [`ReadAtAsync]` variants
39#[derive(Debug, Copy, Clone)]
40pub enum ReadAt<S, A>
41where
42    S: ReadAtSync,
43    A: ReadAtAsync,
44{
45    /// Sync variant
46    Sync(S),
47    /// Async variant
48    Async(A),
49}
50
51impl<S> ReadAt<S, !>
52where
53    S: ReadAtSync,
54{
55    /// Instantiate [`ReadAt`] from some [`ReadAtSync`] implementation
56    pub fn from_sync(value: S) -> Self {
57        Self::Sync(value)
58    }
59}
60
61impl<A> ReadAt<!, A>
62where
63    A: ReadAtAsync,
64{
65    /// Instantiate [`ReadAt`] from some [`ReadAtAsync`] implementation
66    pub fn from_async(value: A) -> Self {
67        Self::Async(value)
68    }
69}
70
71/// Sync version of [`ReadAt`], it is both [`Send`] and [`Sync`] and is supposed to be used with a
72/// thread pool
73pub trait ReadAtSync: Send + Sync {
74    /// Get implementation of [`ReadAtSync`] that add specified offset to all attempted reads
75    fn offset(&self, offset: u64) -> ReadAtOffset<'_, Self>
76    where
77        Self: Sized,
78    {
79        ReadAtOffset {
80            inner: self,
81            offset,
82        }
83    }
84
85    /// Fill the buffer by reading bytes at a specific offset
86    fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<()>;
87}
88
89impl ReadAtSync for ! {
90    fn read_at(&self, _buf: &mut [u8], _offset: u64) -> io::Result<()> {
91        unreachable!("Is never called")
92    }
93}
94
95/// Container or asynchronously reading bytes using in [`ReadAtAsync`]
96#[repr(transparent)]
97#[derive(Debug)]
98pub struct AsyncReadBytes<B>(B)
99where
100    B: AsMut<[u8]> + Unpin + 'static;
101
102impl From<Vec<u8>> for AsyncReadBytes<Vec<u8>> {
103    fn from(value: Vec<u8>) -> Self {
104        Self(value)
105    }
106}
107
108impl From<Box<[u8]>> for AsyncReadBytes<Box<[u8]>> {
109    fn from(value: Box<[u8]>) -> Self {
110        Self(value)
111    }
112}
113
114impl<B> AsMut<[u8]> for AsyncReadBytes<B>
115where
116    B: AsMut<[u8]> + Unpin + 'static,
117{
118    fn as_mut(&mut self) -> &mut [u8] {
119        self.0.as_mut()
120    }
121}
122
123impl<B> AsyncReadBytes<B>
124where
125    B: AsMut<[u8]> + Unpin + 'static,
126{
127    /// Extract inner value
128    pub fn into_inner(self) -> B {
129        self.0
130    }
131}
132
133/// Async version of [`ReadAt`], it is neither [`Send`] nor [`Sync`] and is supposed to be used with
134/// concurrent async combinators
135pub trait ReadAtAsync {
136    /// Get implementation of [`ReadAtAsync`] that add specified offset to all attempted reads
137    fn offset(&self, offset: u64) -> ReadAtOffset<'_, Self>
138    where
139        Self: Sized,
140    {
141        ReadAtOffset {
142            inner: self,
143            offset,
144        }
145    }
146
147    /// Fill the buffer by reading bytes at a specific offset and return the buffer back
148    fn read_at<B>(&self, buf: B, offset: u64) -> impl Future<Output = io::Result<B>>
149    where
150        AsyncReadBytes<B>: From<B>,
151        B: AsMut<[u8]> + Unpin + 'static;
152}
153
154impl ReadAtAsync for ! {
155    async fn read_at<B>(&self, _buf: B, _offset: u64) -> io::Result<B>
156    where
157        AsyncReadBytes<B>: From<B>,
158        B: AsMut<[u8]> + Unpin + 'static,
159    {
160        unreachable!("Is never called")
161    }
162}
163
164impl ReadAtSync for [u8] {
165    fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<()> {
166        if buf.len() as u64 + offset > self.len() as u64 {
167            return Err(io::Error::new(
168                io::ErrorKind::InvalidInput,
169                "Buffer length with offset exceeds own length",
170            ));
171        }
172
173        buf.copy_from_slice(&self[offset as usize..][..buf.len()]);
174
175        Ok(())
176    }
177}
178
179impl ReadAtSync for &[u8] {
180    fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<()> {
181        if buf.len() as u64 + offset > self.len() as u64 {
182            return Err(io::Error::new(
183                io::ErrorKind::InvalidInput,
184                "Buffer length with offset exceeds own length",
185            ));
186        }
187
188        buf.copy_from_slice(&self[offset as usize..][..buf.len()]);
189
190        Ok(())
191    }
192}
193
194impl ReadAtSync for Vec<u8> {
195    fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<()> {
196        self.as_slice().read_at(buf, offset)
197    }
198}
199
200impl ReadAtSync for &Vec<u8> {
201    fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<()> {
202        self.as_slice().read_at(buf, offset)
203    }
204}
205
206impl ReadAtSync for File {
207    fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<()> {
208        self.read_exact_at(buf, offset)
209    }
210}
211
212impl ReadAtSync for &File {
213    fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<()> {
214        self.read_exact_at(buf, offset)
215    }
216}
217
218/// Reader with fixed offset added to all attempted reads
219#[derive(Debug, Copy, Clone)]
220pub struct ReadAtOffset<'a, T> {
221    inner: &'a T,
222    offset: u64,
223}
224
225impl<T> ReadAtSync for ReadAtOffset<'_, T>
226where
227    T: ReadAtSync,
228{
229    fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<()> {
230        self.inner.read_at(buf, offset + self.offset)
231    }
232}
233
234impl<T> ReadAtSync for &ReadAtOffset<'_, T>
235where
236    T: ReadAtSync,
237{
238    fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<()> {
239        self.inner.read_at(buf, offset + self.offset)
240    }
241}
242
243impl<T> ReadAtAsync for ReadAtOffset<'_, T>
244where
245    T: ReadAtAsync,
246{
247    async fn read_at<B>(&self, buf: B, offset: u64) -> io::Result<B>
248    where
249        AsyncReadBytes<B>: From<B>,
250        B: AsMut<[u8]> + Unpin + 'static,
251    {
252        self.inner.read_at(buf, offset + self.offset).await
253    }
254}
255
256impl<T> ReadAtAsync for &ReadAtOffset<'_, T>
257where
258    T: ReadAtAsync,
259{
260    async fn read_at<B>(&self, buf: B, offset: u64) -> io::Result<B>
261    where
262        AsyncReadBytes<B>: From<B>,
263        B: AsMut<[u8]> + Unpin + 'static,
264    {
265        self.inner.read_at(buf, offset + self.offset).await
266    }
267}
268
269// Refuse to compile on non-64-bit platforms, offsets may fail on those when converting from u64 to
270// usize depending on chain parameters
271const _: () = {
272    assert!(std::mem::size_of::<usize>() >= std::mem::size_of::<u64>());
273};
274
275/// Information about the protocol necessary for farmer operation
276#[derive(Debug, Copy, Clone, Encode, Decode, Serialize, Deserialize)]
277#[serde(rename_all = "camelCase")]
278pub struct FarmerProtocolInfo {
279    /// Size of the blockchain history
280    pub history_size: HistorySize,
281    /// How many pieces one sector is supposed to contain (max)
282    pub max_pieces_in_sector: u16,
283    /// Number of latest archived segments that are considered "recent history".
284    pub recent_segments: HistorySize,
285    /// Fraction of pieces from the "recent history" (`recent_segments`) in each sector.
286    pub recent_history_fraction: (HistorySize, HistorySize),
287    /// Minimum lifetime of a plotted sector, measured in archived segment
288    pub min_sector_lifetime: HistorySize,
289}