以太坊原始碼分析(53)以太坊測試網路Clique_PoA介紹

尹成發表於2018-05-14
https://github.com/ethereum/EIPs/issues/225

Clique的模式下,使用者是無法獲取以太幣的,因為無法挖礦,所以如果需要以太幣, 需要通過特殊的途徑來獲取。

可以通過這個網站獲取ether

https://faucet.rinkeby.io/

需要有google+賬號,facebook或者twitter賬號才能獲取, 詳細的獲取辦法參考上面的網站。



Clique 是以太坊的一個Power of authority 的實現, 現在主要在Rinkeby 測試網路使用。

## 背景

以太坊的第一個官方測試網是Morden。它從2015年7月到2016年11月,由於Geth和Parity之間累積的垃圾和一些testnet的共識問題,最終決定停止重新啟動testnet。

Ropsten就這樣誕生了,清理掉了所有的垃圾,從一個乾淨的石板開始。這一執行狀況一直持續到2017年2月底,當時惡意行為者決定濫用Pow,並逐步將GasLimit從正常的470萬提高到90億,此時傳送巨大的交易損害整個網路。甚至在此之前,攻擊者嘗試了多次非常長的區塊鏈重組,導致不同客戶端之間的網路分裂,甚至是不同的版本。

這些攻擊的根本原因在於PoW網路的安全性與它背後的計算能力一樣安全。從零開始重新啟動一個新的測試網路並不能解決任何問題,因為攻擊者可以反覆安裝相同的攻擊。Parity 團隊決定採取一個緊急的解決辦法,回滾大量的區塊,制定一個不允許GasLimit超過一定門檻的軟交叉。

雖然這個解決方案可能在短期內工作:

這並不高雅:以太坊應該有動態的限制
這不是可移植的:其他客戶需要自己實現新的fork邏輯
它與同步模式不相容:fast sync和輕客戶端都運氣不佳
這只是延長了攻擊的時間:垃圾依然可以在無盡的情況下穩步推進
Parity的解決方案雖然不完美,但仍然可行。我想提出一個更長期的替代解決方案,涉及更多,但應該足夠簡單,以便能夠在合理的時間內推出。


## 標準化的PoA

如上所述,在沒有價值的網路中,Pow不能安全地工作。 以太坊有以Casper為基礎的長期PoS目標,但是這是一個繁瑣的研究,所以我們不能很快依靠這個來解決今天的問題。 然而,一種解決方案很容易實施,而且足夠有效地正確地修復測試網路,即權威證明方案(proof-of-authority scheme)。

注意,Parity確實有PoA的實現,雖然看起來比需要的更復雜,沒有太多的協議文件,但是很難看到它可以和其他客戶一起玩。 我歡迎他們基於他們的經驗來給我的這個提案更多的反饋。

這裡描述的PoA協議的主要設計目標是實現和嵌入任何現有的以太坊客戶端應該是非常簡單的,同時允許使用現有的同步技術(快速,輕鬆,扭曲),而不需要客戶端開發者新增 定製邏輯到關鍵軟體。

## PoA101

對於那些沒有意識到PoA如何運作的人來說,這是一個非常簡單的協議,而不是礦工們為了解決一個困難的問題而競相爭奪,授權簽署者可以隨時自行決定是否建立新的塊。

挑戰圍繞著如何控制挖礦頻率,如何在不同的簽名者之間分配負載(和機會)以及如何動態調整簽名者列表。 下一節定義一個處理所有這些場景的建議協議。

## Rinkeby proof-of-authority

總體來說,有兩種同步區塊鏈的方法:

- 傳統的方法是把所有的事務一個接一個地進行起始塊和緊縮。這種方式嘗試過而且已經被證明在以太坊這種複雜的網路中非常耗費計算資源。
另一種是隻下載區塊鏈頭並驗證它們的有效性,此後可以從網路上下載一個任意的最近的狀態並檢查最近的header。
- PoA方案基於這樣的想法,即塊可能只能由可信簽署人完成。 因此,客戶端看到的每個塊(或header)都可以與可信任的簽名者列表進行匹配。 這裡面臨的挑戰是如何維護一個可以及時更改的授權簽名者列表? 明顯的答案(將其儲存在以太坊合同中)也是錯誤的答案:在快速同步期間是無法訪問狀態的。

**維護授權簽名者列表的協議必須完全包含在塊頭中。**

下一個顯而易見的想法是改變塊標題的結構,這樣就可以放棄PoW的概念,並引入新的欄位來迎合投票機制。 這也是錯誤的答案:在多個實現中更改這樣一個核心資料結構將是一個開發,維護和安全的噩夢。

**維護授權簽名者列表的協議必須完全適合當前的資料模型。**

