blockchain/
block.rs

1use std::collections::HashMap;
2
3use chrono::Utc;
4use serde::{Deserialize, Serialize};
5
6use crate::{Chain, ChainTransactions};
7
8/// Identifier of a particular block on an entire blockchain.
9#[derive(Clone, Debug, Serialize, Deserialize)]
10pub struct BlockHeader {
11    /// Timestamp at which a block was mined.
12    pub timestamp: i64,
13
14    /// Integer to achieve the network's difficulty.
15    pub nonce: u32,
16
17    /// Hash of a previous block.
18    pub previous_hash: String,
19
20    /// Merkel root hash.
21    pub merkle: String,
22
23    /// Current difficulty level of the network.
24    pub difficulty: f64,
25}
26
27/// Data storage in a blockchain.
28#[derive(Clone, Debug, Serialize, Deserialize)]
29pub struct Block {
30    /// Information about the block and the miner.
31    pub header: BlockHeader,
32
33    /// List of transactions.
34    pub transactions: ChainTransactions,
35}
36
37impl Block {
38    /// Create a new block.
39    ///
40    /// # Arguments
41    ///
42    /// - `previous_hash`: The hash of the previous block.
43    /// - `difficulty`: The difficulty level of the network.
44    ///
45    /// # Returns
46    ///
47    /// A new block with the given previous hash and difficulty.
48    pub fn new(previous_hash: String, difficulty: f64) -> Self {
49        // Create a new block header
50        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    /// Perform the proof-of-work process to mine a block.
65    ///
66    /// # Arguments
67    /// - `header`: A mutable reference to the block header to be mined.
68    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}