library_blockchain/
block.rs

1// #![warn(missing_docs)]
2// #![warn(missing_doc_code_examples)]
3//#![feature(doc_cfg)]
4
5use serde::{Serialize};
6
7use super::*;
8use crate::transaction::Transaction;
9use std::{
10    cell::{Cell},
11    fmt::{self, Debug, Formatter},
12    rc::Rc,
13};
14
15/// Payload include transactions, difficulty,..
16/// </br></br>
17/// Order store of bytes: there are 2 types big-endian like 00 00 00 2a, little-endian like (our choice) 2a 00 00 00, u128 is in edian order, so because this material 16bytes of our hash will appear at the end of out hash's byte sector.
18/// </br></br>
19/// nonce is just field for changes in block as an arbitary that hashed along with the data. so generating the correct hash for a block is like the puzzle , and the nonce is the key to that puzzle. the process of finding that key is called mining.
20/// </br></br>
21/// </br></br>
22/// Overspending: where did the money come from?  inputs must be >= sum of values of generated outputs.
23/// </br></br>
24/// OverSpending: Sum(inputs)>=Sum(Outputs). I can't input 5 coins and be able to output 7. (on other hand inputs have to be greater since must be enough fee in input section for paying to miner.)
25/// </br></br>
26/// Impersonation: this can be solved by adding a "Signature" to outpus to verify they are being spent by their owner.(We can't assume that whoever sent us the trx over the network is also the person who created the trx. For now we'll kind of ignore solving this problem. we might come back to it when we go over smart contracts).
27/// </br></br>
28/// Impersonation: who owns the money and who is sending it?  Solved by adding signature and smart contract(not cover in this example).
29/// </br></br>
30/// DoubleSpending: make sure that anyone output is never used as an input more than once. This can be done by maintaining a pool of unspent outputs and rejecting any trx that tries to spend outputs that don't exist in the pool.
31/// </br></br>
32/// Double Spending: is the money avaliable? any one output is never used as an input more than once.
33/// </br></br>
34/// </br></br>
35/// Inputs: unused outputs from prev TRXs, Outputs: new outouts That can be used in future TRXs.
36
37#[derive(Serialize)]
38pub struct Block {
39    pub index: u32,
40    pub timestamp: u128,
41    pub hash: Hash,
42    pub prev_block_hash: Hash,
43    pub nonce: u64,
44    pub transactions:  Vec<Transaction> ,
45    pub difficulty: u128,
46}
47
48impl Debug for Block {
49    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
50        write!(f, "Block[{}]: {} at: {} with: {} trx, nonce: {}",
51            &self.index,
52            &hex::encode(&self.hash),
53            &self.timestamp,
54            &self.transactions.len(),
55            &self.nonce,
56       )
57    }
58}
59
60impl Block {
61    pub fn new(
62        index: u32,
63        timestamp: u128,
64        prev_block_hash: Hash,
65        transactions: &mut Rc<Cell<Vec<Transaction>>>,
66        difficulty: u128,
67    ) -> Self {
68        Block {
69            index,
70            timestamp,
71            hash: vec![0; 32],
72            prev_block_hash,
73            nonce: 0,
74            transactions: transactions.take().to_vec(),
75            difficulty,
76        }
77    }
78
79    /// 0xfff... lowest difficulty
80    /// </br>
81    /// 0x000... => highest difficulty => taking more time=> more highest nonce=> the end of blockhash see more zero so nonce 0 means end of of blockchash there isn'nt any zero at the end of blockhash.
82    /// </br></br>
83    /// nonce is just field for changes in block as an arbitary that hashed along with the data. so generating the correct hash for a block is like the puzzle , and the nonce is the key to that puzzle. the process of finding that key is called mining.
84    /// </br></br>
85    /// mining sterategy:
86    /// </br>
87    /// 1.Generate nonce 2.Hash bytes 3.Check hash against difficulty(Insufficant? Go Step1 and Sufficient Go Step 4) 4. Add block to chain 5. Submit to peers
88    pub fn blockchain_mine(&mut self) -> Result<Hash, CustomError> {
89        for nonce_attempt in 0..(u64::max_value()) {
90            self.nonce = nonce_attempt;
91            let hash = self.hash();
92
93            if blockchain_check_difficulty(&hash, self.difficulty) {
94                self.hash = hash;
95                return Ok(self.hash.clone())
96             
97            }
98        }
99        return Err(CustomError::BlockValidation(BlockValidationError::NonceAttemptFailed));
100      
101    }
102}
103
104/// Concatenate together all the bytes
105/// </br></br>
106/// Generate unique data fingerprint: the hash
107impl Hashable for Block {
108    fn bytes(&self) -> Vec<u8> {
109        let mut bytes = vec![];
110
111        bytes.extend(&lib_block_u32_bytes(&self.index));
112        bytes.extend(&lib_block_u128_bytes(&self.timestamp));
113        bytes.extend(&self.prev_block_hash);
114        bytes.extend(&lib_block_u64_bytes(&self.nonce));
115        bytes.extend(
116            self.transactions                
117                .iter()
118                .flat_map(|transaction| transaction.bytes())
119                .collect::<Vec<u8>>(),
120        );
121        bytes.extend(&lib_block_u128_bytes(&self.difficulty));
122
123        bytes
124    }
125}
126
127/// Verify four things:
128/// Actual Index, Block's hash fits stored difficulty value, Time is always increase, Actual previous block's hash
129/// Difficulty: the most significant 16 bytes of the hash of a block must be less than before it is considered "valid"(if those bytes are interoreted as a single number instead of a serices of bytes.)
130pub fn blockchain_check_difficulty(hash: &Hash, difficulty: u128) -> bool {
131    let result = lib_block_difficulty_bytes_as_u128(&hash);
132    difficulty > result
133}