blockchainblock/
blockchainblock.rs

1use crypto_hash::{Algorithm, digest};
2use std::fmt;
3use super::*;
4
5/// Structure for storing one Block of the Blockchain with as few dependencies as possible.
6pub struct BlockchainBlock<'a, T>{
7    /// hash of the current block
8    pub curr_hash: BlockHash,
9    /// hash of the previous block. Is `None` for the first block
10    pub prev_hash: Option<BlockHash>,
11    /// encrypted data in compressed form
12    pub data: &'a[T],
13    /// time of block creation in seconds since 1970-01-01T00:00 UTC
14    pub timestamp: u64,
15    /// field used for giving variability
16    pub nonce: u64,
17    /// root of a sha256 hash tree where the leaves are transactions
18    pub merkle_root: BlockHash,
19    /// version of the protocol used to create the block
20    pub version: u8,
21}
22
23/// Implementation of BlockchainBlock for a generic type `T`
24impl<'a, T> BlockchainBlock<'a, T>
25where
26    T: Byteable + Clone
27{    
28    /// Constructs a new `BlockchainBlock<T>`.
29    ///
30    /// # Description
31    ///
32    /// * `prev_hash` - Hash of the previous block.
33    /// * `data` - Data to be stored in the block.
34    /// * `timestamp` - Creation time in *Unix time* format.
35    /// * `nonce` - Nonce to include variability in the hash calculation.
36    ///    
37    ///
38    /// # Examples
39    ///
40    /// Simple example with i32
41    ///
42    /// ```
43    ///   extern crate blockchainblock;
44    ///   use crate::blockchainblock::*;
45    ///   
46    ///   let prev  : Option<BlockHash> = None;
47    ///   let nonce : u64 = 3;
48    ///   let timestamp : u64 = 4;
49    ///   let data : [i32; 1] = [5];
50    ///   let block : BlockchainBlock<i32> = BlockchainBlock::new(prev, &data, timestamp, nonce);
51    ///   println!("\n{:?}\n", &block);
52    ///   assert_eq!(block.curr_hash, [23, 105, 91, 179, 190, 192, 178, 189, 198, 134, 87, 143, 214, 135, 93, 17, 50, 143, 192, 3, 254, 144, 115, 123, 42, 223, 197, 199, 181, 113, 224, 123]);
53    /// ```
54    ///
55    /// Example with array of Strings
56    ///
57    /// ```
58    /// extern crate blockchainblock;
59    /// use crate::blockchainblock::*;
60    ///     
61    /// let book_reviews = [
62    ///  String::from(
63    ///   "{
64    ///    \"Adventures of Huckleberry Finn\": \"My favorite book.\",
65    ///    \"Grimms' Fairy Tales\": \"Masterpiece.\",
66    ///    \"Pride and Prejudice\": \"Very enjoyable.\",
67    ///    \"The Adventures of Sherlock Holmes\": \"Eye lyked it alot.\",
68    ///    }"),
69    ///  String::from(
70    ///   "{
71    ///    \"Adventures of Huckleberry Finn\": \"My favorite book.\",
72    ///    \"Grimms' Fairy Tales\": \"Masterpiece.\",
73    ///    \"Pride and Prejudice\": \"Very enjoyable.\",
74    ///    \"The Adventures of Sherlock Holmes\": \"Eye lyked it alot.\",
75    ///    }")
76    /// ];
77     
78    /// let prev  : Option<BlockHash> = Some([1; BLOCKHASHLEN]);
79    /// let nonce : u64 = 3;
80    /// let timestamp = std::time::Duration::from_secs(1524885322).as_secs();
81    /// let block : BlockchainBlock<String> = BlockchainBlock::new(prev, &book_reviews, timestamp, nonce);
82    ///   
83    /// println!("\n{:?}\n", &block);
84    /// assert_eq!(block.curr_hash, [220, 149, 236, 219, 173, 29, 131, 71, 35, 245, 97, 228, 58, 247, 45, 86, 197, 104, 26, 236, 232, 98, 144, 4, 220, 210, 177, 17, 235, 113, 214, 18]);
85    /// ```
86   
87    pub fn new(prev_hash: Option<BlockHash>, data: &[T], timestamp: u64, nonce: u64) -> BlockchainBlock<T> {
88        let mut block = BlockchainBlock {
89            prev_hash,
90            data,
91            timestamp, 
92            merkle_root : [ 0; BLOCKHASHLEN],
93            nonce,
94            version : VERSION,
95            curr_hash : [ 0; BLOCKHASHLEN]
96        };
97        if data.len() > 0 { block.merkle_root = block.calculate_merkle_root(data); }
98        block.calculate_hash();        
99        block
100    }
101
102    /// Check data is inside the block.
103    /// Calculate a merkle root and compare it with the one stored in the block.
104    ///
105    /// # Description
106    ///
107    /// * `data` - Data to be checked.
108    /// * `position` - Position of the data in the original array. 0 <= pos < block.data.len()
109    ///
110    /// # Examples
111    ///    
112    /// Example checking String is inside the Block
113    ///
114    /// ```
115    /// extern crate blockchainblock;
116    /// use crate::blockchainblock::*;    
117    /// let string_check = String::from(
118    ///     "{\"The Adventures of Sherlock Holmes\",\"Grimms' Fairy Tales\"}"
119    /// );
120    /// let book_reviews = [
121    ///     String::from(
122    ///         "{\"Adventures of Huckleberry Finn\",\"Grimms' Fairy Tales\"}"
123    ///     ),
124    ///     String::from(
125    ///         "{\"Eloquent JavaScript, Second Edition\",\"Learning JavaScript Design Patterns\"}"
126    ///     ),
127    ///     string_check.clone(),
128    ///     String::from(
129    ///         "{\"Speaking JavaScript\",\"Programming JavaScript Applications\"}"
130    ///     ),
131    /// ];
132    /// 
133    /// let prev  : Option<BlockHash> = None;
134    /// let nonce : u64 = 1;
135    /// let timestamp = std::time::Duration::from_secs(1524885322).as_secs();
136    /// let block : BlockchainBlock<String> = BlockchainBlock::new(prev, &book_reviews, timestamp, nonce);
137    ///    
138    /// println!("\n{:?}\n", &block);
139    /// assert_eq!(block.check_value_inblock(&string_check,2), true);
140    /// ```
141
142    pub fn check_value_inblock(&self, data: &T, position: usize) -> bool{
143        if position >= self.data.len(){ return false; }
144        let mut temp = self.data.to_vec();
145        temp[position] = data.clone();
146        if self.calculate_merkle_root(&temp[..]) == self.merkle_root { return true; }
147        else{ return false; }
148    }
149    
150    fn calculate_merkle_hash<'b>(&self, block_left: &'b BlockHash, block_right: &'b BlockHash) -> BlockHash{
151        const DOUBLE_BLOCK_LEN : usize = BLOCKHASHLEN * 2;
152        let mut bytes: [u8; DOUBLE_BLOCK_LEN] = [0; DOUBLE_BLOCK_LEN];
153        
154        bytes[..BLOCKHASHLEN].clone_from_slice(block_left);
155        bytes[BLOCKHASHLEN..].clone_from_slice(block_right);
156        let digest = digest(Algorithm::SHA256, &bytes);
157        let mut result: BlockHash = [0; BLOCKHASHLEN];
158        result.copy_from_slice(&digest);
159        return result;
160    }
161
162    fn calculate_merkle_root (&self, blocks: &[T]) -> BlockHash{
163        
164        let size = blocks.len();
165        match size {
166            1 | 2 => {
167                let mut bytes : Vec<u8> = Vec::new();
168                if size == 1 {
169                    bytes.append(&mut blocks[0].bytes());
170                    bytes.append(&mut blocks[0].bytes());
171                } else {
172                    bytes.append(&mut blocks[0].bytes());
173                    bytes.append(&mut blocks[1].bytes());
174                }
175                let digest = digest(Algorithm::SHA256, &bytes);
176                let mut result: BlockHash = [0; BLOCKHASHLEN];
177                result.copy_from_slice(&digest);
178                return result;
179            },
180            _ => {
181                let (left, right) = blocks.split_at(size/2);
182                return self.calculate_merkle_hash(
183                    &self.calculate_merkle_root(&left),
184                    &self.calculate_merkle_root(&right));
185            },
186        }
187    }
188    
189}
190
191impl<'a, T: fmt::Debug> fmt::Debug for BlockchainBlock<'a, T>{
192    fn fmt (&self, formatter: &mut fmt::Formatter) -> fmt::Result {
193        formatter.debug_struct("Block")
194            .field("Current Hash", &self.curr_hash)
195            .field("Previous Hash", &self.prev_hash)
196            .field("Data", &self.data)
197            .field("Timestamp", &self.timestamp)
198            .field("Timestamp", &self.timestamp)
199            .field("Nonce", &self.nonce)
200            .field("Merkleroot", &self.merkle_root)
201            .field("Version", &self.version)
202            .finish()
203    }    
204}
205
206
207impl<'a, T> Hashable for BlockchainBlock<'a, T>
208where
209    T: Byteable,
210{
211    fn calculate_hash (&mut self){
212        let prev_hash_bytes = &self.prev_hash;
213        let data_bytes = &self.data.bytes();
214        let timestamp_bytes = &self.timestamp.to_le_bytes();
215        let nonce_bytes = &self.nonce.to_le_bytes();        
216        let merkle_root_bytes = &self.merkle_root;
217        let version_bytes = &self.version.to_le_bytes();
218        let size =
219            match prev_hash_bytes { Some(prev_h) => prev_h.len(), None => 0 } +
220            data_bytes.len() +
221            timestamp_bytes.len() +
222            nonce_bytes.len() +
223            merkle_root_bytes.len() +
224            version_bytes.len();
225        let mut bytes : Vec<u8> = Vec::with_capacity(size);
226
227        match prev_hash_bytes {
228            Some(prev_h) => {
229                for idj in 0..prev_h.len(){
230                    bytes.push(prev_h[idj]);
231                }
232            },
233            None => ()
234        }
235        for idj in 0..data_bytes.len(){
236            bytes.push(data_bytes[idj]);
237        }
238        for idj in 0..timestamp_bytes.len(){
239            bytes.push(timestamp_bytes[idj]);
240        }
241        for idj in 0..nonce_bytes.len(){
242            bytes.push(nonce_bytes[idj]);
243        }
244        for idj in 0..merkle_root_bytes.len(){
245            bytes.push(merkle_root_bytes[idj]);
246        }
247        for idj in 0..version_bytes.len(){
248            bytes.push(version_bytes[idj]);
249        }
250
251        let digest = digest(Algorithm::SHA256, &bytes);
252        &self.curr_hash.copy_from_slice(&digest);
253    }
254
255}
256
257// #[test]
258// fn test() {
259  
260// }
261