所以,根據以上所述,我們不能使用EVM進行投票,而是不得不求助於區塊頭。 而且我們不能改變區塊頭欄位,而不得不求助於當前可用的欄位。 沒有太多的選擇。

### 把區塊頭的一些其他欄位用來實現投票和簽名

當前僅用作有趣後設資料的最明顯的欄位是塊頭中的32位元組的ExtraData部分。 礦工們通常把他們的客戶端和版本放在那裡,但是有些人用另外的“資訊”填充它們。 該協議將擴充套件此欄位以增加65位元組用來存放礦工的KEC簽名。 這將允許任何獲得一個區塊的人員根據授權簽名者的名單對其進行驗證。 同時它也使得區塊頭中的礦工地址的欄位作廢。

請注意,更改區塊頭的長度是非侵入性操作,因為所有程式碼(例如RLP編碼,雜湊)都不可知,所以客戶端不需要定製邏輯。

以上就足以驗證一個鏈,但我們如何更新一個動態的簽名者列表。 答案是,我們可以重新使用新近過時的礦工欄位beneficiary和PoA廢棄的nonce欄位來建立投票協議:

- 在常規塊中,這兩個欄位都將被設定為零。
- 如果簽名者希望對授權簽名人列表進行更改,則會:
    - 將礦工欄位**beneficiary**設定為希望投票的簽署者
    -**nonce**設定為0或0xff ... f來投票贊成新增或踢出

任何同步鏈的客戶端都可以在資料塊處理過程中“統計”選票,並通過普通投票保持授權簽名者的動態變化列表。 初始的一組簽名者通過創世區塊的引數提供(以避免在起始狀態中部署“最初選民名單”合同的複雜性)。

為了避免有一個無限的視窗來統計票數,並且允許定期清除陳舊的提議,我們可以重新使用ethash的概念 epoch,每個epoch 轉換都會重新整理所有未決的投票。 此外,這些epoch 轉換還可以作為包含頭部額外資料內的當前授權簽名者列表的無狀態檢查點。 這允許客戶端僅基於檢查點雜湊進行同步,而不必重播在鏈上進行的所有投票。 它同樣允許用包含了初始簽名者的創世區塊來完全定義區塊鏈

### 攻擊媒介:惡意簽名者

可能發生惡意使用者被新增到簽名者列表中,或者簽名者金鑰/機器受到威脅。 在這種情況下,協議需要能夠抵禦重組和垃圾郵件。 所提出的解決方案是,給定N個授權簽名者的列表,任何簽名者可能只在每個K中填充1個塊。這確保損害是有限的,其餘的礦工可以投出惡意使用者。

## 攻擊媒介:審查簽名者

另一個有趣的攻擊媒介是如果一個簽名者(或者一組簽名者)試圖檢查出從授權列表中刪除它們的塊。 為了解決這個問題,我們限制了簽名者允許的最小頻率為N / 2。 這確保了惡意簽名者需要控制至少51%的簽名帳戶,在這種情況下,遊戲就是無論如何也無法進行下去了。

## 攻擊媒介:垃圾郵件簽名者

最後的小型攻擊媒介就是惡意簽署者在每一個塊內注入新的投票建議。 由於節點需要統計所有投票來建立授權簽名者的實際列表,所以他們需要通過時間跟蹤所有投票。 沒有限制投票視窗,這可能會慢慢增長,但卻是無限的。 解決方法是放置一個W塊的移動視窗,之後投票被認為是陳舊的。 一個理智的窗戶可能是1-2個時代。 我們將這稱為一個時代。

## 攻擊媒介:併發塊

如果授權簽名者的數量是N,並且我們允許每個簽名者在K中填充1個塊,那麼在任何時間N-K個礦工都被允許為Mint。 為了避免這些爭奪塊,每個簽名者將新增一個小的隨機“抵消”,以釋放一個新的塊。 這確保了小叉子是罕見的,但偶爾還會發生(如在主網上)。 如果一個簽名者被濫用權威而引起混亂,那麼這個簽名就可以被投票出去。

## 注意

### 這是否表明建議我們使用一個被審查testnet?

該提議表明,考慮到某些行為者的惡意性質,並且鑑於“壟斷資金”網路中PoW計劃的弱點,最好是建立一個網路,使其具有一定的垃圾過濾功能,開發人員可以依靠它來測試其程式。

為什麼規範PoA?

不同的客戶在不同的情況下會更好。 Go可能在伺服器端環境中很棒,但CPP可能更適合在RPI Zero上執行。

手動投票是不是很麻煩?

這是一個實現細節,但是簽名者可以利用基於合同的投票策略,利用EVM的全部功能,只將結果推送到平均節點的頭部進行驗證。

## 澄清和反饋

