use std::collections::HashMap;
use chrono::Utc;
use serde::{Deserialize, Serialize};
use crate::{Chain, ChainTransactions};
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct BlockHeader {
pub timestamp: i64,
pub nonce: u32,
pub previous_hash: String,
pub merkle: String,
pub difficulty: f64,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Block {
pub header: BlockHeader,
pub transactions: ChainTransactions,
}
impl Block {
pub fn new(previous_hash: String, difficulty: f64) -> Self {
let header = BlockHeader {
nonce: 0,
difficulty,
previous_hash,
merkle: String::new(),
timestamp: Utc::now().timestamp(),
};
Block {
header,
transactions: HashMap::default(),
}
}
pub fn proof_of_work(header: &mut BlockHeader) {
loop {
let hash = Chain::hash(header);
let slice = &hash[..header.difficulty as usize];
match slice.parse::<u32>() {
Ok(val) => {
if val != 0 {
header.nonce += 1;
} else {
break;
}
}
Err(_) => {
header.nonce += 1;
continue;
}
};
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_proof_of_work() {
let mut block = Block::new("0".to_string(), 1.0);
Block::proof_of_work(&mut block.header);
assert_eq!(block.header.difficulty, 1.0);
assert!(!block.header.previous_hash.is_empty());
}
#[test]
fn test_new_block() {
let block = Block::new("0".to_string(), 3.0);
assert_eq!(block.transactions.len(), 0);
}
}