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