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

4 阅读1分钟

区块链技术自比特币诞生以来,已经走过了十多年的发展历程。尽管这项技术听起来高深莫测,但其核心概念却出奇地简单。今天,我们将抛开复杂的分布式系统和加密经济学,专注于区块链最基础的数据结构,用 Rust 语言从头实现一个简化版的区块链。

理解区块链的核心:链式数据结构

区块链本质上是一个只能追加的链表,每个区块都包含前一个区块的哈希值,形成一条不可篡改的链。这种设计使得一旦数据被写入,修改任何一个区块都会导致后续所有区块的哈希值发生变化,从而立即被检测到。

让我们从定义区块结构开始:

use sha2::{Sha256, Digest};
use serde::{Serialize, Deserialize};
use chrono::{DateTime, Utc};

#[derive(Debug, Clone, Serialize, Deserialize)]
struct Block {
    index: u64,           // 区块在链中的位置
    timestamp: DateTime<Utc>, // 区块创建时间
    data: String,         // 区块存储的数据
    previous_hash: String, // 前一个区块的哈希
    hash: String,         // 当前区块的哈希
    nonce: u64,           // 工作量证明的随机数
}

计算区块哈希:区块链的指纹

每个区块的哈希值就像它的数字指纹,由区块的所有内容计算得出。任何微小的改动都会产生完全不同的哈希值。

impl Block {
    fn calculate_hash(&self) -> String {
        let input = format!(
            "{}{}{}{}{}",
            self.index,
            self.timestamp.to_rfc3339(),
            self.data,
            self.previous_hash,
            self.nonce
        );
        
        let mut hasher = Sha256::new();
        hasher.update(input.as_bytes());
        format!("{:x}", hasher.finalize())
    }
    
    fn new(index: u64, data: String, previous_hash: String) -> Self {
        let timestamp = Utc::now();
        let mut block = Block {
            index,
            timestamp,
            data,
            previous_hash,
            hash: String::new(),
            nonce: 0,
        };
        
        // 初始计算哈希
        block.hash = block.calculate_hash();
        block
    }
}

工作量证明:区块链的安全基石

工作量证明(Proof of Work)是区块链防止垃圾攻击的关键机制。它要求矿工通过不断尝试不同的随机数(nonce)来找到一个满足特定条件的哈希值。

impl Block {
    fn mine_block(&mut self, difficulty: usize) {
        // 定义难度目标:哈希值必须以指定数量的零开头
        let target = "0".repeat(difficulty);
        
        // 不断尝试不同的 nonce 值,直到找到满足条件的哈希
        while !self.hash.starts_with(&target) {
            self.nonce += 1;
            self.hash = self.calculate_hash();
        }
        
        println!("区块挖矿成功!Nonce: {}", self.nonce);
    }
    
    fn is_valid(&self, difficulty: usize) -> bool {
        // 检查哈希是否满足难度要求
        let target = "0".repeat(difficulty);
        if !self.hash.starts_with(&target) {
            return false;
        }
        
        // 检查哈希计算是否正确
        if self.hash != self.calculate_hash() {
            return false;
        }
        
        true
    }
}

构建区块链:连接区块形成链

现在我们可以创建区块链结构,它将管理所有的区块并确保链的完整性。

struct Blockchain {
    chain: Vec<Block>,
    difficulty: usize,
}

impl Blockchain {
    fn new(difficulty: usize) -> Self {
        let mut blockchain = Blockchain {
            chain: Vec::new(),
            difficulty,
        };
        
        // 创建创世区块
        blockchain.create_genesis_block();
        blockchain
    }
    
    fn create_genesis_block(&mut self) {
        let genesis_block = Block::new(
            0,
            "创世区块".to_string(),
            "0".to_string(),  // 创世区块没有前驱区块
        );
        
        // 挖矿创世区块
        let mut block = genesis_block;
        block.mine_block(self.difficulty);
        self.chain.push(block);
    }
    
