以太坊系列 - 挖矿与共识

以太坊挖矿与共识的源码分析

讲述一个新区块被挖掘出的过程

1.挖矿

对于一个新区块被挖掘出的过程,代码实现上基本分为两个环节:

  • 一是组装出一个新区块,这个区块的数据基本完整,包括成员Header的部分属性,和叔区块组uncles[],以及交易列表txs,并且所有交易已经执行完毕,所有收据(Receipt)也已收集完毕,这部分主要由worker完成;

  • 二是填补该区块剩余的成员属性,比如Header.Difficulty,coinbase等,并完成授权,这些工作是由Agent调用接口实现体Prepare,Seal,利用共识算法来完成的。

1.1 收集数据 worker.commitNewWork()(miner/worker.go)

  • 4种情况会调用到这个函数

  • 程序启动时,执行newWorker方法初始化worker对象时,调用commitNewWork方法,开始组装新区块。

  • 启动挖矿时,miner.start里会调用worker.start()和worker.commitNewWork()

  • 网络接收到其他矿工广播过来的新区块,该区块验证有效插入到区块链后,会产生ChainHeadEvent事件,worker对象的update协程检测到该事件后,会调用commitNewWork方法,开始生成新的区块。

  • 矿工自己生成新的区块并入链后,会向全网广播NewMinedBlockEvent,同时也会给自己发一个ChainHeadEvent,之后就跟上面的一样

挖矿UML_1
挖矿UML_2

  • commitNewWork()做了什么?
    • 准备新区块的Header属性,可确定的有Time,Number,ParentHash,其余留待之后共识算法中确定
    • 调用engine.Prepare()函数,完成部分Header对象的准备
    • 准备新区块的交易列表,并执行这些交易
    • 准备新区块的叔块uncles[]
    • 调用engine.Finalize()函数,对新区块“定型”,填充Header对象 Root(默克尔根),TxHash(默克尔根), ReceiptHash(默克尔根), UncleHash等属性。
    • 把创建的Work对象,通过channel发送给每一个登记过的Agent,进行后续的挖掘。
      worker.push() -> CpuAgent.update()

1.2 授权 CpuAgent(miner/agent.go)

  • 和共识有关的主要是这几个函数Start(),update()和mine()
    • CpuAgent.Start() 用来启动CpuAgent.update()协程
      • miner.New() -> miner.Register(NewCpuAgent) -> (if Mining) agent.Start() -> go agent.update()
      • miner.Start() -> worker.start() -> agent.Start() -> go agent.update()
    • CpuAgent.update() 用来监听worker.commitNewWork()结束前通过worker.push()发出的channel
      • worker.push() -> CpuAgent.update() -> CpuAgent.mine()
    • CpuAgent.mine() 利用Engine实现体的共识算法对传入的Block进行最终的授权, 如果成功,就将Block同Work一起通过channel发还给worker,那边worker.wait()会接收并处理
      • CpuAgent.mine() -> engine.Seal() -> worker.wait()

挖矿UML_3

扫描二维码关注公众号,回复: 8584713 查看本文章

到此,形成一个大的消息循环, 产生出了新区块,哦也!!!

2.共识

不过真正的主角还未出场,注意到这三个函数engine.Prepare() , engine.Finalize() , engine.Seal() ,它们是共识算法对外暴露的接口.该接口有两种实现体,即PoW和PoA
共识

发布了58 篇原创文章 · 获赞 66 · 访问量 8183

猜你喜欢

转载自blog.csdn.net/wcc19840827/article/details/90647000