Skip to main content

uhash_prover/cpu/
solver.rs

1//! Single-threaded CPU solver.
2
3use anyhow::Result;
4use uhash_core::{meets_difficulty, UniversalHash};
5
6use crate::solver::{ProofResult, Solver};
7
8/// Single-threaded CPU solver. Reuses one `UniversalHash` instance to
9/// avoid repeated 2 MB scratchpad allocations.
10pub struct CpuSolver {
11    hasher: UniversalHash,
12}
13
14impl CpuSolver {
15    pub fn new() -> Self {
16        Self {
17            hasher: UniversalHash::new(),
18        }
19    }
20}
21
22impl Default for CpuSolver {
23    fn default() -> Self {
24        Self::new()
25    }
26}
27
28impl Solver for CpuSolver {
29    fn backend_name(&self) -> &'static str {
30        "cpu"
31    }
32
33    fn recommended_lanes(&mut self, requested: usize) -> usize {
34        if requested == 0 {
35            1024
36        } else {
37            requested
38        }
39    }
40
41    fn find_proof_batch(
42        &mut self,
43        header_without_nonce: &[u8],
44        start_nonce: u64,
45        lanes: usize,
46        difficulty: u32,
47    ) -> Result<(ProofResult, usize)> {
48        let mut input = Vec::with_capacity(header_without_nonce.len() + 8);
49        for i in 0..lanes {
50            let nonce = start_nonce.saturating_add(i as u64);
51            input.clear();
52            input.extend_from_slice(header_without_nonce);
53            input.extend_from_slice(&nonce.to_le_bytes());
54            let hash = self.hasher.hash(&input);
55            if meets_difficulty(&hash, difficulty) {
56                return Ok((Some((nonce, hash)), i + 1));
57            }
58        }
59        Ok((None, lanes))
60    }
61
62    fn benchmark_hashes(
63        &mut self,
64        header_without_nonce: &[u8],
65        start_nonce: u64,
66        lanes: usize,
67    ) -> Result<usize> {
68        let mut input = Vec::with_capacity(header_without_nonce.len() + 8);
69        for i in 0..lanes {
70            let nonce = start_nonce.saturating_add(i as u64);
71            input.clear();
72            input.extend_from_slice(header_without_nonce);
73            input.extend_from_slice(&nonce.to_le_bytes());
74            let _ = self.hasher.hash(&input);
75        }
76        Ok(lanes)
77    }
78}