Skip to main content

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}