- 這個建議並不排除客戶端執行基於PoW的測試網路,無論是Ropsten還是基於它的新的測試網路。理想的情況是客戶提供一種連線PoW以及基於PoA的測試網路的方法(#225(評論))。

- 協議引數儘管可以在客戶端實施者的破壞中進行配置,但Rinkeby網路應該儘可能地靠近主網路。這包括動態GasLimit,15秒左右的可變區塊時間,GasPrice等(#225(評論))。

- 該方案要求至少有K個簽名者隨時上網,因為這是確保“最小化”多樣性所需的最少人數。這意味著如果超過K,則網路停止。這應該通過確保簽名者是高執行時間的機器來解決,並且在發生太多故障之前及時地將失敗的機器投票出去(#225(評論))。

- 該提案並沒有解決“合法的”垃圾郵件問題,就像在攻擊者有效地使用testnet以建立垃圾一樣,但是如果沒有PoW挖掘,攻擊者可能無法獲得無限的ether來攻擊。一種可能性是以有限的方式(例如每天10次)(#225(評論)),以GitHub(或其他任何方式)帳戶為基礎提供一個獲取ether的途徑。

- 有人建議為當時包含授權簽名者列表的每個epoch建立checkpoint block。這將允許稍後的輕客戶說“從這裡同步”,而不需要從起源開始。這可以在簽名之前作為字首新增到extradata欄位(#225(comment))。


## Clique PoA 一致性協議 (Clique proof-of-authority consensus protocol )
我們定義下面的常量:

- EPOCH_LENGTH:檢查點並重置未決投票的塊數。
    - 建議30000,以便和主網路的ethhash epoch類似
- BLOCK_PERIOD:兩個連續塊的時間戳之間的最小差異。
    - 建議15,以便和主網路的ethhash epoch類似
- EXTRA_VANITY:固定數量的ExtraData字首位元組為簽名者vanity保留。
    - 建議的32個位元組以便和當前的ExtraData的長度相同。
- EXTRA_SEAL:為簽名者印章保留的固定數量的額外資料字尾位元組。
    - 儲存簽名的65個位元組,基於標準secp256k1曲線。
- NONCE_AUTH:魔術隨機數字0xffffffffffffffff投票新增一個新的簽名者。
- NONCE_DROP:魔術隨機數字0x0000000000000000對移除簽名者進行投票。
- UNCLE_HASH:始終Keccak256(RLP([]))作為Uncles在PoW之外沒有任何意義。
- DIFF_NOTURN:如果當前沒有輪到你簽名,那麼你簽名的區塊的難度就是這個難度。
    - 建議1,因為它只需要是一個任意的基線常數。
- DIFF_INTURN:如果當前輪到你簽名,那麼你簽名的難度。
    - 建議2, 這樣就比沒有輪到的簽名者難度要高。

我們還定義了以下每塊的常量:

- BLOCK_NUMBER:鏈中的塊高度,創世區塊的高度是0。
- SIGNER_COUNT:在區塊鏈中中特定例項上有效的授權簽名者的數量。
- SIGNER_INDEX:當前授權簽名者的排序列表中的索引。
- SIGNER_LIMIT:每隔這麼多塊,簽名者只能簽署一塊。
    - 必須有floor(SIGNER_COUNT / 2)+1 這麼多簽名者同意才能達成某項決議。

我們重新調整區塊頭欄位的用途,如下所示:

- beneficiary:建議修改授權簽名人名單的地址。
    - 應該正常填寫零,只有投票時修改。
    - 儘管如此,仍然允許任意值(甚至是無意義的值,例如投出非簽名者),以避免增加圍繞投票機制的額外複雜性。
    - 必須在檢查點(即epoch轉換)塊填充零。
- nonce:Signer關於受益人欄位中定義的賬戶的建議。
    - NONCE_DROP 提議取消授權受益人作為現有簽名者。
    - NONCE_AUTH 提出授權受益人作為新的簽名者。
    - 必須在檢查點塊填充零。
    - 除了上述兩者(現在)之外,不得采用任何其他值。
- extraData: vanity, checkpointing and signer signatures的組合欄位。
    - 第一個EXTRA_VANITY位元組(固定長度)可以包含任意簽名者vanity data。
    - 最後一個EXTRA_SEAL位元組(固定長度)是密封標題的簽名者簽名。
    - 檢查點塊必須包含一個簽名者列表(N * 20位元組),否則省略。
    - 檢查點塊附加資料部分中的簽署者列表必須按升序排序。
- mixHash:為了分叉保留。類似於Dao的額外資料
    - 在正常操作期間必須填入零。
- ommersHash:必須是UNCLE_HASH,因為在PoW之外,Uncles叔沒有任何意義。
- timestamp:必須至少為父區塊的時間戳 + BLOCK_PERIOD。
- difficulty:包含塊的獨立得分 來推導鏈的質量。
    - 如果BLOCK_NUMBER%SIGNER_COUNT!= SIGNER_INDEX,則必須為DIFF_NOTURN
    - 如果BLOCK_NUMBER%SIGNER_COUNT == SIGNER_INDEX,則必須為DIFF_INTURN


### Authorizing a block
為了給網路授權一個塊,簽名者需要簽署包含除簽名本身以外的所有內容。 這意味著雜湊包含區塊頭的每個欄位(包括nonce和mixDigest),還有除了65位元組簽名字尾外的extraData。 這些欄位按照其在黃皮書中定義的順序進行hash。

該雜湊使用標準的secp256k1曲線進行簽名,得到的65位元組簽名(R,S,V,其中V為0或1)作為尾隨的65位元組字尾嵌入到extraData中。

為了確保惡意簽名者(簽名金鑰丟失)不能在網路上受到破壞,每位簽名者都可以在SIGNER_LIMIT連續塊中籤最多一個。 順序不是固定的,不過(DIFF_INTURN)的簽名者簽出的區塊難度要比(DIFF_NOTURN)高

#### 授權策略

只要簽名者符合上述規範,他們可以授權和分配他們認為合適的塊, 下面的建議策略會減少網路流量和分叉,所以這是一個建議的功能:

- 如果簽署者被允許簽署一個區塊(在授權清單上並且最近沒有簽署)。
    - 計算下一個塊的最佳簽名時間(父+ BLOCK_PERIOD)。
    - 如果輪到了,等待準確的時間到達,立即簽字和播放。
    - 如果沒有輪到,則延遲 rand(SIGNER_COUNT * 500ms)這麼久的時間簽名。
這個小小的策略將確保當前輪到的簽名者(誰的塊更重)對簽名和傳播與外轉簽名者有稍微的優勢。 此外,該方案允許隨著簽名者數目的增加而具有一定規模。

### 投票簽署者

每個epoch轉換(包括創世區塊)作為一個無狀態的檢查點,有能力的客戶端應該能夠同步而不需要任何以前的狀態。 這意味著新epoch header不得包含投票,所有未落實的投票都將被丟棄,並從頭開始計數。

對於所有非epoch 轉換塊:

- 簽名者可以使用自己簽署的區塊投一票,以提出對授權列表的更改。
- 對每一個提案只保留最新的一個投票。
- 隨著鏈條的進展,投票也會生效(允許同時提交提案)。
- 達成多數人意見的提案SIGNER_LIMIT立即生效。
- 對於客戶端實現的簡單性,無效的提議不會受到懲罰。


**生效的提案意味著放棄對該提案的所有未決投票(無論是贊成還是反對),並從一個清晰的名單開始。**

### 級聯投票

簽名者取消授權期間可能會出現複雜的案例。如果先前授權的簽署者被撤銷,則批准提案所需的簽名者數量可能會減少一個。這可能會導致一個或多個未決的提案達成共識,執行這些提案可能會進一步影響新的提案。

當多個相沖突的提議同時通過時(例如,新增新的簽名者vs刪除現有的提案者),處理這種情況並不明顯,評估順序可能會徹底改變最終授權列表的結果。由於簽名者可能會在他們自己的每一個區塊中反轉他們自己的投票,所以哪一個提案將是“第一”並不那麼明顯。

為了避免級聯執行所帶來的缺陷,解決的辦法是明確禁止級聯效應。換句話說:只有當前標題/投票的受益人可以被新增到授權列表或從授權列表中刪除。如果這導致其他建議達成共識,那麼當他們各自的受益者再次“觸發”時,這些建議將被執行(因為大多數人的共識仍然在這一點上)。

### 投票策略

由於區塊鏈可以有很小的reorgs,所以“cast-and-forget”的天真投票機制可能不是最優的,因為包含singleton投票的區塊可能不會在最終的鏈中結束。

一個簡單但工作的策略是允許使用者在簽名者上配置“提案”(例如“add 0x ...”,“drop 0x ...”)。 簽署的程式碼,然後可以選擇一個隨機的建議,每塊它簽署和注入。 這確保了多個併發提案以及reorgs最終在鏈上被注意到。

這個列表可能在一定數量的塊/epoch後過期,但重要的是要認識到“看”一個提案通過並不意味著它不會被重新組合,所以當提案通過時不應該立即放棄。




網址:http://www.qukuailianxueyuan.io/



欲領取造幣技術與全套虛擬機器資料

區塊鏈技術交流QQ群:756146052  備註:CSDN

尹成學院微信:備註:CSDN



相關文章