use tari_node_components::blocks::BlockHeader;
use crate::{
chain_storage::{BlockchainBackend, fetch_target_difficulty_for_next_block},
consensus::BaseNodeConsensusManager,
proof_of_work::{AchievedTargetDifficulty, randomx_factory::RandomXFactory},
validation::{ValidationError, helpers::check_target_difficulty},
};
pub const TARI_RX_VM_KEY_BLOCK_SWAP: u64 = 2048;
const TARI_RX_VM_KEY_REORG_SAFETY_NUMBER: u64 = 64;
#[derive(Clone)]
pub struct DifficultyCalculator {
pub rules: BaseNodeConsensusManager,
pub randomx_factory: RandomXFactory,
}
impl DifficultyCalculator {
pub fn new(rules: BaseNodeConsensusManager, randomx_factory: RandomXFactory) -> Self {
Self { rules, randomx_factory }
}
pub fn check_achieved_and_target_difficulty<B: BlockchainBackend>(
&self,
db: &B,
block_header: &BlockHeader,
) -> Result<AchievedTargetDifficulty, ValidationError> {
let difficulty_window =
fetch_target_difficulty_for_next_block(db, &self.rules, block_header.pow_algo(), &block_header.prev_hash)?;
let constants = self.rules.consensus_constants(block_header.height);
let target = difficulty_window.calculate(
constants.min_pow_difficulty(block_header.pow.pow_algo),
constants.max_pow_difficulty(block_header.pow.pow_algo),
);
let gen_hash = *self.rules.get_genesis_block().hash();
let vm_key = *db
.fetch_chain_header_by_height(tari_rx_vm_key_height(block_header.height))?
.hash();
let achieved_target = check_target_difficulty(
block_header,
target,
&self.randomx_factory,
&gen_hash,
&self.rules,
vm_key,
)?;
Ok(achieved_target)
}
}
pub fn tari_rx_vm_key_height(height: u64) -> u64 {
if height <= TARI_RX_VM_KEY_BLOCK_SWAP + TARI_RX_VM_KEY_REORG_SAFETY_NUMBER {
0
} else {
(height - TARI_RX_VM_KEY_REORG_SAFETY_NUMBER - 1) & !(TARI_RX_VM_KEY_BLOCK_SWAP - 1)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_tari_vm_key_calc() {
let height = 0;
let expected = 0;
assert_eq!(tari_rx_vm_key_height(height), expected);
let height = 1000;
let expected = 0;
assert_eq!(tari_rx_vm_key_height(height), expected);
let height = 2047;
let expected = 0;
assert_eq!(tari_rx_vm_key_height(height), expected);
let height = 2048;
let expected = 0;
assert_eq!(tari_rx_vm_key_height(height), expected);
let height = 3048;
let expected = 2048;
assert_eq!(tari_rx_vm_key_height(height), expected);
let height = 4000;
let expected = 2048;
assert_eq!(tari_rx_vm_key_height(height), expected);
let height = 4159;
let expected = 2048;
assert_eq!(tari_rx_vm_key_height(height), expected);
let height = 4160;
let expected = 2048;
assert_eq!(tari_rx_vm_key_height(height), expected);
let height = 4161;
let expected = 4096;
assert_eq!(tari_rx_vm_key_height(height), expected);
}
}