blockchain/block.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
use chrono::Utc;
use serde::{Deserialize, Serialize};
use crate::{Chain, Transaction};
/// Identifier of a particular block on an entire blockchain.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct BlockHeader {
/// Timestamp at which a block was mined.
pub timestamp: i64,
/// Integer to achieve the network's difficulty.
pub nonce: u32,
/// Hash of a previous block.
pub previous_hash: String,
/// Merkel root hash.
pub merkle: String,
/// Current difficulty level of the network.
pub difficulty: f64,
}
/// Data storage in a blockchain.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Block {
/// Information about the block and the miner.
pub header: BlockHeader,
/// Total amount of transactions.
pub count: usize,
/// An amount of transactions.
pub transactions: Vec<Transaction>,
}
impl Block {
/// Create a new block.
///
/// # Arguments
///
/// - `previous_hash`: The hash of the previous block.
/// - `difficulty`: The difficulty level of the network.
///
/// # Returns
///
/// A new block with the given previous hash and difficulty.
pub fn new(previous_hash: String, difficulty: f64) -> Self {
// Create a new block header
let header = BlockHeader {
nonce: 0,
difficulty,
previous_hash,
merkle: String::new(),
timestamp: Utc::now().timestamp(),
};
// Create a new block
Block {
header,
count: 0,
transactions: vec![],
}
}
/// Perform the proof-of-work process to mine a block.
///
/// # Arguments
/// - `header`: A mutable reference to the block header to be mined.
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.count, 0);
assert_eq!(block.transactions.len(), 0);
}
}