1use std::collections::HashMap;
2
3use chrono::Utc;
4use serde::{Deserialize, Serialize};
5
6use crate::{Chain, ChainTransactions};
7
8#[derive(Clone, Debug, Serialize, Deserialize)]
10pub struct BlockHeader {
11 pub timestamp: i64,
13
14 pub nonce: u32,
16
17 pub previous_hash: String,
19
20 pub merkle: String,
22
23 pub difficulty: f64,
25}
26
27#[derive(Clone, Debug, Serialize, Deserialize)]
29pub struct Block {
30 pub header: BlockHeader,
32
33 pub transactions: ChainTransactions,
35}
36
37impl Block {
38 pub fn new(previous_hash: String, difficulty: f64) -> Self {
49 let header = BlockHeader {
51 nonce: 0,
52 difficulty,
53 previous_hash,
54 merkle: String::new(),
55 timestamp: Utc::now().timestamp(),
56 };
57
58 Block {
59 header,
60 transactions: HashMap::default(),
61 }
62 }
63
64 pub fn proof_of_work(header: &mut BlockHeader) {
69 loop {
70 let hash = Chain::hash(header);
71 let slice = &hash[..header.difficulty as usize];
72
73 match slice.parse::<u32>() {
74 Ok(val) => {
75 if val != 0 {
76 header.nonce += 1;
77 } else {
78 break;
79 }
80 }
81 Err(_) => {
82 header.nonce += 1;
83
84 continue;
85 }
86 };
87 }
88 }
89}
90
91#[cfg(test)]
92mod tests {
93 use super::*;
94
95 #[test]
96 fn test_proof_of_work() {
97 let mut block = Block::new("0".to_string(), 1.0);
98 Block::proof_of_work(&mut block.header);
99
100 assert_eq!(block.header.difficulty, 1.0);
101 assert!(!block.header.previous_hash.is_empty());
102 }
103
104 #[test]
105 fn test_new_block() {
106 let block = Block::new("0".to_string(), 3.0);
107
108 assert_eq!(block.transactions.len(), 0);
109 }
110}