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