本文将手把手带你实现一个完整的区块链分叉检测与回扫系统,适合对区块链同步机制感兴趣的开发者

代码链接:https://github.com/Meiwen1/rollback-scan

在说区块链分叉检测之前,首先要明白分叉是什么

一、分叉

可以将链想象成一根分叉的树叉

正常情况:

分叉情况:

1.1 分叉分类

1.1.1 硬分叉
  (1) 定义

     协议规则的不向后兼容变更,旧版本节点无法验证新版本产生的区块。


   (2) 底层原理


    旧规则:区块大小上限 = 1MB
    新规则:区块大小上限 = 8MB

    当新节点产出一个 2MB 的区块时:
    新节点: 合法,接受 ✅
    旧节点: 非法,拒绝 ❌

    (3) 分叉结果


    链永久分裂成两条独立链,各自运行,互不承认

    可以参考 etc 与eth 的硬分叉案例

1.1.2 软分叉
    (1) 定义


     协议规则的向后兼容变更,旧版本节点可以验证新版本产生的区块(虽然可能不理解新功能)。


    (2) 底层原理


    旧规则: 交易格式 = [nonce, gasPrice, gasLimit, to, value, data]
    新规则: 交易格式 = [nonce, gasPrice, gasLimit, to, value, data]+可选的新字段(旧节点忽略)


    (3) 典型场景


    比特币改进方案(BIP) 66:比特币签名验证的软叉
    支付给脚本哈希(P2SH):在比特币网络上,一个软叉产生多重签名地址


    (4) 分叉结果


    链不会永久分裂,最终会统一到新规则链上(因为新节点算力通常更强)

1.1.3 🌟🌟链重组

这是我们项目要处理的核心


   (1) 定义


    链重组是指在区块链中,由于网络延迟或节点故障等原因,导致某些区块暂时无法被所有节点确认,从而出现多个 competing chains(竞争链)。当这些 competing chains 的长度相同时,网络会选择最长的 chain 作为主链,其他 competing chains 会被舍弃。这个过程就叫做链重组。


    所以与分叉最大的区别是 主动与被动的关系 分叉是主动 链重组为被动

    (2) 链重组发生过程详述:

    时间线(T0到T3):
   

    T3时刻同时存在101-A和101-B,这样就发生了 一种被迫的临时分叉

    区块链自己如何去解决这个问题呢?

  •     最长链原则(Longest Chain Rule)

    在T4时刻 A链长度>B链长度,故维护A链 淘汰B链 但这不是一瞬的,是需要一段时间来进行选择的结果 

   
   最长链原则是链上遵循的一种基本原则,

    链上数据是落到我们数据库里的,所以在代码中,我们要遵循最长链原则,就必须始终保持我们数据库的数据 都是来自链A(最长链)的数据,不能有链B(短链)的数据,如果我们有链B的数据在数据库,会造成  

currentBlock.Hash!= nextBlock.preHash

使得程序报错,此时必须要有应对手段,这就是本项目所要讲的回扫问题

      (3)逻辑概要


    假设你的数据库当前是:
   
    数据库状态:100 ->101-B
    链上实际: 100->101-A->102-A

    检测逻辑:

    //从链上拉取高度 102 的区块
    block102 := getBlockFromChain(102)

    //检查: 102 的 parentHash 是否等于我数据库里 101 的hash
    if block102.ParentHash != db.GetBlock(101).Hash{
    //不等! 说明我将 101-B 这个区块存储到数据库这个行为是错的
    //链上的101 已经变成101-A了
    //需要重组(Reorg)!
    }

    回扫逻辑:
 

    Step 1:找到分叉点
            从当前高度往回找,直到parentHash 匹配

            检查101:链上 101-A.parentHash == 数据库100.hash

            分叉点 = 高度 100
    Step 2:回滚
            删除数据库中 101 及以后的所有区块(删除101-B)

    Step 3:重新同步
            从高度101开始重新拉取(得到 101-A,102-A)

    (4) Reorg(回扫) 观念理解

    Reorg 深度 = 被回滚的区块数量

    深度1       =  只回滚 1个区块(常见)
    深度2-3    =  偶尔发生
    深度6+     =  非常罕见(这就是为什么BTC 要等 6 个确认)
    深度100+ =  意味着51%攻击(几乎不可能,除非调用国家级的算力)

1.2 分叉对比

特性 硬分叉 软分叉 链重组
层级 协议层 协议层 共识层
兼容性 不兼容 向后兼容 N/A
是否永久 永久分裂 最终统一 临时,很快解决
需要处理? 换节点/换链 通常自动 需要回扫
触发原因 人为升级 人为升级 网络延迟/攻击

可以大致的理解为   软硬分叉是主动分叉 而链重组是被动的临时分叉

二、分叉检测实现

检测原理:

  • 每个区块都有一个 parentHash,指向它的父区块:
区块100               区块101                     区块102

100 hash=”0xaaa“ <-----  parentHash=“0xaaa” <--------parentHash="0xbbb"
    
                         101 Hash= “0xbbb”.          102 Hash="0xccc"

  • 核心逻辑:

    链上区块 N 的 parentHash == 数据库中区块 (N-1) 的 hash ?
        相等 → 正常
        不等 → Reorg
  • 关键代码:
dbBlock := GetBlockByHeight(height - 1)
    if chainBlock.ParentHash != dbBlock.Hash {
        return true  // Reorg!
    }

三、回扫实现

回扫分三个步骤:

   1. 找分叉点:从当前高度往回找,直到 parentHash 匹配
    2. 回滚:删除分叉点及以后的区块
    3. 重新同步:从分叉点拉取新数据

关键代码:

    // 找分叉点
    for height := startHeight; height > 0; height-- {
        if chainBlock.ParentHash == dbBlock.Hash {
            forkHeight = height
            break
        }
    }
    // 回滚
    DeleteBlocksAbove(forkHeight)

    主循环:
    for h := startHeight; h <= chainHeight; h++ {
        if CheckReorg(h) {
            forkHeight := HandleReorg(h)
            h = forkHeight - 1  // 重置起点
            continue
        }
        SaveBlock(chainBlock)
    }

四、运行代码

测试过程很简单只需要讲 hash值手动更改使得 currentBlock.Hash!=nextBlock.PreHash即可。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