參考地址:Ethereum Homestead
什么是智能合約
智能合約是代碼和數據的集合,寄存與Blockchain的具體的地址。智能合約更想是在Blockchain中的一個自動化的代理(或者說是機器人or NPC),智能合約有自己的賬戶,在時間或事件的驅動下能自動執行一些功能,如可以在相互之間傳遞信息,修改區塊鏈的狀態(賬戶信息等),以及圖靈完備計算(可以用圖靈機做到的所有事情,通俗來說就是一般編程語言可以做的所有事情)。以太坊的智能合約是以太坊特定的字節碼,被叫做EVM字節碼。
智能合約高級語言
用戶不可能直接編寫EVM字節碼,所以以太坊提供了幾種編寫智能合約的高級語言。
Solidity:類JavaScript,這是以太坊推薦的旗艦語言,也是最流行的智能合約語言。具體用法參加Solidity文檔。
Serpent:類Python
LLL:類Lisp
可以根據不同的習慣選擇不同的高級語言。這里選用最流行的Solidity
相關概念
以下的概念是智能合約可能用到的,這里不做詳細介紹,想了解的可以參考 智能合約菜鳥教程
公鑰加密系統:
點對點網絡:
區塊鏈:區塊鏈可以看做是智能合約的基礎設施
以太坊虛擬機:解釋執行智能合約字節碼的東西,功能類似於Java虛擬機
節點:
礦工:區塊鏈中參與處理區塊的節點叫做礦工。當前以太坊活躍的礦工:https://ethstats.net/
工作量證明:礦工們總是在競爭解決一些數學問題。第一個解出答案的(算出下一個區塊)將獲得以太幣作為獎勵。然后所有節點都更新自己的區塊鏈。所有想要算出下一個區塊的礦工都有與其他節點保持同步,並且維護同一個區塊鏈的動力,因此整個網絡總是能達成共識。
以太幣:ETH,以太坊中的虛擬貨幣,可以購買和使用,也可以與真實貨幣交易。以太幣的走勢圖
Gas:相當於手續費。在以太坊執行程序以保存數據都要消耗一定量的以太幣。這個機制可以控制區塊鏈中計算的數量,保證效率。
智能合約與DApp
以太坊社區把基於智能合約的應用稱為去中心化的應用程序(Decentralized App)。DApp的目標是(或者應該是)讓你的智能合約有一個友好的界面,外加一些額外的東西,例如IPFS(可以存儲和讀取數據的去中心化網絡,不是出自以太坊團隊但有類似的精神)。DApp可以跑在一台能與以太坊節點交互的中心化服務器上,也可以跑在任意一個以太坊平等節點上。(花一分鍾思考一下:與一般的網站不同,DApp不能跑在普通的服務器上。他們需要提交交易到區塊鏈並且從區塊鏈而不是中心化數據庫讀取重要數據。相對於典型的用戶登錄系統,用戶有可能被表示成一個錢包地址而其它用戶數據保存在本地。許多事情都會與目前的web應用有不同架構。)
DApp流程:
- 用Solidity(或其他語言)編寫智能合約(后綴為.sol)
- 用solc編譯器將.sol合約編譯成EVM字節碼
- 編譯好的字節碼回送給dapp前端
- 前端將編譯好的智能合約部署到區塊鏈中
- 區塊鏈返回智能合約地址+ABI(合約接口的二進制表示。合約接口用JSON表示,包括變量,事件和可以調用的方法)
- 前端通過Address+ABI+nonce,調用智能合約。智能合約開始處理。
智能合約編譯器
Solidity智能合約可以通過多種方式進行編譯
- 通過在線Solidity實時編譯器來編譯。online Solidity realtime compiler
- 安裝solc編譯器編譯
- 在客戶端javascript console中,通過web3.eth.compile.solidity編譯。不過這個需要環境中安裝solc編譯器。
- The Meteor dapp Cosmo for building solidity contracts
- The Mix IDE
- The Ethereum Wallet
在這里選擇solc和web3.eth.compile.solidity方式
geth安裝
參考:go Ethereum client。安裝不比較簡單,這里詳細說了
solc安裝
1. 作為cpp-ethereum的一部分安裝
如果通過編譯的方式安裝了cpp-ethereum(參考:http://www.cnblogs.com/fengzhiwu/p/5547911.html),那么solc編譯器就會作為cpp-ethereum的一個子項目也被編譯安裝,在webthree-umbrella/build/solidity/solc目錄下找到solc編譯器的可執行文件。
然后,在/bin或/usr/bin目錄下創建軟鏈接就行了
ln -s /home/vagrant/Code/workspace/webthree-umbrella/build/solidity/solc/solc /bin/solc
2. 單獨安裝solc
參考:http://solidity.readthedocs.io/en/latest/installing-solidity.html
- 通過npm安裝:這種比較簡單,運行npm install solc就行了,不過我沒有在console中找到solc
- 通過apt-get安裝:
sudo add-apt-repository ppa:ethereum/ethereum
sudo apt-get update
sudo apt-get install solc
which solc
把solc添加入geth中直接使用(在geth中輸入)
admin.setSolc("path/to/solc")
- 從源碼編譯安裝
這種方法和安裝cpp-etheruemle類似,不過最后的編譯步驟改為:
cd webthree-umbrella./webthree-helpers/scripts/ethupdate.sh --no-push --simple-pull --project solidity # update Solidity repo ./webthree-helpers/scripts/ethbuild.sh --no-git --project solidity --cores 4 -DEVMJIT=0 -DETHASHCL=0 # build Solidity only
測試
打開一個geth console,輸入:web3.eth.getCompilers(),就會打印
智能合約體驗
編譯一個簡單的合約
直接在console中編譯一個簡單的合約代碼
> source = "contract test { function multiply(uint a) returns(uint d) { return a * 7; } }"> clientContract = eth.compile.solidity(source).test
編譯返回的結果的JSON格式如下
其中,
code:編譯后的EVM字節碼
info:編譯器返回的metadata
abiDefination:Application Binary Interface定義。具體接口規則參見這里
compilerVersion:編譯此代碼的solidity編譯器版本
developerDoc:針對開發者的Natural Specification Format,類似於Doxygen。具體規則參見這里
language:合約語言
languageVersion:合約語言版本
source:源代碼
userDoc:針對用戶的Ethereum的Natural Specification Format,類似於Doxygen。
編譯器返回的JSON結構反映了合約部署的兩種不同的路徑。info信息真實的存在於區中心化的雲中,作為metadata信息來公開驗證Blockchain中合約代碼的實現。而code信息通過創建交易的方式部署到區塊鏈中。
創建和部署合約
在進行此步驟前,確保你有一個解鎖的賬戶並且賬戶中有余額。(可以創建自己獨立的測試網絡,即自己的區塊鏈,初始化的時候就可以初始化一些有余額的賬戶)。參考:Test Networks
現在就可以在區塊鏈中創建一個合約了。創建合約的方式是發送一個交易,交易的目的地址是空地址,數據是前面JSON結構中的code字段。
創建合約的流程如下
var primaryAddress = eth.accounts[0]
var abi = [{ constant: false, inputs: [{ name: 'a', type: 'uint256' } ]}]
var MyContract = eth.contract(abi)
var contract = MyContract.new(arg1, arg2, ..., {from: primaryAddress, data: evmByteCodeFromPreviousSection}) //arg1,arg2,...是構造參數,這里沒有,需要去掉。紅色部分用前面生成的code代替
i. 獲得賬戶
ii. 定義一個abi (abi是個js的數組,否則不成功)
iii. 創建智能合約
iv. 發送交易部署合約
如果交易被pending,如圖說明你的miner沒有在挖礦,
啟動一個礦工
miner.setEtherbase(eth.primaryAddress) //設定開采賬戶miner.start(8)
eth.getBlock("pending", true).transactions
這時候發現交易已經在區塊中
不過會發現,交易還是pending,這是因為該交易區塊沒有人協助進行運算驗證,這時候只需要再啟動一個礦工就行了
miner.start(8)
參考:Private Testnet
發現區塊1部署了交易
與合約進行交互
可以通過eth.contract()定義一個合約對象,這個對象包含變數合約接口的abi
Multiply7 = eth.contract(clientContract.info.abiDefinition); var myMultiply7 = Multiply7.at(contract.address);
到這兒,就可以調用智能合約的函數了。
myMultiply7.multiply.call(3)或myMultiply7.multiply.sendTransaction(3, {from: contract.address})
結束
到此,對智能合約的初次體驗就結束了。另外智能合約以及DApp還可以干很多NB的事情。以后會進一步討論。