从零到一:用 Rust 实现一个简单的区块链

0 阅读1分钟

引言

区块链技术自比特币诞生以来,已经走过了十多年的发展历程。虽然这项技术常常与加密货币联系在一起,但其底层原理——分布式账本、共识机制、密码学等——在金融、供应链、数字身份等领域都有着广泛的应用前景。

对于开发者来说,理解区块链最好的方式就是亲手实现一个简化版本。今天,我将带领大家使用 Rust 语言,从零开始构建一个简单的区块链系统。选择 Rust 是因为它的安全性、性能和并发特性特别适合构建区块链这类对安全性要求极高的系统。

一、区块链基础概念回顾

在开始编码之前,让我们先回顾几个核心概念:

  1. 区块(Block):区块链的基本组成单位,包含交易数据、时间戳、前一个区块的哈希等
  2. 哈希(Hash):将任意长度的数据映射为固定长度的字符串,具有单向性和抗碰撞性
  3. 工作量证明(Proof of Work):一种共识机制,要求节点完成一定的计算工作
  4. 默克尔树(Merkle Tree):高效验证数据完整性的数据结构

二、项目结构设计

首先创建我们的项目:

cargo new simple_blockchain
cd simple_blockchain

Cargo.toml 中添加依赖:

[package]
name = "simple_blockchain"
version = "0.1.0"
edition = "2021"

[dependencies]
chrono = "0.4"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
sha2 = "0.10"
hex = "0.4"

三、核心数据结构实现

3.1 交易结构

// src/transaction.rs
use serde::{Deserialize, Serialize};
use std::fmt;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Transaction {
    pub sender: String,
    pub receiver: String,
    pub amount: f64,
    pub timestamp: i64,
}

impl Transaction {
    pub fn new(sender: String, receiver: String, amount: f64) -> Self {
        Self {
            sender,
            receiver,
            amount,
            timestamp: chrono::Utc::now().timestamp(),
        }
    }
}

impl fmt::Display for Transaction {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "Transaction {{ sender: {}, receiver: {}, amount: {}, timestamp: {} }}",
            self.sender, self.receiver, self.amount, self.timestamp
        )
    }
}

3.2 区块结构

// src/block.rs
use crate::transaction::Transaction;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use std::fmt;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Block {
    pub index: u64,
    pub timestamp: i64,
    pub transactions: Vec<Transaction>,
    pub previous_hash: String,
    pub hash: String,
    pub nonce: u64,
    pub difficulty: u64,
}

impl Block {
    pub fn new(
        index: u64,
        transactions: Vec<Transaction>,
        previous_hash: String,
        difficulty: u64,
    ) -> Self {
        let timestamp = Utc::now().timestamp();
        let mut block = Self {
            index,
            timestamp,
            transactions,
            previous_hash,
            hash: String::new(),
            nonce: 0,
            difficulty,
        };
        
        block.hash = block.calculate_hash();
        block
    }
    
    pub fn calculate_hash(&self) -> String {
        let mut hasher = Sha256::new();
        let data = format!(
            "{}{}{:?}{}{}",
            self.index,
            self.timestamp,
            self.transactions,
            self.previous_hash,
            self.nonce
        );
        hasher.update(data);
        let result = hasher.finalize();
        hex::encode(result)
    }
    
    pub fn mine_block(&mut self) {
        println!("Mining block {}...", self.index);
        
        while !self.is_hash_valid() {
            self.nonce += 1;
            self.hash = self.calculate_hash();
        }
        
        println!("Block mined: {}", self.hash);
    }
    
    fn is_hash_valid(&self) -> bool {
        let target = "0".repeat(self.difficulty as usize);
        &self.hash[0..self.difficulty as usize] == target
    }
}

impl fmt::Display for Block {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let datetime: DateTime<Utc> = DateTime::from_timestamp(self.timestamp, 0).unwrap();
        
        write!(
            f,
            "Block #{} [\n  Hash: {}\n  Previous Hash: {}\n  Timestamp: {}\n  Transactions: {}\n  Nonce: {}\n  Difficulty: {}\n]",
            self.index,
            self.hash,
            self.previous_hash,
            datetime.format("%Y-%m-%d %H:%M:%S"),
            self.transactions.len(),
            self.nonce,
            self.difficulty
        )
    }
}

3.3 区块链结构

// src/blockchain.rs
use crate::block::Block;
use crate::transaction::Transaction;
use std::fmt;

pub struct Blockchain {
    pub chain: Vec<Block>,
    pub difficulty: u64,
    pub pending_transactions: Vec<Transaction>,
}

impl Blockchain {
    pub fn new(difficulty: u64) -> Self {
        let mut blockchain = Self {
            chain: Vec::new(),
            difficulty,
            pending_transactions: Vec::new(),
        };
        
        // 创建创世区块
        blockchain.create_genesis_block();
        blockchain
    }
    
    fn create_genesis_block(&mut self) {
        let genesis_block = Block::new(
            0,
            vec![Transaction::new(
                "0".to_string(),
                "0".to_string(),
                0.0,
            )],
            "0".to_string(),
            self.difficulty,
        );
        
        self.chain.push(genesis_block);
        println!("Genesis block created");
    }
    
    pub fn get_latest_block(&self) -> &Block {
        self.chain.last().unwrap()
    }
    
    pub fn add_transaction(&mut self, transaction: Transaction) {
        self.pending_transactions.push(transaction);
    }
    
    pub fn mine_pending_transactions(&mut self, miner_address: String) {
        if self.pending_transactions.is_empty() {
            println!("No transactions to mine");
            return;
        }
        
        // 添加矿工奖励交易
        let reward = Transaction::new(
            "system".to_string(),
            miner_address,
            1.0, // 挖矿奖励
        );
        
        let mut transactions = std::mem::take(&mut self.pending_transactions);
        transactions.push(reward);
        
        let mut new_block = Block::new(
            self.chain.len() as u64,
            transactions,
            self.get_latest_block().hash.clone(),
            self.difficulty,
        );
        
        new_block.mine_block();
        self.chain.push(new_block);
        println!("Block successfully mined and added to chain");
    }
    
    pub fn is_chain_valid(&self) -> bool {
        for i in 1..self.chain.len() {
            let current_block = &self.chain[i];
            let previous_block = &self.chain[i - 1];
            
            // 检查当前区块的哈希是否正确
            if current_block.hash != current_block.calculate_hash() {
                println!("Invalid hash at block {}", i);
                return false;
            }
            
            // 检查是否链接到前一个区块
            if current_block.previous_hash != previous_block.hash {
                println!("Invalid previous hash at block {}", i);
                return false;
            }
            
            // 检查工作量证明
            if !current_block.is_hash_valid() {
                println!("Invalid proof of work at block {}", i);
                return false;
            }
        }
        
        true
    }
    
    pub fn get_balance(&self, address: &str) -> f64 {
        let mut balance = 0.0;
        
        for block in &self.chain {
            for transaction in &block.transactions {
                if transaction.sender == address {
                    balance -= transaction.amount;
                }
                if transaction.receiver == address {
                    balance += transaction.amount;
                }
            }
        }
        
        balance
    }
}

impl fmt::Display for Blockchain {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        writeln!(f, "Blockchain ({} blocks):", self.chain.len())?;
        writeln!(f, "Difficulty: {}", self.difficulty)?;
        writeln!(f, "Pending transactions: {}", self.pending_transactions.len())?;
        
        for (i, block) in self.