1. 程式人生 > >以太坊私有鏈搭建節點叢集 到 簡單helloworld智慧合約編寫 操作流程

以太坊私有鏈搭建節點叢集 到 簡單helloworld智慧合約編寫 操作流程

1.選擇一種以太坊客戶端

Go-ethereum客戶端通常被稱為Geth,它是個命令列介面,執行在Go上實現的完整以太坊節點。Geth得益於Go語言的多平臺特性,支援在多個平臺上使用(比如Windows、Linux、Mac)。Geth是以太坊協議的具體落地實現,通過Geth,你可以實現以太坊的各種功能,如賬戶的新建編輯刪除,開啟挖礦,ether幣的轉移,智慧合約的部署和執行等等。所以,我們選擇 geth工具來進行開發。

Mac 中安裝geth如下:

brew tap ethereum/ethereum
brew install ethereum

檢查是否安裝成功:

geth --help

如果輸出一些幫助命令,則安裝成功。

2.搭建私有鏈

以太坊支援自定義創世區塊,要執行私有鏈,我們就需要定義自己的創世區塊,創世區塊資訊寫在一個json格式的配置檔案中。

json檔案內容如下:

{
  "config": {
        "chainId": 10, 
        "homesteadBlock": 0,
        "eip155Block": 0,
        "eip158Block": 0
    },
  "alloc"      : {},
  "coinbase"   : "0x0000000000000000000000000000000000000000",
  "difficulty" : "0x20000",
  "extraData"  : "",
  "gasLimit"   : "0x2fefd8",
"nonce"     : "0x0000000000000042", "mixhash"   : "0x0000000000000000000000000000000000000000000000000000000000000000", "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", "timestamp" : "0x00" }

2.1初始化:寫入創世區塊

準備好創世區塊json配置檔案後,需要初始化區塊鏈,將上面的創世區塊資訊寫入到區塊鏈中。首先要新建一個目錄data0用來存放區塊鏈資料(其實,這個目錄data0就相當於一個根節點。當我們基於genesis.json生成根節點後,其他人就可以來連線此根節點,從而能進行交易)。data0目錄結構如圖所示:

接下來進入privatechain目錄中,執行初始化命令:

cd privatechain
geth --datadir data0 init genesis.json

上面的命令的主體是 geth init,表示初始化區塊鏈,命令可以帶有選項和引數,其中–datadir選項後面跟一個目錄名,這裡為 data0,表示指定資料存放目錄為 data0, genesis.json是init命令的引數。

執行上面的命令,會讀取genesis.json檔案,根據其中的內容,將創世區塊寫入到區塊鏈中。如果看到log資訊中含有Successfully wrote genesis state字樣,說明初始化成功。

初始化成功後的目錄如下:

其中geth/chaindata中存放的是區塊資料,keystore中存放的是賬戶資料。

2.2啟動私有鏈節點

初始化完成後,就有了一條自己的私有鏈,之後就可以啟動自己的私有鏈節點並做一些操作,在終端中輸入以下命令即可啟動節點:

geth --datadir data0 --networkid 1008 console

上面命令的主體是geth console,表示啟動節點並進入互動式控制檯,–datadir選項指定使用data0作為資料目錄,–networkid選項後面跟一個數字,這裡是1008,表示指定這個私有鏈的網路id為1008。網路id在連線到其他節點的時候會用到,以太坊公網的網路id是1,為了不與公有鏈網路衝突,執行私有鏈節點的時候要指定自己的網路id。

執行上面的命令後,就啟動了區塊鏈節點並進入了Javascript Console:

這是一個互動式的Javascript執行環境,在這裡面可以執行Javascript程式碼,其中>是命令提示符。在這個環境裡也內建了一些用來操作以太坊的Javascript物件,可以直接使用這些物件。這些物件主要包括:

eth:包含一些跟操作區塊鏈相關的方法 net:包含以下檢視p2p網路狀態的方法 admin:包含一些與管理節點相關的方法 miner:包含啟動&停止挖礦的一些方法 personal:主要包含一些管理賬戶的方法 txpool:包含一些檢視交易記憶體池的方法 web3:包含了以上物件,還包含一些單位換算的方法

2.3 Javascript Console

進入以太坊Javascript Console後,就可以使用裡面的內建物件做一些操作,這些內建物件提供的功能很豐富,比如檢視區塊和交易、建立賬戶、挖礦、傳送交易、部署智慧合約等。接下來介紹幾個常用功能,下面的操作中,前面帶>的表示在Javascript Console中執行的命令。

建立賬戶

前面只是搭建了私有鏈,並沒有自己的賬戶,可以在js console中輸入eth.accounts來驗證:

> eth.accounts
[]

此時沒有賬戶,接下來使用personal物件來建立一個賬戶:

> personal.newAccount()
> Passphrase:
> Repeat passphrase:
"0x67346d5619ae5747eb69629c8b1c8cbae71111c3"

Passphrase其實就是密碼的意思,輸入兩次密碼後,就建立了一個賬戶。再次執行命令:

