前言
礦工在PoW中負責了產生區塊的工作,把一大堆交易交給它,它生成一個證明自己做了很多工作的區塊,然後將這個區塊加入到本地區塊鏈並且廣播給其他節點。
接下來我們將從以下角度介紹礦工:
- 角色。礦工不是一個人,而是一類人,可以把這一類人分成若干角色。
- 通過了解一個區塊產生的主要流程,掌握礦工的工作流。
- 通過了解礦工的主要函數介紹,掌握礦工的主要挖礦機制。
<!--more-->
介紹礦工由哪些部分組成,會和哪些其他模塊進行交互,這些部分是如何協作產生區塊的。
角色
有3種角色:miner、worker、agent。我們分別使用礦長、副礦長、礦工進行類比。
- miner:是礦長,負責管理整個礦場的運作,比如:啓動、停止挖礦,處理外部請求,設置挖礦獲得的獎勵的錢包地址等等。
- worker:副礦長,負責具體挖礦工作的安排,把挖礦任務(Work)安排給agent。
- agent:真實的礦工,他們負責挖礦,把自己的勞動成果(Result)交給worker,agent默認只有1個,可以通過API創建多個。
一個區塊產生的主要流程
實際的挖礦過程基本不涉及miner,只涉及worker、agent和engine,engine是共識引擎模塊,我們利用下圖介紹生成一個區塊的主要流程。
挖礦過程中只涉及engine的3個接口:1)Prepare()挖礦前的準備工作,2)Finalize()形成一個基本定型的區塊,3)Seal()形成最終的區塊。
- worker把區塊頭、交易、交易執行的收據等傳遞給engine.Finalize。
- engine.Finalize返回一個
block
,該block的header中缺少Nonce
和MixDigest
,這兩個值是挖礦獲取的。 - worker把block封裝到
work
,把work發送給所有的agent。 - agent.update把work傳遞給agent.mine。
- agent.mine把work傳遞給engine.Seal,調用engine.Seal挖礦。
- engine.Seal把
Nonce
和MixDigest
填到區塊頭,生成一個new block
交給agent.mine. - agent.mine把
new block
封裝成Result
,發送給worker。
礦工的主要函數
介紹miner、worker和agent的主要函數,他們是礦工的具體運作機制。
miner的主要函數
主要關注2個函數:
-
New()
:負責創建miner。還創建1個worker和1個agent,但agent還可以通過API創建,然後啓動update
函數。 -
update()
:負責關注downloader的3個事件:StartEvent、DoneEvent、FailedEvent。StartEvent是開始同步區塊,必須停止挖礦,DoneEvent和FailedEvent是同步成功或者失敗,是同步的結束,已經可以挖礦了。表明:挖礦和同步區塊不可同時進行,儘量降低了區塊衝突的可能。
worker的主要函數
主要是3個函數:
-
commitNewWork()
:負責生成work,分配agent。這個階段做了很多工作,調用Engine.Prepare進行準備工作,創建Header,執行交易,獲取Uncle,使用Engine.Finalize形成“基本定型”的臨時區塊,創建Work,最後把work傳遞給agent。另外commitNewWork
存在多處調用,並且worker有wait
和update
另外2個協程,他們都會調用commitNewWork
,所以存在臨界區需要謹慎加鎖。 -
update()
:負責處理外部事件。它是死循環,主要處理3種事件:1)ChainHeadEvent,有了新區塊頭,所以得切換到挖下一個高度的區塊,2)ChainSideEvent,收到了uncle區塊,緩存起來,3)TxPreEvent,預處理交易,如果在挖礦執行commitNewWork
,如果未挖礦,則交易設置爲未決狀態。 -
wait()
:負責處理agent挖礦的結果。它是死循環,一直等待接收agent發回的result,然後把區塊加入到本地數據庫,如果沒有問題,就發佈NewMinedBlockEvent
事件,通告其他節點挖到了一個新塊。
agent的主要函數
主要2個函數:
-
update()
:負責接收worker發來的任務(work)。它是死循環,把work交給mine去挖礦。 -
mine()
:負責挖礦。它擁有挖礦的能力,調用Engine.Seal挖礦,如果挖礦成功則生成result,發送給worker。
最後兩張圖片來源網絡,侵刪。