snap_coin/core/
block.rs

1use bincode::{Decode, Encode, error::EncodeError};
2use num_bigint::BigUint;
3use rand::Rng;
4use serde::{Deserialize, Serialize};
5
6use crate::{
7    core::{difficulty::calculate_block_difficulty, transaction::Transaction},
8    crypto::Hash,
9};
10
11/// Stores transaction, difficulties, its hash, and its nonce
12/// The hash can be often used for indexing, however can only be trusted if this node checked this block already
13#[derive(Encode, Decode, Serialize, Deserialize, Clone, Debug)]
14pub struct Block {
15    pub transactions: Vec<Transaction>,
16    pub timestamp: u64,
17    pub nonce: u64,
18    pub block_pow_difficulty: [u8; 32],
19    pub tx_pow_difficulty: [u8; 32],
20    pub previous_block: Hash,
21    pub hash: Option<Hash>,
22}
23
24impl Block {
25    /// Create a new block timestamped now, with a set of transactions, specifying transaction difficulty and block difficulty
26    pub fn new_block_now(
27        transactions: Vec<Transaction>,
28        block_pow_difficulty: &[u8; 32],
29        tx_pow_difficulty: &[u8; 32],
30        previous_block: Hash
31    ) -> Self {
32        Block {
33            transactions,
34            timestamp: chrono::Utc::now().timestamp() as u64,
35            nonce: 0,
36            block_pow_difficulty: *block_pow_difficulty,
37            tx_pow_difficulty: *tx_pow_difficulty,
38            previous_block,
39            hash: None,
40        }
41    }
42
43    /// Get this blocks hashing buffer required to mine this transaction. Essentially makes sure that any hash attached to this block is not included in the block hashing buffer
44    /// WARNING: Slow
45    pub fn get_hashing_buf(&self) -> Result<Vec<u8>, EncodeError> {
46        let mut hash_less_block = self.clone();
47        hash_less_block.hash = None; // Remove hash
48        
49        // Remove all transaction inputs because, we can just hash the transaction hash and keep the integrity
50        for transaction in &mut hash_less_block.transactions {
51            transaction.inputs = vec![];
52            transaction.outputs = vec![];
53        }
54        bincode::encode_to_vec(hash_less_block, bincode::config::standard())
55    }
56
57    /// Mine this block and attach its hash.
58    /// DEPRECATED: This is single threaded and cannot be used for actual mining as proper, multi-threaded mining machines outperform this by absolute miles
59    #[deprecated]
60    pub fn compute_pow(&mut self) -> Result<(), EncodeError> {
61        let tx_difficulty_big_int = BigUint::from_bytes_be(&calculate_block_difficulty(
62            &self.block_pow_difficulty,
63            self.transactions.len(),
64        ));
65        let mut rng: rand::prelude::ThreadRng = rand::rng();
66        loop {
67            self.nonce = rng.random();
68            let hashing_buf = self.get_hashing_buf()?;
69            if BigUint::from_bytes_be(&*Hash::new(&hashing_buf)) <= tx_difficulty_big_int {
70                self.hash = Some(Hash::new(&hashing_buf));
71                return Ok(());
72            }
73        }
74    }
75}