以太坊私有鏈搭建節點叢集 到 簡單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:包含一些檢視交易記憶體池的方法
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!'