以太坊 eth/handle.go处理newblockMsg消息的主要流程

本文详细解析了以太坊eth/handle.go模块中newblockMsg消息的处理流程,包括区块验证、主链重组、数据同步等关键步骤,深入探讨了fetcher与downloader在区块同步中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天把以太坊 eth/handle.go处理newblockMsg消息的流程基本看完了,记录一下。

以太坊 eth/handle.go处理newblockMsg消息的主要流程:

Fetcher负责验证区块并插入区块,如果符合条件,还会重组主链区块。

如果收到的远程peer节点发来的区块TD-区块难度(即上个区块的TD) 大于  之前保存的peer最新的TD,则证明中间还差了一些区块没有同步,并且远程peer节点发来的区块TD-区块难度(即上个区块的TD) 大于 本地最新区块的TD,则调用downloader进行数据同步。

 

《1》pm.fetcher.Enqueue(p.id, request.Block) 

  1.1 Equeu会进入fetcher的loop函数里面的case op := <-f.inject:处理

    propBroadcastInMeter.Mark(1)

     f.enqueue(op.origin, op.block) 注意这个方法的enqueue的e是小写的。

    这个方法会检查区块号是否和本地区块号相差太远,如果相差的距离小于maxUncleDist或者大于maxQueueDist,则forgetHash然后退出。

     最后会给queue队列push一个block,然后在loop方法里会循环取出block,如果检查通过,就调用  f.insert(op.origin, op.block)方法

1.2 f.insert(op.origin, op.block)方法。

       1. 检验区块,如果父hash在本地区块链,并且header通过验证的话没就立刻把区块广播出去。

           go f.broadcastBlock(block, true)

    2.然后通过在newProtocolManager时给fetcher注入的type chainInsertFn func(types.Blocks)方法,

    调用blockchain.InsertChain(blocks)把区块插入主链中。InsertChain()会调用insertChain(),最终会调用

    status, err := bc.WriteBlockWithState(block, receipts, state),该方法里如果发现区块td( >=0的情况判断) 符合条件,会调用reorg()方法重组主链。如果status是主链(CanonStatTy),则将会PostChainEvents()发送ChainEvent消息,如果status是侧链(SideStatTy),则会发送ChainSideEvent消息。

 1.3 .如果执行insertChain导入成功,会调用newProtocolManager时给fetcher注入的blockBroadcasterFn

  (实际上是protocolManager的BroadcastBlock方法)再次广播区块,这次只广播区块hash。

1.4 fetcher方法内所有内容执行完成后,就发送一个done的信号:defer func() { f.done <- hash }()

   于是又跳回fetcher.loop方法里的case hash := <-f.done:去处理。主要会执行forgetHash和forgetBlock

   f.forgetHash(hash)

  f.forgetBlock(hash)

 

《2》go pm.synchronise(p)

 2.1 如果收到peer发来的区块td 比 之前peer发来的最大td 还要小,则直接退出不处理。(这一点设计真贴心。。)

  2.2 如果大于之前peer的最大Td,则调用downloader开始同步数据

        接下里将会进行downloader的Synchronise方法,会再调用synchronise方法

     1. 从peerSet里的peerConnection取出key为p.id的con连接对象,如果没有该ID的对象,则直接退出。

        如果有,则调用d.syncWithPeer(p, hash, td)方法。

        2. d.syncWithPeer(p, hash, td)方法

      (1)调用d.fetchHeight(p)获取远程peer的高度

      (2)调用d.findAncestor(p, height)获取本地节点和远程节点的共同祖先

      (3)初始化下载队列,d.queue.Prepare(origin+1, d.mode)

      (4)注入4个函数到fetchers:fetchers := []func() error{

        func() error { return d.fetchHeaders(p, origin+1, pivot) }, // Headers are always retrieved

        func() error { return d.fetchBodies(origin + 1) },          // Bodies are retrieved during normal and fast sync

       func() error { return d.fetchReceipts(origin + 1) },        // Receipts are retrieved during fast sync

       func() error { return d.processHeaders(origin+1, pivot, td) },

       } 如果是全同步模式,还要注入:fetchers = append(fetchers, d.processFullSyncContent)

     (5)调用d.spawnSync(fetchers)分别开始同步区块头,区块体和收据,并逐一进行处理。

 2.3 把当前主链的最新区块hash广播给所有peers

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值