subspace_core_primitives/
solutions.rsuse crate::pieces::{PieceOffset, Record, RecordCommitment, RecordWitness};
use crate::pos::PosProof;
use crate::sectors::SectorIndex;
use crate::segments::{HistorySize, SegmentIndex};
use crate::{PublicKey, ScalarBytes};
use core::array::TryFromSliceError;
use derive_more::{AsMut, AsRef, Deref, DerefMut, From, Into};
use num_traits::WrappingSub;
use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
use scale_info::TypeInfo;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg(feature = "serde")]
use serde::{Deserializer, Serializer};
#[cfg(feature = "serde")]
use serde_big_array::BigArray;
use static_assertions::const_assert;
pub type SolutionRange = u64;
pub const fn pieces_to_solution_range(pieces: u64, slot_probability: (u64, u64)) -> SolutionRange {
let solution_range = SolutionRange::MAX
/ slot_probability.1 * slot_probability.0
/ Record::NUM_CHUNKS as u64
* Record::NUM_S_BUCKETS as u64;
solution_range / pieces
}
pub const fn solution_range_to_pieces(
solution_range: SolutionRange,
slot_probability: (u64, u64),
) -> u64 {
let pieces = SolutionRange::MAX
/ slot_probability.1 * slot_probability.0
/ Record::NUM_CHUNKS as u64
* Record::NUM_S_BUCKETS as u64;
pieces / solution_range
}
const_assert!(solution_range_to_pieces(pieces_to_solution_range(1, (1, 6)), (1, 6)) == 1);
const_assert!(solution_range_to_pieces(pieces_to_solution_range(3, (1, 6)), (1, 6)) == 3);
const_assert!(solution_range_to_pieces(pieces_to_solution_range(5, (1, 6)), (1, 6)) == 5);
#[derive(
Debug,
Copy,
Clone,
PartialEq,
Eq,
Ord,
PartialOrd,
Hash,
Encode,
Decode,
TypeInfo,
Deref,
From,
Into,
)]
pub struct RewardSignature([u8; RewardSignature::SIZE]);
#[cfg(feature = "serde")]
#[derive(Serialize, Deserialize)]
#[serde(transparent)]
struct RewardSignatureBinary(#[serde(with = "BigArray")] [u8; RewardSignature::SIZE]);
#[cfg(feature = "serde")]
#[derive(Serialize, Deserialize)]
#[serde(transparent)]
struct RewardSignatureHex(#[serde(with = "hex")] [u8; RewardSignature::SIZE]);
#[cfg(feature = "serde")]
impl Serialize for RewardSignature {
#[inline]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
if serializer.is_human_readable() {
RewardSignatureHex(self.0).serialize(serializer)
} else {
RewardSignatureBinary(self.0).serialize(serializer)
}
}
}
#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for RewardSignature {
#[inline]
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Ok(Self(if deserializer.is_human_readable() {
RewardSignatureHex::deserialize(deserializer)?.0
} else {
RewardSignatureBinary::deserialize(deserializer)?.0
}))
}
}
impl AsRef<[u8]> for RewardSignature {
#[inline]
fn as_ref(&self) -> &[u8] {
&self.0
}
}
impl RewardSignature {
pub const SIZE: usize = 64;
}
#[derive(
Debug,
Copy,
Clone,
Eq,
PartialEq,
Hash,
Deref,
DerefMut,
From,
Into,
Encode,
Decode,
TypeInfo,
MaxEncodedLen,
)]
#[repr(transparent)]
pub struct ChunkWitness([u8; ChunkWitness::SIZE]);
#[cfg(feature = "serde")]
#[derive(Serialize, Deserialize)]
#[serde(transparent)]
struct ChunkWitnessBinary(#[serde(with = "BigArray")] [u8; ChunkWitness::SIZE]);
#[cfg(feature = "serde")]
#[derive(Serialize, Deserialize)]
#[serde(transparent)]
struct ChunkWitnessHex(#[serde(with = "hex")] [u8; ChunkWitness::SIZE]);
#[cfg(feature = "serde")]
impl Serialize for ChunkWitness {
#[inline]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
if serializer.is_human_readable() {
ChunkWitnessHex(self.0).serialize(serializer)
} else {
ChunkWitnessBinary(self.0).serialize(serializer)
}
}
}
#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for ChunkWitness {
#[inline]
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Ok(Self(if deserializer.is_human_readable() {
ChunkWitnessHex::deserialize(deserializer)?.0
} else {
ChunkWitnessBinary::deserialize(deserializer)?.0
}))
}
}
impl Default for ChunkWitness {
#[inline]
fn default() -> Self {
Self([0; Self::SIZE])
}
}
impl TryFrom<&[u8]> for ChunkWitness {
type Error = TryFromSliceError;
#[inline]
fn try_from(slice: &[u8]) -> Result<Self, Self::Error> {
<[u8; Self::SIZE]>::try_from(slice).map(Self)
}
}
impl AsRef<[u8]> for ChunkWitness {
#[inline]
fn as_ref(&self) -> &[u8] {
&self.0
}
}
impl AsMut<[u8]> for ChunkWitness {
#[inline]
fn as_mut(&mut self) -> &mut [u8] {
&mut self.0
}
}
impl ChunkWitness {
pub const SIZE: usize = 48;
}
#[derive(Clone, Debug, Eq, PartialEq, Encode, Decode, TypeInfo)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
pub struct Solution<RewardAddress> {
pub public_key: PublicKey,
pub reward_address: RewardAddress,
pub sector_index: SectorIndex,
pub history_size: HistorySize,
pub piece_offset: PieceOffset,
pub record_commitment: RecordCommitment,
pub record_witness: RecordWitness,
pub chunk: ScalarBytes,
pub chunk_witness: ChunkWitness,
pub proof_of_space: PosProof,
}
impl<RewardAddressA> Solution<RewardAddressA> {
pub fn into_reward_address_format<T, RewardAddressB>(self) -> Solution<RewardAddressB>
where
RewardAddressA: Into<T>,
T: Into<RewardAddressB>,
{
let Solution {
public_key,
reward_address,
sector_index,
history_size,
piece_offset,
record_commitment,
record_witness,
chunk,
chunk_witness,
proof_of_space,
} = self;
Solution {
public_key,
reward_address: Into::<T>::into(reward_address).into(),
sector_index,
history_size,
piece_offset,
record_commitment,
record_witness,
chunk,
chunk_witness,
proof_of_space,
}
}
}
impl<RewardAddress> Solution<RewardAddress> {
pub fn genesis_solution(public_key: PublicKey, reward_address: RewardAddress) -> Self {
Self {
public_key,
reward_address,
sector_index: 0,
history_size: HistorySize::from(SegmentIndex::ZERO),
piece_offset: PieceOffset::default(),
record_commitment: RecordCommitment::default(),
record_witness: RecordWitness::default(),
chunk: ScalarBytes::default(),
chunk_witness: ChunkWitness::default(),
proof_of_space: PosProof::default(),
}
}
}
#[inline(always)]
pub fn bidirectional_distance<T: WrappingSub + Ord>(a: &T, b: &T) -> T {
let diff = a.wrapping_sub(b);
let diff2 = b.wrapping_sub(a);
diff.min(diff2)
}