/
nirvand
/
rust-blockchain
Обзор
Документация
Войти
/
nirvand
/
rust-blockchain
Код
Запросы
1
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
pull-request
src/blockchain.rs
160 строк
6 KB
Nirvand
chore: add some commentaries
22 мар 2025, 13:51
22 мар 2025, 13:51
ecc5324
Код
Авторство
О чём код?
use chrono::Utc; // Для работы с датами и временем use serde::{Deserialize, Serialize}; // Для работы serde_json use serde_json; // Для сериализации и десериализации формата JSON use sha2::{Digest, Sha256}; // Для хеширования #[derive(Debug, Serialize, Deserialize)] pub struct Block { pub index: u32, pub timestamp: String, pub data: String, // Произвольная строка (по заданию) pub previous_hash: String, pub hash: String, pub difficulty: u32, // Сложность, задает время добычи блока pub nonce: u64, // Одноразовое число, которое характеризует итерарацию, на которой был добыт блок } impl Block { pub fn new(index: u32, data: String, previous_hash: String, difficulty: u32) -> Self { let timestamp = Utc::now().to_string(); let (hash, nonce) = Self::mine_block(index, ×tamp, &data, &previous_hash, difficulty); Block { index, timestamp, data, previous_hash, hash, difficulty, nonce, } } fn calculate_hash( // Непосредственно метод, считающий хэш, в зависимости от переданных параметров index: u32, timestamp: &str, data: &str, previous_hash: &str, nonce: u64, ) -> String { let input = format!("{}{}{}{}{}", index, timestamp, data, previous_hash, nonce); let mut hasher = Sha256::new(); hasher.update(input.as_bytes()); format!("{:x}", hasher.finalize()) } fn mine_block( index: u32, timestamp: &str, data: &str, previous_hash: &str, difficulty: u32, ) -> (String, u64) { let prefix = "0".repeat(difficulty as usize); // От заданной сложности зависит время, // требующееся для подбора хэша, начинающегося с заданного колличества нулей let mut nonce = 0; loop { let hash = Self::calculate_hash(index, timestamp, data, previous_hash, nonce); if hash.starts_with(&prefix) { return (hash, nonce); } nonce += 1; } } pub fn is_block_valid(&self) -> bool { let prefix = "0".repeat(self.difficulty as usize); if !self.hash.starts_with(&prefix) { return false; } let recalculated_hash = Self::calculate_hash( self.index, &self.timestamp, &self.data, &self.previous_hash, self.nonce, ); self.hash == recalculated_hash } } #[derive(Debug, Serialize, Deserialize)] pub struct Blockchain { pub blocks: Vec<Block>, pub difficulty: u32, } impl Blockchain { pub fn new(difficulty: u32) -> Self { let genesis_block = Block::new(0, "Genesis Block".to_string(), "0".to_string(), difficulty); Blockchain { blocks: vec![genesis_block], difficulty, } } pub fn add_block(&mut self, data: String) { // Метод для добавления нового блока в цепь let prev_block = self.blocks.last().unwrap(); if !prev_block.is_block_valid() { // Проверка целостности предыдущего блока println!("The previous block is invalid. It is not possible to add a new block."); return; } if !self.is_chain_valid() { // Дополнительная проверка валидности всей сети (иначе зачем добавлять блок в невалидную цепь?) println!("Blockchain is invalid. Aborting block addition."); return; } let new_block = Block::new( prev_block.index + 1, data, prev_block.hash.clone(), self.difficulty, ); self.blocks.push(new_block); println!( "Block {} successfully added", self.blocks.last().unwrap().index ); } pub fn is_chain_valid(&self) -> bool { // Метод для проверки валидности всей цепи for i in 1..self.blocks.len() { let prev = &self.blocks[i - 1]; let curr = &self.blocks[i]; if curr.previous_hash != prev.hash { println!( "Previous block hash mismatch. Block {} is invalid.", curr.index ); return false; } if !curr.is_block_valid() { println!("Block {} is invalid.", curr.index); return false; } } true } } // Методы для сериализации/десериализации блоков и всей цепочки impl Block { pub fn to_json(&self) -> Result<String, serde_json::Error> { serde_json::to_string_pretty(self) } pub fn from_json(json_data: &str) -> Result<Self, serde_json::Error> { serde_json::from_str(json_data) } } impl Blockchain { pub fn to_json(&self) -> Result<String, serde_json::Error> { serde_json::to_string_pretty(self) } pub fn from_json(json_data: &str) -> Result<Self, serde_json::Error> { serde_json::from_str(json_data) } }