【Rust】マイニングの難易度自動調整の仕組みを実装する

– PoWの難易度の自動調整を追加する
 L originの難易度があり、マイニングの経過した時間により難易度を上げたり下げたりする

5秒以上かかったらdifficultyを下げ、1秒以下ならdifficultyを上げる。

use serde::{Serialize, Deserialize};
use chrono::{Utc, Local, DateTime, Date};
use sha2::{Digest, Sha256};
use rand::Rng;
use std::{thread, time};
use floating_duration::TimeAsFloat;

#[derive(Debug, Serialize, Clone, Deserialize)]
struct Block {
    time: String,
    transactions: Vec<String>,
    hash: String,
    nonce: String,
}

unsafe fn pow() {
    let now = time::Instant::now();
    let previous_hash = "b9b9ee9ffc95fa4956b63b6043a99d0a8f04e0e52e687fc1958d3c6dff885f01";
    let mut num = rand::thread_rng().gen_range(0..1000000);
    let mut hash_num = format!("{}{}", previous_hash, num.to_string());
    let mut header = Sha256::digest(hash_num);
    let mut target: String  = (&hex::encode(header)[..4]).to_string();
    
    let mut cnt = 1;
    println!("count: {} {:x}", cnt, header);

    let str: String = "0".to_string();
    let difficulty_str = str.repeat(difficulty.try_into().unwrap());
    let n:usize = difficulty as usize;

    while target != difficulty_str {
        println!("count: {} {:x}", cnt, header);
        num = rand::thread_rng().gen_range(0..1000000);
        hash_num = format!("{}{}", previous_hash, num.to_string());
        header = Sha256::digest(hash_num);
        target = (&hex::encode(header)[..n]).to_string();
        cnt += 1;
    }
    println!("count: {} {:x}", cnt, header);
    println!("{:?}", now.elapsed());

    let t = vec!["sender".to_string(), "receiver".to_string(), "amount".to_string()];
    let utc_datetime: DateTime<Utc> = Utc::now();
    let b = Block{time:utc_datetime.to_string(), transactions: t, hash: hex::encode(header).to_string(), nonce:num.to_string()};
    println!("{:?}", b);
    println!("difficulty is {}", difficulty);
    if now.elapsed().as_fractional_secs() >= 5.0 {
        difficulty -= 1;
    } else if now.elapsed().as_fractional_secs() < 1.0 {
        difficulty += 1;
    }
}

static mut difficulty: u32 = 4;

fn main(){
    unsafe {pow()};       
    unsafe {pow()};   
    unsafe {pow()};        
}

$ cargo run

count: 393498 5c3b6663fe657641be5f6732ab2762fcc762aa9ffa598d6ee94dad59a4c4b9ca
count: 393499 000000215ec2fa2c01340818563a8397e50514204dcdca7f0addeeb7ff053e95
9.333024984s
Block { time: “2025-01-09 22:49:40.884851370 UTC”, transactions: [“sender”, “receiver”, “amount”], hash: “000000215ec2fa2c01340818563a8397e50514204dcdca7f0addeeb7ff053e95”, nonce: “175647” }
difficulty is 5

最初、difficultyが4だったのが、difficultyが5に変化しているのがわかります。
unsafeはあまり使いたくないですね。