使用Parity建立Proof-of-Authority (PoA) Ethereum Chain
5分鐘快速從無到有建立Ethereum聯盟鏈
開發Ethereum Dapp的過程中,需要一個測試用的chain,之前是使用testrpc或直接連到Ethereum testnet (Ropsten),不過testrpc有各種雷需要處理,而Ropsten testnet則是需要同步與等待block,相當的煩人。前幾天看到Parity 1.5版以後支援建立Proof of Authority Chains,可以直接解決上述的問題,果然一試成主顧。
若你有下列困擾,可以建立自己測試用的PoA chain
- 公司內網或無對外網路,無法同步區塊
- 降低測試時等待區塊的時間
- 不想碰到testrpc各種雷
PoA Chain特點有
- 有別於PoW (Proof-of-Work)需要解數學難題來產生block,PoA是依靠預設好的Authority nodes,負責產生block。
- 可依照需求設定Authority node數量。
- 可指定產生block的時間,例如收到交易的5秒後產生block。
- 一般的Ethereum node也可以連接到PoA Chain,正常發起transactions, contracts等。
這篇教學文基本上是照著Parity Demo PoA tutorial來撰寫。
Parity是一個注重效能的Ethereum Client端軟體
1. 安裝Parity (1.5.0以上版本)
請自行到Parity官網安裝,支援Ubutnu, OSX, Docker, Windows
2. 設定chain spec
PoA chain需要設定一個創世區塊
{
"name": "DemoPoA",
"engine": {
"authorityRound": {
"params": {
"gasLimitBoundDivisor": "0x400",
"stepDuration": "5",
"validators" : {
"list": []
}
}
}
},
"params": {
"maximumExtraDataSize": "0x20",
"minGasLimit": "0x1388",
"networkID" : "0x2323"
},
"genesis": {
"seal": {
"authorityRound": {
"step": "0x0",
"signature": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
}
},
"difficulty": "0x20000",
"gasLimit": "0x5B8D80"
},
"accounts": {
"0x0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
"0x0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
"0x0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
"0x0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }
}
}
stepDuration
設定成5秒產生一個區塊validators
設定Authority的地方,目前先空著,後續產生account之後再回來填入
將上述資料存成 demo-spec.json
3. 設定兩個node
此教學會在同一台機器上跑兩個node,因此有些Parity原生的設定參數會有衝突,兩個node需要分別設定不同值。
-d
指定儲存資料與帳號的目錄--dport
指定Parity的network port,可用來讓其他node連接--jsonrpc-port
這是JSON RPC port,使用web3.js時會需要ui-port
Parity提供的Web-based UI portdapps-port
Parity Dapps使用的port
可以用下列指令啟動Parity node
parity --chain demo-spec.json -d /tmp/parity0 --port 30300 --jsonrpc-port 8540 --ui-port 8180 --dapps-port 8080 --jsonrpc-apis web3,eth,net,personal,parity,parity_set,traces,rpc,parity_accounts
除了打一長串的指令外,Parity也提供更為簡潔的config檔案設定方式,使用 --config
即可引用設定檔。
node0
使用如下設定檔 node0.toml
[parity]
chain = "demo-spec.json"
base_path = "/tmp/parity0"
[network]
port = 30300
[rpc]
port = 8540
apis = ["web3", "eth", "net", "personal", "parity", "parity_set", "traces", "rpc", "parity_accounts"]
[ui]
port = 8180
[dapps]
port = 8080
node1
使用如下設定檔 node1.toml
[parity]
chain = "demo-spec.json"
base_path = "/tmp/parity1"
[network]
port = 30301
[rpc]
port = 8541
apis = ["web3", "eth", "net", "personal", "parity", "parity_set", "traces", "rpc", "parity_accounts"]
[ui]
port = 8181
[dapps]
port = 8081
4. 設定帳號(Account)
我們總共要開3個帳號:2個Authority跟1個user帳號。
Step 1 首先啟動 node0
: parity --config node0.toml
接著開啟網頁 http://localhost:8180
我不知道怎麼略過WELCOME操作,所以先跟著指示隨便建立一個account,然後再刪除XD
接著新增一個user account,使用Recover account from recovery phrase功能,為了示範的一致性,使用 user
當作pass phrase
新增Authority account,一樣使用Recover account from recovery phrase功能,為了示範的一致性,使用 node0
當作pass phrase
這樣就完成 node0
的帳號設定
- Authority account:
0x00Bd138aBD70e2F00903268F3Db08f2D25677C9e
- User account:
0x004ec07d2329997267Ec62b4166639513386F32E
Step 2 再來設定 node1
的帳號,啟動 parity --config node1.toml
,步驟相同,連接到 http://localhost:8181
,pass phrase使用 node1
這樣就完成 node1
的帳號設定
- Authority account:
0x00Aa39d30F0D20FF03a22cCfc30B7EfbFca597C2
Step 3 將Authority account寫入 demo-spec.json
檔案
"validators" : {
"list": [
"0x00Bd138aBD70e2F00903268F3Db08f2D25677C9e",
"0x00Aa39d30F0D20FF03a22cCfc30B7EfbFca597C2"
]
}
再將user account加入accounts,並給一些balance,後續可以使用
"0x004ec07d2329997267Ec62b4166639513386F32E": { "balance": "10000000000000000000000" }
完成後的demo-spec.json如下
{
"name": "DemoPoA",
"engine": {
"authorityRound": {
"params": {
"gasLimitBoundDivisor": "0x400",
"stepDuration": "5",
"validators" : {
"list": [
"0x00Bd138aBD70e2F00903268F3Db08f2D25677C9e",
"0x00Aa39d30F0D20FF03a22cCfc30B7EfbFca597C2"
]
}
}
}
},
"params": {
"maximumExtraDataSize": "0x20",
"minGasLimit": "0x1388",
"networkID" : "0x2323"
},
"genesis": {
"seal": {
"authorityRound": {
"step": "0x0",
"signature": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
}
},
"difficulty": "0x20000",
"gasLimit": "0x5B8D80"
},
"accounts": {
"0x0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
"0x0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
"0x0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
"0x0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } },
"0x004ec07d2329997267Ec62b4166639513386F32E": { "balance": "10000000000000000000000" }
}
}
5. 啟動Authority node
為了啟動Authority node來產生區塊,我們必須設定負責產生block的signer,分別是 node0
與 node1
account
Step 1 開啟一個 node.pwds
檔案,寫入 node0
與 node1
的password,內容如下
node0
node1
Step 2 在設定檔 node0.toml
加入 [account]
及 [mining]
設定,如下
[parity]
chain = "demo-spec.json"
base_path = "/tmp/parity0"
[network]
port = 30300
[rpc]
port = 8540
apis = ["web3", "eth", "net", "personal", "parity", "parity_set", "traces", "rpc", "parity_accounts"]
[ui]
port = 8180
[dapps]
port = 8080
[account]
password = ["node.pwds"]
[mining]
engine_signer = "0x00Bd138aBD70e2F00903268F3Db08f2D25677C9e"
reseal_on_txs = "none"
Step 3 node1.toml
也一樣,如下
[parity]
chain = "demo-spec.json"
base_path = "/tmp/parity1"
[network]
port = 30301
[rpc]
port = 8541
apis = ["web3", "eth", "net", "personal", "parity", "parity_set", "traces", "rpc", "parity_accounts"]
[ui]
port = 8181
[dapps]
port = 8081
[account]
password = ["node.pwds"]
[mining]
engine_signer = "0x00Aa39d30F0D20FF03a22cCfc30B7EfbFca597C2"
reseal_on_txs = "none"
Step 4 分別啟動兩個node
parity --config node0.toml
parity --config node1.toml
6.連接兩個node
使用Postman透過JSON RPC來測試
Step 1 Post下列JSON資料至 http://localhost:8540
以取得 node0
的enode資料
{
"jsonrpc":"2.0",
"method":"parity_enode",
"params":[],
"id":0
}
Step 2 將 node0
的enode加入 node1
,Post下列JSON資料至node1
(http://localhost:8541
)
{
"jsonrpc":"2.0",
"method":"parity_addReservedPeer",
"params":["enode://6c4f53fc8536553c8f151516b7ee17f4b0719d21abe8fdd273588419cf467e3deafb414cd8efa331e4ad55fd7c2820a303a160895129e142a4306e7c3367d67c@172.20.160.80:30300"],
"id":0
}
你的IP位址會不一樣,172.20.160.80
最後到 node1
的console畫面,會看到 0/1/25 peers,就表示已經連接上。
7. 發送transaction
透過Parity提供的web-based UI可以很容易發送transaction,這邊就不贅述了。
補充:分享給區網內其他人使用
在開發時通常會將node跑在server上,讓其他人可以透過JSON RPC port連接上去使用,此時只要在config檔裡面加入 [interface]
設定即可。
假設server ip為192.168.1.1,將 node0.toml
修改如下:
[parity]
chain = "demo-spec.json"
base_path = "/tmp/parity0"
[network]
port = 30300
[rpc]
port = 8540
apis = ["web3", "eth", "net", "personal", "parity", "parity_set", "traces", "rpc", "parity_accounts"]
interface = "192.168.1.1"
[ui]
port = 8180
[dapps]
port = 8080
[account]
password = ["node.pwds"]
[mining]
engine_signer = "0x00Bd138aBD70e2F00903268F3Db08f2D25677C9e"
reseal_on_txs = "none"
同樣 node1.toml
修改如下:
[parity]
chain = "demo-spec.json"
base_path = "/tmp/parity1"
[network]
port = 30301
[rpc]
port = 8541
apis = ["web3", "eth", "net", "personal", "parity", "parity_set", "traces", "rpc", "parity_accounts"]
interface = "192.168.1.1"
[ui]
port = 8181
[dapps]
port = 8081
[account]
password = ["node.pwds"]
[mining]
engine_signer = "0x00Aa39d30F0D20FF03a22cCfc30B7EfbFca597C2"
reseal_on_txs = "none"