HiHuo
首页
博客
手册
工具
关于
首页
博客
手册
工具
关于
  • Web3 完整技术体系

    • Web3 完整技术体系
    • 区块链基础与密码学
    • 第一章:比特币原理与实现
    • 第二章:以太坊架构与核心概念
    • Solidity智能合约开发基础
    • 04-Solidity进阶与安全
    • 05-ERC标准详解
    • 06-DeFi核心协议-去中心化交易所
    • 07-DeFi核心协议-借贷协议
    • 08-DeFi核心协议-稳定币
    • NFT与元宇宙
    • Layer2扩容方案
    • 跨链技术
    • Web3前端开发
    • 链下数据与预言机
    • 智能合约测试与部署
    • MEV与交易优化
    • DAO治理
    • 项目实战:完整DeFi借贷协议

第一章:比特币原理与实现

1.1 比特币概述

比特币(Bitcoin)是第一个成功的去中心化数字货币系统,由中本聪(Satoshi Nakamoto)在2008年发布的白皮书《Bitcoin: A Peer-to-Peer Electronic Cash System》中提出。比特币解决了数字货币领域长期存在的"双重支付"问题,通过巧妙结合密码学、分布式系统和博弈论等技术,创建了一个无需信任中介的电子现金系统。

1.1.1 比特币的核心特性

比特币系统具有以下核心特性:

  1. 去中心化:没有中央权威机构控制网络,所有节点地位平等
  2. 防篡改:通过工作量证明和链式结构,历史交易几乎不可篡改
  3. 透明性:所有交易记录公开可查,任何人都可以验证
  4. 有限供应:总量恒定为2100万枚,通过减半机制控制发行速度
  5. 匿名性:用户通过公钥地址进行交易,不直接关联真实身份

1.1.2 比特币网络架构

比特币网络采用点对点(P2P)架构,主要包含以下组件:

  • 全节点(Full Node):存储完整区块链数据,验证所有交易和区块
  • 轻节点(Light Node):只存储区块头,通过SPV验证交易
  • 矿工节点(Miner Node):参与挖矿,竞争记账权
  • 钱包(Wallet):管理私钥,创建和签名交易

1.2 UTXO模型详解

UTXO(Unspent Transaction Output,未花费的交易输出)是比特币的核心数据模型,与传统的账户余额模型有本质区别。

1.2.1 UTXO基本概念

在UTXO模型中,比特币的余额不是通过账户记录的,而是由多个UTXO组成。每个UTXO代表一定数量的比特币,具有以下特征:

  • 每个UTXO是原子性的,要么完全花费,要么完全不花费
  • 一次交易可以消费多个UTXO作为输入
  • 一次交易可以产生多个新的UTXO作为输出
  • UTXO一旦被花费,就从UTXO集合中移除

UTXO的优势:

  1. 并行验证:不同的UTXO可以独立验证,提高并发性能
  2. 隐私保护:每次交易可以使用新地址,增强匿名性
  3. 简化验证:只需验证输入UTXO是否存在且未被花费
  4. 防止双花:通过UTXO集合快速检测双重支付

1.2.2 交易结构

比特币交易包含以下核心字段:

Transaction {
    Version: 版本号
    Inputs: [{
        PrevTxHash: 引用的前一笔交易哈希
        OutputIndex: 引用的输出索引
        ScriptSig: 解锁脚本(签名)
        Sequence: 序列号
    }]
    Outputs: [{
        Value: 输出金额(聪为单位)
        ScriptPubKey: 锁定脚本(收款地址)
    }]
    LockTime: 锁定时间
}

交易示例:

假设Alice有一个10 BTC的UTXO,想要给Bob转账6 BTC:

输入:
- UTXO_1: 10 BTC (来自交易Hash_X的输出0)

输出:
- UTXO_2: 6 BTC (Bob的地址)
- UTXO_3: 3.99 BTC (Alice的找零地址)
- 0.01 BTC (矿工费,隐含在差额中)

1.2.3 脚本系统

比特币使用基于栈的脚本语言来实现灵活的支付条件。脚本分为两部分:

锁定脚本(ScriptPubKey):定义花费条件

OP_DUP OP_HASH160 <PubKeyHash> OP_EQUALVERIFY OP_CHECKSIG

解锁脚本(ScriptSig):提供满足条件的数据

<Signature> <PubKey>

验证过程:

  1. 将解锁脚本和锁定脚本拼接
  2. 从左到右依次执行操作码
  3. 如果最终栈顶为真,则验证通过
执行流程:
1. <Signature> <PubKey> OP_DUP OP_HASH160 <PubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
2. 压入签名和公钥
3. OP_DUP复制公钥
4. OP_HASH160计算公钥哈希
5. 压入期望的公钥哈希
6. OP_EQUALVERIFY验证哈希是否相等
7. OP_CHECKSIG验证签名

1.3 区块结构与链式存储

1.3.1 区块头结构

区块头(Block Header)包含80字节的关键信息:

BlockHeader {
    Version: 4字节,版本号
    PrevBlockHash: 32字节,前一个区块哈希
    MerkleRoot: 32字节,交易的Merkle树根
    Timestamp: 4字节,时间戳
    Bits: 4字节,难度目标
    Nonce: 4字节,工作量证明随机数
}

1.3.2 Merkle树

Merkle树是一种哈希二叉树,用于高效验证交易是否包含在区块中。

构建过程:

  1. 对每笔交易计算哈希(叶子节点)
  2. 两两配对计算父节点哈希:Hash(Hash_A + Hash_B)
  3. 重复步骤2,直到得到根哈希(Merkle Root)
         Root Hash
        /          \
    Hash_AB      Hash_CD
    /    \       /    \
Hash_A Hash_B Hash_C Hash_D
  |      |      |      |
 Tx_A   Tx_B   Tx_C   Tx_D

Merkle证明(SPV验证):

轻节点只需下载区块头,通过Merkle路径即可验证交易:

验证Tx_B在区块中:
1. 提供路径:Hash_A, Hash_CD
2. 计算:Hash_AB = Hash(Hash_A + Hash_B)
3. 计算:Root = Hash(Hash_AB + Hash_CD)
4. 对比Root与区块头中的MerkleRoot

时间复杂度:O(log n),空间复杂度:O(log n)

1.3.3 区块链式结构

每个区块通过PrevBlockHash字段指向前一个区块,形成链式结构:

