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    pub fn get_hashing_buf(&self) -> Result<Vec<u8>, EncodeError> {
45        let mut hash_less_block = self.clone();
46        hash_less_block.hash = None;
47        bincode::encode_to_vec(hash_less_block, bincode::config::standard())
48    }
49
50    /// Mine this block and attach its hash.
51    /// DEPRECATED: This is single threaded and cannot be used for actual mining as proper, multi-threaded mining machines outperform this by absolute miles
52    #[deprecated]
53    pub fn compute_pow(&mut self) -> Result<(), EncodeError> {
54        let tx_difficulty_big_int = BigUint::from_bytes_be(&calculate_block_difficulty(
55            &self.block_pow_difficulty,
56            self.transactions.len(),
57        ));
58        let mut rng: rand::prelude::ThreadRng = rand::rng();
59        loop {
60            self.nonce = rng.random();
61            let hashing_buf = self.get_hashing_buf()?;
62            if BigUint::from_bytes_be(&*Hash::new(&hashing_buf)) <= tx_difficulty_big_int {
63                self.hash = Some(Hash::new(&hashing_buf));
64                return Ok(());
65            }
66        }
67    }
68}