1. 程式人生 > >第一行程式碼:以太坊(1)-建立自己的私有區塊鏈

第一行程式碼:以太坊(1)-建立自己的私有區塊鏈

本文會利用以太坊客戶端(geth)搭建一個私有區塊鏈,並在這個私有區塊鏈上挖礦,通過本文的案例,讀者可以更深入理解區塊鏈、以太坊、挖礦的理論。

通過閱讀本文,您可以:

  • 掌握搭建以太坊開發環境的方法
  • 掌握geth的基本使用方法
  • 瞭解如何啟動JavaScript控制檯
  • 掌握建立一個私有區塊鏈的步驟
  • 掌握如何在私有區塊鏈上挖礦

1. 以太坊(Ethereum)開發環境搭建

在玩以太坊之前,首先要搭建以太坊的開發環境。第一步就是安裝geth。那麼geth是什麼呢?geth(或稱為go-ethereum)是以太坊節點的一個實現。也就是說,geth是一個客戶端,用於連線以太坊網路。從geth的名 字可以看出,geth是用go語言實現的一個以太坊節點。那麼為什麼需要這個節點呢?

這是因為以太坊網路由多個節點組成,這些節點可能是用不同技術實現的。如geth就是官方的以太坊節點。通過這些節點可以用命令列方式直接訪問區塊鏈網路,如廣播交易,釋出智慧合約等,但對於大多數使用者來說,都是非程式設計師出身,讓他們通過命令列方式去操作以太坊網路是不可能的,所以就要求有圖形化的操作介面來操作以太坊網路。但geth這樣的節點是做不到的,因此,就需要像web3.js,web3.py這樣的程式庫,再配合JavaScript、Python實現視覺化的以太坊客戶端,但這些庫是無法直接連線進以太坊網路的,他們只能連線像geth這樣的以太坊節點,然後通過一塔發節點訪問以太坊網路,所以geth其實同時起到客戶端和服務端的作用。也就是說,geth是以太坊網路的客戶端,是web3.js的服務端。

安裝geth也非常容易,可以直接到下面的官網下載不同平臺的geth安裝程式。

訪問上面的Url,會看到頁面上面顯示如下圖所示的下載按鈕。

image.png

目前geth的最新版本是1.8.3,支援Linux、Mac OS X和Windows平臺,讀者可以根據實際情況下載相應平臺的geth安裝程式,也可以直接下載原始碼(最後一個按鈕),然後編譯和安裝geth,不過這種方式只適合於專業人員,對於初學者,並不推薦使用這種方式。

(1)安裝Windows版geth

Windows版安裝程式是一個exe檔案(geth-windows-amd64-1.8.3-329ac18e.exe或類似的檔名),直接雙擊安裝即可。雙擊該檔案會顯示如下圖所示的安裝介面。

image.png

單擊“I Agree”按鈕會顯示如下圖所示的選擇元件介面。

image.png

建議讀者將Geth和Development tools都選上,否則在用到相關工具時還需要安裝。然後單擊“Next”按鈕進入下一個安裝介面。該介面主要用於指定geth的安裝目錄,預設安裝目錄是“C:\Program Files\Geth”,如果讀者不想將geth安裝到這個目錄,可以修改成其他目錄,如“D:\geth”效果如下圖所示。

image.png

接下來單擊“Install”按鈕開始安裝geth。安裝的過程會顯示當前安裝進度的百分比,直到最後顯示“Completed”,表示已經安裝成功,如下圖所示。最後單擊“Close”按鈕關閉安裝介面。

image.png

Windows版的geth其實就是一些exe檔案,如下圖所示。其中geth.exe是本書主要使用的工具。

image.png

安裝完geth後,最好將geth.exe檔案所在的目錄加到PATH環境變數中,這樣在任何目錄下就都可以使用geth.exe檔案。

(2)安裝Mac OS X版geth

Mac OS X版安裝程式是一個壓縮檔案(geth-darwin-amd64-1.8.3-329ac18e.tar.gz或類似的名字),將該壓縮檔案解壓,會發現只有一個geth可執行檔案,如下圖所示。

image.png

