zebra_chain/work/
equihash.rs1use std::{fmt, io};
4
5use hex::ToHex;
6use serde_big_array::BigArray;
7
8use crate::{
9 block::Header,
10 serialization::{
11 zcash_serialize_bytes, SerializationError, ZcashDeserialize, ZcashDeserializeInto,
12 ZcashSerialize,
13 },
14};
15
16#[cfg(feature = "internal-miner")]
17use crate::serialization::AtLeastOne;
18
19#[non_exhaustive]
21#[derive(Debug, thiserror::Error)]
22#[error("invalid equihash solution for BlockHeader")]
23pub struct Error(#[from] equihash::Error);
24
25#[derive(Copy, Clone, Debug, Eq, PartialEq, thiserror::Error)]
27#[error("solver was cancelled")]
28pub struct SolverCancelled;
29
30pub(crate) const SOLUTION_SIZE: usize = 1344;
32
33pub(crate) const REGTEST_SOLUTION_SIZE: usize = 36;
35
36#[derive(Deserialize, Serialize)]
45#[allow(clippy::large_enum_variant)]
47pub enum Solution {
48 Common(#[serde(with = "BigArray")] [u8; SOLUTION_SIZE]),
50 Regtest(#[serde(with = "BigArray")] [u8; REGTEST_SOLUTION_SIZE]),
52}
53
54impl Solution {
55 pub const INPUT_LENGTH: usize = 4 + 32 * 3 + 4 * 2;
61
62 fn value(&self) -> &[u8] {
64 match self {
65 Solution::Common(solution) => solution.as_slice(),
66 Solution::Regtest(solution) => solution.as_slice(),
67 }
68 }
69
70 #[allow(clippy::unwrap_in_result)]
72 pub fn check(&self, header: &Header) -> Result<(), Error> {
73 let n = 200;
77 let k = 9;
78 let nonce = &header.nonce;
79
80 let mut input = Vec::new();
81 header
82 .zcash_serialize(&mut input)
83 .expect("serialization into a vec can't fail");
84
85 let input = &input[0..Solution::INPUT_LENGTH];
88
89 equihash::is_valid_solution(n, k, input, nonce.as_ref(), self.value())?;
90
91 Ok(())
92 }
93
94 pub fn from_bytes(solution: &[u8]) -> Result<Self, SerializationError> {
97 match solution.len() {
98 SOLUTION_SIZE => {
100 let mut bytes = [0; SOLUTION_SIZE];
101 bytes.copy_from_slice(solution);
102 Ok(Self::Common(bytes))
103 }
104 REGTEST_SOLUTION_SIZE => {
105 let mut bytes = [0; REGTEST_SOLUTION_SIZE];
106 bytes.copy_from_slice(solution);
107 Ok(Self::Regtest(bytes))
108 }
109 _unexpected_len => Err(SerializationError::Parse(
110 "incorrect equihash solution size",
111 )),
112 }
113 }
114
115 pub fn for_proposal() -> Self {
117 Self::Common([0; SOLUTION_SIZE])
119 }
120
121 #[cfg(feature = "internal-miner")]
133 #[allow(clippy::unwrap_in_result)]
134 pub fn solve<F>(
135 mut header: Header,
136 mut _cancel_fn: F,
137 ) -> Result<AtLeastOne<Header>, SolverCancelled>
138 where
139 F: FnMut() -> Result<(), SolverCancelled>,
140 {
141 header.solution = Solution::for_proposal();
145 Ok(AtLeastOne::from_one(header))
146 }
147
148 }
152
153impl PartialEq<Solution> for Solution {
154 fn eq(&self, other: &Solution) -> bool {
155 self.value() == other.value()
156 }
157}
158
159impl fmt::Debug for Solution {
160 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
161 f.debug_tuple("EquihashSolution")
162 .field(&hex::encode(self.value()))
163 .finish()
164 }
165}
166
167impl Copy for Solution {}
170
171impl Clone for Solution {
172 fn clone(&self) -> Self {
173 *self
174 }
175}
176
177impl Eq for Solution {}
178
179#[cfg(any(test, feature = "proptest-impl"))]
180impl Default for Solution {
181 fn default() -> Self {
182 Self::Common([0; SOLUTION_SIZE])
183 }
184}
185
186impl ZcashSerialize for Solution {
187 fn zcash_serialize<W: io::Write>(&self, writer: W) -> Result<(), io::Error> {
188 zcash_serialize_bytes(&self.value().to_vec(), writer)
189 }
190}
191
192impl ZcashDeserialize for Solution {
193 fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
194 let solution: Vec<u8> = (&mut reader).zcash_deserialize_into()?;
195 Self::from_bytes(&solution)
196 }
197}
198
199impl ToHex for &Solution {
200 fn encode_hex<T: FromIterator<char>>(&self) -> T {
201 self.value().encode_hex()
202 }
203
204 fn encode_hex_upper<T: FromIterator<char>>(&self) -> T {
205 self.value().encode_hex_upper()
206 }
207}
208
209impl ToHex for Solution {
210 fn encode_hex<T: FromIterator<char>>(&self) -> T {
211 (&self).encode_hex()
212 }
213
214 fn encode_hex_upper<T: FromIterator<char>>(&self) -> T {
215 (&self).encode_hex_upper()
216 }
217}