snap_coin/core/
difficulty.rs1use crate::core::{
2 block::Block,
3 economics::{DIFFICULTY_DECAY_PER_TX, MAX_DIFF_CHANGE, TARGET_TIME, TX_TARGET},
4 utils::{clamp_f, max_256_bui},
5};
6use bincode::{Decode, Encode};
7use num_bigint::BigUint;
8
9pub const STARTING_BLOCK_DIFFICULTY: [u8; 32] = [u8::MAX; 32];
10pub const STARTING_TX_DIFFICULTY: [u8; 32] = [u8::MAX; 32];
11
12#[derive(Encode, Decode, Copy, Clone, Debug)]
13pub struct DifficultyManager {
14 pub block_difficulty: [u8; 32],
15 pub transaction_difficulty: [u8; 32],
16 pub last_timestamp: u64,
17}
18
19impl DifficultyManager {
21 pub fn new(last_timestamp: u64) -> Self {
23 DifficultyManager {
24 block_difficulty: STARTING_BLOCK_DIFFICULTY,
25 transaction_difficulty: STARTING_TX_DIFFICULTY,
26 last_timestamp,
27 }
28 }
29
30 pub fn update_difficulty(&mut self, new_block: &Block) {
32 let time_ratio = (clamp_f(
34 (new_block.timestamp.saturating_sub(self.last_timestamp)) as f64 / TARGET_TIME as f64,
35 MAX_DIFF_CHANGE,
36 2.0 - MAX_DIFF_CHANGE,
37 ) * 1000.0) as u64;
38
39 let mut block_big = BigUint::from_bytes_be(&self.block_difficulty);
40 block_big = block_big * BigUint::from(time_ratio) / BigUint::from(1000u64);
41 self.block_difficulty =
42 biguint_to_32_bytes(block_big.min(max_256_bui()).max(BigUint::ZERO));
43
44 let tx_ratio = (clamp_f(
46 TX_TARGET as f64 / new_block.transactions.len() as f64,
47 MAX_DIFF_CHANGE,
48 2.0 - MAX_DIFF_CHANGE,
49 ) * 1000.0) as u64;
50
51 let mut tx_big = BigUint::from_bytes_be(&self.transaction_difficulty);
52 tx_big = tx_big * BigUint::from(tx_ratio) / BigUint::from(1000u64);
53 self.transaction_difficulty = biguint_to_32_bytes(tx_big.min(max_256_bui()).max(BigUint::ZERO));
54
55 self.last_timestamp = new_block.timestamp;
57 }
58}
59
60pub fn calculate_block_difficulty(block_difficulty: &[u8; 32], tx_count: usize) -> [u8; 32] {
62 let big = BigUint::from_bytes_be(block_difficulty);
63 biguint_to_32_bytes(
64 (big * BigUint::from(((1f64 + DIFFICULTY_DECAY_PER_TX * tx_count as f64) * 1000f64) as u64)
65 / BigUint::from(1000u64)).min(max_256_bui()),
66 )
67}
68
69fn biguint_to_32_bytes(value: BigUint) -> [u8; 32] {
70 let mut bytes = value.to_bytes_be();
71 if bytes.len() < 32 {
72 let mut padded = vec![0u8; 32 - bytes.len()];
73 padded.extend(bytes);
74 bytes = padded;
75 } else if bytes.len() > 32 {
76 bytes = bytes[bytes.len() - 32..].to_vec();
77 }
78 let mut array = [0u8; 32];
79 array.copy_from_slice(&bytes);
80 array
81}