如果要想下載Mac OS X版的geth相關工具,可以到圖2-1所示頁面下方選擇相應的作業系統,下載Tools壓縮包或安裝程式(點選Geth&Tools 1.8.3即可下載相應作業系統的Tools),如下圖所示。為了使用方便,可以將geth所在的路徑加到/etc/profile檔案的PATH變數中,然後執行source /etc/profile命令,讓配置立即生效。這樣在任何目錄下都可以使用geth。

image.png

在Mac OS X下還可以使用brew命令安裝以太坊開發環境。

brew tap ethereum/ethereum
brew install ethereum

讀者可以選擇自己喜歡的方式在Mac OS X下安裝以太坊開發環境。

(3)安裝Linux版geth

Linux版的geth與Mac OS X版的geth差不多,安裝程式同樣是一個壓縮檔案(geth-linux-amd64-1.8.3-329ac18e.tar.gz或類似的檔名),將該壓縮檔案複製到Linux的某個目錄,然後在Console中進入該目錄,執行如下的命令對該檔案解壓。

tar zxvf geth-linux-amd64-1.8.3-329ac18e.tar.gz

解壓後,仍然只有一個geth可執行檔案,這個可執行檔案是靜態編譯的,在任何Linux發行版上都可以獨立執行。

在Linux下安裝完geth後,最好將geth檔案所在的路徑新增到PATH變數中,設定的方法與Mac OS X類似。

2. 使用geth命令建立以太坊賬戶

安裝完geth,需要測試一下,可以在控制檯輸入geth version命令(用於檢視geth的版本資訊),如果輸出類似下圖所示的資訊,表示geth已經安裝成功。

image.png

在Windows下執行geth version命令,也會得到與圖2-9類似的版本資訊,只是部分資訊稍有差異,如下圖所示。

image.png

使用geth的第一步就是建立賬戶。以太坊的賬戶用40位十六進位制的地址表示,如下面的十六進位制數就是一個標準的以太坊賬戶地址(前面的0x表示十六進位制)。

0x24924f33a9c49d312a8d885ade76ece76b315982

第一次使用geth時,geth中沒有任何賬戶,所以首先需要使用geth命令建立以太坊賬戶。在建立以太坊賬戶之前,可以使用下面的命令檢視以太坊當前的賬戶。

geth account list

執行上面的命令,會顯示如下圖所示的資訊,很明顯,沒有任何賬戶。

image.png

現在使用geth account new命令建立以太坊賬戶,在建立的過程中要求輸入賬戶的密碼。如果最後輸出了一個以太坊地址,就說明賬戶建立成功了,如下圖所示。該地址就是以太坊賬戶。

image.png

可以使用同樣的方法多建立幾個以太坊賬戶。然後使用geth account list命令檢視以太坊當前的賬戶,會得到如下圖所示的查詢結果。根據查詢結果顯示,以太坊當前有3個賬戶。

image.png

3. 刪除以太坊賬戶

geth並沒有直接提供刪除以太坊賬戶的命令,不過可以通過刪除賬戶本地檔案的方式刪除以太坊賬戶(因為每一個以太坊賬戶對應一個檔案)。根據上圖所示的以太坊賬戶資訊,可以得知賬戶檔案的儲存路徑如下:

/Users/lining/Library/Ethereum/keystore

進入該目錄,會看到如下圖所示的3個檔案,分別對應上一節建立的3個以太坊賬戶。如果要刪除某個以太坊賬戶,只需要刪除對應的檔案即可,然後再次執行geth accountlist命令,會發現與檔案對應的以太坊賬戶消失了。

image.png

在Windows中的操作與Mac OS X相同,只是儲存賬戶檔案的路徑不同。在Windows下使用同樣的方式建立3個以太坊賬戶,然後使用geth account list命令列出所有的賬戶,如下圖所示。

image.png

從上圖所示的賬戶資訊可知,儲存賬戶檔案的路徑如下:

C:\Users\androidguy\AppData\Roaming\Ethereum\keystore

其中androidguy是Windows使用者名稱,請將其改成自己機器的使用者名稱。

4. geth JavaScript控制檯

