以太坊挖礦(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,廣播和寫入
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。