1. 程式人生 > >以太坊如何搭建私有連聯盟鏈

以太坊如何搭建私有連聯盟鏈

如何啟動geth節點對大家來說已經不是什麼難事,今天博主就帶大家學習一下如何搭建兩個節點的聯盟鏈。

私有鏈的建立

在之前的文章中我們已經講到過私有鏈的建立,本篇文章我們會有道私有鏈建立的知識,就重新溫故一下。建立私有鏈首先需要指定創始塊的配置,也就是genesis.json的配置。此檔案就是一個內容格式為json的文字檔案。

配置檔案的內容格式基本如下:

{
 "alloc": {},
 "config": {
   "chainID": 72,
   "homesteadBlock": 0,
   "eip155Block": 0,
   "eip158Block": 0
 },
 "nonce
": "0x0000000000000000", "difficulty": "0x4000", "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000", "coinbase": "0x0000000000000000000000000000000000000000", "timestamp": "0x00", "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa", "gasLimit": "0xffffffff" }

配置項簡介

我們對配置項的內容進行一下簡單的介紹。

alloc: 用來預置賬號以及賬號的以太幣數量,因為私有鏈挖礦比較容易,所以不需要預置有幣的賬號,需要的時候自己建立即可以。例項程式碼如下:

"alloc": {
    "de1e758511a7c67e7db93d1c23c1060a21db4615": {
      "balance": "1000"
    },
    "27dc8de9e9a1cb673543bd5fce89e83af09e228f": {
      "balance": "1100"
    },
    "d64a66c28a6ae5150af5e7c34696502793b91ae7": {
      "balance": "900"
    }

nonce:一個64位隨機數,用於挖礦,和mixhash的設定需要滿足以太坊的Yellow paper, 4.3.4.Block Header Validity (44)章節所描述的條件。

difficulty: 設定計算區塊的難度,如果數值過大,挖礦時間較長,在測試環境為節省算力和等帶時間可設定較小值。

mixhash:與nonce配合用於挖礦,由上一個區塊的一部分生成的hash。和nonce的設定需要滿足以太坊的Yellow paper, 4.3.4. Block Header Validity, (44)章節所描述的條件。

coinbase: 礦工賬號,隨便填寫。

timestamp: 設定創世塊的時間戳。

parentHash: 上一個區塊的hash值,因為是創世塊,所以這個值是0。

extraData: 附加資訊,隨便填,可以填你的個性資訊,必須為十六進位制的字串。

gasLimit: 該值設定對GAS的消耗總量限制,用來限制區塊能包含的交易資訊總和,因為是私有鏈,所以填最大。

創世塊初始化

本教程以mac作業系統為例,其他作業系統可對照執行。
執行以下命令來啟動初始化創世塊的命令,最簡單的一組操作就是制定dir檔案路徑,和初始化檔案目錄。前面我們已經寫好了genesis.json的配置檔案,下面就執行一下初始化操作,涉及到操作引數為init。

ershixiongdeMacBook-Pro:geth zzs$ ./geth --datadir ./data-init1/ init genesis.json

本教程將初始化json檔案放在geth同級目錄下,如果放在其他目錄下,指定具體的路徑即可。同時建立了一個data-init1目錄專門儲存節點資料,執行完成會發現在該目錄下多出兩個目錄,一個為geth一個為keystore。其中geth裡面放資料相關資訊,keystore裡面放加密過的私鑰檔案。

執行時列印日誌如下:

WARN [12-28|19:12:03] No etherbase set and no accounts found as default
INFO [12-28|19:12:03] Allocated cache and file handles         database=/Users/zzs/develop/eth/geth/data-init1/geth/chaindata cache=16 handles=16
INFO [12-28|19:12:03] Writing custom genesis block
INFO [12-28|19:12:03] Successfully wrote genesis state         database=chaindata                                             hash=942f59…a2588a
INFO [12-28|19:12:03] Allocated cache and file handles         database=/Users/zzs/develop/eth/geth/data-init1/geth/lightchaindata cache=16 handles=16
INFO [12-28|19:12:03] Writing custom genesis block
INFO [12-28|19:12:03] Successfully wrote genesis state         database=lightchaindata                                             hash=942f59…a2588a

經過以上命令,我們已經完成了私有連的初始化工作。因為我們要建立聯盟鏈,因此需要再建立執行一遍同樣的命令,json檔案必須相同,datadir目錄必須不同。博主使用data-init2目錄來儲存第二個節點的資料。

ershixiongdeMacBook-Pro:geth zzs$ ./geth --datadir ./data-init2/ init genesis.json

啟動並進入控制檯

根據具體的作業系統,開兩個視窗來啟動兩個節點。這裡有一點需要注意的是,雖然是兩個節點,但他們的啟動程式都是geth,只不過datadir目錄不同而已。
在第一個視窗執行以下命令啟動一個節點,注意啟動之後不要關閉視窗。

./geth --datadir ./data-init1/ --networkid 88 --nodiscover console

引數簡介:

networkid 指定網路ID,確保不適用1-4。

nodiscover 此引數確保geth不去尋找peers,主要是為了嚴格控制聯盟鏈連入的節點。

這裡我們需要注意的是在啟動第一個節點時並沒有指定port引數,因此此處採用了預設的port,也就是30303。
以下為執行時列印的日誌,並進入控制檯。通過日誌我們也可以發現埠為30303。

WARN [12-28|19:23:16] No etherbase set and no accounts found as default
INFO [12-28|19:23:16] Starting peer-to-peer node               instance=Geth/v1.7.3-stable-4bb3c89d/darwin-amd64/go1.9.2
INFO [12-28|19:23:16] Allocated cache and file handles         database=/Users/zzs/develop/eth/geth/data-init2/geth/chaindata cache=128 handles=1024
WARN [12-28|19:23:16] Upgrading database to use lookup entries
INFO [12-28|19:23:16] Database deduplication successful        deduped=0
INFO [12-28|19:23:16] Initialised chain configuration          config="{ChainID: 72 Homestead: 0 DAO: <nil> DAOSupport: false EIP150: <nil> EIP155: 0 EIP158: 0 Byzantium: <nil> Engine: unknown}"
INFO [12-28|19:23:16] Disk storage enabled for ethash caches   dir=/Users/zzs/develop/eth/geth/data-init2/geth/ethash count=3
INFO [12-28|19:23:16] Disk storage enabled for ethash DAGs     dir=/Users/zzs/.ethash                                 count=2
INFO [12-28|19:23:16] Initialising Ethereum protocol           versions="[63 62]" network=88
INFO [12-28|19:23:16] Loaded most recent local header          number=0 hash=942f59…a2588a td=16384
INFO [12-28|19:23:16] Loaded most recent local full block      number=0 hash=942f59…a2588a td=16384
INFO [12-28|19:23:16] Loaded most recent local fast block      number=0 hash=942f59…a2588a td=16384
INFO [12-28|19:23:16] Regenerated local transaction journal    transactions=0 accounts=0
INFO [12-28|19:23:16] Starting P2P networking
INFO [12-28|19:23:16] RLPx listener up                         self="enode://aa621c010c685665ef217044dac4d57f4d1d682c682a5b3f92ca23b4098238324[email protected][::]:30303?discport=0"
INFO [12-28|19:23:16] IPC endpoint opened: /Users/zzs/develop/eth/geth/data-init2/geth.ipc
Welcome to the Geth JavaScript console!

instance: Geth/v1.7.3-stable-4bb3c89d/darwin-amd64/go1.9.2
 modules: admin:1.0 debug:1.0 eth:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0

> INFO [12-28|19:23:18] Mapped network port                      proto=tcp extport=30303 intport=30303 interface="UPNP IGDv1-IP1"

下面在另外一個視窗,換一個埠,比如30306,再換一下datadir,來啟動第二個節點。

./geth --datadir ./data-init2/ --port 30306 --networkid 88 --nodiscover console

執行上面命令,完成節點2的啟動,並進入控制檯。

新增coinbase賬戶

上面的日誌我們也看到警告資訊,提示沒有賬戶存在,那麼現在我們就在第一個節點上建立一個賬戶,具體在控制檯操作命令如下:

> personal.listAccounts
[]
> personal.newAccount("123456")
"0x60c8abe58c9dbc52a4ee9f8510f1799c432c0f3e"
>

上面的命令先是查看了節點下的地址,結果為空,然後建立了一個祕密為123456的賬號。

同樣的,在另外一個視窗我們執行同樣的命令:

> personal.listAccounts
[]
> personal.newAccount("123456")
"0x02b7344004c45465796f779b7b95d7912c2ef572"
>

這樣,兩個節點就擁有了兩個地址。同時,在它們的keystore目錄下對應生成了加密的私鑰檔案。

我們也可以再次執行list命令檢視新增賬戶之後的情況。同時可以執行以下命令檢視coinbase賬號:

> eth.coinbase
"0x02b7344004c45465796f779b7b95d7912c2ef572"
>

由於只有一個地址,因此該地址就作為coinbase地址。如果想檢視更多的資訊可以執行以下命令:

> personal.listWallets
[{
    accounts: [{
        address: "0x02b7344004c45465796f779b7b95d7912c2ef572",
        url: "keystore:///Users/zzs/develop/eth/geth/data-init2/keystore/UTC--2017-12-28T11-36-18.185974427Z--02b7344004c45465796f779b7b95d7912c2ef572"
    }],
    status: "Locked",
    url: "keystore:///Users/zzs/develop/eth/geth/data-init2/keystore/UTC--2017-12-28T11-36-18.185974427Z--02b7344004c45465796f779b7b95d7912c2ef572"
}]

這裡不僅列印了賬戶資訊,還打印出了私鑰儲存的位置和賬戶狀態等資訊。

聯盟鏈互通

上面分別是在兩個節點上進行的操作,下面我們需要把兩個節點之間建立起連結。首先,我們執行以下命令檢視以下節點的peers的情況。

> admin.peers
[]

發現節點並沒有連結上任何其他節點,這也是我們的nodiscover引數發揮了效果。

下面就通過分享enode地址的方式來讓兩個節點建立連結。

> admin.nodeInfo.enode
"enode://aa621c010c685665ef217044dac4d57f4d1d682c682a5b3f92ca23b4098238324[email protected][::]:30306?discport=0"
>

通過上面命令,我們獲得了節點2的encode資訊。這是geth用來連線到不同節點的enode資訊,在這些不同的節點它們能夠分享交易和成功挖掘資訊。

其實這個資訊如果留心的話,在啟動節點的列印日誌中已經打印出每個節點的encode資訊。比如:

INFO [12-28|19:23:16] RLPx listener up                         self="enode://aa621c010c685665ef217044dac4d57f4d1d682c682a5b3f92ca23b4098238324[email protected][::]:30303?discport=0"

現在,我們要告知一個節點,另外一個節點的encode資訊。首先複製節點2的日誌中self等號後面的資訊,在節點1的控制檯執行以下命令:

> admin.addPeer("enode://aa621c010c685665ef217044dac4d57f4d1d682c682a5b3f92ca23b4098238324[email protected][::]:30306?discport=0")
true

返回true,說明執行成功。再次驗證一下:

> admin.peers
[{
    caps: ["eth/63"],
    id: "aa621c010c685665ef217044dac4d57f4d1d682c682a5b3f92ca23b40982383240a05b680060ce8b0ce020a96c49c9c2c3628c4ea3281845211bd4cf4f03b35c",
    name: "Geth/v1.7.3-stable-4bb3c89d/darwin-amd64/go1.9.2",
    network: {
      localAddress: "[::1]:49426",
      remoteAddress: "[::1]:30306"
    },
    protocols: {
      eth: {
        difficulty: 16384,
        head: "0x942f596f99dc8879b426b59080824662e1f97587353d087487fea0a0e2a2588a",
        version: 63
      }
    }
}]
>

發現節點1已經有一個peer了,同時我們可以看到remoteAddress: “[::1]:30306”,正是我們節點2的埠資訊。在節點2執行admin.peers會發現有類似的資訊,指向的peer正是節點1的。

查詢餘額並挖礦

執行檢視餘額命令:

> eth.getBalance(eth.coinbase0
>

發現兩個節點的賬號餘額都為0。

在節點1執行miner.start()進行挖礦,執行miner.stop()停止挖礦。停止挖礦的時候開業忽略控制檯輸出,只要正確拼寫命令回車即可。

當我們在節點1執行挖礦時,我們會發現節點2的控制檯出現了這樣的日誌資訊:

> INFO [12-28|20:05:32] Block synchronisation started
INFO [12-28|20:05:33] Imported new state entries               count=1 elapsed=47.661µs processed=1 pending=0 retry=0 duplicate=0 unexpected=0
WARN [12-28|20:05:33] Discarded bad propagated block           number=1 hash=ab49ba…1cf32f
INFO [12-28|20:05:33] Imported new block headers               count=2 elapsed=9.208ms  number=2 hash=738225000e3b ignored=0
INFO [12-28|20:05:33] Imported new chain segment               blocks=2 txs=0 mgas=0.000 elapsed=1.724ms  mgasps=0.000 number=2 hash=738225000e3b
INFO [12-28|20:05:33] Fast sync complete, auto disabling
INFO [12-28|20:05:34] Imported new chain segment               blocks=1 txs=0 mgas=0.000 elapsed=5.978ms  mgasps=0.000 number=3 hash=b069a9…426060
INFO [12-28|20:05:38] Imported new chain segment               blocks=1 txs=0 mgas=0.000 elapsed=6.930ms  mgasps=0.000 number=4 hash=21217e…526253
INFO [12-28|20:05:41] Imported new chain segment               blocks=1 txs=0 mgas=0.000 elapsed=6.419ms  mgasps=0.000 number=5 hash=3fa6ff…cf2794
INFO [12-28|20:05:43] Imported new chain segment               blocks=1 txs=0 mgas=0.000 elapsed=6.557ms  mgasps=0.000 number=6 hash=4c35b9…78b3ec
INFO [12-28|20:05:45] Imported new chain segment               blocks=1 txs=0 mgas=0.000 elapsed=6.514ms  mgasps=0.000 number=7 hash=328e621bd3d3
INFO [12-28|20:05:46] Imported new chain segment               blocks=1 txs=0 mgas=0.000 elapsed=6.513ms  mgasps=0.000 number=8 hash=12287e…0465b5
INFO [12-28|20:06:19] Imported new chain segment               blocks=1 txs=0 mgas=0.000 elapsed=7.048ms  mgasps=0.000 number=9 hash=8e844b…b99d6c
INFO [12-28|20:06:22] Imported new chain segment               blocks=1 txs=0 mgas=0.000 elapsed=8.156ms  mgasps=0.000 number=10 hash=159b36…d4dde5
INFO [12-28|20:06:24] Imported new chain segment               blocks=1 txs=0 mgas=0.000 elapsed=6.549ms  mgasps=0.000 number=11 hash=9691005658a5

也就是說,節點1挖礦,節點2在同步資料資訊。

停止節點1的挖礦,並檢視coinbase地址金額:

> miner.stop()
true
> eth.getBalance(eth.coinbase)
140000000000000000000
> eth.coinbase
"0x60c8abe58c9dbc52a4ee9f8510f1799c432c0f3e"

這裡我們知道了節點一種的地址資訊和餘額資訊,那我們拿節點1的這個地址在節點2的控制檯查詢一下資訊:

> eth.getBalance("0x60c8abe58c9dbc52a4ee9f8510f1799c432c0f3e")
140000000000000000000
>

很顯然,節點2中也能查詢到節點1中地址的餘額。以上資訊說明,節點1和節點2的資料是完全同步的。

交易轉賬

現在我們從節點1的coinbase賬戶發一筆交易到節點2的coinbase賬戶。

> personal.unlockAccount("0x60c8abe58c9dbc52a4ee9f8510f1799c432c0f3e")
Unlock account 0x60c8abe58c9dbc52a4ee9f8510f1799c432c0f3e
Passphrase:
true
> eth.sendTransaction({from: eth.coinbase, to: '0x02b7344004c45465796f779b7b95d7912c2ef572', value: 100000000})
INFO [12-28|20:13:21] Submitted transaction                    fullhash=0xc32e40f0f606a6368aa2c4c6a27db20f5a1d728fb9ef1f50a0410f4889e095a0 recipient=0x02b7344004c45465796F779B7b95d7912C2eF572
"0xc32e40f0f606a6368aa2c4c6a27db20f5a1d728fb9ef1f50a0410f4889e095a0"
>

解鎖賬戶併發送1幣交易資訊。現在檢視一下節點2的地址內是否有餘額:

> eth.getBalance("0x02b7344004c45465796f779b7b95d7912c2ef572")
0
>

發現餘額是0,為什麼呢?因為雖然我們發起了交易,單並沒有礦工挖礦打包交易。再次執行miner.start()。再次查詢,就會發現節點2的coinbase地址已經有金額了。

> eth.getBalance("0x02b7344004c45465796f779b7b95d7912c2ef572")
100000000

通過以上的操作我們已經建立了一個擁有兩個節點的聯盟鏈,如果想建立更多節點的聯盟鏈,可以此新增新的節點。

注意事項

需要注意的是,如果一個節點重啟,則需要重新新增peer。另外,在實際生產中可去掉console命令,通過之前介紹的attach命令進入控制檯。

更多資訊

或許更多相關資訊可關注微信公眾號:《程式新視界》和知識星球(小密圈),為你解疑答惑。也可加入QQ技術群(659809063)進行交流。
這裡寫圖片描述

這裡寫圖片描述