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