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