Genesis Block → Block 1 → Block 2 → ... → Block N
    Hash_0   →  Hash_1  →  Hash_2  → ... → Hash_N

链式结构的特性:

  1. 不可篡改性:修改历史区块会导致后续所有区块哈希失效
  2. 唯一性:最长链代表网络共识
  3. 追溯性:可以从任意区块追溯到创世区块

1.4 工作量证明(Proof of Work)

1.4.1 PoW原理

工作量证明是比特币共识机制的核心,要求矿工找到一个Nonce值,使得区块哈希满足难度目标。

目标条件:

SHA256(SHA256(BlockHeader)) < Target

Target是一个256位的数,由Bits字段编码。区块哈希必须小于这个目标值,即前导零的数量要达到要求。

难度计算:

Difficulty = 最大目标值 / 当前目标值

最大目标值(难度1):
0x00000000FFFF0000000000000000000000000000000000000000000000000000

当前比特币网络难度通常在数十万亿以上,意味着需要进行大量哈希计算才能找到有效区块。

1.4.2 难度调整机制

比特币网络每2016个区块(约两周)自动调整一次难度,目标是保持平均出块时间为10分钟。

调整公式:

新难度 = 旧难度 × (实际用时 / 20160分钟)

限制条件:
- 单次调整幅度不超过4倍
- 最小难度为1

这种动态调整确保了无论算力如何变化,出块速度都能保持稳定。

1.4.3 挖矿过程

挖矿是寻找有效Nonce的过程:

1. 收集待确认交易,构建交易列表
2. 创建Coinbase交易(区块奖励)
3. 构建Merkle树,计算MerkleRoot
4. 填充区块头其他字段
5. 循环尝试不同的Nonce值:
   a. 计算区块哈希
   b. 检查是否满足难度目标
   c. 如果满足,广播区块;否则增加Nonce继续
6. 如果遍历完所有Nonce仍未找到,修改Coinbase交易或时间戳

挖矿难度示例:

假设当前难度要求前导20个零(十六进制5个零):

有效哈希:0x00000a1b2c3d4e5f...
无效哈希:0x00001a1b2c3d4e5f...

平均需要尝试2^20 ≈ 100万次才能找到一个有效哈希。

1.4.4 区块奖励与减半

矿工成功挖出区块后获得两部分收益:

  1. 区块奖励(Coinbase):新发行的比特币
  2. 交易手续费:区块内所有交易的手续费总和

减半机制:

区块高度          区块奖励
0 - 209,999       50 BTC
210,000 - 419,999 25 BTC
420,000 - 629,999 12.5 BTC
630,000 - 839,999 6.25 BTC
840,000 - ...     3.125 BTC
...

每21万个区块(约4年)奖励减半,预计在2140年左右,所有比特币将被挖完,之后矿工仅依靠交易手续费获得收益。

总供应量计算:

总量 = 50×210,000 + 25×210,000 + 12.5×210,000 + ...
     = 210,000 × (50 + 25 + 12.5 + 6.25 + ...)
     = 210,000 × 100
     = 21,000,000 BTC

1.5 共识机制与分叉处理

1.5.1 最长链原则

当网络中出现多条竞争链时,节点遵循"最长链"(累计工作量最大的链)原则:

     Block A1 → Block A2 → Block A3
    /
Block 0
    \
     Block B1 → Block B2

如果链A的累计难度更高,节点会选择链A作为主链,链B的区块成为孤块(Orphan Block)。

1.5.2 临时分叉

当两个矿工几乎同时找到有效区块时,会产生临时分叉:

时刻T1: ... → Block N → Block X (矿工A广播)
                      → Block Y (矿工B广播)

时刻T2: ... → Block N → Block X → Block X' (链X更长)
                      → Block Y (成为孤块)

网络会自动收敛到最长链,孤块中的交易会重新回到交易池等待打包。

1.5.3 硬分叉与软分叉

软分叉(Soft Fork):

  • 新规则是旧规则的子集
  • 旧节点仍可验证新区块
  • 向后兼容,不强制升级
  • 例如:SegWit、P2SH

硬分叉(Hard Fork):

  • 新规则与旧规则不兼容
  • 旧节点无法验证新区块
  • 需要所有节点升级
  • 可能导致链分裂(如Bitcoin Cash)

1.6 比特币网络协议

1.6.1 P2P网络通信

比特币节点通过TCP协议进行通信,默认端口8333。主要消息类型:

握手过程:

节点A → 节点B: version (包含版本号、时间戳、服务类型)
节点B → 节点A: version
节点B → 节点A: verack (确认)
节点A → 节点B: verack

消息类型:

  • version/verack:版本协商
  • addr:节点地址信息
  • inv:库存声明(通知有新的区块或交易)
  • getdata:请求数据
  • block:区块数据
  • tx:交易数据
  • ping/pong:心跳保活

1.6.2 区块同步

新节点加入网络后,需要同步完整区块链:

1. 发送getblocks消息,包含本地最高区块哈希
2. 对方返回inv消息,列出后续区块哈希
3. 发送getdata消息,请求具体区块
4. 接收block消息,验证并存储
5. 重复步骤1-4,直到同步完成

快速同步优化:

  • Headers-First:先同步所有区块头,再下载区块体
  • 并行下载:从多个节点同时下载不同区块
  • Checkpoint:硬编码已知安全的区块哈希,跳过早期验证

1.6.3 交易传播

新交易的传播过程:

1. 钱包创建并签名交易
2. 发送至连接的节点
3. 节点验证交易(签名、UTXO、手续费)
4. 验证通过后,加入本地内存池(Mempool)
5. 向其他节点广播inv消息
6. 其他节点请求并验证,继续传播
7. 矿工从Mempool选择交易打包进区块

交易手续费估算:

手续费率 = 总手续费 / 交易大小(字节)

矿工优先打包高手续费率的交易
用户可根据网络拥堵情况调整手续费

1.7 密码学基础

1.7.1 SHA-256哈希算法

比特币使用SHA-256作为主要哈希函数,具有以下特性:

  • 确定性:相同输入总是产生相同输出
  • 快速计算:计算哈希速度快
  • 抗碰撞:几乎不可能找到两个输入产生相同哈希
  • 单向性:无法从哈希反推原始数据
  • 雪崩效应:输入微小变化导致哈希完全不同

应用场景:

  • 区块哈希计算
  • 交易哈希计算
  • Merkle树构建
  • 地址生成(RIPEMD-160(SHA-256(PubKey)))