geth可以通過JavaScript控制檯和JavaScript程式碼訪問以太坊網路。只需要執行geth console命令,就可以啟動JavaScript控制檯,在該控制檯可以直接輸入JavaScript程式碼,按Enter鍵會執行輸入的JavaScript程式碼,不過有一個問題,就是geth命令同時也負責同步區塊,以及其他工作,這樣會產生大量的日誌資訊,這些日誌資訊會與JavaScript程式碼交替出現,非常煩人。效果如下圖所示。

image.png

為了不讓日誌資訊在JavaScript控制檯輸出,可以使用下面的命令啟動JavaScript控制檯,其中2表示日誌管道,也就是將日誌資訊直接輸出到geth.log檔案。

geth console 2>>geth.log

執行上面的命令,會進入JavaScript控制檯,在控制檯中,除了輸入的JavaScript程式碼和執行結果外,什麼都不會輸出,效果如下圖所示。

image.png

在Windows下使用同樣的操作會得到與Mac OS X下完全一樣的效果,如下圖所示。

image.png

JavaScript控制檯並不是簡簡單單用來執行JavaScript程式碼的,其實這個控制檯可以通過web3.js API直接訪問以太坊網路。web3.js就是一套API,支援Web和Node.js。可能很多讀者看到這些估計有些懵,一下丟擲這麼多概念,又是web3.js,又是Node.js。這些技術會在本書後面詳細介紹,本節只要知道在JavaScript控制檯可以使用JavaScript程式碼訪問以太坊網路就可以了。如果使用geth console命令進入JavaScript控制檯,並不需要單獨安裝web3.js,直接就可以使用web3.js的API。

在JavaScript控制檯中內建了很多JavaScript物件,其中web3就是其中最重要的物件。當啟動JavaScript控制檯後,這些物件會自動建立,可以直接使用。例如,可以直接在JavaScript控制檯中執行下面的JavaScript程式碼。

str = web3.fromAscii('ethereum')   //  將'ethereum'按ASCII轉換為十六進位制數
web3.toDecimal('0xa')           //  將十六進位制數(0xa)轉換為十進位制數
//  判斷地址是否有效
isAddress = web3.isAddress("0x8888f1f195afa192cfee860698584c030f4c9db1");

這些命令執行的效果如下圖所示。在Windows中的JavaScript控制檯也會得到完全相同的效果。

image.png

使用web3.js API的方式有很多,除了在JavaScript控制檯中使用web3.js API外,至少還可以在下面的環境中使用web3.js。

• 瀏覽器

• Node.js

• IPython

• Jupyter Notebook

5. 建立私有區塊鏈與挖礦

本節會利用geth命令建立一個私有區塊鏈,然後自己挖礦,可以通過這個操作過程更深入理解以太坊和區塊鏈的概念。

建立私有區塊鏈的步驟如下:

(1)建立創世塊

區塊鏈是由若干個區塊組成的。在私有鏈啟動後,需要為區塊鏈建立第一個區塊(創世塊),相當於資料結構中連結串列的頭節點。不過以太坊並不知道如何建立這個創世塊,需要我們告訴以太坊如何建立,因此,首先需要建立一個創世塊的描述檔案,這個描述檔案是JSON格式的,本例起名為block.json,程式碼如下:

block.json檔案

檔案位置:src/chapter2/block.json


{
    "config":
    {
        "chainId":15,
        "homesteadBlock":0
    },
    "difficulty":"20",
    "gasLimit":"2100000",
    "alloc":{
        "7df9a875a174b3bc565e6424a0050ebc1b2d1d82":{"balance":"300000"},
        "f41c74c9ae680c1aa78f42e5647a62f353b7bdde":{"balance":"400000"}
    }
}

一個完整的區塊描述檔案非常複雜,本例只對區塊進行了一些基本設定,這些設定項的描述如下:

• chainId:指定了獨立的區塊鏈網路 ID。網路 ID在連線到其他節點的時候會用到,以太坊公網的網路 ID 是 1,為了不與公有鏈網路衝突,執行私有鏈節點的時候要指定自己的網路 ID。不同 ID 網路的節點無法相互連線。

• homesteadBlock:以太坊推出的第2個主要的區塊發行版本,Frontier是第1個推出的區塊發行版本(也是測試版本)。建議使用homesteadBlock,這裡的0表示有效。

