geth基於PoA共識機制構建聯盟鏈

1 PoA共識機制

PoW機制的缺陷

以太坊現階段是基於PoW共識機制,PoW工作量證明機制就是區塊鏈網路中一堆計算機通過計算隨機數的Hash值,誰先找到這個隨機數誰就贏的當前區塊的記賬權。PoW通過比拼算力,誰的算力大,誰就能夠搶到記賬權。這樣導致網路大量算力用來計算毫無意義的隨機數工作中去了,而真正用來打包和驗證的算力就受到影響。

  • PoW機制存在51%算力共計問題。只要挖礦者掌握全網51%算力就能控制整個網路。
  • PoW機制消耗大量電力。
  • PoW機製造成了以太坊網路算力的損失,從而無法支援很高的tps。

PoA共識機制

所謂授權證明PoA(Proofof Authority),就是由一組授權節點來負責新區塊的產生和區塊驗證。以太坊測試網(Kovan)便是採用PoA演算法。以太坊原始碼中帶有Clique共識演算法即為一種PoA共識演算法。

在PoA中,驗證者(validator)是整個共識機制的關鍵。驗證者不需要昂貴的顯示卡,也不需要足夠的資產,但他必須具有已知的,並且已獲得驗證的身份。驗證者通過放置這個身份來獲得擔保網路的權利,從而換取區塊獎勵。若是驗證者在整個過程中有惡意行為,或與其他驗證者勾結。那通過鏈上管理可以移除和替換惡意行為者。現有的法律反欺詐保障會被用於整個網路的參與者免受驗證者的惡意行為。


PoA共識機制的特點

PoA是依靠預設好的授權節點(signers),負責產生block.可以由已授權的signer選舉(投票超過50%)加入新的signer。即使存在惡意signer,他最多隻能攻擊連續塊(數量是 (SIGNER_COUNT / 2) 1) 中的1個,期間可以由其他signer投票踢出該惡意signer。可指定產生block的時間。

2 PoA聯盟鏈搭建


準備工作

在ubuntu系統中首先安裝geth客戶端,這裡使用geth 1.8.8版本。
然後建立三個資料夾,分別是bootdir,boot1,boot2三個資料夾。在bootdir資料夾中建立bootnode節點用來做p2p網路路由。使用命令 sudo bootnode –genkey boot.key來建立名為boot.key的key檔案。
然後使用 sudo bootnode –nodekey boot.key 命令啟動bootnode路由節點。
建立賬戶


使用puppeth來產生創世檔案

puppeth是geth自帶的程式,可以引導使用者建立geth的創世檔案。執行puppeth

[email protected]:/home/lzj/boot1# sudo puppeth
----------------------------------------------------------- 
| Welcome to puppeth, your Ethereum private network manager |
|                                                           |
| This tool lets you create a new Ethereum network down to  |
| the genesis block, bootnodes, miners and ethstats servers |
| without the hassle that it would normally entail.         |
|                                                           |
| Puppeth uses SSH to dial in to remote servers, and builds |
| its network components out of Docker containers using the |
| docker-compose toolset.                                   |
----------------------------------------------------------- 
Please specify a network name to administer (no spaces or hyphens, please)
> lzj
Sweet, you can set this via --network=lzj next time!
INFO [06-23|17:10:34] Administering Ethereum network           name=lzj
INFO [06-23|17:10:34] No remote machines to gather stats from 
What would you like to do? (default = stats)
1. Show network stats
2. Configure new genesis
3. Track new remote server
4. Deploy network components
> 2
Which consensus engine to use? (default = clique)
1. Ethash - proof-of-work
2. Clique - proof-of-authority
> 2
How many seconds should blocks take? (default = 15)
> 2
Which accounts are allowed to seal? (mandatory at least one)
> 0xd71ad920f80e6a1e06689a720f24b335f22d557e
> 0x8bbc43acd355be0cecc61872e13e0a0e53c700b7
> 0x
Which accounts should be pre-funded? (advisable at least one)
> 0x0xd71ad920f80e6a1e06689a720f24b335f22d557e
ERROR[06-23|17:11:33] Invalid address length, please retry 
> 0xd71ad920f80e6a1e06689a720f24b335f22d557e
> 0x
Specify your chain/network ID if you want an explicit one (default = random)
> 1500
INFO [06-23|17:12:05] Configured new genesis block 
What would you like to do? (default = stats)
1. Show network stats
2. Manage existing genesis
3. Track new remote server
4. Deploy network components
> 2
1. Modify existing fork rules
2. Export genesis configuration
3. Remove genesis configuration
> 2
Which file to save the genesis into? (default = lzj.json)
> genesis.json
INFO [06-23|17:12:27] Exported existing genesis block 
What would you like to do? (default = stats)
1. Show network stats
2. Manage existing genesis
3. Track new remote server
4. Deploy network components
> ^C
[email protected]:/home/lzj/boot1# ls
genesis.json  keystore
[email protected]:/home/lzj/boot1# 

