前言
本篇文章簡單介紹使用go-ethereum連線以太坊的主網和測試網以及一些基礎開發須知,著重介紹如何搭建一個私網的以太坊,至於以太坊應用開發,有機會的話,將在後面的文章中重點介紹。
本篇文章中包含筆者花費大量心血理解並整理的配置和引數說明資料,望可以為諸位道友提供一些幫助。
安裝
Go Ethereum可以安裝的作業系統平臺有Mac OS X,Windows以及Linux/Unix。詳情請看Installation Instructions。
這裡介紹在Linux上,從go-ethereum原始碼構建的安裝流程。官方提到的Linux/Unix平臺包括Ubuntu,Arch和FreeBSD。這裡以Ubuntu為例。
編譯環境準備
編譯環境要求有 Go 和 C編譯程式。安裝方法如下:
apt-get install -y build-essential golang
複製程式碼
獲取原始碼並編譯
獲取原始碼
切換到你準備編譯go-ethereum原始碼的目錄,執行命令:
git clone https://github.com/ethereum/go-ethereum
複製程式碼
上述命令會clone go-ethereum的主幹分支程式碼,該分支程式碼是持續開發程式碼,如果想要使用釋出程式碼,參見go-ethereum release。這裡以當時最新的釋出程式碼 v1.8.7 為例:
- 下載程式碼
wget https://github.com/ethereum/go-ethereum/archive/v1.8.7.tar.gz
複製程式碼
- 解壓
tar zxvf v1.8.7.tar.gz
複製程式碼
將解壓後的程式碼移動到你準備編譯go-ethereum原始碼的目錄。
編譯原始碼
當你準備好go-ethereum的原始碼後,進入go-ethereum原始碼工程頂級目錄,執行命令:
make geth
複製程式碼
(推薦)如果你想要編譯出所有工具,執行:
make all
複製程式碼
編譯完成後,所有工具可以在 build/bin 目錄下找到,將這些二進位制檔案取出來放到你選好的安裝目錄,或者就在原來的位置放著,這裡我放到 /opt/xingweidong/eth/bin 目錄下,接下來根據你的喜好設定系統環境變數,新增如下內容:
export ETH_HOME=/opt/xingweidong/eth
export PATH=$PATH:$ETH_HOME/bin
複製程式碼
別忘了使用 source /etc/profile 或者其他你喜歡的方法更新你的環境變數資訊。
執行geth
geth命令,主要的Ethereum CLI客戶端,是Ethereum網(main-, test- 或 private網)的入口,有能力作為一個full node(預設)存檔節點(保留所有歷史資料)或者一個light node(現場檢索資料)節點執行。經由暴露在HTTP, WebSocket 或 IPC傳輸的頂部的JSON RPC端點,它可以被其他過程用作Ethereum網的閘道器。
提示:檢視 geth 所有命令列選項使用 geth –help 或者檢視 CLI Wiki page。
Ethereum main網的full node
目前為止,大多數情況是人們想要簡單地與Ethereum網進行互動:建立賬戶;轉移資金;部署並與合約互動。對於這種特殊的使用情況,使用者不關心以前的歷史資料,所以我們能快速的同步當前的Ethereum網狀態。執行命令:
geth console
複製程式碼
命令作用:
- 開始 geth 進入快速同步模式(預設模式,可以使用 –syncmode 選項改變同步模式),由於它為了避免處理整個Ethereum網的歷史資料,會下載大量的事務資料,所以會佔用大量CPU資源。
- 啟動 Geth 內在的互動式 JavaScript console,(經由 console 子命令)通過這個,你能呼叫所有官方 web3 methods 以及Geth自己的 management APIs。這個也是可選的,如果你離開,你能使用 geth attach 連線一個已經存在的 Geth 例項。
Ethereum test網的full node
向開發者過渡,如果你想要創造合約,你幾乎肯定想要在沒有任何真實資金的情況下做到這一點,直到你掌握整個系統。換句話說,代替連線到Ethereum main網,你會想要加入到一個 test網,它是和 main網完全等價的,只需要:
geth --testnet console
複製程式碼
console子命令與上面的含義完全相同並且它們在一個測試網上也同樣有用。如果你跳到這一步,請看上面對它們的解釋。
然而,指定 –testnet 將重新配置你的 Geth 例項一小部分:
- 代替使用預設資料目錄(例如Linux上的 ~/.ethereum),Geth將會深入一層目錄建立 testnet 子資料夾(在Linux上是 ~/.ethereum/testnet)。注意,在OSX和Linux上,這也意味著連線一個執行的testnet節點要求使用一個自定義的端點,因為 geth attach 預設將連線一個生產節點。例如:geth attach /testnet/geth.ipc。Windows使用者不受影響。
- 代替連線 Ethereum main網,客戶端將連線到一個 test網,使用不同的P2P bootnodes,不同的網路ID和創世狀態。
注意:儘管有一些內部安全措施防止main網和test網的交易互換,你也應該確認總是為測試資產和真實資產使用分開的賬戶。除非你手動移動賬戶,Geth將預設正確分開兩個網路,並且在它們之間將不會有任何賬戶可用。
Rinkeby test網的full node
上述測試網路是基於ethash工作證明共識演算法的跨客戶端網路。因此,由於網路的低難度/安全性,它有一定的額外開銷,並且更容易受到重組攻擊。Go Ethereum還支援連線到稱為Rinkeby的權威證明測試網路(由社群成員運營)。這個網路更輕,更安全,但只受到go-ethereum的支援。
geth --rinkeby console
複製程式碼
配置
代替傳遞大量選項給 geth 二進位制,你能傳遞一個配置檔案經由:
geth --config /path/to/your_config.toml
複製程式碼
為了理解這個檔案的寫法,你能使用 dumpconfig 子命令export你的現有配置:
geth --your-favourite-flags dumpconfig
eg:geth --testnet dumpconfig
複製程式碼
注意:這個只在 geth v1.6.0以及以上版本有效。
Docker quick start
通過使用Docker,你可以在你的機器上快速啟動Ethereum並執行:
docker run -d --name ethereum-node -v /Users/alice/ethereum:/root
-p 8545:8545 -p 30303:30303
ethereum/client-go
複製程式碼
上述命令將以快速同步模式啟動geth,並具有1GB的DB記憶體容量。它也將在你的home目錄下建立一個永久捲來儲存你的區塊鏈和對映的預設埠。還有一個 alpine 標籤可用於image的精簡版本。
如果你想要從其他容器或主機訪問RPC,不要忘了 –rpcaddr 0.0.0.0。預設情況下,geth 繫結本地介面並且不可從外訪問RPC端點。
可程式設計介面 Geth nodes
作為一個開發者,你將想要及早開始經由你自己的程式而不是手動控制檯與Geth和Ethereum網互動。為此,Geth已經內建支援一個基於APIs(standard APIs 和 Geth specific APIs)的JSON-RPC。它能夠經由HTTP, WebSockets 和 IPC (unix sockets on unix based platforms, and named pipes on Windows)暴露。
IPC介面預設是啟用的並暴露所有Geth支援的APIs,然而HTTP 和 WS介面需要手動啟用並且由於安全原因只能暴露一個APIs子集。這些可以根據你的需要開啟或關閉並被配置。
詳情請看 Programatically interfacing Geth nodes
操作一個私網
維護你自己的私網是十分複雜的,因為在一個正規的網路中,大量配置的獲取和授權需要手動設定。下面,我們建立一個簡單的私網以太坊。
說明:為了使下面建立私網以太坊的步驟更加直白,筆者將預設使用以下的geth選項值(請自行檢視選項含義):
- –datadir /root/privatenet/.ethereum
- –config config/privatenet.toml
在開始之前,筆者先介紹一下如何建立以太坊賬戶:
- 建立主網以太坊賬戶,執行命令:
geth account new
複製程式碼
- 建立私網以太坊賬戶,執行命令:
geth --datadir /root/privatenet/.ethereum account new
複製程式碼
按照提示輸入賬戶密碼即可。
注意:建立私網以太坊賬戶時,務必指定 –datadir 選項,否則會預設建立主網以太坊賬戶。
定義一個私有的創世狀態
首先,你需要創造你的網路的所有節點需要意識到並同意的創世狀態。這個由一個小JSON檔案組成(例如,稱它為 genesis.json):
{
"config": {
"chainId": 15,
"homesteadBlock": 0,
"eip155Block": 0,
"eip158Block": 0
},
"alloc" : {},
"coinbase" : "0x0000000000000000000000000000000000000000",
"difficulty" : "0x20000",
"extraData" : "",
"gasLimit" : "0x2fefd8",
"nonce" : "0x0000000000001993",
"mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp" : "0x00"
}
複製程式碼
引數說明(下表是筆者參考go-ethereum原始碼README和ethereum_yellow_paper整理所得,如有錯誤,請幫忙指正):
引數 | 描述 |
---|---|
alloc | 可以預置賬號以及賬號的以太幣數量 |
coinbase | 區塊受益者地址,可以設定成已存在的賬戶。後面挖出的區塊的受益者將是挖掘出那個區塊的賬戶(礦工) |
difficulty | 代表當前區塊的難度等級(十六進位制),這裡定義創世區塊的難度等級,難度等級越高,挖礦越難。後面生成的區塊難度等級根據前一個區塊的難度等級和時間戳計算得到 |
extraData | 一個包含這個區塊相關資料的位元組陣列,任意填寫。必須是32位以內 |
gasLimit | 執行這個事務應該被使用的gas的最大量。這個在任何計算被做之前是預付的,並且在之後不會增加 |
nonce | 代表從這個地址傳送的事務數目,或者在關聯程式碼的賬戶情況下,這代表這個賬戶創造的合約數目。(在Yellow Paper中對nonce有多處描述,這裡選擇了4.1章節的描述,) |
mixhash | 一個256位的hash,由nonce合併,證明在這個區塊上已經執行足夠量的計算 |
parentHash | 前一個(父級)區塊的header的keccak256演算法hash |
timestamp | 這個區塊開始的Unix的time()和合理輸出 |
上面這些域應該可以滿足大多數需求,不過我們建議改變 nonce 為一些隨機值,這樣你就能阻止不知名的遠端節點訪問你。如果你想要為了更早測試,預儲備一些賬戶,你能在 alloc 域進行賬戶配置:
"alloc": {
"0x0000000000000000000000000000000000000001": {"balance": "111111111"},
"0x0000000000000000000000000000000000000002": {"balance": "222222222"}
}
複製程式碼
隨著創世狀態定義在上面的JSON檔案,你應該在啟動每個節點之前,優先初始化它,以確認所有區塊鏈引數被正確設定:
geth --datadir /root/privatenet/.ethereum init genesis.json
複製程式碼
啟動bootstrap
當所有你想要執行的節點初始化到期望的創世狀態,你將需要開始一個bootstrap節點,其他節點可以使用它在你的網路或因特網中找到彼此。乾淨的方式是配置並執行一個獨立的bootnode:
- 每個ethereum節點,包括一個bootnode,通過一個enode識別符號聯絡。這些識別符號源自一個key。於是你將需要給bootnode這樣一個key。因為我們當前沒有這樣的key,所以我們可以在bootnode啟動前生成一個key(並儲存它到一個檔案):
bootnode -genkey bootnode.key
複製程式碼
- 為了bootnode每次啟動都使用相同的enode,需要在bootnode啟動時指定一個key:
bootnode -nodekey bootnode.key
複製程式碼
當bootnode上線,它將展示一個 enode URL,例如:
INFO [05-09|01:47:05] UDP listener up self=enode://75535ebac1f5b2a644edb134dbe91c6c288353be1a5301864edae529630b35c5ff0c0ae9e07b2bcdef578c3ac1b72b2cda105c061c2c77067f1fd8ec54d852b7@[::]:30301
複製程式碼
其他節點可以使用這個 enode URL 連線它並交換對等資訊。確認用你的外部訪問IP替換展示的IP地址資訊(很可能是 [::])去得到真正的 enode URL。例如:
enode://75535ebac1f5b2a644edb134dbe91c6c288353be1a5301864edae529630b35c5ff0c0ae9e07b2bcdef578c3ac1b72b2cda105c061c2c77067f1fd8ec54d852b7@192.168.1.214:30301
複製程式碼
儲存這個準確的 enode URL 到你的一個文字中或者其他什麼地方,下面需要用到。
注意:你也可以使用完全成熟的Geth節點作為引導節點,但這是不太推薦的方式。
定義一個配置檔案
為了成員節點啟動時使用的配置一致,需要寫一個配置檔案,例如 privatenet.toml(參考自 testnet 的配置, 執行命令 geth –testnet dumpconfig 可見):
# Note: this config doesn`t contain the genesis block.
[Eth]
NetworkId = 3369
DatabaseCache = 768
GasPrice = 18000000000
[Eth.Ethash]
CacheDir = "ethash"
CachesInMem = 2
CachesOnDisk = 3
DatasetDir = "/root/privatenet/.ethash"
DatasetsInMem = 1
DatasetsOnDisk = 2
[Eth.TxPool]
NoLocals = false
Journal = "transactions.rlp"
Rejournal = 3600000000000
PriceLimit = 1
PriceBump = 10
AccountSlots = 16
GlobalSlots = 4096
AccountQueue = 64
GlobalQueue = 1024
Lifetime = 10800000000000
[Eth.GPO]
Blocks = 20
Percentile = 60
[Shh]
MaxMessageSize = 1048576
MinimumAcceptedPOW = 2e-01
[Node]
DataDir = "/root/privatenet/.ethereum"
IPCPath = "geth.ipc"
HTTPPort = 8545
HTTPVirtualHosts = ["localhost"]
HTTPModules = ["net", "web3", "eth", "shh"]
WSPort = 8546
WSModules = ["net", "web3", "eth", "shh"]
[Node.P2P]
MaxPeers = 25
NoDiscovery = false
BootstrapNodes = ["enode://75535ebac1f5b2a644edb134dbe91c6c288353be1a5301864edae529630b35c5ff0c0ae9e07b2bcdef578c3ac1b72b2cda105c061c2c77067f1fd8ec54d852b7@1
92.168.1.214:30301"]StaticNodes = []
TrustedNodes = []
ListenAddr = ":30303"
EnableMsgEvents = false
[Dashboard]
Host = "localhost"
Port = 8080
Refresh = 5000000000
複製程式碼
配置說明(下表是筆者參考geth引數說明和go-ethereum相關配置項程式碼整理所得,如有錯誤,請幫忙指正):
域 | 配置項 | 對應引數 | 說明 |
---|---|---|---|
Eth | NetworkId | –networkid value | Network識別符號(integer型別,1=Frontier,2=Morden(disused),3=Ropsten,4=Rinkeby),預設為1。如果建立在私網上,使用另外的任意值,比如:3369 |
Eth | DatabaseCache | null | (個人理解)為database申請的系統記憶體,單位為MB,最小值和預設值是16MB |
Eth | GasPrice | –gasprice “18000000000” | 接受挖掘事務的最低gas價格。可能指miner的報酬 |
Eth.Ethash | CacheDir | –ethash.cachedir | 儲存ethash證明快取的目錄(預設在 datadir 目錄裡) |
Eth.Ethash | CachesInMem | –ethash.cachesinmem value | 保留在記憶體中的最新ethash快取的數目(每16MB)(預設:2)。 |
Eth.Ethash | CachesOnDisk | –ethash.cachesondisk value | 保留在磁碟中的最新ethash快取的數目(每16MB)(預設:3)。 |
Eth.Ethash | DatasetDir | –ethash.dagdir “/home/karalabe/.ethash” | 儲存ethash挖掘DAGs的目錄(預設在home目錄裡) |
Eth.Ethash | DatasetsInMem | –ethash.dagsinmem value | 保留在記憶體中的最新ethash挖掘DAGs(每1+GB)(預設:1)。 |
Eth.Ethash | DatasetsOnDisk | –ethash.dagsondisk value | 保留在磁碟中的最新ethash挖掘DAGs(每1+GB)(預設:2)。 |
Eth.TxPool | NoLocals | –txpool.nolocals | 免除本地提交事務的費用 |
Eth.TxPool | Journal | –txpool.journal value | 用於節點重啟的本地事務磁碟日誌(預設:”transactions.rlp”) |
Eth.TxPool | Rejournal | –txpool.rejournal value | 重新生成本地事務日誌的時間間隔(預設:1h0m0s) |
Eth.TxPool | PriceLimit | –txpool.pricelimit value | 強制接納入池的最小gas價格限制(預設:1) |
Eth.TxPool | PriceBump | –txpool.pricebump value | 替代一個已經存在的事務的價格碰撞百分比(預設:10) |
Eth.TxPool | AccountSlots | –txpool.accountslots value | 每個賬戶擔保的可執行事務時隙的最小數目(預設:16) |
Eth.TxPool | GlobalSlots | –txpool.globalslots value | 所有賬戶的可執行事務時隙的最大數目(預設:4096) |
Eth.TxPool | AccountQueue | –txpool.accountqueue value | 每個賬戶許可的非可執行事務時隙的最大數目(預設:64) |
Eth.TxPool | GlobalQueue | –txpool.globalqueue | 所有賬戶的非可執行事務時隙的最大數目(預設:1024) |
Eth.TxPool | Lifetime | –txpool.lifetime value | 非可執行事務的排隊最大時間(預設:3h0m0s) |
Eth.GPO | Blocks | –gpoblocks value | 檢查gas價格的最新區塊的數目(預設:10) |
Eth.GPO | Percentile | –gpopercentile value | 建議的gas價格是一組最新事務gas價格的百分位(預設:50) |
Shh | MaxMessageSize | –shh.maxmessagesize value | 可接受的最大資訊大小(預設:1048576) |
Shh | MinimumAcceptedPOW | –shh.pow value | 可接受的最小POW(預設:0.2) |
Node | DataDir | –datadir “/home/karalabe/.ethereum” | databases和keystore的資料目錄 |
Node | IPCPath | –ipcpath | datadir裡的IPC socket/pipe的檔名 |
Node | HTTPPort | –rpcport value | HTTP-RPC服務監聽埠(預設:8545) |
Node | HTTPVirtualHosts | –rpcaddr value | HTTP-RPC服務監聽介面(預設:”localhost”) |
Node | HTTPModules | null | 經由HTTP RPC介面暴露的API modules列表 |
Node | WSPort | –wsport value | WS-RPC 服務監聽埠(預設:8546) |
Node | WSModules | null | 經由websocket RPC介面暴露的API modules列表,如果modules是空的,所有指向public的RPC API端點將會被暴露 |
Node.P2P | MaxPeers | –maxpeers value | network peers的最大數目(如果設定為0,network失效)(預設:25) |
Node.P2P | NoDiscovery | –nodiscover | 使peer發現機制無效(手動peer新增)。這裡設定為false,以便使用這個配置檔案的新節點可以被發現。 |
Node.P2P | BootstrapNodes | –bootnodes value | 逗號分割的P2P discovery bootstrap enode URLs(對於 light servers,設定 v4+v5 代替)。將上面啟動bootnodes時獲取的enode URL替換IP後新增到這裡。 |
Node.P2P | BootstrapNodesV5 | –bootnodesv5 value | 逗號分割的P2P v5 discovery bootstrap enode URLs(light server,light nodes) |
Node.P2P | StaticNodes | null | 配置作為static nodes的節點enode URLs列表 |
Node.P2P | TrustedNodes | null | 配置作為trusted nodes的節點enode URLs列表 |
Node.P2P | ListenAddr | –port | network監聽埠(預設:30303) |
Node.P2P | EnableMsgEvents | null | 如果EnableMsgEvents被設定,伺服器將發出PeerEvents,無論一個peer何時傳送或接收一條資訊 |
Dashboard | Host | null | 啟動dashboard服務的主機介面,如果這個域為空,則沒有dashboard將被啟動 |
Dashboard | Port | null | 啟動dashboard服務的TCP埠數字。預設0值是有效的,並將使用一個隨機埠數字(用於臨時節點) |
Dashboard | Refresh | null | 資料更新的重新整理速率,chartEntry將被經常收集 |
在你的操作目錄建立config資料夾,將寫好的配置檔案privatenet.toml移動到config目錄裡。
啟動你的成員節點
以太坊的成員節點,之間是完全對等的,每個節點都可以有多個賬戶。
啟動私網以太坊的成員節點:
geth --config config/privatenet.toml
複製程式碼
連線到剛剛啟動的或者已經在執行的node,開始一個互動式JavaScript環境:
geth attach privatenet/.ethereum/geth.ipc
複製程式碼
官方說明: 當bootnode運轉起來並且外部可達(你能嘗試 telnet 去確認它的確可達),開始隨後的Geth節點,為了對等發現,經由 –bootnodes 選項指向bootnode。保持你的私網的資料目錄單獨將很可能是明智的選擇,所以也指定一個自定義的 –datadir 選項。
geth --datadir=path/to/custom/data/folder --bootnodes=<bootnode-enode-url-from-above>
複製程式碼
注意:因為你的網路將被從main和test網完全切除,所以你將需要配置一個 miner 去處理交易併為你創造新塊。
執行一個私有的miner
公共Ethereum網的mining是一個複雜的任務,因為它唯一可行的是使用GPUs,要求一個OpenCL 或 CUDA啟用 ethminer 例項。更多資訊請查閱 EtherMining subreddit和 Genoil miner 倉庫。
然而在一個私網的設定,一個單一的 CPU miner例項是足夠滿足實際需求的,因為它不需要沉重的資源(考慮到執行在一個單一的執行緒上,也不需要多個)就能在一個正確的間隔內生產一個穩定的區塊流(stable stream of blocks)。為mining開始一個Geth例項,指定你通常使用的選項執行它,通過以下方法擴充套件:
geth --config config/privatenet.toml --mine --minerthreads=1 --etherbase=0x0000000000000000000000000000000000000000
複製程式碼
這將開始mining區塊並在一個單一CPU執行緒上交易,存入所有事件到一個 –etherbase 選項指定的賬戶,如果不指定賬戶,則會預設指定當前節點上的第一個賬戶。你能進一步調節mining,通過(–targetgaslimit)改變預設gas限制區塊並且在(–gasprice)處接受價格交易。
另外,也可以在互動式JavaScript環境中控制mining例項:
- 開始一個4執行緒的mining例項:
miner.start(4)
複製程式碼
- 停止mining例項:
miner.stop()
複製程式碼
更多Mining相關資訊,請參看Mining
至此,私網以太坊搭建完成,感謝閱讀!
原創不易,與君共勉!