> personal.newAccount()
> Passphrase:
> Repeat passphrase:
"0xa48dba91281ee727c2424c85400f51f7a22716de"

這時候再去看賬戶,就有兩個了。

> eth.accounts
["0x67346d5619ae5747eb69629c8b1c8cbae71111c3", "0xa48dba91281ee727c2424c85400f51f7a22716de"]

賬戶預設會儲存在資料目錄的keystore資料夾中。檢視目錄結構,發現data0/keystore中多了兩個檔案,這兩個檔案就對應剛才建立的兩個賬戶,這是json格式的文字檔案,可以開啟檢視,裡面存的是私鑰經過密碼加密後的資訊。

檢視賬戶餘額

> eth.getBalance(eth.accounts[0])
0
> eth.getBalance(eth.accounts[1])
0

啟動、停止挖礦

> miner.start(10)

其中start的引數表示挖礦使用的執行緒數。第一次啟動挖礦會先生成挖礦所需的DAG檔案,這個過程有點慢,等進度達到100%後,就會開始挖礦,此時螢幕會被挖礦資訊刷屏。

如果想停止挖礦,並且進度已經達到100%之後,可以在js console中輸入

> miner.stop()

挖到一個區塊會獎勵5個以太幣,挖礦所得的獎勵會進入礦工的賬戶,這個賬戶叫做coinbase,預設情況下coinbase是本地賬戶中的第一個賬戶:

> eth.coinbase
"0x67346d5619ae5747eb69629c8b1c8cbae71111c3"

getBalance()返回值的單位是wei,wei是以太幣的最小單位,1個以太幣=10的18次方個wei。要檢視有多少個以太幣,可以用web3.fromWei()將返回值換算成以太幣:

> web3.fromWei(eth.getBalance(eth.accounts[0]),'ether')

傳送一筆交易

> eth.sendTransaction({from:eth.accounts[0],to:eth.accounts[1],value:amount})

這裡報錯了,原因是賬戶每隔一段時間就會被鎖住,要傳送交易,必須先解鎖賬戶,由於我們要從賬戶0傳送交易,所以要解鎖賬戶0:

> personal.unlockAccount(eth.accounts[0])

輸入建立賬戶時設定的密碼,就可以成功解鎖賬戶。然後再發送交易。

我們去檢視賬戶1中的餘額,發現還沒轉過去,此時交易已經提交到區塊鏈,但還未被處理,這可以通過檢視txpool來驗證:

> txpool.status
{
  pending: 1,
  queued: 0
}

其中有一條pending的交易,pending表示已提交但還未被處理的交易。

要使交易被處理,必須要挖礦。這裡我們啟動挖礦,然後等待挖到一個區塊之後就停止挖礦:

> miner.start(1);admin.sleepBlocks(1);miner.stop();

當miner.stop()返回true後,txpool中pending的交易數量應該為0了,說明交易已經被處理了,而賬戶1應該收到幣了:

> web3.fromWei(eth.getBalance(eth.accounts[1]),'ether')
10

檢視交易

eth物件封裝了檢視交易和區塊資訊的方法。

檢視當前區塊總數:

> eth.blockNumber

3.建立節點叢集

在私有網路中建立多個節點組成的叢集,並互相發現,產生交易。

如果是為了在本地網路執行多個以太坊節點的例項,必須確保一下幾點:
1. 每個例項都有獨立的資料目錄(--datadir)
2. 每個例項執行都有獨立的埠.(eth和rpc兩者都是)(--port 和 --rpcprot)
3. 在叢集的情況下, 例項之間都必須要知道彼此.

4. 唯一的ipc通訊端點,或者禁用ipc.

在這裡,我們選擇在不同的電腦上分別建立節點組成叢集,互相發現,產生交易。

在第一臺電腦上啟動節點

geth --datadir data0 --networkid 1008 console

在第二臺電腦上初始化並啟動節點,注意網路ID要相同,確保節點都在一個私有網路中。

geth --datadir ./data/01 init ./genesis.json  初始化 注意和第一個節點使用相同的創始快json檔案

geth --datadir data0 --networkid 1008 --bootnodes "enode://b86d51f0737672b80c9000caa706955b2a94286f8593774aab40c86cbb4fc871c[email protected]192.168.6.150:30303" console

bootnodes後邊的引數是第一臺電腦上節點的enode url 可以在第一臺電腦上通過

>admin.nodeInfo.enode

來獲取。

@192.168.6.150:30303  是第一臺電腦的IP地址:192.168.150 以及ports:30303

本節點的ports可以通過

admin.nodeInfo

來獲取。

至此兩個節點應該就連結成功了。

3.1節點間傳送以太幣

> eth.sendTransaction({from: "0x5fba50fce50baf0b8a7314200ba46336958ac97e", to: "0x0a8c35653d8b229c16f0c9ce6f63cffb877cfdcf", value: web3.toWei(1, "ether")})

from中填當前節點的賬號地址,to中填要傳送給的節點的賬號地址。

執行以上命令傳送一個以太幣。注意傳送交易操作前要先解鎖賬號:

