kaspa_pow/
lib.rs

1// public for benchmarks
2#[doc(hidden)]
3pub mod matrix;
4#[cfg(feature = "wasm32-sdk")]
5pub mod wasm;
6#[doc(hidden)]
7pub mod xoshiro;
8
9use std::cmp::max;
10
11use crate::matrix::Matrix;
12use kaspa_consensus_core::{hashing, header::Header, BlockLevel};
13use kaspa_hashes::PowHash;
14use kaspa_math::Uint256;
15
16/// State is an intermediate data structure with pre-computed values to speed up mining.
17pub struct State {
18    pub(crate) matrix: Matrix,
19    pub(crate) target: Uint256,
20    // PRE_POW_HASH || TIME || 32 zero byte padding; without NONCE
21    pub(crate) hasher: PowHash,
22}
23
24impl State {
25    #[inline]
26    pub fn new(header: &Header) -> Self {
27        let target = Uint256::from_compact_target_bits(header.bits);
28        // Zero out the time and nonce.
29        let pre_pow_hash = hashing::header::hash_override_nonce_time(header, 0, 0);
30        // PRE_POW_HASH || TIME || 32 zero byte padding || NONCE
31        let hasher = PowHash::new(pre_pow_hash, header.timestamp);
32        let matrix = Matrix::generate(pre_pow_hash);
33
34        Self { matrix, target, hasher }
35    }
36
37    #[inline]
38    #[must_use]
39    /// PRE_POW_HASH || TIME || 32 zero byte padding || NONCE
40    pub fn calculate_pow(&self, nonce: u64) -> Uint256 {
41        // Hasher already contains PRE_POW_HASH || TIME || 32 zero byte padding; so only the NONCE is missing
42        let hash = self.hasher.clone().finalize_with_nonce(nonce);
43        let hash = self.matrix.heavy_hash(hash);
44        Uint256::from_le_bytes(hash.as_bytes())
45    }
46
47    #[inline]
48    #[must_use]
49    pub fn check_pow(&self, nonce: u64) -> (bool, Uint256) {
50        let pow = self.calculate_pow(nonce);
51        // The pow hash must be less or equal than the claimed target.
52        (pow <= self.target, pow)
53    }
54}
55
56pub fn calc_block_level(header: &Header, max_block_level: BlockLevel) -> BlockLevel {
57    if header.parents_by_level.is_empty() {
58        return max_block_level; // Genesis has the max block level
59    }
60
61    let state = State::new(header);
62    let (_, pow) = state.check_pow(header.nonce);
63    let signed_block_level = max_block_level as i64 - pow.bits() as i64;
64    max(signed_block_level, 0) as BlockLevel
65}