將在boot1目錄下產生genesis.json檔案,將這個檔案拷貝到boot2目錄下去

初始化boot1和boot2倆個節點

/home/lzj/boot1# sudo geth --datadir ./ init genesis.json
/home/lzj/boot2# sudo geth --datadir ./ init genesis.json

啟動boot1節點

boot1節點啟動挖礦

boot1節點這個時候挖出了區塊1,在等待其它節點加入。

啟動boot2節點

因為在同一臺機器上,所以要注意boot2的port埠和rpc埠跟boot1的有所不同。

boot2啟動挖礦

boot1節點:

boot2節點:

可以看到倆個節點都在挖礦,每個區塊產生間隔2s,每個節點挖礦間隔4s。

3 發起交易

在boot1節點再新建一個賬戶,從賬號0給新建賬號1轉賬:

> eth.sendTransaction({from:eth.coinbase,to:eth.accounts[1],value:web3.toWei(100,"ether")})

查詢賬號1的餘額:

web3.fromWei(eth.getBalance(eth.accounts[1])
100

然後再boot2新建一個賬號,從boot1的賬號1給boot2的新建賬號轉賬:

eth.sendTransaction({from:eth.accounts[1],to:"0xa114e1381cfa44d66682cbff4e7aa5f788c44a64",value:web3.toWei(10,"ether")})

查詢boot1的賬戶餘額:

> web3.fromWei(eth.getBalance(eth.accounts[1]))
89.999622

查詢boot2的賬戶1餘額:

> web3.fromWei(eth.getBalance("0xa114e1381cfa44d66682cbff4e7aa5f788c44a64"))
10

可見從從boot1的賬號0給賬號1轉賬100ether的交易成功,此時boot1的賬號1有錢100ether。從boot1的賬號1給boot2的賬號1轉賬10ether的交易也成功了,boot2的賬號1收到了10ether,轉賬後boot1的賬號1只剩下89.9996222ether,說明轉賬是收取了gas費用。

4 新加節點並提名挖礦

新建目錄boot3,拷貝創世檔案genesis.json到該目錄,然後按照前面的放方法啟動節點

建立新賬號

初始化節點

[email protected]:~/boot3$ sudo geth --datadir ./ init genesis.json

啟動節點

開始同步了:

這個時候由於boot3節點的賬號不在genesis.json指定的驗證節點列表裡,所以無法挖礦,驗證一下:

報了未授權的錯誤: 

WARN [06-25|10:45:09] Block sealing failed                     err=unauthorized

現在共有3個節點,所以需要一半以上的節點提名節點3的根賬號,它才能被加入驗證人列表。在boot1節點和boot2節點提名boot3的根賬號:

> clique.propose("0x5b5bb21eb5dede180d97fd014e3d4fb277b08dee",true)

這個時候boot3挖礦成功了:

5 踩坑記錄

(1)啟動節點挖礦時,需要帶上標誌–syncmode “full”,否則彙報錯誤:

Clique : Discarded bad propagated block#1 when syncing

(2)啟動節點挖礦時,需要在啟動時帶上 –unlock “賬號”,否則會在挖礦一定時間後會報挖礦失敗,需要解鎖的錯誤。