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