1.7.2 椭圆曲线密码学(ECC)

比特币使用secp256k1椭圆曲线进行数字签名。

密钥生成:

1. 生成私钥:随机256位数字 (k)
2. 计算公钥:P = k × G (G为基点)
3. 私钥范围:1 到 n-1 (n为曲线阶数)

数字签名(ECDSA):

签名过程:
1. 计算消息哈希:z = Hash(message)
2. 生成随机数:k
3. 计算点:(x, y) = k × G
4. 计算 r = x mod n
5. 计算 s = k^(-1) × (z + r × private_key) mod n
6. 签名为 (r, s)

验证过程:
1. 计算消息哈希:z = Hash(message)
2. 计算 u1 = z × s^(-1) mod n
3. 计算 u2 = r × s^(-1) mod n
4. 计算点:(x, y) = u1 × G + u2 × Public_Key
5. 验证 r == x mod n

1.7.3 地址生成

比特币地址由公钥通过多步哈希和编码生成:

1. 计算公钥哈希:
   PubKeyHash = RIPEMD-160(SHA-256(PublicKey))

2. 添加版本前缀:
   VersionedHash = 0x00 + PubKeyHash (主网)

3. 计算校验和:
   Checksum = SHA-256(SHA-256(VersionedHash))[0:4]

4. 拼接并Base58编码:
   Address = Base58(VersionedHash + Checksum)

地址类型:

  • P2PKH (Pay-to-PubKey-Hash):1开头,传统地址
  • P2SH (Pay-to-Script-Hash):3开头,多签地址
  • Bech32 (SegWit):bc1开头,原生隔离见证地址

1.8 Go语言实现简化版比特币

下面使用Go语言实现一个简化的比特币系统,包含区块链、交易、挖矿等核心功能。

1.8.1 基础数据结构

package main

import (
    "bytes"
    "crypto/sha256"
    "encoding/gob"
    "encoding/hex"
    "fmt"
    "log"
    "math"
    "math/big"
    "time"
)

// 区块结构
type Block struct {
    Timestamp     int64          // 时间戳
    Transactions  []*Transaction // 交易列表
    PrevBlockHash []byte         // 前一个区块哈希
    Hash          []byte         // 当前区块哈希
    Nonce         int            // 工作量证明随机数
    Height        int            // 区块高度
}

// 区块链结构
type Blockchain struct {
    tip []byte   // 最新区块的哈希
    db  *DB      // 数据库接口
}

// 交易输入
type TXInput struct {
    Txid      []byte // 引用的交易ID
    Vout      int    // 引用的输出索引
    Signature []byte // 签名
    PubKey    []byte // 公钥
}

// 交易输出
type TXOutput struct {
    Value      int    // 金额(聪)
    PubKeyHash []byte // 公钥哈希
}

// 交易
type Transaction struct {
    ID   []byte     // 交易ID
    Vin  []TXInput  // 输入列表
    Vout []TXOutput // 输出列表
}

// UTXO集合
type UTXOSet struct {
    Blockchain *Blockchain
}

// 常量定义
const (
    targetBits       = 16                // 挖矿难度(前导零的位数)
    maxNonce         = math.MaxInt64     // 最大Nonce值
    blockReward      = 50                // 区块奖励(BTC)
    version          = byte(0x00)        // 地址版本
    addressChecksumLen = 4               // 地址校验和长度
)

1.8.2 工作量证明实现

// 工作量证明结构
type ProofOfWork struct {
    block  *Block
    target *big.Int // 难度目标
}

// 创建工作量证明
func NewProofOfWork(b *Block) *ProofOfWork {
    target := big.NewInt(1)
    target.Lsh(target, uint(256-targetBits)) // 左移,设置难度

    pow := &ProofOfWork{b, target}
    return pow
}

// 准备数据进行哈希
func (pow *ProofOfWork) prepareData(nonce int) []byte {
    data := bytes.Join(
        [][]byte{
            pow.block.PrevBlockHash,
            pow.block.HashTransactions(),
            IntToHex(pow.block.Timestamp),
            IntToHex(int64(targetBits)),
            IntToHex(int64(nonce)),
        },
        []byte{},
    )
    return data
}

// 执行工作量证明(挖矿)
func (pow *ProofOfWork) Run() (int, []byte) {
    var hashInt big.Int
    var hash [32]byte
    nonce := 0

    fmt.Printf("Mining a new block")
    for nonce < maxNonce {
        data := pow.prepareData(nonce)
        hash = sha256.Sum256(data)

        if math.Remainder(float64(nonce), 100000) == 0 {
            fmt.Printf("\r%x", hash)
        }

        hashInt.SetBytes(hash[:])

        // 检查哈希是否小于目标值
        if hashInt.Cmp(pow.target) == -1 {
            fmt.Printf("\r%x\n", hash)
            break
        } else {
            nonce++
        }
    }
    fmt.Print("\n\n")

    return nonce, hash[:]
}

// 验证工作量证明
func (pow *ProofOfWork) Validate() bool {
    var hashInt big.Int

    data := pow.prepareData(pow.block.Nonce)
    hash := sha256.Sum256(data)
    hashInt.SetBytes(hash[:])

    isValid := hashInt.Cmp(pow.target) == -1

    return isValid
}

// 计算区块内所有交易的哈希(Merkle Root)
func (b *Block) HashTransactions() []byte {
    var transactions [][]byte

    for _, tx := range b.Transactions {
        transactions = append(transactions, tx.Serialize())
    }
    mTree := NewMerkleTree(transactions)

    return mTree.RootNode.Data
}

1.8.3 Merkle树实现

// Merkle树节点
type MerkleNode struct {
    Left  *MerkleNode
    Right *MerkleNode
    Data  []byte
}

// Merkle树
type MerkleTree struct {
    RootNode *MerkleNode
}

// 创建Merkle节点
func NewMerkleNode(left, right *MerkleNode, data []byte) *MerkleNode {
    mNode := MerkleNode{}

    if left == nil && right == nil {
        // 叶子节点
        hash := sha256.Sum256(data)
        mNode.Data = hash[:]
    } else {
        // 中间节点
        prevHashes := append(left.Data, right.Data...)
        hash := sha256.Sum256(prevHashes)
        mNode.Data = hash[:]
    }

    mNode.Left = left
    mNode.Right = right

    return &mNode
}

