區塊鏈開發(二)部署和執行第一個以太坊智慧合約
區塊鏈開發(二)部署並執行第一個以太坊智慧合約
李赫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中,實際上,部署在區塊鏈上程式碼是能夠在本地產生原智慧合約程式碼的程式碼,可以理解區塊鏈為一個數據庫,而客戶端從資料庫中讀取了儲存的執行程式碼,並在本地執行後,將結果寫入到了區塊鏈這個資料庫中。
本質上,以太坊的錢包也是智慧合約的一個應用,以太坊搭建的是一個可供編寫各種應用的平臺。下一篇,將詳細講述智慧合約的開發編寫和除錯方法