區塊鏈開發(二)部署並運行第一個以太坊智能合約
李赫2016年8月22日
本文首發8BTC
網路上不少部署智能合約的文章,但是都有一個共同的特點,就是採用命令列的方式來部署,先是建立SOLC的編譯環境,然後部署Geth或者Eth節點,然後一步一步產生錢包、ABI、合約地址進行部署,對初學者來說晦澀難懂而且容易失敗,本文主要介紹如何在圖形化介面下一鍵部署和調用智能合約。對於其他區塊鏈知識,請參考我的其他文章:http://blog.csdn.net/sportshark
一、 智能合約和DAPP概述
1、 智能合約基本概念
智能合約是一段代碼和資料的集合,可以部署以太坊網路上運行。如果做比喻的話智能合約更像是JAVA程式,JAVA程式通過JAVA虛擬機器(JVM)將代碼解釋位元組進行執行,以太坊的智能合約通過以太坊虛擬機器(EVM)解釋成位元組碼進行執行,如果你學過彙編,會發現編譯後的位元組碼和彙編很類似。同時智能合約有自己的賬戶,在時間或事件的驅動下能自動執行一些功能,如可以在相互之間傳遞資訊,修改區塊鏈的狀態比如賬戶資訊等。以太坊的智能合約最大的特點是圖靈完備,通俗來說可以完全類比一台電腦所能做的所有事情,大家熟知的比特幣其實也可以執行一些簡單指令碼,但是他就不是圖靈完備,比如迴圈指令比特幣就無法執行。
以太坊虛擬機器(EVM)
以太坊虛擬機器(EVM)是以太坊中智能合約的運行環境。它不僅被沙箱封裝起來,事實上它被完全隔離運行,也就是說運行在EVM內部的代碼不能接觸到網路、檔案系統或者其它進程,甚至智能合約之間也只有有限的調用。
2、 DAPP基本概念
初學者經常把智能合約和DAPP搞混,以太坊社區把基於智能合約的應用稱為去中心化的應用程式(Decentralized App)。DApp的目標是讓你的智能合約有一個友好的介面,外加一些額外的有利於使用者使用的東西。典型的DApp例子由一個html介面,web3運行庫,一段JS代碼以及部署在區塊鏈上的一段智能合約組成。與一般CS架構的網站不同,DApp不能在普通的伺服器上運行,DApp必須運行在一台能與以太坊節點互動的伺服器上,或者任意一個以太坊節點上。DApp通過提交交易到區塊鏈網路與對應的智能合約進行互動,並且從區塊鏈網路而不是中心化資料庫比如(MYSQL資料庫)讀取重要資料。相對於典型的BS架構使用者登入系統不同,以太坊使用者被表示成一個十六進位的地址而且所有使用者資料和其他資料均儲存在本地,與目前的web應用架構有很多不同。
3、 智能合約進階語言
使用者不可能直接編寫以太坊虛擬機器(EVM)位元組碼,所以以太坊提供了幾種編寫智能合約的進階語言。
Solidity:類似JavaScript,這是以太坊推薦的旗艦語言,也是最流行的智能合約語言。具體用法參加Solidity文檔,地址:https://solidity.readthedocs.io/en/latest/
Serpent:類似Python風格,文檔地址:https://github.com/ethereum/wiki/wiki/Serpent
LLL:類似Lisp風格,目前已經被終止了。
可以根據不同的習慣選擇不同的進階語言,目前最流行的是Solidity。
二、 在以太坊私人鏈上部署第一個智能合約
本文的智能合約採用以太坊官方的樣本合約,功能就是在區塊鏈上儲存一個數字,並能夠讀取出來。代碼如下:
contract SimpleStorage {
uint storedData;
function set(uint x) {
storedData = x;
}
function get() constant returns (uintretVal) {
return storedData;
}
}
即使沒有學過Solidity語言也可以大致看出,該合約set函數儲存一個數字在X變數中,get函數從X變數中讀取這個數字出來,下面對這個合約進行部署:
1、 啟動私人鏈
啟動以太坊私人鏈Geth和Ethereum-Wallet圖形介面(本文使用Geth 1.41版本, Ethereum-Wallet 0.8.1版本)。如果不知道如何啟動,請參考我上一篇文章《區塊鏈開發(一)搭建基於以太坊的私人鏈環境》地址:http://blog.csdn.net/sportshark/article/details/51855007,啟動後介面如下, Ethereum-Wallet會顯示紅色的PRIVTE-NET標記。
2、建立兩個錢包
點擊”ADD ACCOUNT” 按鈕,添加一個錢包,程式會彈出一個對話方塊,提示輸入兩遍密碼,輸入完密碼後,帳號即建立成功。建立其他的帳號,一樣的操作,從上面的截圖可以看到,有三個帳號,一個是MAIN ACCOUNT,一個是ACCOUNT2,一個是ACCOUNT3
3、挖礦擷取一些以太幣
帳號建立後,還沒有以太幣,需要在私人鏈上挖礦,切換到Geth介面,輸入
miner.start(1)
miner命令括弧中的1表示用一個線程進行挖礦,如果不配置,就會讓CPU全速運行,影響電腦的使用。
運行一會後,主帳號就會擷取很多以太幣,這個時候螢幕會快速刷屏,不用管,輸入命令miner.stop()停止挖礦。
4、 將一個錢包的以太幣轉到另一個錢包中
先點擊ACCOUNT2帳號,進入帳號詳情的介面,點擊右側的“COPY address”,把ACCOUNT2的地址拷貝下來,系統會提示你現在你處在一個測試網路,不要轉入真正的以太幣到這個帳號。
點擊錢包中“SEND”按鈕,從MAINACCOUNT給ACCOUNT2轉入一定以太幣,同時可以看到執行這筆交易的費用是0.00042個以太幣。
點擊發送後會提示如輸入密碼,但這時還沒有發送成功,根據區塊鏈的交易規則,需要礦工的確認,並且每筆交易需要確認12個塊,一個塊是16秒的產生時間。切換到Geth程式,輸入挖礦命令,直到ACCOUNT2上顯示100個以太幣,然後停止挖礦。
5、 部署智能合約
點“CONTRACTS”,進入智能合約管理介面,點擊“DEPOLY NEW CONTRACT”,開始部署智能合約,選擇部署智能合約的帳號,並輸入智能合約的代碼後,如下圖
輸入完畢後點擊“DEPLOY”,系統會提示輸入帳號密碼,因為部署智能合約是需要費用的。
這個時候是看不到部署的智能合約的,切換到Geth介面,進行挖礦,在12個塊後,智能合約就能確認並顯示出來。
三、 運行智能合約
1、 在本節點上運行智能合約
點擊“CONTRACTS”進入智能合約介面,可以看到剛才部署的智能合約“SimpleStorage”,點擊進入該智能合約,進入詳情介面,其中有智能合約寫入地區和讀取地區,首先啟動Geth的挖礦,然後在寫入地區選取項目相應的智能合約函數SET,在下面的數值輸入框輸入想設定的數值,運行一會後就可以在讀取地區看到智能合約函數GET中Retval的傳回值有變化。
其他智能合約的運行也是一樣,無非就是函數多點,輸入多點。
2、 在其他節點上運行智能合約
此時的智能合約只能自己能看到,別人是無法看到和啟動並執行,如果其他人要運行你部署好的智能合約需要提供一些資訊,就是其他教程中所說的智能合約的ABI和地址。
進入剛部署的“SimpleStorage”智能合約介面,右側有四個按鈕
A.“Deposit Eher”:向該智能合約發送以太幣
B.“Copy address”:拷貝該智能合約的地址
C.“Show QR Code”:顯示一個二維碼,如果用手機掃描的話,顯示該智能合約的地址
D.“Show Interface”:顯示該智能合約的JSON介面,也就是ABI
首先我們點“Copy address”,拷貝該智能合約的地址,然後點“Show Interface”將智能合約的JSON介面全部拷貝出來,在另一個需要運行智能合約的節點開啟Ethereum-Wallet,開啟“CONTRACTS”介面點擊“WATCH CONTRACTS”添加一個智能合約。
如上圖所示,CONTRACT NAME隨便填,CONTRACT ADDRESS填寫智能合約地址,JSON INTERFACE填寫剛才在”Show Interface “中拷貝的內容。點OK後,就可以看到這個智能合約並運行了。
四、 智能合約的部署原理
1、智能合約的部署架構
本文介紹的智能合約的部署雖然是在圖形化介面編譯和執行,但其實最主要的是依賴於後台運行Geth的節點,此時Geth提供了一個RPC的介面向圖形化介面的錢包提供區塊鏈的資訊。
RPC介面
Geth在8545連接埠提供了JSON RPC API ,資料轉送採用JSON格式,可以執行Web3庫的各種命令,比如向前端,比如mist等圖形化用戶端提供區塊鏈的資訊,預設訪問地址為http://localhost:8545。
我們部署一個智能合約時,首先Ethereum-Wallet調用SOLC智能合約編譯器將代碼編譯成成EVM位元組碼,然後將EVM位元組碼通過Geth的RPC介面發送到以太坊網路,經過全網驗證後,同時寫入到每個Geth管理的區塊鏈中,架構如下
2、 部署的資料流
首先代碼先經過SOLC編譯變為了二進位碼,然後通過一筆交易來建立智能合約,該筆交易包含了建立者帳號、智能合約內容、智能合約的地址這幾個關鍵資訊,其中智能合約地址的產生是由建立者的帳號和發送的交易數作為隨機數輸入,通過Kecca-256密碼編譯演算法重新建立一個地址作為帳號。
部署過程中,需要通過交易來部署,同時資料要儲存到區塊鏈上,這些需要使用到GAS。
交易(Transactions)
一筆交易是一條訊息,從一個賬戶發送到另一個賬戶。交易可以包含位元據(payload)和以太幣。
如果目標賬戶包含代碼,該代碼和輸入資料會被執行。
如果目標賬戶是零賬戶(賬戶地址是0),交易將建立一個新合約。正如上文所講,這個智能合約地址不是零地址,而是由合約建立者的地址和該地址發出過的交易數量計算得到。建立合約交易的payload被當作EVM位元組碼執行。執行的輸出做為合約代碼被永久儲存。這意味著,為了建立一個合約,你不需要向合約發送真正的合約代碼,而是發送能夠返回可執行代碼的代碼。
Gas
以太坊上的每筆交易都會被收取一定數量的gas,gas的目的是限制執行證券交易所需的工作量,同時為執行支付費用。當EVM執行智能合約時,gas將按照特定規則被逐漸消耗,其實GAS就是以太幣的比較小的單位,如果以太幣比作100元,那麼GAS可以看作是1分錢。如果只有以太幣,會有問題,以太幣是需要大家買賣的,市場會有價格波動。可能會出現比特幣這樣的狀況,一天跌50%漲50%。這個對計算的成本是不能接受的,例如今天做一個加法需要十塊錢,明天做一個加法需要一百塊錢。所以這裡引入gas來解耦。把市場的波動和計算的開銷來解耦,也就是說以太幣和gas之間是有匯率的,以太幣漲沒關係,gas價格下降就可以了。它要保證我做同樣的計算,消耗的法幣是一致的。
gas price(gas價格,以太幣計)是由交易建立者設定的,發送賬戶需要預付的交易費用 = gas price * gas amount。 如果執行結束還有gas剩餘,這些gas將被返還給發送賬戶。
前文中曾經提到部署智能合約使用了0.00042個以太幣,換算成gas就是21000個gas。
無論執行到什麼位置,一旦gas被耗盡(比如降為負值),將會觸發一個out-of-gas異常。當前調用幀所做的所有狀態修改都將被復原。
五、 智能合約的運行原理
智能合約是部署在區塊鏈的代碼,區塊鏈本身不能執行代碼,代碼的執行是在本地的EVM中,實際上,部署在區塊鏈上代碼是能夠在本地產生原智能合約代碼的代碼,可以理解區塊鏈為一個資料庫,而用戶端從資料庫中讀取了儲存的運行代碼,並在本地運行後,將結果寫入到了區塊鏈這個資料庫中。
本質上,以太坊的錢包也是智能合約的一個應用,以太坊搭建的是一個可供編寫各種應用的平台。下一篇,將詳細講述智能合約的開發編寫和調試方法