> personal.unlockAccount(eth.accounts[0], "passwoed")

然後執行挖礦太能讓交易生效。

> miner.start()

4.編寫helloworld智慧合約

   讓我們開始你的第一個嚴肅的合約。前沿是一個很大的開放領土,有時候你可能會感到孤獨,所以我們的第一步就是創造一個自動伴侶,在你感到孤獨時迎接你。我們會稱他為“Greeter”。

   Greeter是一個智慧數字化實體,它存在於區塊鏈中,並能夠根據其輸入與任何與之互動的人進行對話。它可能不是一個說話者,但它是一個很好的傾聽者。這是它的程式碼:

contract Mortal {
    /* Define variable owner of the type address */
    address owner;

    /* This function is executed at initialization and sets the owner of the contract */
    function Mortal() { owner = msg.sender; }

    /* Function to recover the funds on the contract */
    function kill() { if (msg.sender == owner) selfdestruct(owner); }
}

contract Greeter is Mortal {
    /* Define variable greeting of the type string */
    string greeting;

    /* This runs when the contract is executed */
    function Greeter(string _greeting) public {
        greeting = _greeting;
    }

    /* Main function */
    function greet() constant returns (string) {
        return greeting;
    }
}
   你會注意到這個程式碼中有兩個不同的合約:“Mortal”和“Greeter”。這是因為Solidity(我們使用的高階合同語言)具有繼承性,這意味著一個合約可以繼承另一個合約的特徵。這對簡化編碼非常有用,因為合約的通用特徵不需要每次重寫,並且所有合約都可以用更小,更易讀的塊編寫。所以通過只宣告Greeter是Mortal的,你就繼承了來自“Mortal”合約的所有特徵,並使Greeter程式碼簡單易讀。

  繼承特徵的“Mortal”僅僅意味著Greeter合同可以被其所有者殺死,以清理區塊鏈並在不再需要合同時收回鎖定在其中的資金。以太坊中的契約預設為不朽,並且沒有所有者,這意味著一旦部署,作者就沒有特殊的特權了。部署前請考慮這一點。

  在部署合同前,需要準備兩樣東西:

1.編譯後的程式碼。

2.應用程式二進位制介面(ABI),它是一個定義如何與合約進行互動的JavaScript物件

  我們可以通過使用Solidity編譯器來獲得這兩者。(線上編譯器remix的地址:點選開啟連結

4.1獲得編譯後的程式碼

   將原始碼(位於本頁頂部)複製到Remix,它應該自動編譯您的程式碼。 您可以放心地忽略右側任何黃色警告框。


  要訪問已編譯的程式碼,請確保右窗格中的下拉選單已選中Greeter。 然後直接點選下拉選單右邊的details按鈕。 在彈出視窗中,向下滾動並複製WEB3DEPLOY文字框中的所有程式碼。



  在計算機上建立一個臨時文字檔案並貼上該程式碼。 確保將第一行更改為如下所示:

var _greeting = "Hello World!"

  現在,可以將結果文字貼上到geth視窗中,或者使用loadScript(“yourFilename.js”)匯入檔案。

 然後執行挖礦。  

 等待一會終端中會看到類似這樣的訊息:


您可能必須先使用您在開始時選擇的密碼來“解鎖”傳送交易的帳戶,因為您需要支付部署合同的GAS費用。 

personal.unlockAccount(web3.eth.accounts [0],“yourPassword”)

您可以使用以下命令來驗證已部署的程式碼(將被編譯):

eth.getCode(greeter.address)

如果它返回“0x”以外的任何內容,那麼恭喜! 你的小傢伙活著! 如果再次建立合同(通過執行另一個eth.sendTransaction),它將釋出到新地址。

4.2 執行Greeter

為了召喚你的機器人,只需在終端上輸入以下命令:

greeter.greet();

由於這個呼叫沒引起在區塊鏈上的任何變化,因此它會立即返回並且無需任何燃氣費用。 你應該看到它返回你的問候語:

'Hello World!'

4.3 讓其他人與您的程式碼互動

為了讓其他人來執行你的合同,他們需要兩個東西:
1.合同所在地址
2. ABI(應用程式二進位制介面),這是一種使用者手冊,描述合同功能的名稱以及如何將它們呼叫到您的JavaScript控制檯
    想要獲取地址,請執行以下命令:
greeter.address;

    得到類似下圖的一個合約地址:


   為了得到ABI,您需要直接從Remix複製ABI,類似於複製WEB3DEPLOY編譯程式碼的方式。 在右側窗格中,單擊詳細資訊按鈕並向下滾動到ABI文字框。 點選複製按鈕複製整個ABI,然後將其貼上到臨時文字文件中。




然後,您可以例項化一個可用於在連線到網路的任何計算機上呼叫合同的JavaScript物件。 在以下行中,替換ABI(一個數組)和Address(一個字串)以在JavaScript中建立合同物件:

var greeter = eth.contract(ABI).at(Address);
這樣別的節點就也可以通過
greeter.greet();

呼叫你的機器人了。結果顯示:

'Hello World!'