教程区块链区块链技术ch1616.3 实现 PoW 挖矿与动态难度调整

本页目录

工作量证明不是"浪费算力"——它是一个去中心化的时钟,谁算出了 hash,谁就获得了在这个时间点写入区块的"发言权"。


16.3.1 挖矿核心

flowchart TD
    A[矿工收集待打包交易] --> B[构造区块头<br/>index + timestamp + prevHash + nonce]
    B --> C[计算 hash = SHA-256(header)]
    C --> D{hash 前导零 >= difficulty?}
    D -->|否| E[nonce += 1]
    E --> C
    D -->|是| F[广播新区块到网络]
    F --> G[其他节点验证后追加到本地链]
    style D fill:#fff3e0
    style G fill:#c8e6c9
目标=0000...0D 个前导零XXXX...\text{目标} = \underbrace{0000...0}_{D \text{ 个前导零}}\text{XXXX...}
python
# 已在 16.1 中实现核心逻辑
# 本节增加动态难度

def mine(self) -> None:
    """调整 nonce 直到 hash 前导零数 >= difficulty"""
    target = '0' * self.difficulty  # 如 '0000'
    while not self.hash.startswith(target):
        self.nonce += 1
        self.hash = self.compute_hash()

# 16.1 中的测试(difficulty=4):
# 出块时间:秒级(CPU 单核)
# 难度每增加 1,预计工作量 × 16
# 因为 SHA-256 输出均匀分布,每增加一个零,概率 × 1/16

16.3.2 难度调整算法

比特币每 2016 个区块(约 2 周)调整一次目标。我们简化为每 5 个区块。

python
class Blockchain:
    def __init__(self, difficulty=4, target_block_time=10):
        self.difficulty = difficulty
        self.target_block_time = target_block_time  # 目标出块秒数
        self.adjustment_interval = 5
    
    def adjust_difficulty(self) -> None:
        """每 5 个区块调整一次"""
        if len(self.chain) % self.adjustment_interval != 0:
            return
        
        # 计算前 5 个块的平均出块时间
        recent_blocks = self.chain[-self.adjustment_interval:]
        avg_time = (recent_blocks[-1].timestamp - recent_blocks[0].timestamp) / len(recent_blocks)
        
        print(f"\n📊 前 5 块平均出块: {avg_time:.1f}s, 目标: {self.target_block_time}s")
        
        adjustment = self.target_block_time / avg_time
        
        if avg_time < self.target_block_time * 0.75:
            self.difficulty += 1  # 太快,增难
            print(f"⬆️ 难度 +1 → {self.difficulty}")
        elif avg_time > self.target_block_time * 1.5 and self.difficulty > 1:
            self.difficulty -= 1  # 太慢,减难
            print(f"⬇️ 难度 -1 → {self.difficulty}")
        else:
            print(f"⏸️ 难度不变: {self.difficulty}")

难度调整的经济学

场景原因调整方向
更多算力加入竞争加剧增加难度
算力退出竞争减弱降低难度
ASIC 出现效率飞跃大幅提升难度
D_{new} = D_{old} \times \frac{\text{actual_time}}{\text{target_time}}

16.3.3 难度与出块时间关系

难度前导零预计尝试次数单核 CPU 出块时间
3000163=4,09616^3 = 4,096< 1 秒
40000164=65,53616^4 = 65,536~1 秒
500000165=1M16^5 = 1M~20 秒
6000000166=16M16^6 = 16M~5 分钟
比特币当前~72167216^{72}~10 分钟(全网 ASIC)

比特币的 72 位前导零需要全球算力联合尝试约 10 分钟找到。我们的测试网络保持难度 4-5,确保秒级出块。


16.3.4 完整验证

python
# 16.1 中的链验证已包含 PoW 检查
# 难度是否正确?检查每个区块的 difficulty 与根据历史计算出的期望值

def verify_difficulty(chain: List[Block]) -> bool:
    """验证难度调整是否正确(简化)"""
    # 每 5 个块,检查其难度与前 5 块的平均时间匹配
    for i in range(5, len(chain), 5):
        # 简化验证逻辑
        pass
    return True

, 前往 → 16.4 交易、余额与签名 |*

评论

0

评论加载中…

发表评论

0/2000