// 创建Merkle树
func NewMerkleTree(data [][]byte) *MerkleTree {
    var nodes []MerkleNode

    // 如果交易数量为奇数,复制最后一个
    if len(data)%2 != 0 {
        data = append(data, data[len(data)-1])
    }

    // 创建叶子节点
    for _, datum := range data {
        node := NewMerkleNode(nil, nil, datum)
        nodes = append(nodes, *node)
    }

    // 逐层构建树
    for len(nodes) > 1 {
        var newLevel []MerkleNode

        // 如果当前层节点数为奇数,复制最后一个
        if len(nodes)%2 != 0 {
            nodes = append(nodes, nodes[len(nodes)-1])
        }

        for j := 0; j < len(nodes); j += 2 {
            node := NewMerkleNode(&nodes[j], &nodes[j+1], nil)
            newLevel = append(newLevel, *node)
        }

        nodes = newLevel
    }

    mTree := MerkleTree{&nodes[0]}

    return &mTree
}

1.8.4 交易实现

// 设置交易ID
func (tx *Transaction) Hash() []byte {
    var hash [32]byte

    txCopy := *tx
    txCopy.ID = []byte{}

    hash = sha256.Sum256(txCopy.Serialize())

    return hash[:]
}

// 序列化交易
func (tx Transaction) Serialize() []byte {
    var encoded bytes.Buffer

    enc := gob.NewEncoder(&encoded)
    err := enc.Encode(tx)
    if err != nil {
        log.Panic(err)
    }

    return encoded.Bytes()
}

// 创建Coinbase交易(挖矿奖励)
func NewCoinbaseTX(to, data string) *Transaction {
    if data == "" {
        data = fmt.Sprintf("Reward to '%s'", to)
    }

    txin := TXInput{[]byte{}, -1, nil, []byte(data)}
    txout := NewTXOutput(blockReward*100000000, to) // 转换为聪
    tx := Transaction{nil, []TXInput{txin}, []TXOutput{*txout}}
    tx.ID = tx.Hash()

    return &tx
}

// 创建UTXO交易
func NewUTXOTransaction(wallet *Wallet, to string, amount int, UTXOSet *UTXOSet) *Transaction {
    var inputs []TXInput
    var outputs []TXOutput

    pubKeyHash := HashPubKey(wallet.PublicKey)
    acc, validOutputs := UTXOSet.FindSpendableOutputs(pubKeyHash, amount)

    if acc < amount {
        log.Panic("ERROR: Not enough funds")
    }

    // 构建输入列表
    for txid, outs := range validOutputs {
        txID, err := hex.DecodeString(txid)
        if err != nil {
            log.Panic(err)
        }

        for _, out := range outs {
            input := TXInput{txID, out, nil, wallet.PublicKey}
            inputs = append(inputs, input)
        }
    }

    // 构建输出列表
    from := fmt.Sprintf("%s", wallet.GetAddress())
    outputs = append(outputs, *NewTXOutput(amount, to))
    if acc > amount {
        // 找零
        outputs = append(outputs, *NewTXOutput(acc-amount, from))
    }

    tx := Transaction{nil, inputs, outputs}
    tx.ID = tx.Hash()
    UTXOSet.Blockchain.SignTransaction(&tx, wallet.PrivateKey)

    return &tx
}

// 检查是否为Coinbase交易
func (tx Transaction) IsCoinbase() bool {
    return len(tx.Vin) == 1 && len(tx.Vin[0].Txid) == 0 && tx.Vin[0].Vout == -1
}

// 创建交易输出
func NewTXOutput(value int, address string) *TXOutput {
    txo := &TXOutput{value, nil}
    txo.Lock([]byte(address))

    return txo
}

// 锁定输出到地址
func (out *TXOutput) Lock(address []byte) {
    pubKeyHash := Base58Decode(address)
    pubKeyHash = pubKeyHash[1 : len(pubKeyHash)-addressChecksumLen]
    out.PubKeyHash = pubKeyHash
}

// 检查输出是否被指定公钥哈希锁定
func (out *TXOutput) IsLockedWithKey(pubKeyHash []byte) bool {
    return bytes.Compare(out.PubKeyHash, pubKeyHash) == 0
}

// 检查输入是否使用了指定公钥
func (in *TXInput) UsesKey(pubKeyHash []byte) bool {
    lockingHash := HashPubKey(in.PubKey)
    return bytes.Compare(lockingHash, pubKeyHash) == 0
}

1.8.5 区块链核心实现

// 创建区块
func NewBlock(transactions []*Transaction, prevBlockHash []byte, height int) *Block {
    block := &Block{
        Timestamp:     time.Now().Unix(),
        Transactions:  transactions,
        PrevBlockHash: prevBlockHash,
        Hash:          []byte{},
        Nonce:         0,
        Height:        height,
    }

    // 执行工作量证明
    pow := NewProofOfWork(block)
    nonce, hash := pow.Run()

    block.Hash = hash[:]
    block.Nonce = nonce

    return block
}

// 创建创世区块
func NewGenesisBlock(coinbase *Transaction) *Block {
    return NewBlock([]*Transaction{coinbase}, []byte{}, 0)
}

// 创建区块链
func CreateBlockchain(address, nodeID string) *Blockchain {
    dbFile := fmt.Sprintf("blockchain_%s.db", nodeID)
    if dbExists(dbFile) {
        fmt.Println("Blockchain already exists.")
        os.Exit(1)
    }

    var tip []byte

    cbtx := NewCoinbaseTX(address, "Genesis Block")
    genesis := NewGenesisBlock(cbtx)

    db := openDB(dbFile)
    err := db.Update(func(txn *Txn) error {
        // 存储区块
        err := txn.Set(genesis.Hash, genesis.Serialize())
        if err != nil {
            return err
        }

        // 存储最新区块哈希
        err = txn.Set([]byte("l"), genesis.Hash)
        if err != nil {
            return err
        }
        tip = genesis.Hash

        return nil
    })

    if err != nil {
        log.Panic(err)
    }

    bc := Blockchain{tip, db}

    return &bc
}

