目錄
1 名詞介紹
2 礦工投票方法
3 委員會確定投票流程
3.1 關鍵概念描述
3.1.1 Epoch & checkpointInterval
3.1.2 Snapshot
3.2 投票方法
1.名詞介紹
節點:普通的以太坊節點,沒有區塊生成的權利。
礦工:具有區塊生成權利的以太坊節點
委員會:所有礦工的集合
2.礦工投票方法
-
用戶通過RPC接口,調用Propose(address common.Address, auth bool)方法(consensus/clique/api.go),進行投票,address表示要投票的節點的地址,auth表示要從將該地址加入委員會,還是從委員會中刪除。
-
Propose方法將address和auth兩個輸入參數寫入到clique.proposals集合中。
-
任何一個委員會的委員,可以在任意時刻進行投票,投票包括兩種,即加入委員會和從委員會中刪除。
3.委員會確定投票流程
3.1 關鍵概念描述
3.1.1 Epoch & checkpointInterval
-
CheckpointInterval:為常量1024(consensus/clique/clique.go中定義),即每當區塊鏈的高度為1024的整數倍時,到達checkpointInterval時間點。
-
Epoch:默認為30000(cmd/puppet/wizard_genesis.go中makeGenesis方法中定義),即每當區塊鏈的高度為30000的整數倍時,到達Epoch時間點。
3.1.2 Snapshot
Snapshot是一個快照,礦工程序在區塊鏈高度為CheckpointInterval的整數倍時,會對當前相關數據和狀態形成快照,並存儲到數據庫中。
snapshot結構體(consensus/clique/snapshot.go)關鍵成員:
-
Number:生成快照時的區塊鏈高度
-
Signers:生成快照時的委員會地址
-
Votes:生成快照時所有的投票集合
-
Tally:被投票的節點集合,其中的Tally是該節點被投票的次數
3.2投票方法
所有投票都是在委員生成新區塊的過程中完成,具體流程如下:
1)委員生成新區塊時,先為該區塊初始化一個header。(prepare方法,consensus/clique/clique.go)
2)從proposals中隨機獲取一個投票,將被投票的節點地址寫入header.coinbase,將提名是添加還是刪除寫入header.Nonce(添加:0xffffffffffffffff 刪除:0),若該委員生成的這個區塊最終被寫入區塊鏈,則header中的投票也被寫入區塊鏈。(prepare方法,consensus/clique/clique.go)
3)委員在生成新區塊時,會創建新的snapshot,新的snapshot是由上一checkponitinterval時間點存儲到數據庫中的快照加入當前時間點和checkpointinterval時間點之間所有的headers數據組成。添加header過程中,若該header的number是Epoch時間點,則會將snap中的Votes和Tally兩個集合清零。
(apply方法,consensus/clique/snapshot.go)
4)新的snapshot添加header過程中,會檢查每一個header中存儲的投票,若該投票snap.Votes中已經存在,則將snap.Votes和snap.Tally兩個集合的該投票刪除。
(apply方法,consensus/clique/snapshot.)
將每一個header中有效的提名寫入新snapshot的snap.Votes和snap.Tally集合。(apply方法,consensus/clique/snapshot.go)
5)判斷snap.Tally集合中某個被提名的節點,提名的次數是否大於snap.Signers的1/2,即是否有超過一半的委員對該節點進行投票,若超過,則投票成功,該節點會被添加到委員會或者從委員會中刪除。
(apply方法,consensus/clique/snapshot.go)
注釋:snapshot快照中的記錄的委員會,即Signers集合,初始化時來源於創世塊header中的Extra