uqoin_core/block.rs
1//! Defines the structure and validation logic for blocks within the Uqoin
2//! blockchain.
3//!
4//! A block in Uqoin encapsulates a set of transactions and metadata essential
5//! for maintaining the blockchain's integrity.
6//! Each block contains:
7//! - `offset`: The position of the block in the blockchain sequence.
8//! - `size`: The number of transactions included in the block.
9//! - `hash_prev`: The hash of the preceding block, establishing a link between
10//! blocks.
11//! - `validator`: The public key of the validator who created the block.
12//! - `nonce`: A 256-bit random value used in the proof-of-work mechanism.
13//! - `hash`: The resulting hash of the block, which must satisfy the network's
14//! difficulty requirements.
15//!
16//! The module also defines:
17//! - `BlockInfo`: A concise summary of a block's essential information.
18//! - `BlockData`: An extended structure that includes all transactions
19//! associated with a block.
20//!
21//! Constants:
22//! - `GENESIS_HASH`: The predefined hash value for the genesis (first) block.
23//! - `COMPLEXITY`: The network's difficulty level, determining the required
24//! number of trailing zeros in a valid block hash.
25//!
26//! The `Block` struct provides methods for:
27//! - Creating new blocks.
28//! - Validating blocks against the previous block's information, current state,
29//! and network complexity.
30//! - Calculating the block's message and hash.
31//! - Ensuring the block's hash meets the required complexity.
32//!
33//! This module ensures that each block adheres to the Uqoin protocol's rules,
34//! maintaining the blockchain's security and consistency.
35
36use rand::Rng;
37use sha3::{Sha3_256, Digest};
38use serde::{Serialize, Deserialize};
39
40use crate::validate;
41use crate::utils::*;
42use crate::transaction::{Type, Transaction, group_transactions};
43use crate::state::State;
44
45
46/// Hash of the zero block.
47pub const GENESIS_HASH: &str =
48 "E12BA98A17FD8F70608668AA32AEB3BE1F202B4BD69880A6C0CFE855B1A0706B";
49
50/// Complexity after calibration.
51pub const COMPLEXITY: usize = 24;
52
53
54/// Basic structure for block.
55#[derive(Debug, Clone, Serialize, Deserialize)]
56pub struct Block {
57 pub offset: u64,
58 pub size: u64,
59 pub hash_prev: U256,
60 pub validator: U256,
61 pub nonce: U256,
62 pub hash: U256,
63}
64
65
66impl Block {
67 /// New block.
68 pub fn new(offset: u64, size: u64, hash_prev: U256, validator: U256,
69 nonce: U256, hash: U256) -> Self {
70 Self { offset, size, hash_prev, validator, nonce, hash }
71 }
72
73 /// Full validation of the block that includes transactions, info of the
74 /// previous block, complexity, state between this block and the previous
75 /// one.
76 pub fn validate(&self, transactions: &[Transaction],
77 block_info_prev: &BlockInfo, complexity: usize,
78 state: &State, senders: &[U256]) -> UqoinResult<()> {
79 // Check block hash
80 validate!(block_info_prev.hash == self.hash_prev,
81 BlockPreviousHashMismatch)?;
82
83 // Check block offset
84 validate!(block_info_prev.offset == self.offset,
85 BlockOffsetMismatch)?;
86
87 // Validate transactions
88 Self::validate_transactions(transactions, &self.validator, state,
89 senders)?;
90
91 // Calculate the message
92 let msg = Self::calc_msg(&self.hash_prev, &self.validator,
93 transactions);
94
95 // Calculate the hash
96 let hash = Self::calc_hash(&msg, &self.nonce);
97
98 // Check hash
99 validate!(hash == self.hash, BlockInvalidHash)?;
100
101 // Validate hash
102 Self::validate_hash_complexity(&self.hash, transactions.len(),
103 complexity)?;
104
105 // Return
106 Ok(())
107 }
108
109 /// Build a new block for the transactions. It validates the final hash.
110 pub fn build(block_info_prev: &BlockInfo, validator: U256,
111 transactions: &[Transaction], nonce: U256,
112 complexity: usize, state: &State,
113 senders: &[U256]) -> UqoinResult<Self> {
114 // Validate transactions
115 Self::validate_transactions(transactions, &validator, state, senders)?;
116
117 // Calculate the message
118 let msg = Self::calc_msg(&block_info_prev.hash, &validator,
119 transactions);
120
121 // Calculate the hash
122 let hash = Self::calc_hash(&msg, &nonce);
123
124 // Validate hash
125 Self::validate_hash_complexity(&hash, transactions.len(), complexity)?;
126
127 // Create a block
128 Ok(Self::new(block_info_prev.offset,
129 transactions.len() as u64,
130 block_info_prev.hash.clone(),
131 validator, nonce, hash))
132 }
133
134 /// Validate coins. The checks:
135 /// 1. All coins are unique.
136 /// 2. All transactions are valid (see `Transaction::validate_coins()`).
137 #[deprecated(since="0.1.0", note="use groups and check_unique instead")]
138 pub fn validate_coins(transactions: &[Transaction], state: &State,
139 senders: &[U256]) -> UqoinResult<()> {
140 // Repeated coins are not valid
141 validate!(check_unique(transactions.iter().map(|tr| &tr.coin)),
142 CoinNotUnique)?;
143
144 // Validate coin in each transaction
145 for (transaction, sender) in transactions.iter().zip(senders.iter()) {
146 transaction.validate_coin(state, sender)?;
147 }
148
149 Ok(())
150 }
151
152 /// Validate transactions. The checks:
153 /// 1. All coins are valid (see `validate_coins`).
154 /// 2. All transactions can be groupped into groups and extensions.
155 /// 3. Sender of each extension is the validator.
156 /// 4. Values of groups and extensions correspond each other.
157 /// Each group or extension has valid structure after the groupping because
158 /// they cannot be created invalid due to inner validation.
159 pub fn validate_transactions(transactions: &[Transaction], validator: &U256,
160 state: &State, senders: &[U256]) ->
161 UqoinResult<()> {
162 // // Check coins
163 // Self::validate_coins(transactions, state, senders)?;
164
165 // Repeated coins are not valid
166 validate!(check_unique(transactions.iter().map(|tr| &tr.coin)),
167 CoinNotUnique)?;
168
169 // Set a countdown for groupped transactions
170 let mut countdown = transactions.len();
171
172 // Loop for groups and extensions
173 for (offset, group, ext) in group_transactions(transactions.to_vec(),
174 state, senders) {
175 // Get senders
176 let group_senders = &senders[offset .. offset + group.len()];
177 let ext_senders = &senders[
178 offset + group.len() .. offset + group.len() + ext.len()
179 ];
180
181 // Check validator
182 if let Some(ext_sender) = ext.get_sender(ext_senders) {
183 validate!(&ext_sender == validator, BlockValidatorMismatch)?;
184 }
185
186 // Check value
187 if ext.get_type() != Type::Transfer {
188 validate!(group.get_order(state, group_senders)
189 == ext.get_order(state, ext_senders), BlockOrderMismatch)?;
190 }
191
192 // Decrement the countdown
193 countdown -= group.len() + ext.len();
194 }
195
196 // Validate that all transactions have been groupped
197 validate!(countdown == 0, BlockBroken)?;
198
199 Ok(())
200 }
201
202 /// Validate hash for the certain complexity.
203 pub fn validate_hash_complexity(hash: &U256, size: usize,
204 complexity: usize) -> UqoinResult<()> {
205 let limit_hash = Self::calc_limit_hash(size, complexity);
206 validate!(Self::is_hash_valid(&hash.to_bytes(), &limit_hash),
207 BlockInvalidHashComplexity)
208 }
209
210 /// calculate block message as hash of the important content.
211 pub fn calc_msg(block_hash_prev: &U256, validator: &U256,
212 transactions: &[Transaction]) -> U256 {
213 let mut elems = vec![block_hash_prev.clone(), validator.clone()];
214 elems.extend(transactions.iter().map(|tr| tr.get_hash()));
215 hash_of_u256(elems.iter())
216 }
217
218 /// Calculate block hash from message and nonce.
219 pub fn calc_hash(msg: &U256, nonce: &U256) -> U256 {
220 hash_of_u256([msg, nonce].into_iter())
221 }
222
223 /// Chech if the hash corresponds to the necessary size.
224 pub fn is_hash_valid(hash_bytes: &[u8], limit_hash_bytes: &[u8]) -> bool {
225 hash_bytes <= limit_hash_bytes
226 }
227
228 /// Find correct nonce bytes to mine the block.
229 pub fn mine<R: Rng>(rng: &mut R, block_hash_prev: &U256, validator: &U256,
230 transactions: &[Transaction],
231 complexity: usize,
232 iterations: Option<usize>) -> Option<[u8; 32]> {
233 // Calculate the message bytes
234 let msg = Self::calc_msg(block_hash_prev, validator, transactions);
235
236 // Number of transactions
237 let size = transactions.len();
238
239 // Calculate limit hash
240 let limit_hash = Self::calc_limit_hash(size, complexity);
241
242 // Initialize SHA3 hasher with the block message
243 let mut hasher = Sha3_256::new();
244 hasher.update(msg.to_bytes());
245
246 // Mining loop
247 for iteration in 0.. {
248 // Stop by iterations
249 if let Some(iterations) = iterations {
250 if iteration >= iterations {
251 break;
252 }
253 }
254
255 // Clone the hasher state before adding nonce
256 let mut hasher_clone = hasher.clone();
257
258 // Generate a random 256-bit nonce
259 let nonce_bytes: [u8; 32] = rng.random();
260
261 // Update the hasher with the generated nonce
262 hasher_clone.update(nonce_bytes);
263
264 // Get the bytes of the final hash
265 let hash_bytes = hasher_clone.finalize();
266
267 // If the hash is valid return the generated nonce and U256
268 if Self::is_hash_valid(&hash_bytes, &limit_hash) {
269 return Some(nonce_bytes);
270 }
271 }
272
273 // Return `None` if nothing mined
274 None
275 }
276
277 /// Calculate maximum allowed block hash depending on the size.
278 fn calc_limit_hash(size: usize, complexity: usize) -> Vec<u8> {
279 assert!(complexity > 0);
280 let mut num = U256::from(1);
281 num <<= 256 - complexity;
282 let bytes = if size > 1 {
283 num.divide_unit(size as u64).unwrap().0.to_bytes()
284 } else {
285 num.to_bytes()
286 };
287 bytes.into_iter().rev().collect::<Vec<u8>>()
288 }
289}
290
291
292/// Short information about the block.
293#[derive(Debug, Clone, Serialize, Deserialize)]
294pub struct BlockInfo {
295 /// Block number.
296 pub bix: u64,
297
298 /// Total number of transaction up to this block (`offset` for the next
299 /// block).
300 pub offset: u64,
301
302 /// Last block hash.
303 pub hash: U256,
304}
305
306
307impl BlockInfo {
308 /// Get information of the genesis block (`bix=0`).
309 pub fn genesis() -> Self {
310 Self {
311 bix: 0,
312 offset: 0,
313 hash: U256::from_hex(GENESIS_HASH),
314 }
315 }
316}
317
318
319/// Full information about the block.
320#[derive(Debug, Clone, Serialize, Deserialize)]
321pub struct BlockData {
322 /// Block number.
323 pub bix: u64,
324
325 /// Block data.
326 pub block: Block,
327
328 /// Included transactions.
329 pub transactions: Vec<Transaction>,
330}
331
332
333impl BlockData {
334 /// Get data of the genesis block (`bix=0`).
335 pub fn genesis() -> Self {
336 Self {
337 bix: 0,
338 block: Block {
339 offset: 0,
340 size: 0,
341 hash_prev: U256::from(0),
342 validator: U256::from(0),
343 nonce: U256::from(0),
344 hash: U256::from_hex(GENESIS_HASH),
345 },
346 transactions: Vec::new(),
347 }
348 }
349
350 /// Get short information.
351 pub fn get_block_info(&self) -> BlockInfo {
352 BlockInfo {
353 bix: self.bix,
354 offset: self.block.offset + self.block.size,
355 hash: self.block.hash.clone(),
356 }
357 }
358}
359
360
361#[cfg(test)]
362mod tests {
363 use super::*;
364 use test::Bencher;
365 use crate::schema::Schema;
366
367 #[test]
368 fn test_mine() {
369 // Best value is complexity = 24 that corresponds to ~10 seconds
370 // per empty block (for --release, 1 core, desktop)
371 let complexity = 8;
372
373 // Initial arguments
374 let mut rng = rand::rng();
375 let schema = Schema::new();
376
377 let block_hash_prev: U256 = rng.random();
378 let validator: U256 = schema.gen_pair(&mut rng).1;
379
380 let transactions: Vec<Transaction> = vec![];
381
382 // Mining the nonce
383 let nonce_bytes = Block::mine(&mut rng, &block_hash_prev, &validator,
384 &transactions, complexity,
385 Some(10000)).unwrap();
386
387 // Calculate hash
388 let msg = Block::calc_msg(&block_hash_prev, &validator, &transactions);
389 let nonce = U256::from_bytes(&nonce_bytes);
390 let hash = hash_of_u256([&msg, &nonce].into_iter());
391
392 // Calculate limit hash
393 let limit_hash = Block::calc_limit_hash(transactions.len(), complexity);
394
395 // Check that the hash is valid
396 assert!(hash.to_bytes() <= limit_hash);
397 assert!(Block::is_hash_valid(&hash.to_bytes(), &limit_hash));
398 }
399
400 #[bench]
401 fn bench_mine_10(bencher: &mut Bencher) {
402 let size = 10;
403
404 let mut rng = rand::rng();
405 let schema = Schema::new();
406
407 let block_hash_prev: U256 = rng.random();
408 let validator: U256 = schema.gen_pair(&mut rng).1;
409 let coin: U256 = rng.random();
410 let addr: U256 = rng.random();
411 let key: U256 = schema.gen_key(&mut rng);
412
413 let transactions: Vec<Transaction> = vec![
414 Transaction::build(
415 &mut rng, coin.clone(), addr.clone(), &key, 0, &schema
416 );
417 size
418 ];
419
420 bencher.iter(|| {
421 let _nonce = Block::mine(&mut rng, &block_hash_prev, &validator,
422 &transactions, 1, None);
423 });
424 }
425
426 // Uncomment it to start calibration:
427 // `cargo bench block::tests::bench_mine_calibration`
428 // #[bench]
429 // fn bench_mine_calibration(bencher: &mut Bencher) {
430 // // The result is ~4 s/iter
431 // let complexity = 24;
432
433 // let mut rng = rand::rng();
434 // let schema = Schema::new();
435
436 // let block_hash_prev: U256 = rng.random();
437 // let validator: U256 = schema.gen_pair(&mut rng).1;
438 // let coin: U256 = rng.random();
439 // let addr: U256 = rng.random();
440 // let key: U256 = schema.gen_key(&mut rng);
441
442 // let transactions: Vec<Transaction> = vec![
443 // Transaction::build(
444 // &mut rng, coin.clone(), addr.clone(), &key, 0, &schema
445 // ),
446 // ];
447
448 // bencher.iter(|| {
449 // let _nonce = Block::mine(&mut rng, &block_hash_prev, &validator,
450 // &transactions, complexity, None);
451 // });
452 // }
453}