// 添加区块到区块链
func (bc *Blockchain) MineBlock(transactions []*Transaction) *Block {
    var lastHash []byte
    var lastHeight int

    // 验证所有交易
    for _, tx := range transactions {
        if bc.VerifyTransaction(tx) != true {
            log.Panic("ERROR: Invalid transaction")
        }
    }

    // 获取最新区块信息
    err := bc.db.View(func(txn *Txn) error {
        lastHash = txn.Get([]byte("l"))
        blockData := txn.Get(lastHash)
        block := DeserializeBlock(blockData)
        lastHeight = block.Height
        return nil
    })

    if err != nil {
        log.Panic(err)
    }

    // 创建新区块
    newBlock := NewBlock(transactions, lastHash, lastHeight+1)

    // 存储新区块
    err = bc.db.Update(func(txn *Txn) error {
        err := txn.Set(newBlock.Hash, newBlock.Serialize())
        if err != nil {
            return err
        }

        err = txn.Set([]byte("l"), newBlock.Hash)
        if err != nil {
            return err
        }

        bc.tip = newBlock.Hash

        return nil
    })

    if err != nil {
        log.Panic(err)
    }

    return newBlock
}

// 序列化区块
func (b *Block) Serialize() []byte {
    var result bytes.Buffer
    encoder := gob.NewEncoder(&result)

    err := encoder.Encode(b)
    if err != nil {
        log.Panic(err)
    }

    return result.Bytes()
}

// 反序列化区块
func DeserializeBlock(d []byte) *Block {
    var block Block

    decoder := gob.NewDecoder(bytes.NewReader(d))
    err := decoder.Decode(&block)
    if err != nil {
        log.Panic(err)
    }

    return &block
}

1.8.6 UTXO集合管理

// UTXO集合中的交易输出
type TXOutputs struct {
    Outputs []TXOutput
}

// 查找可花费的输出
func (u UTXOSet) FindSpendableOutputs(pubkeyHash []byte, amount int) (int, map[string][]int) {
    unspentOutputs := make(map[string][]int)
    accumulated := 0
    db := u.Blockchain.db

    err := db.View(func(txn *Txn) error {
        cursor := txn.NewCursor()

        for k, v := cursor.Seek([]byte("utxo-")); bytes.HasPrefix(k, []byte("utxo-")); k, v = cursor.Next() {
            txID := hex.EncodeToString(k[5:])
            outs := DeserializeOutputs(v)

            for outIdx, out := range outs.Outputs {
                if out.IsLockedWithKey(pubkeyHash) && accumulated < amount {
                    accumulated += out.Value
                    unspentOutputs[txID] = append(unspentOutputs[txID], outIdx)
                }
            }
        }

        return nil
    })

    if err != nil {
        log.Panic(err)
    }

    return accumulated, unspentOutputs
}

// 查找指定地址的UTXO
func (u UTXOSet) FindUTXO(pubKeyHash []byte) []TXOutput {
    var UTXOs []TXOutput
    db := u.Blockchain.db

    err := db.View(func(txn *Txn) error {
        cursor := txn.NewCursor()

        for k, v := cursor.Seek([]byte("utxo-")); bytes.HasPrefix(k, []byte("utxo-")); k, v = cursor.Next() {
            outs := DeserializeOutputs(v)

            for _, out := range outs.Outputs {
                if out.IsLockedWithKey(pubKeyHash) {
                    UTXOs = append(UTXOs, out)
                }
            }
        }

        return nil
    })

    if err != nil {
        log.Panic(err)
    }

    return UTXOs
}

// 重建UTXO集合
func (u UTXOSet) Reindex() {
    db := u.Blockchain.db
    bucketName := []byte("utxo-")

    // 删除旧的UTXO集合
    err := db.Update(func(txn *Txn) error {
        cursor := txn.NewCursor()
        for k, _ := cursor.Seek(bucketName); bytes.HasPrefix(k, bucketName); k, _ = cursor.Next() {
            err := txn.Delete(k)
            if err != nil {
                return err
            }
        }
        return nil
    })

    if err != nil {
        log.Panic(err)
    }

    // 查找所有未花费输出
    UTXO := u.Blockchain.FindUTXO()

    // 存储新的UTXO集合
    err = db.Update(func(txn *Txn) error {
        for txID, outs := range UTXO {
            key := append(bucketName, []byte(txID)...)
            err := txn.Set(key, outs.Serialize())
            if err != nil {
                return err
            }
        }

        return nil
    })

    if err != nil {
        log.Panic(err)
    }
}

// 更新UTXO集合
func (u UTXOSet) Update(block *Block) {
    db := u.Blockchain.db

    err := db.Update(func(txn *Txn) error {
        for _, tx := range block.Transactions {
            if tx.IsCoinbase() == false {
                // 删除已花费的输出
                for _, vin := range tx.Vin {
                    updatedOuts := TXOutputs{}
                    key := append([]byte("utxo-"), vin.Txid...)
                    outsBytes := txn.Get(key)
                    outs := DeserializeOutputs(outsBytes)

                    for outIdx, out := range outs.Outputs {
                        if outIdx != vin.Vout {
                            updatedOuts.Outputs = append(updatedOuts.Outputs, out)
                        }
                    }

                    if len(updatedOuts.Outputs) == 0 {
                        err := txn.Delete(key)
                        if err != nil {
                            return err
                        }
                    } else {
                        err := txn.Set(key, updatedOuts.Serialize())
                        if err != nil {
                            return err
                        }
                    }
                }
            }

            // 添加新的输出
            newOutputs := TXOutputs{}
            for _, out := range tx.Vout {
                newOutputs.Outputs = append(newOutputs.Outputs, out)
            }

            key := append([]byte("utxo-"), tx.ID...)
            err := txn.Set(key, newOutputs.Serialize())
            if err != nil {
                return err
            }
        }

        return nil
    })

    if err != nil {
        log.Panic(err)
    }
}

// 序列化输出
func (outs TXOutputs) Serialize() []byte {
    var buff bytes.Buffer

    enc := gob.NewEncoder(&buff)
    err := enc.Encode(outs)
    if err != nil {
        log.Panic(err)
    }

    return buff.Bytes()
}

// 反序列化输出
func DeserializeOutputs(data []byte) TXOutputs {
    var outputs TXOutputs

    dec := gob.NewDecoder(bytes.NewReader(data))
    err := dec.Decode(&outputs)
    if err != nil {
        log.Panic(err)
    }

    return outputs
}

1.8.7 数字签名实现

import (
    "crypto/ecdsa"
    "crypto/elliptic"
    "crypto/rand"
    "encoding/hex"
    "math/big"
)

// 钱包结构
type Wallet struct {
    PrivateKey ecdsa.PrivateKey
    PublicKey  []byte
}