    fn get_latest_block(&self) -> &Block {
        self.chain.last().unwrap()
    }
    
    fn add_block(&mut self, data: String) {
        let latest_block = self.get_latest_block();
        let mut new_block = Block::new(
            latest_block.index + 1,
            data,
            latest_block.hash.clone(),
        );
        
        // 挖矿新区块
        new_block.mine_block(self.difficulty);
        self.chain.push(new_block);
    }
    
    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.is_valid(self.difficulty) {
                println!("区块 {} 无效", current_block.index);
                return false;
            }
            
            // 检查区块是否正确地链接到前一个区块
            if current_block.previous_hash != previous_block.hash {
                println!("区块 {} 的前驱哈希不匹配", current_block.index);
                return false;
            }
        }
        
        true
    }
}

测试我们的区块链

让我们创建一个简单的测试来验证区块链的功能:

fn main() {
    println!("创建新的区块链...");
    let mut blockchain = Blockchain::new(4); // 难度为4个前导零
    
    println!("\n添加第一个区块...");
    blockchain.add_block("Alice 转账给 Bob 10 BTC".to_string());
    
    println!("\n添加第二个区块...");
    blockchain.add_block("Bob 转账给 Charlie 5 BTC".to_string());
    
    println!("\n添加第三个区块...");
    blockchain.add_block("Charlie 转账给 David 3 BTC".to_string());
    
    println!("\n区块链验证结果: {}", blockchain.is_chain_valid());
    
    println!("\n打印区块链内容:");
    for block in &blockchain.chain {
        println!("------------------------");
        println!("区块索引: {}", block.index);
        println!("时间戳: {}", block.timestamp);
        println!("数据: {}", block.data);
        println!("前驱哈希: {}", &block.previous_hash[0..16]);
        println!("当前哈希: {}", &block.hash[0..16]);
        println!("Nonce: {}", block.nonce);
    }
    
    // 尝试篡改数据
    println!("\n尝试篡改区块链数据...");
    blockchain.chain[1].data = "Alice 转账给 Bob 100 BTC".to_string();
    
    println!("篡改后区块链验证结果: {}", blockchain.is_chain_valid());
}

区块链的扩展可能性

我们实现的这个简单区块链虽然功能基础,但它包含了区块链最核心的概念。在此基础上,我们可以进行多种扩展:

1. 添加交易系统

#[derive(Debug, Clone, Serialize, Deserialize)]
struct Transaction {
    sender: String,
    receiver: String,
    amount: f64,
    timestamp: DateTime<Utc>,
}

impl Block {
    fn new_with_transactions(index: u64, transactions: Vec<Transaction>, previous_hash: String) -> Self {
        let data = serde_json::to_string(&transactions).unwrap();
        Block::new(index, data, previous_hash)
    }
}

2. 实现简单的P2P网络

use std::net::{TcpListener, TcpStream};
use std::io::{Read, Write};
use std::thread;

struct Node {
    blockchain: Blockchain,
    peers: Vec<String>,
}

impl Node {
    fn start_server(&self, port: u16) {
        let listener = TcpListener::bind(format!("127.0.0.1:{}", port)).unwrap();
        
        for stream in listener.incoming() {
            let mut stream = stream.unwrap();
            let mut buffer = [0; 1024];
            
            stream.read(&mut buffer).unwrap();
            // 处理网络消息
        }
    }
}

3. 添加默克尔树优化

fn calculate_merkle_root(transactions: &[Transaction]) -> String {
    if transactions.is_empty() {
        return String::new();
    }
    
    let mut hashes: Vec<String> = transactions
        .iter()
        .map(|tx| calculate_hash(tx))
        .collect();
    
    while hashes.len() > 1 {
        let mut new_hashes = Vec::new();
        
        for i in (0..hashes.len()).step_by(2) {
            let left = &hashes[i];
            let right = if i + 1 < hashes.len() {
                &hashes[i + 1]
            } else {
                &hashes[i]
            };
            
            let combined = format!("{}{}", left, right);
            new