subspace_core_primitives/
solutions.rs1use crate::pieces::{PieceOffset, Record, RecordCommitment, RecordWitness};
4use crate::pos::{PosProof, PosSeed};
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, DecodeWithMemTracking, 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,
69 Clone,
70 PartialEq,
71 Eq,
72 Ord,
73 PartialOrd,
74 Hash,
75 Encode,
76 Decode,
77 TypeInfo,
78 Deref,
79 From,
80 Into,
81 DecodeWithMemTracking,
82)]
83pub struct RewardSignature([u8; RewardSignature::SIZE]);
84
85impl fmt::Debug for RewardSignature {
86 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
87 write!(f, "{}", hex::encode(self.0))
88 }
89}
90
91#[cfg(feature = "serde")]
92#[derive(Serialize, Deserialize)]
93#[serde(transparent)]
94struct RewardSignatureBinary(#[serde(with = "BigArray")] [u8; RewardSignature::SIZE]);
95
96#[cfg(feature = "serde")]
97#[derive(Serialize, Deserialize)]
98#[serde(transparent)]
99struct RewardSignatureHex(#[serde(with = "hex")] [u8; RewardSignature::SIZE]);
100
101#[cfg(feature = "serde")]
102impl Serialize for RewardSignature {
103 #[inline]
104 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
105 where
106 S: Serializer,
107 {
108 if serializer.is_human_readable() {
109 RewardSignatureHex(self.0).serialize(serializer)
110 } else {
111 RewardSignatureBinary(self.0).serialize(serializer)
112 }
113 }
114}
115
116#[cfg(feature = "serde")]
117impl<'de> Deserialize<'de> for RewardSignature {
118 #[inline]
119 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
120 where
121 D: Deserializer<'de>,
122 {
123 Ok(Self(if deserializer.is_human_readable() {
124 RewardSignatureHex::deserialize(deserializer)?.0
125 } else {
126 RewardSignatureBinary::deserialize(deserializer)?.0
127 }))
128 }
129}
130
131impl AsRef<[u8]> for RewardSignature {
132 #[inline]
133 fn as_ref(&self) -> &[u8] {
134 &self.0
135 }
136}
137
138impl RewardSignature {
139 pub const SIZE: usize = 64;
141}
142
143#[derive(
145 Copy,
146 Clone,
147 Eq,
148 PartialEq,
149 Hash,
150 Deref,
151 DerefMut,
152 From,
153 Into,
154 Encode,
155 Decode,
156 TypeInfo,
157 MaxEncodedLen,
158 DecodeWithMemTracking,
159)]
160#[repr(transparent)]
161pub struct ChunkWitness([u8; ChunkWitness::SIZE]);
162
163impl fmt::Debug for ChunkWitness {
164 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
165 write!(f, "{}", hex::encode(self.0))
166 }
167}
168
169#[cfg(feature = "serde")]
170#[derive(Serialize, Deserialize)]
171#[serde(transparent)]
172struct ChunkWitnessBinary(#[serde(with = "BigArray")] [u8; ChunkWitness::SIZE]);
173
174#[cfg(feature = "serde")]
175#[derive(Serialize, Deserialize)]
176#[serde(transparent)]
177struct ChunkWitnessHex(#[serde(with = "hex")] [u8; ChunkWitness::SIZE]);
178
179#[cfg(feature = "serde")]
180impl Serialize for ChunkWitness {
181 #[inline]
182 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
183 where
184 S: Serializer,
185 {
186 if serializer.is_human_readable() {
187 ChunkWitnessHex(self.0).serialize(serializer)
188 } else {
189 ChunkWitnessBinary(self.0).serialize(serializer)
190 }
191 }
192}
193
194#[cfg(feature = "serde")]
195impl<'de> Deserialize<'de> for ChunkWitness {
196 #[inline]
197 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
198 where
199 D: Deserializer<'de>,
200 {
201 Ok(Self(if deserializer.is_human_readable() {
202 ChunkWitnessHex::deserialize(deserializer)?.0
203 } else {
204 ChunkWitnessBinary::deserialize(deserializer)?.0
205 }))
206 }
207}
208
209impl Default for ChunkWitness {
210 #[inline]
211 fn default() -> Self {
212 Self([0; Self::SIZE])
213 }
214}
215
216impl TryFrom<&[u8]> for ChunkWitness {
217 type Error = TryFromSliceError;
218
219 #[inline]
220 fn try_from(slice: &[u8]) -> Result<Self, Self::Error> {
221 <[u8; Self::SIZE]>::try_from(slice).map(Self)
222 }
223}
224
225impl AsRef<[u8]> for ChunkWitness {
226 #[inline]
227 fn as_ref(&self) -> &[u8] {
228 &self.0
229 }
230}
231
232impl AsMut<[u8]> for ChunkWitness {
233 #[inline]
234 fn as_mut(&mut self) -> &mut [u8] {
235 &mut self.0
236 }
237}
238
239impl ChunkWitness {
240 pub const SIZE: usize = 48;
242}
243
244pub trait SolutionPotVerifier {
246 fn is_proof_valid(seed: &PosSeed, challenge_index: u32, proof: &PosProof) -> bool;
248}
249
250#[derive(Clone, Debug, Eq, PartialEq, Encode, Decode, TypeInfo, DecodeWithMemTracking)]
252#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
253#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
254pub struct Solution<RewardAddress> {
255 pub public_key: PublicKey,
257 pub reward_address: RewardAddress,
259 pub sector_index: SectorIndex,
261 pub history_size: HistorySize,
263 pub piece_offset: PieceOffset,
265 pub record_commitment: RecordCommitment,
267 pub record_witness: RecordWitness,
269 pub chunk: ScalarBytes,
271 pub chunk_witness: ChunkWitness,
273 pub proof_of_space: PosProof,
275}
276
277impl<RewardAddressA> Solution<RewardAddressA> {
278 pub fn into_reward_address_format<T, RewardAddressB>(self) -> Solution<RewardAddressB>
281 where
282 RewardAddressA: Into<T>,
283 T: Into<RewardAddressB>,
284 {
285 let Solution {
286 public_key,
287 reward_address,
288 sector_index,
289 history_size,
290 piece_offset,
291 record_commitment,
292 record_witness,
293 chunk,
294 chunk_witness,
295 proof_of_space,
296 } = self;
297 Solution {
298 public_key,
299 reward_address: Into::<T>::into(reward_address).into(),
300 sector_index,
301 history_size,
302 piece_offset,
303 record_commitment,
304 record_witness,
305 chunk,
306 chunk_witness,
307 proof_of_space,
308 }
309 }
310}
311
312impl<RewardAddress> Solution<RewardAddress> {
313 pub fn genesis_solution(public_key: PublicKey, reward_address: RewardAddress) -> Self {
315 Self {
316 public_key,
317 reward_address,
318 sector_index: 0,
319 history_size: HistorySize::from(SegmentIndex::ZERO),
320 piece_offset: PieceOffset::default(),
321 record_commitment: RecordCommitment::default(),
322 record_witness: RecordWitness::default(),
323 chunk: ScalarBytes::default(),
324 chunk_witness: ChunkWitness::default(),
325 proof_of_space: PosProof::default(),
326 }
327 }
328}
329
330#[inline(always)]
332pub fn bidirectional_distance<T: WrappingSub + Ord>(a: &T, b: &T) -> T {
333 let diff = a.wrapping_sub(b);
334 let diff2 = b.wrapping_sub(a);
335 diff.min(diff2)
337}