// 创建钱包
func NewWallet() *Wallet {
    private, public := newKeyPair()
    wallet := Wallet{private, public}

    return &wallet
}

// 生成密钥对
func newKeyPair() (ecdsa.PrivateKey, []byte) {
    curve := elliptic.P256()
    private, err := ecdsa.GenerateKey(curve, rand.Reader)
    if err != nil {
        log.Panic(err)
    }
    pubKey := append(private.PublicKey.X.Bytes(), private.PublicKey.Y.Bytes()...)

    return *private, pubKey
}

// 获取地址
func (w Wallet) GetAddress() []byte {
    pubKeyHash := HashPubKey(w.PublicKey)

    versionedPayload := append([]byte{version}, pubKeyHash...)
    checksum := checksum(versionedPayload)

    fullPayload := append(versionedPayload, checksum...)
    address := Base58Encode(fullPayload)

    return address
}

// 公钥哈希
func HashPubKey(pubKey []byte) []byte {
    publicSHA256 := sha256.Sum256(pubKey)

    RIPEMD160Hasher := ripemd160.New()
    _, err := RIPEMD160Hasher.Write(publicSHA256[:])
    if err != nil {
        log.Panic(err)
    }
    publicRIPEMD160 := RIPEMD160Hasher.Sum(nil)

    return publicRIPEMD160
}

// 计算校验和
func checksum(payload []byte) []byte {
    firstSHA := sha256.Sum256(payload)
    secondSHA := sha256.Sum256(firstSHA[:])

    return secondSHA[:addressChecksumLen]
}

// 签名交易
func (bc *Blockchain) SignTransaction(tx *Transaction, privKey ecdsa.PrivateKey) {
    prevTXs := make(map[string]Transaction)

    for _, vin := range tx.Vin {
        prevTX, err := bc.FindTransaction(vin.Txid)
        if err != nil {
            log.Panic(err)
        }
        prevTXs[hex.EncodeToString(prevTX.ID)] = prevTX
    }

    tx.Sign(privKey, prevTXs)
}

// 交易签名
func (tx *Transaction) Sign(privKey ecdsa.PrivateKey, prevTXs map[string]Transaction) {
    if tx.IsCoinbase() {
        return
    }

    for _, vin := range tx.Vin {
        if prevTXs[hex.EncodeToString(vin.Txid)].ID == nil {
            log.Panic("ERROR: Previous transaction is not correct")
        }
    }

    txCopy := tx.TrimmedCopy()

    for inID, vin := range txCopy.Vin {
        prevTx := prevTXs[hex.EncodeToString(vin.Txid)]
        txCopy.Vin[inID].Signature = nil
        txCopy.Vin[inID].PubKey = prevTx.Vout[vin.Vout].PubKeyHash

        dataToSign := fmt.Sprintf("%x\n", txCopy)

        r, s, err := ecdsa.Sign(rand.Reader, &privKey, []byte(dataToSign))
        if err != nil {
            log.Panic(err)
        }
        signature := append(r.Bytes(), s.Bytes()...)

        tx.Vin[inID].Signature = signature
        txCopy.Vin[inID].PubKey = nil
    }
}

// 验证交易
func (bc *Blockchain) VerifyTransaction(tx *Transaction) bool {
    if tx.IsCoinbase() {
        return true
    }

    prevTXs := make(map[string]Transaction)

    for _, vin := range tx.Vin {
        prevTX, err := bc.FindTransaction(vin.Txid)
        if err != nil {
            log.Panic(err)
        }
        prevTXs[hex.EncodeToString(prevTX.ID)] = prevTX
    }

    return tx.Verify(prevTXs)
}

// 交易验证
func (tx *Transaction) Verify(prevTXs map[string]Transaction) bool {
    if tx.IsCoinbase() {
        return true
    }

    for _, vin := range tx.Vin {
        if prevTXs[hex.EncodeToString(vin.Txid)].ID == nil {
            log.Panic("ERROR: Previous transaction is not correct")
        }
    }

    txCopy := tx.TrimmedCopy()
    curve := elliptic.P256()

    for inID, vin := range tx.Vin {
        prevTx := prevTXs[hex.EncodeToString(vin.Txid)]
        txCopy.Vin[inID].Signature = nil
        txCopy.Vin[inID].PubKey = prevTx.Vout[vin.Vout].PubKeyHash

        r := big.Int{}
        s := big.Int{}
        sigLen := len(vin.Signature)
        r.SetBytes(vin.Signature[:(sigLen / 2)])
        s.SetBytes(vin.Signature[(sigLen / 2):])

        x := big.Int{}
        y := big.Int{}
        keyLen := len(vin.PubKey)
        x.SetBytes(vin.PubKey[:(keyLen / 2)])
        y.SetBytes(vin.PubKey[(keyLen / 2):])

        dataToVerify := fmt.Sprintf("%x\n", txCopy)

        rawPubKey := ecdsa.PublicKey{Curve: curve, X: &x, Y: &y}
        if ecdsa.Verify(&rawPubKey, []byte(dataToVerify), &r, &s) == false {
            return false
        }
        txCopy.Vin[inID].PubKey = nil
    }

    return true
}

// 创建交易副本(用于签名)
func (tx *Transaction) TrimmedCopy() Transaction {
    var inputs []TXInput
    var outputs []TXOutput

    for _, vin := range tx.Vin {
        inputs = append(inputs, TXInput{vin.Txid, vin.Vout, nil, nil})
    }

    for _, vout := range tx.Vout {
        outputs = append(outputs, TXOutput{vout.Value, vout.PubKeyHash})
    }

    txCopy := Transaction{tx.ID, inputs, outputs}

    return txCopy
}

1.8.8 工具函数

import (
    "bytes"
    "encoding/binary"
)

// 整数转字节
func IntToHex(num int64) []byte {
    buff := new(bytes.Buffer)
    err := binary.Write(buff, binary.BigEndian, num)
    if err != nil {
        log.Panic(err)
    }

    return buff.Bytes()
}

// Base58编码字符集
var b58Alphabet = []byte("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz")

// Base58编码
func Base58Encode(input []byte) []byte {
    var result []byte

    x := big.NewInt(0).SetBytes(input)

    base := big.NewInt(int64(len(b58Alphabet)))
    zero := big.NewInt(0)
    mod := &big.Int{}

    for x.Cmp(zero) != 0 {
        x.DivMod(x, base, mod)
        result = append(result, b58Alphabet[mod.Int64()])
    }

    // 反转
    ReverseBytes(result)

    // 添加前导零
    for b := range input {
        if b == 0x00 {
            result = append([]byte{b58Alphabet[0]}, result...)
        } else {
            break
        }
    }

    return result
}

