subspace_core_primitives/
solutions.rs1use crate::pieces::{PieceOffset, Record, RecordCommitment, RecordWitness};
4use crate::pos::PosProof;
5use crate::sectors::SectorIndex;
6use crate::segments::{HistorySize, SegmentIndex};
7use crate::{PublicKey, ScalarBytes};
8use core::array::TryFromSliceError;
9use core::fmt;
10use derive_more::{AsMut, AsRef, Deref, DerefMut, From, Into};
11use num_traits::WrappingSub;
12use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
13use scale_info::TypeInfo;
14#[cfg(feature = "serde")]
15use serde::{Deserialize, Serialize};
16#[cfg(feature = "serde")]
17use serde::{Deserializer, Serializer};
18#[cfg(feature = "serde")]
19use serde_big_array::BigArray;
20use static_assertions::const_assert;
21
22pub type SolutionRange = u64;
25
26pub const fn pieces_to_solution_range(pieces: u64, slot_probability: (u64, u64)) -> SolutionRange {
31 let solution_range = SolutionRange::MAX
32 / slot_probability.1 * slot_probability.0
34 / Record::NUM_CHUNKS as u64
36 * Record::NUM_S_BUCKETS as u64;
37
38 solution_range / pieces
40}
41
42pub const fn solution_range_to_pieces(
47 solution_range: SolutionRange,
48 slot_probability: (u64, u64),
49) -> u64 {
50 let pieces = SolutionRange::MAX
51 / slot_probability.1 * slot_probability.0
53 / Record::NUM_CHUNKS as u64
55 * Record::NUM_S_BUCKETS as u64;
56
57 pieces / solution_range
59}
60
61const_assert!(solution_range_to_pieces(pieces_to_solution_range(1, (1, 6)), (1, 6)) == 1);
63const_assert!(solution_range_to_pieces(pieces_to_solution_range(3, (1, 6)), (1, 6)) == 3);
64const_assert!(solution_range_to_pieces(pieces_to_solution_range(5, (1, 6)), (1, 6)) == 5);
65
66#[derive(
68 Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, Encode, Decode, TypeInfo, Deref, From, Into,
69)]
70pub struct RewardSignature([u8; RewardSignature::SIZE]);
71
72impl fmt::Debug for RewardSignature {
73 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74 write!(f, "{}", hex::encode(self.0))
75 }
76}
77
78#[cfg(feature = "serde")]
79#[derive(Serialize, Deserialize)]
80#[serde(transparent)]
81struct RewardSignatureBinary(#[serde(with = "BigArray")] [u8; RewardSignature::SIZE]);
82
83#[cfg(feature = "serde")]
84#[derive(Serialize, Deserialize)]
85#[serde(transparent)]
86struct RewardSignatureHex(#[serde(with = "hex")] [u8; RewardSignature::SIZE]);
87
88#[cfg(feature = "serde")]
89impl Serialize for RewardSignature {
90 #[inline]
91 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
92 where
93 S: Serializer,
94 {
95 if serializer.is_human_readable() {
96 RewardSignatureHex(self.0).serialize(serializer)
97 } else {
98 RewardSignatureBinary(self.0).serialize(serializer)
99 }
100 }
101}
102
103#[cfg(feature = "serde")]
104impl<'de> Deserialize<'de> for RewardSignature {
105 #[inline]
106 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
107 where
108 D: Deserializer<'de>,
109 {
110 Ok(Self(if deserializer.is_human_readable() {
111 RewardSignatureHex::deserialize(deserializer)?.0
112 } else {
113 RewardSignatureBinary::deserialize(deserializer)?.0
114 }))
115 }
116}
117
118impl AsRef<[u8]> for RewardSignature {
119 #[inline]
120 fn as_ref(&self) -> &[u8] {
121 &self.0
122 }
123}
124
125impl RewardSignature {
126 pub const SIZE: usize = 64;
128}
129
130#[derive(
132 Copy,
133 Clone,
134 Eq,
135 PartialEq,
136 Hash,
137 Deref,
138 DerefMut,
139 From,
140 Into,
141 Encode,
142 Decode,
143 TypeInfo,
144 MaxEncodedLen,
145)]
146#[repr(transparent)]
147pub struct ChunkWitness([u8; ChunkWitness::SIZE]);
148
149impl fmt::Debug for ChunkWitness {
150 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
151 write!(f, "{}", hex::encode(self.0))
152 }
153}
154
155#[cfg(feature = "serde")]
156#[derive(Serialize, Deserialize)]
157#[serde(transparent)]
158struct ChunkWitnessBinary(#[serde(with = "BigArray")] [u8; ChunkWitness::SIZE]);
159
160#[cfg(feature = "serde")]
161#[derive(Serialize, Deserialize)]
162#[serde(transparent)]
163struct ChunkWitnessHex(#[serde(with = "hex")] [u8; ChunkWitness::SIZE]);
164
165#[cfg(feature = "serde")]
166impl Serialize for ChunkWitness {
167 #[inline]
168 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
169 where
170 S: Serializer,
171 {
172 if serializer.is_human_readable() {
173 ChunkWitnessHex(self.0).serialize(serializer)
174 } else {
175 ChunkWitnessBinary(self.0).serialize(serializer)
176 }
177 }
178}
179
180#[cfg(feature = "serde")]
181impl<'de> Deserialize<'de> for ChunkWitness {
182 #[inline]
183 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
184 where
185 D: Deserializer<'de>,
186 {
187 Ok(Self(if deserializer.is_human_readable() {
188 ChunkWitnessHex::deserialize(deserializer)?.0
189 } else {
190 ChunkWitnessBinary::deserialize(deserializer)?.0
191 }))
192 }
193}
194
195impl Default for ChunkWitness {
196 #[inline]
197 fn default() -> Self {
198 Self([0; Self::SIZE])
199 }
200}
201
202impl TryFrom<&[u8]> for ChunkWitness {
203 type Error = TryFromSliceError;
204
205 #[inline]
206 fn try_from(slice: &[u8]) -> Result<Self, Self::Error> {
207 <[u8; Self::SIZE]>::try_from(slice).map(Self)
208 }
209}
210
211impl AsRef<[u8]> for ChunkWitness {
212 #[inline]
213 fn as_ref(&self) -> &[u8] {
214 &self.0
215 }
216}
217
218impl AsMut<[u8]> for ChunkWitness {
219 #[inline]
220 fn as_mut(&mut self) -> &mut [u8] {
221 &mut self.0
222 }
223}
224
225impl ChunkWitness {
226 pub const SIZE: usize = 48;
228}
229
230#[derive(Clone, Debug, Eq, PartialEq, Encode, Decode, TypeInfo)]
232#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
233#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
234pub struct Solution<RewardAddress> {
235 pub public_key: PublicKey,
237 pub reward_address: RewardAddress,
239 pub sector_index: SectorIndex,
241 pub history_size: HistorySize,
243 pub piece_offset: PieceOffset,
245 pub record_commitment: RecordCommitment,
247 pub record_witness: RecordWitness,
249 pub chunk: ScalarBytes,
251 pub chunk_witness: ChunkWitness,
253 pub proof_of_space: PosProof,
255}
256
257impl<RewardAddressA> Solution<RewardAddressA> {
258 pub fn into_reward_address_format<T, RewardAddressB>(self) -> Solution<RewardAddressB>
261 where
262 RewardAddressA: Into<T>,
263 T: Into<RewardAddressB>,
264 {
265 let Solution {
266 public_key,
267 reward_address,
268 sector_index,
269 history_size,
270 piece_offset,
271 record_commitment,
272 record_witness,
273 chunk,
274 chunk_witness,
275 proof_of_space,
276 } = self;
277 Solution {
278 public_key,
279 reward_address: Into::<T>::into(reward_address).into(),
280 sector_index,
281 history_size,
282 piece_offset,
283 record_commitment,
284 record_witness,
285 chunk,
286 chunk_witness,
287 proof_of_space,
288 }
289 }
290}
291
292impl<RewardAddress> Solution<RewardAddress> {
293 pub fn genesis_solution(public_key: PublicKey, reward_address: RewardAddress) -> Self {
295 Self {
296 public_key,
297 reward_address,
298 sector_index: 0,
299 history_size: HistorySize::from(SegmentIndex::ZERO),
300 piece_offset: PieceOffset::default(),
301 record_commitment: RecordCommitment::default(),
302 record_witness: RecordWitness::default(),
303 chunk: ScalarBytes::default(),
304 chunk_witness: ChunkWitness::default(),
305 proof_of_space: PosProof::default(),
306 }
307 }
308}
309
310#[inline(always)]
312pub fn bidirectional_distance<T: WrappingSub + Ord>(a: &T, b: &T) -> T {
313 let diff = a.wrapping_sub(b);
314 let diff2 = b.wrapping_sub(a);
315 diff.min(diff2)
317}