Skip to main content

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