// Base58解码
func Base58Decode(input []byte) []byte {
    result := big.NewInt(0)

    for _, b := range input {
        charIndex := bytes.IndexByte(b58Alphabet, b)
        result.Mul(result, big.NewInt(58))
        result.Add(result, big.NewInt(int64(charIndex)))
    }

    decoded := result.Bytes()

    // 添加前导零
    for b := range input {
        if b == b58Alphabet[0] {
            decoded = append([]byte{0x00}, decoded...)
        } else {
            break
        }
    }

    return decoded
}

// 反转字节数组
func ReverseBytes(data []byte) {
    for i, j := 0, len(data)-1; i < j; i, j = i+1, j-1 {
        data[i], data[j] = data[j], data[i]
    }
}

// 验证地址
func ValidateAddress(address string) bool {
    pubKeyHash := Base58Decode([]byte(address))
    actualChecksum := pubKeyHash[len(pubKeyHash)-addressChecksumLen:]
    version := pubKeyHash[0]
    pubKeyHash = pubKeyHash[1 : len(pubKeyHash)-addressChecksumLen]
    targetChecksum := checksum(append([]byte{version}, pubKeyHash...))

    return bytes.Compare(actualChecksum, targetChecksum) == 0
}

1.8.9 CLI命令行接口

import (
    "flag"
    "fmt"
    "os"
)

// CLI结构
type CLI struct{}

// 打印使用说明
func (cli *CLI) printUsage() {
    fmt.Println("Usage:")
    fmt.Println("  createblockchain -address ADDRESS - 创建区块链")
    fmt.Println("  createwallet - 创建新钱包")
    fmt.Println("  getbalance -address ADDRESS - 获取余额")
    fmt.Println("  listaddresses - 列出所有地址")
    fmt.Println("  printchain - 打印区块链")
    fmt.Println("  send -from FROM -to TO -amount AMOUNT - 发送交易")
    fmt.Println("  reindexutxo - 重建UTXO集合")
}

// 验证参数
func (cli *CLI) validateArgs() {
    if len(os.Args) < 2 {
        cli.printUsage()
        os.Exit(1)
    }
}

// 运行CLI
func (cli *CLI) Run() {
    cli.validateArgs()

    nodeID := os.Getenv("NODE_ID")
    if nodeID == "" {
        fmt.Printf("NODE_ID env. var is not set!")
        os.Exit(1)
    }

    getBalanceCmd := flag.NewFlagSet("getbalance", flag.ExitOnError)
    createBlockchainCmd := flag.NewFlagSet("createblockchain", flag.ExitOnError)
    createWalletCmd := flag.NewFlagSet("createwallet", flag.ExitOnError)
    listAddressesCmd := flag.NewFlagSet("listaddresses", flag.ExitOnError)
    printChainCmd := flag.NewFlagSet("printchain", flag.ExitOnError)
    reindexUTXOCmd := flag.NewFlagSet("reindexutxo", flag.ExitOnError)
    sendCmd := flag.NewFlagSet("send", flag.ExitOnError)

    getBalanceAddress := getBalanceCmd.String("address", "", "查询余额的地址")
    createBlockchainAddress := createBlockchainCmd.String("address", "", "接收挖矿奖励的地址")
    sendFrom := sendCmd.String("from", "", "源地址")
    sendTo := sendCmd.String("to", "", "目标地址")
    sendAmount := sendCmd.Int("amount", 0, "发送金额")

    switch os.Args[1] {
    case "getbalance":
        err := getBalanceCmd.Parse(os.Args[2:])
        if err != nil {
            log.Panic(err)
        }
    case "createblockchain":
        err := createBlockchainCmd.Parse(os.Args[2:])
        if err != nil {
            log.Panic(err)
        }
    case "createwallet":
        err := createWalletCmd.Parse(os.Args[2:])
        if err != nil {
            log.Panic(err)
        }
    case "listaddresses":
        err := listAddressesCmd.Parse(os.Args[2:])
        if err != nil {
            log.Panic(err)
        }
    case "printchain":
        err := printChainCmd.Parse(os.Args[2:])
        if err != nil {
            log.Panic(err)
        }
    case "reindexutxo":
        err := reindexUTXOCmd.Parse(os.Args[2:])
        if err != nil {
            log.Panic(err)
        }
    case "send":
        err := sendCmd.Parse(os.Args[2:])
        if err != nil {
            log.Panic(err)
        }
    default:
        cli.printUsage()
        os.Exit(1)
    }

    if getBalanceCmd.Parsed() {
        if *getBalanceAddress == "" {
            getBalanceCmd.Usage()
            os.Exit(1)
        }
        cli.getBalance(*getBalanceAddress, nodeID)
    }

    if createBlockchainCmd.Parsed() {
        if *createBlockchainAddress == "" {
            createBlockchainCmd.Usage()
            os.Exit(1)
        }
        cli.createBlockchain(*createBlockchainAddress, nodeID)
    }

    if createWalletCmd.Parsed() {
        cli.createWallet(nodeID)
    }

    if listAddressesCmd.Parsed() {
        cli.listAddresses(nodeID)
    }

    if printChainCmd.Parsed() {
        cli.printChain(nodeID)
    }

    if reindexUTXOCmd.Parsed() {
        cli.reindexUTXO(nodeID)
    }

    if sendCmd.Parsed() {
        if *sendFrom == "" || *sendTo == "" || *sendAmount <= 0 {
            sendCmd.Usage()
            os.Exit(1)
        }

        cli.send(*sendFrom, *sendTo, *sendAmount, nodeID)
    }
}

// 主函数
func main() {
    defer os.Exit(0)

    cli := CLI{}
    cli.Run()
}

1.9 比特币的安全性分析

1.9.1 51%攻击

当攻击者控制超过50%的全网算力时,可以进行以下攻击:

可能的攻击:

  • 双重支付:在私有链上重写交易历史
  • 阻止交易确认:拒绝打包特定交易
  • 阻止其他矿工出块:始终挖出更长的链

无法做到:

  • 凭空创造比特币
  • 盗取他人的比特币(需要私钥)
  • 修改已深度确认的区块(成本极高)

