以太坊挖矿(PoW)流程

配合代码食用(Geth v1.9.0 stable)

以太坊目前有ethash和clique两个共识引擎,其中ethash是用于正式网络的PoW(proof-of-work)共识引擎,clique是用于测试网络的PoA(proof-of-authority)共识引擎

代码流程

1.eth/backend.go
  • New方法创建Ethereum对象时,会调用miner.New方法创建矿工对象,作为Ethereum的一个字段
  • Ethereum.StartMining方法会根据给定的cpu线程数开启挖矿Ethereum.miner.Start
2.miner/miner.go
  • Miner,矿工类型,其字段包括worker(执行挖矿工作),eth(所关联的以太坊节点),engine(共识引擎)等
  • New方法会创建Miner对象,并开启协程go miner.update()处理downloader同步相关事件(在同步开始时停止挖矿,在同步结束或失败后重新开始挖矿)和退出事件
  • Miner.Start方法会调用Miner.worker.start开始挖矿
3.miner/worker.go
  • worker,负责提交新的工作(new work)给共识引擎(进行hash运算或其他方式得到满足条件的block)并收集打包好的block
  • newWorker方法,创建worker并协程启动四个loop:
    • go worker.newWorkLoop(recommit)
      • startCh收到挖矿开始信号,移除pendingTasks中过时的task,提交新的挖矿任务请求(发送newWorkReq到newWorkCh)
      • chainHeadCh收到ChainHeadEvent,移除pendingTasks中过时的task,提交新的挖矿任务请求
      • <-timer.C,default流程,判断如果正在挖矿则重新提交挖矿工作(周期性地拉取价格更高的交易)
      • exitCh收到退出信号,return
    • go worker.mainLoop()
      • newWorkCh收到的新的挖矿任务请求(newWorkReq),执行worker.commitNewWork提交新的task(发送task到taskCh)
      • chainSideCh收到ChainSideEvent,在叔区块未知/正在挖矿/当前叔区块数小于2时,添加该叔区块并执行worker.commit提交新的task
      • txsCh收到NewTxsEvent时,判断如果不在挖矿,执行worker.commitTransactions处理交易并更新快照,否则不做操作
      • exitCh收到退出信号或txsSub/chainHeadSub/chainSideSub收到Error,return
    • go worker.taskLoop()
      • taskCh收到commit方法中提交的task(receipts,state,block,createdAt),将task加入pendingTasks中,并调用worker.engine.Seal方法进行hash运算直到找到一个nonce使得区块的难度值满足要求(即挖矿成功)
      • exitCh收到退出信号,return
    • go worker.resultLoop()
      • resultCh收到共识引擎找到nonce后发送的block:
        • 删除pendingTasks中的记录
        • worker.chain.WriteBlockWithState(block, receipts, task.state)提交block,receipts和state到数据库
        • 广播block(NewMinedBlockEvent{Block: block})
        • 广播链的插入事件(ChainEvent{Block: block, Hash: block.Hash(), Logs: logs}, ChainHeadEvent{Block: block})
        • 将block插入unconfirmed以进行后续的确认
      • exitCh收到退出信号,return
  • worker.commitNewWork具体逻辑:
    • 判断时间戳,要保证timestamp大于上一个块的时间戳,如果timestamp>now+1要等待避免timestamp太超前
    • 构造Header对象
    • 调用worker.engine.Prepare方法,根据parent计算难度值给header的Difficulty字段赋值
    • 提交叔区块
    • 取出交易池pending中的交易并执行worker.commitTransactions,该方法提交交易给evm执行并更新状态
    • 调用worker.commit方法
  • worker.commit具体逻辑:
    • 调用worker.engine.Finalize方法,该方法给矿工计算并加上矿工奖励,计算header.Root并赋值,返回最终定稿的block
    • 判断如果在挖矿,提交新的task(发送task到taskCh)
4.consensus/ethash/sealer.go
  • Ethash.Seal方法,核心逻辑是调用Ethash.mine方法,一直做hash运算直到符合难度值要求,把挖出的block放入worker.resultCh,在worker.resultLoop中处理

流程总结

worker:

  • newWorkLoop:发送newWorkReq到newWorkCh

  • mainLoop:newWorkCh收到newWorkReq,发送task到taskCh

  • taskLoop:taskCh收到task,worker.engine.Seal进行hash运算

consensus:

  • hash解题成功,发送block到worker.resultCh

worker:

  • resultLoop:resultCh收到block,广播和写入

你可能感兴趣的:(以太坊挖矿(PoW)流程)