Skip to content

Commit 72d7ab1

Browse files
committed
restores internal miner with equihash solver
1 parent 15b1e2d commit 72d7ab1

File tree

3 files changed

+85
-13
lines changed

3 files changed

+85
-13
lines changed

Cargo.lock

+4-3
Original file line numberDiff line numberDiff line change
@@ -1301,12 +1301,13 @@ dependencies = [
13011301

13021302
[[package]]
13031303
name = "equihash"
1304-
version = "0.2.0"
1304+
version = "0.2.1"
13051305
source = "registry+https://github.com/rust-lang/crates.io-index"
1306-
checksum = "ab579d7cf78477773b03e80bc2f89702ef02d7112c711d54ca93dcdce68533d5"
1306+
checksum = "756c3654e279e572484a6061a4f90a67849baeab43be89a622b9950105254674"
13071307
dependencies = [
13081308
"blake2b_simd",
1309-
"byteorder",
1309+
"cc",
1310+
"core2",
13101311
]
13111312

13121313
[[package]]

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ crossbeam-channel = "0.5.14"
5757
dirs = "6.0.0"
5858
ed25519-zebra = "4.0.3"
5959
elasticsearch = { version = "8.17.0-alpha.1", default-features = false }
60-
equihash = "0.2.0"
60+
equihash = { version = "0.2.1", features = ["solver"] }
6161
ff = "0.13.0"
6262
futures = "0.3.31"
6363
futures-core = "0.3.28"

zebra-chain/src/work/equihash.rs

+80-9
Original file line numberDiff line numberDiff line change
@@ -133,21 +133,92 @@ impl Solution {
133133
#[allow(clippy::unwrap_in_result)]
134134
pub fn solve<F>(
135135
mut header: Header,
136-
mut _cancel_fn: F,
136+
mut cancel_fn: F,
137137
) -> Result<AtLeastOne<Header>, SolverCancelled>
138138
where
139139
F: FnMut() -> Result<(), SolverCancelled>,
140140
{
141-
// TODO: Function code was removed as part of https://github.com/ZcashFoundation/zebra/issues/8180
142-
// Find the removed code at https://github.com/ZcashFoundation/zebra/blob/v1.5.1/zebra-chain/src/work/equihash.rs#L115-L166
143-
// Restore the code when conditions are met. https://github.com/ZcashFoundation/zebra/issues/8183
144-
header.solution = Solution::for_proposal();
145-
Ok(AtLeastOne::from_one(header))
141+
use crate::shutdown::is_shutting_down;
142+
143+
let mut input = Vec::new();
144+
header
145+
.zcash_serialize(&mut input)
146+
.expect("serialization into a vec can't fail");
147+
// Take the part of the header before the nonce and solution.
148+
// This data is kept constant for this solver run.
149+
let input = &input[0..Solution::INPUT_LENGTH];
150+
151+
while !is_shutting_down() {
152+
// Don't run the solver if we'd just cancel it anyway.
153+
cancel_fn()?;
154+
155+
let solutions = equihash::tromp::solve_200_9(input, || {
156+
// Cancel the solver if we have a new template.
157+
if cancel_fn().is_err() {
158+
return None;
159+
}
160+
161+
// This skips the first nonce, which doesn't matter in practice.
162+
Self::next_nonce(&mut header.nonce);
163+
Some(*header.nonce)
164+
});
165+
166+
let mut valid_solutions = Vec::new();
167+
168+
// If we got any solutions, try submitting them, because the new template might just
169+
// contain some extra transactions. Mining extra transactions is optional.
170+
for solution in &solutions {
171+
header.solution = Self::from_bytes(solution)
172+
.expect("unexpected invalid solution: incorrect length");
173+
174+
// TODO: work out why we sometimes get invalid solutions here
175+
if let Err(error) = header.solution.check(&header) {
176+
info!(?error, "found invalid solution for header");
177+
continue;
178+
}
179+
180+
if Self::difficulty_is_valid(&header) {
181+
valid_solutions.push(header);
182+
}
183+
}
184+
185+
match valid_solutions.try_into() {
186+
Ok(at_least_one_solution) => return Ok(at_least_one_solution),
187+
Err(_is_empty_error) => debug!(
188+
solutions = ?solutions.len(),
189+
"found valid solutions which did not pass the validity or difficulty checks"
190+
),
191+
}
192+
}
193+
194+
Err(SolverCancelled)
146195
}
147196

148-
// TODO: Some methods were removed as part of https://github.com/ZcashFoundation/zebra/issues/8180
149-
// Find the removed code at https://github.com/ZcashFoundation/zebra/blob/v1.5.1/zebra-chain/src/work/equihash.rs#L171-L196
150-
// Restore the code when conditions are met. https://github.com/ZcashFoundation/zebra/issues/8183
197+
/// Returns `true` if the `nonce` and `solution` in `header` meet the difficulty threshold.
198+
///
199+
/// Assumes that the difficulty threshold in the header is valid.
200+
#[cfg(feature = "internal-miner")]
201+
fn difficulty_is_valid(header: &Header) -> bool {
202+
// Simplified from zebra_consensus::block::check::difficulty_is_valid().
203+
let difficulty_threshold = header
204+
.difficulty_threshold
205+
.to_expanded()
206+
.expect("unexpected invalid header template: invalid difficulty threshold");
207+
208+
// TODO: avoid calculating this hash multiple times
209+
let hash = header.hash();
210+
211+
// Note: this comparison is a u256 integer comparison, like zcashd and bitcoin. Greater
212+
// values represent *less* work.
213+
hash <= difficulty_threshold
214+
}
215+
216+
/// Modifies `nonce` to be the next integer in big-endian order.
217+
/// Wraps to zero if the next nonce would overflow.
218+
#[cfg(feature = "internal-miner")]
219+
fn next_nonce(nonce: &mut [u8; 32]) {
220+
let _ignore_overflow = crate::primitives::byte_array::increment_big_endian(&mut nonce[..]);
221+
}
151222
}
152223

153224
impl PartialEq<Solution> for Solution {

0 commit comments

Comments
 (0)