Skip to main content

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
4//! necessary.
5
6#![feature(
7    const_block_items,
8    iter_array_chunks,
9    maybe_uninit_array_assume_init,
10    never_type,
11    portable_simd,
12    try_blocks
13)]
14#![warn(rust_2018_idioms, missing_debug_implementations, missing_docs)]
15
16pub mod auditing;
17pub mod file_ext;
18pub mod plotting;
19pub mod proving;
20pub mod reading;
21pub mod sector;
22mod segment_reconstruction;
23pub mod shard_commitment;
24
25use crate::file_ext::FileExt;
26use ab_core_primitives::segments::HistorySize;
27use parity_scale_codec::{Decode, Encode};
28use serde::{Deserialize, Serialize};
29use std::fs::File;
30use std::future::Future;
31use std::io;
32
33/// Enum to encapsulate the selection between [`ReadAtSync`] and [`ReadAtAsync]` variants
34#[derive(Debug, Copy, Clone)]
35pub enum ReadAt<S, A>
36where
37    S: ReadAtSync,
38    A: ReadAtAsync,
39{
40    /// Sync variant
41    Sync(S),
42    /// Async variant
43    Async(A),
44}
45
46impl<S> ReadAt<S, !>
47where
48    S: ReadAtSync,
49{
50    /// Instantiate [`ReadAt`] from some [`ReadAtSync`] implementation
51    pub fn from_sync(value: S) -> Self {
52        Self::Sync(value)
53    }
54}
55
56impl<A> ReadAt<!, A>
57where
58    A: ReadAtAsync,
59{
60    /// Instantiate [`ReadAt`] from some [`ReadAtAsync`] implementation
61    pub fn from_async(value: A) -> Self {
62        Self::Async(value)
63    }
64}
65
66/// Sync version of [`ReadAt`], it is both [`Send`] and [`Sync`] and is supposed to be used with a
67/// thread pool
68pub trait ReadAtSync: Send + Sync {
69    /// Get implementation of [`ReadAtSync`] that add specified offset to all attempted reads
70    fn offset(&self, offset: u64) -> ReadAtOffset<'_, Self>
71    where
72        Self: Sized,
73    {
74        ReadAtOffset {
75            inner: self,
76            offset,
77        }
78    }
79
80    /// Fill the buffer by reading bytes at a specific offset
81    fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<()>;
82}
83
84impl ReadAtSync for ! {
85    fn read_at(&self, _buf: &mut [u8], _offset: u64) -> io::Result<()> {
86        unreachable!("Is never called")
87    }
88}
89
90/// Container or asynchronously reading bytes using in [`ReadAtAsync`]
91#[repr(transparent)]
92#[derive(Debug)]
93pub struct AsyncReadBytes<B>(B)
94where
95    B: AsMut<[u8]> + Unpin + 'static;
96
97impl From<Vec<u8>> for AsyncReadBytes<Vec<u8>> {
98    fn from(value: Vec<u8>) -> Self {
99        Self(value)
100    }
101}
102
103impl From<Box<[u8]>> for AsyncReadBytes<Box<[u8]>> {
104    fn from(value: Box<[u8]>) -> Self {
105        Self(value)
106    }
107}
108
109impl<B> AsMut<[u8]> for AsyncReadBytes<B>
110where
111    B: AsMut<[u8]> + Unpin + 'static,
112{
113    fn as_mut(&mut self) -> &mut [u8] {
114        self.0.as_mut()
115    }
116}
117
118impl<B> AsyncReadBytes<B>
119where
120    B: AsMut<[u8]> + Unpin + 'static,
121{
122    /// Extract inner value
123    pub fn into_inner(self) -> B {
124        self.0
125    }
126}
127
128/// Async version of [`ReadAt`], it is neither [`Send`] nor [`Sync`] and is supposed to be used with
129/// concurrent async combinators
130pub trait ReadAtAsync {
131    /// Get implementation of [`ReadAtAsync`] that add specified offset to all attempted reads
132    fn offset(&self, offset: u64) -> ReadAtOffset<'_, Self>
133    where
134        Self: Sized,
135    {
136        ReadAtOffset {
137            inner: self,
138            offset,
139        }
140    }
141
142    /// Fill the buffer by reading bytes at a specific offset and return the buffer back
143    fn read_at<B>(&self, buf: B, offset: u64) -> impl Future<Output = io::Result<B>>
144    where
145        AsyncReadBytes<B>: From<B>,
146        B: AsMut<[u8]> + Unpin + 'static;
147}
148
149impl ReadAtAsync for ! {
150    #[expect(
151        clippy::unused_async_trait_impl,
152        reason = "https://github.com/rust-lang/rust-clippy/issues/17162"
153    )]
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!(size_of::<usize>() >= 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}