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

4 阅读1分钟

引言

区块链技术自比特币诞生以来,已经走过了十多年的发展历程。尽管这项技术听起来高深莫测,但其核心原理并不复杂。今天,我将带领大家用 Rust 语言从零开始实现一个极简的区块链系统。通过这个实践项目,你不仅能深入理解区块链的工作原理,还能掌握 Rust 在系统编程中的实际应用。

区块链的核心概念

在开始编码之前,我们先简要回顾一下区块链的几个核心概念:

  1. 区块(Block):存储交易数据的基本单位
  2. 链(Chain):按时间顺序连接的区块序列
  3. 哈希(Hash):区块的唯一标识符
  4. 工作量证明(Proof of Work):保证区块链安全性的共识机制
  5. 分布式网络:多个节点共同维护区块链的状态

项目结构设计

首先,我们创建项目的基本结构:

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"

实现区块结构

让我们从最基本的区块开始。在 src/main.rs 中:

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

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

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

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

impl Block {
    pub fn new(
        index: u64,
        transactions: Vec<Transaction>,
        previous_hash: String,
    ) -> Self {
        let timestamp = Utc::now();
        let mut block = Self {
            index,
            timestamp,
            transactions,
            previous_hash,
            hash: String::new(),
            nonce: 0,
        };
        block.hash = block.calculate_hash();
        block
    }

    pub fn calculate_hash(&self) -> String {
        let data = format!(
            "{}{}{:?}{}{}",
            self.index,
            self.timestamp,
            self.transactions,
            self.previous_hash,
            self.nonce
        );
        
        let mut hasher = Sha256::new();
        hasher.update(data);
        let result = hasher.finalize();
        
        hex::encode(result)
    }

    pub fn mine_block(&mut self, difficulty: usize) {
        let prefix = "0".repeat(difficulty);
        
        while !self.hash.starts_with(&prefix) {
            self.nonce += 1;
            self.hash = self.calculate_hash();
        }
        
        println!("Block mined: {}", self.hash);
    }
}

impl fmt::Display for Block {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "Block #{} [Hash: {}, Previous: {}, Transactions: {}]",
            self.index,
            self.hash,
            self.previous_hash,
            self.transactions.len()
        )
    }
}

实现区块链结构

接下来,我们实现区块链的主体结构:

pub struct Blockchain {
    pub chain: Vec<Block>,
    pub pending_transactions: Vec<Transaction>,
    pub difficulty: usize,
    pub mining_reward: f64,
}

impl Blockchain {
    pub fn new() -> Self {
        let mut blockchain = Self {
            chain: Vec::new(),
            pending_transactions: Vec::new(),
            difficulty: 2,
            mining_reward: 100.0,
        };
        
        // 创建创世区块
        blockchain.create_genesis_block();
        blockchain
    }

    fn create_genesis_block(&mut self) {
        let genesis_block = Block::new(
            0,
            vec![Transaction::new(
                "0".to_string(),
                "genesis".to_string(),
                0.0,
            )],
            "0".to_string(),
        );
        
        self.chain.push(genesis_block);
    }

    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, mining_reward_address: String) {
        let mut block = Block::new(
            self.chain.len() as u64,
            self.pending_transactions.clone(),
            self.get_latest_block().hash.clone(),
        );
        
        block.mine_block(self.difficulty);
        
        self.chain.push(block);
        self.pending_transactions = vec![Transaction::new(
            "0".to_string(),
            mining_reward_address,
            self.mining_reward,
        )];
    }

    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 chain link 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
    }
}

实现 P2P 网络基础

为了让我们的区块链能够运行在分布式网络中,我们需要实现基本的 P2P 功能。创建一个新的文件 src/network.rs

use std::collections::HashSet;
use std::net::{TcpListener, TcpStream};
use std::io::{Read, Write};
use std::sync::{Arc, Mutex};
use std::thread;

use crate::{Blockchain, Transaction};

pub struct Node {
    pub blockchain: Arc<Mutex<Blockchain>>,
    pub peers: Arc<Mutex<HashSet<String>>>,
    pub address: String,
}

impl Node {
    pub fn new(address: String) -> Self {
        Self {
            blockchain: Arc::new(Mutex::new(Blockchain::new())),
            peers: Arc::new(Mutex::new(HashSet::new())),
            address: address.clone(),
        }
    }

    pub fn start_server(&self) {
        let listener = TcpListener::bind(&self.address).unwrap();
        let blockchain_clone = Arc::clone(&self.blockchain);
        let peers_clone = Arc::clone(&self.peers);
        
        thread::spawn(move || {
            for stream in listener.incoming() {
                match stream {
                    Ok(stream) => {
                        let blockchain = Arc::clone(&blockchain_clone);
                        let peers = Arc::clone(&peers_clone);
                        
                        thread::spawn(move || {
                            handle_connection(stream, blockchain, peers);
                        });
                    }
                    Err(e) => {
                        eprintln!("Failed to establish connection: {}", e);
                    }
                }
            }
        });
    }

    pub fn connect_to_peer(&mut self, address: &str) {
        let mut peers = self.peers.lock().unwrap();
        peers.insert(address.to_string());
        
        // 发送握手消息
        if let Ok(mut stream) = TcpStream::connect(address) {
            let message = format!("CONNECT {}", self.address);
            stream.write_all(message.as_bytes()).unwrap();
        }
    }

    pub fn broadcast_transaction(&self, transaction: &Transaction) {
        let peers = self.peers.lock().unwrap();
        let message = serde_json::to_string(transaction).unwrap();
        
        for peer in peers.iter() {
            if let Ok(mut stream) = TcpStream::connect(peer) {
                let msg = format!("TRANSACTION {}", message);
                stream.write_all(msg.as_bytes()).