• difficulty:挖礦的難易程度,該值越小,挖礦越容易。也就是說,該值越小,挖礦需要的算力越小,在測試時,建議設定一個比較小的值,否則挖礦會需要很長時間。

• gasLimit:挖每個區塊需要消耗資源的上限,gas與以太幣(ether)一樣,都是以太坊中的單位。之所以將gas與ether分開,是為了防止ether的波動對挖每個區塊消耗資源的影響。

• alloc:為了測試挖礦,臨時分配的賬戶,其中balance表示當前賬戶的餘額,單位是Wei。

(2)初始化區塊鏈

這一步需要使用如下的命令對區塊鏈進行初始化。

geth init block.json --datadir test

其中test表示與區塊鏈相關資料儲存的目錄,本例test與block.json檔案在同一個目錄下。執行上面的命令後,會在當前block.json檔案所在的目錄生成一個test子目錄。test子目錄的結構如下圖所示。

image.png

很明顯,在test目錄下面還有兩個子目錄:geth和keystore。其中geth目錄儲存了同步區塊鏈以及相關的資料,keystore目錄儲存了賬戶檔案。由於私有鏈剛建立,還沒有建立賬戶,所以keystore目錄為空。如果在Windows下執行前面初始化區塊鏈的命令,會得到與Mac OS X下完全一樣的結果。讀者可以自己在Windows做實驗。

(3)啟動以太坊客戶端(geth)

在這一步使用下面的命令啟動以太坊客戶端(進入JavaScript控制檯)。其中datadir命令列引數表示geth會使用test目錄儲存相關檔案。

geth --datadir test console

(4) 將賬戶與礦工繫結

負責挖礦的賬戶稱為礦工。miner是JavaScript控制檯中內建的礦工物件,在Java可以使用下面的命令將block.json檔案中的兩個地址中的一個與miner物件繫結。

miner.setEtherbase("0x7df9a875a174b3bc565e6424a0050ebc1b2d1d82")

(5)開始挖礦

在開始挖礦之前,可以使用下面的命令查一下兩個臨時賬號的餘額。

eth.getBalance("0x7df9a875a174b3bc565e6424a0050ebc1b2d1d82")
eth.getBalance("0xf41c74c9ae680c1aa78f42e5647a62f353b7bdde")

查詢結果分別是300000和400000。現在礦工(miner)已經和餘額為300000的賬戶繫結,接下來在JavaScript控制檯執行如下的程式碼開始挖礦。

miner.start()

執行這行程式碼後,就會開始挖礦,如果要停止挖礦,需要在JavaScript控制檯執行如下的程式碼。

miner.stop()

停止挖礦後,可以執行下面的程式碼查詢當前區塊鏈中的區塊數,其中eth是JavaScript控制檯內建的物件。在本例中一共挖了36個區塊,也就是目前在網路中有一條由36個區塊組成的區塊鏈。

eth.blockNumber

再次使用下面的程式碼查詢兩個臨時賬戶的餘額。

eth.getBalance("0x7df9a875a174b3bc565e6424a0050ebc1b2d1d82")
eth.getBalance("0xf41c74c9ae680c1aa78f42e5647a62f353b7bdde")

我們會發現與礦工(miner)繫結的賬戶的餘額變多了,多出的餘額就是挖礦的獎勵(以太幣),如下圖所示。

image.png

在Windows下執行同樣的命令會獲得相同的結果(挖了30個區塊),如下圖所示。

image.png

(6)控制挖礦數量

有時需要控制挖礦數量,也就是說,挖到指定數量的區塊後自動終止挖礦,要達到這個目的,需要在JavaScript控制檯執行下面的命令。

miner.start(3);
admin.sleepBlocks(10);
miner.stop();

其中start方法的引數表示挖礦使用的執行緒,預設值是CPU核心的數量,如CPU是雙核的,那麼執行緒數就是2。sleepBlocks方法的引數表示要挖的區塊數,本例是10個區塊。如果還沒有挖完10個區塊,那麼sleepBlocks方法會處於阻塞狀態,直到挖完10個區塊,會繼續執行下面的程式碼,也就是miner.stop(),這時挖礦就會結束。