防御措施:

  • 等待足够的确认数(通常6个确认)
  • 分散化挖矿(避免矿池过于集中)
  • 监控算力分布

1.9.2 双重支付攻击

攻击者试图将同一笔UTXO花费两次:

攻击场景:

1. 攻击者创建交易Tx1:支付给商家
2. 商家看到交易,发货(0确认接受)
3. 攻击者同时创建交易Tx2:将相同UTXO转回自己
4. 攻击者利用算力使Tx2所在链成为主链
5. Tx1被废弃,攻击者既获得商品又保留比特币

防御措施:

  • 等待多个确认(推荐6个确认)
  • 大额交易等待更多确认
  • 0确认交易仅用于小额支付

1.9.3 私钥安全

私钥是控制比特币的唯一凭证,丢失私钥意味着永久失去比特币。

最佳实践:

  1. 冷钱包存储:离线生成和保存私钥
  2. 硬件钱包:专用硬件设备管理私钥
  3. 多重签名:要求多个私钥共同签名
  4. 助记词备份:使用BIP39标准助记词
  5. 定期备份:多地备份,防止单点故障

多重签名示例:

2-of-3多签地址:
- 需要3个密钥中的任意2个才能花费
- 即使丢失1个密钥,仍可使用剩余2个
- 适合企业账户和大额存储

1.10 比特币的扩展性问题

1.10.1 区块容量限制

比特币区块大小限制为1MB(SegWit后约4MB),导致:

  • 每秒处理约7笔交易(TPS)
  • 网络拥堵时手续费飙升
  • 交易确认时间延长

对比传统支付系统:

  • Visa: 约24,000 TPS
  • 支付宝: 超过100,000 TPS

1.10.2 扩容方案

链上扩容(On-chain):

  1. 增大区块:提高区块大小限制

    • 优点:直接提升TPS
    • 缺点:增加节点存储和带宽压力
  2. 隔离见证(SegWit):将签名数据分离

    • 优点:变相增加区块容量,修复交易延展性
    • 缺点:需要软分叉升级

链下扩容(Off-chain):

  1. 闪电网络(Lightning Network):

    • 建立双向支付通道
    • 链下进行大量微交易
    • 仅在开启和关闭通道时上链
    • 理论TPS可达百万级
  2. 侧链(Sidechain):

    • 独立的区块链,与主链双向锚定
    • 可实验新特性,不影响主链
    • 例如:Liquid Network

1.10.3 区块链膨胀问题

完整区块链大小已超过500GB(截至2024年),带来以下问题:

  • 全节点同步时间长
  • 存储成本增加
  • 带宽要求高

解决方案:

  • 轻节点:仅存储区块头,使用SPV验证
  • 修剪模式:删除旧UTXO,仅保留最近区块
  • UTXO承诺:将UTXO集合哈希写入区块,加速同步

1.11 比特币的经济模型

1.11.1 通缩属性

比特币总量恒定2100万枚,且不断有私钥丢失导致永久损失,呈现通缩特性。

通缩影响:

  • 长期持有激励(HODL文化)
  • 作为价值存储(数字黄金)
  • 不鼓励日常消费支付

1.11.2 手续费市场

随着区块奖励减少,手续费将成为矿工的主要收入:

当前(2024年):
区块奖励: 6.25 BTC
平均手续费: 0.1-0.5 BTC

预计2140年:
区块奖励: 0 BTC
手续费: 必须足够激励矿工维持网络安全

手续费市场动态:

  • 用户竞价:高手续费交易优先打包
  • 动态调整:根据网络拥堵程度
  • RBF(Replace-By-Fee):用更高手续费替换未确认交易

1.11.3 挖矿经济学

挖矿是否盈利取决于:

收益 = 区块奖励 + 交易手续费
成本 = 电费 + 硬件成本 + 维护费用

盈利条件:收益 > 成本

影响因素:

  • 比特币价格
  • 网络难度
  • 电费成本
  • 矿机效率(算力/功耗比)

矿业集中化问题:

  • 规模经济导致大型矿场优势明显
  • 地理位置(廉价电力地区)影响显著
  • 矿池的兴起降低个人挖矿门槛

1.12 比特币生态系统

1.12.1 比特币改进提案(BIP)

BIP是比特币协议改进的标准化流程:

重要BIP:

  • BIP-32:分层确定性钱包(HD Wallet)
  • BIP-39:助记词标准
  • BIP-44:多币种HD钱包路径
  • BIP-141:隔离见证
  • BIP-173:Bech32地址格式
  • BIP-340/341/342:Taproot升级

1.12.2 比特币应用层

第二层协议:

  1. 染色币(Colored Coins):在比特币上发行资产
  2. Omni Layer:智能合约平台(USDT最初在此发行)
  3. RSK:兼容以太坊的侧链
  4. Stacks:智能合约层,使用STX代币

其他应用:

  • 时间戳服务:利用区块链不可篡改性
  • 公证服务:文档存证
  • 去中心化身份:DID系统

1.13 本章总结

本章详细介绍了比特币的核心原理和技术实现:

  1. UTXO模型:比特币独特的账本模型,提供并发性能和隐私保护
  2. 工作量证明:通过哈希计算保证网络安全和共识
  3. 区块结构:链式存储和Merkle树实现高效验证
  4. 密码学:ECC签名、SHA-256哈希确保交易安全
  5. 共识机制:最长链原则解决分布式一致性问题
  6. 经济模型:固定供应和减半机制创造稀缺性

通过Go语言实现的简化版比特币,展示了核心组件的工作原理:

  • 区块链数据结构和存储
  • 工作量证明挖矿算法
  • UTXO交易模型
  • 数字签名和验证
  • Merkle树构建

比特币的创新意义:

比特币不仅是第一个成功的加密货币,更重要的是证明了去中心化数字货币的可行性。它解决了困扰密码学家数十年的拜占庭将军问题,在无需信任的环境中实现了价值转移。

局限性:

尽管比特币具有开创性,但也存在明显的局限:

  • 扩展性受限(TPS低)
  • 能耗高(PoW挖矿)
  • 脚本功能有限(不支持复杂智能合约)
  • 交易确认慢(平均10分钟)

这些局限促使了新一代区块链的诞生,其中最具代表性的就是以太坊。下一章将详细讲解以太坊的架构和核心概念,了解它如何在比特币的基础上实现更强大的可编程性和灵活性。

Prev
区块链基础与密码学
Next
第二章:以太坊架构与核心概念