以太坊 C++ 源码深度解析:穿过 Block 1920000 的 The DAO 硬分叉

Posted by JZW 加密货币资讯站 on September 5, 2025

强烈建议先快速回顾 区块链分叉的基础概念,再深入源码细节,你会对为啥代码里突然出现“dao-hard-fork”四个字节更有体感。

回顾 2016:价值 5 000 万美元的一次智能合约事故

2016 年 4 月 30 日,The DAO—一个用智能合约运作的链上风险投资基金—向全世界开放“众筹”。28 天吸金 1.5 亿美元的 ETH,成为当时最风光的 去中心化自治组织。谁也想不到,一份小小的递归调用漏洞,让黑客在 6 月 17 日转走了 3 600 000 ETH,按市价约 5 000 万美元。
市场震动、社区分裂,“是否直接回滚这笔交易”成为考验 去中心化精神 的社会级难题。

软硬分叉纷争与最终裁决

  • 软分叉:只会让黑客资金继续“冻结”,但代码改动小,兼容老节点。
  • 硬分叉:在区块高度 1920000 直接“回滚”,把 DAO 余额整体搬去退款合约。

投票、争论、算力站队,最终 “ETH 派” 胜出,执行硬分叉;拒绝回滚的矿工继续维护旧链,自此 Ethereum Classic(ETC) 诞生。

区块 1920000:ETH 与 ETC 的楚河汉界

关键信息 实际值
分叉高度 1 920 000(0x1d4c00)
extraData 标志 dao-hard-fork(十六进制 0x64616f2d686172642d666f726b
退款合约地址 0xbf4ed7b27f1d666546e30d74d50d173d20bca754
当天转账总额 12,001,961.845205763407115004 ETH 由 58 个 DAO 合约转出

这笔转账并没有出现在任何一笔 交易 里,而是被写进了 C++ 客户端源码,永不磨灭的 “链上补丁”


C++ 源码剖析:补丁是怎么植入的?

1. 参数下发:哪儿记录了 1920000?

文件位置
libethashseal/genesis/mainNetwork.cpp

"daoHardforkBlock": "0x1d4c00"

同样目录里的 ropsten.cpp 将该值设为 0,意味着 Ropsten 测试网不做 DAO 分叉,方便开发者做无重放保护的测试。

关键词 “daoHardforkBlock” 既是硬分叉开关,也是未来所有 DAO challenge 的基准。

2. 一次性搬运余额:performIrregularModifications()

文件位置
libethereum/Block.cpp

void Block::performIrregularModifications()
{
    u256 const& daoHardfork = m_sealEngine->chainParams().daoHardforkBlock;
    if (daoHardfork != 0 && info().number() == daoHardfork)
    {
        Address recipient("0xbf4ed7b27f1d666546e30d74d50d173d20bca754");
        Addresses allDAOs = childDaos();
        for (Address const& dao : allDAOs)
            m_state.transferBalance(dao, recipient, m_state.balance(dao));
        m_state.commit(State::CommitBehaviour::KeepEmptyAccounts);
    }
}

核心动作:

  1. 判断是否到达分叉高度;
  2. 遍历所有 DAO 子合约;
  3. 把余额 整包移动 给退款合约且不产生 交易回执
  4. 提交状态,空账户保留,避免破坏后续 以太坊状态树

3. 共识检测:DAO-Challenge 机制

当节点第一次与陌生 peer 建立连接,必须确认彼此在同一分叉上,于是出现了 DAO-Challenge——一次额外的协议握手。

发起挑战
BlockChainSync::onPeerStatus()requestDaoForkBlockHeader()

if (!requestDaoForkBlockHeader(_peer)) {
    syncPeer(_peer, false);
}

验证回应
BlockChainSync::verifyDaoChallengeResponse()

return header.number() == daoHardforkBlock
       && header.extraData() == fromHex("0x64616f2d686172642d666f726b");

如果对方回应的区块不含 dao-hard-fork 四字标记,节点会立刻 ban 掉该 peer,避免未来陷入 重放攻击链错乱


为什么这事对开发者仍值得关心?

  1. 以太坊节点二层网络 如果忽略了 DAO challenge,会连不上大部分的 ETH Mainnet;
  2. 分叉实现技巧:以太坊过去 9 年只用过一次“代码级回滚”,源码就是 经典模板
  3. 审计智能合约:DAO 事件催生了如今一整套 形式化验证、测试网复读、奖金众测 的全链路安全体系。

极速 FAQ:5 个常被问到的疑问

Q1:退款合约里的 ETH 后来都去哪了?
A:所有 DAO 代币持有者根据持币比例,在 2017 年初提现完毕,合约余额跌至 0,从此停止运行——完整追踪可以👉 通过链上数据工具查到每一步

Q2:现在还能挖出 ETC 吗?
A:可以,但 ETC 采用与 ETH 不同的 ThanosECIP-1100 调整算法,需用支持该算法的矿机,并留意 算力波动51% 攻击历史

Q3:为什么测试网不一起做 DAO 分叉?
A:Ropsten、Goerli 等测试网就是为了复现主网“之前”的环境;如果强制带 daoHardforkBlock > 0,开发者难以调试早期历史数据。

Q4:有没有官方文档解释 performIrregularModifications()
A:社区文档散见于 Ethereum Classic & Ethereum.org 的许多旧帖,可被视为 非正式的 EIP 0xdead,但它确实存在于 核心源码 里,自行阅读源码反而最权威。

Q5:未来还会出现类似的人为硬分叉吗?
A:理论上有,只要社区共识足够强大;但 2016→2024 的实践 表明概率极低,如今的治理更依循 EIP、Rollup、Layer2 模块化 的软升级路径。


扩展阅读与避坑提示

  • 链上浏览器练习:到区块 1920000 观察 extraData 的十六进制原始字符串,把它抄下来再对照文中 0x64616f2d686172642d666f726b,体会 “四个字节定乾坤” 的玄学。