【區塊鏈學習】以Linux為例,通過控制檯部署和執行智慧合約
安裝環境
安裝以太坊環境
(1) sudo apt-get install software-properties-common
(2)sudo add-apt-repository -y ppa:ethereum/ethereum
(3)sudo add-apt-repository -y ppa:ethereum/ethereum-dev
(4)sudo apt-get update
(5)sudo apt-get install ethereum
,如果這一步失敗,一直重試安裝
安裝solidity語言編譯器
(1)Chrome裡面外掛安裝
開啟Chrome網上應用商店,搜尋solidity
安裝後開啟,一般solidity語言編寫的智慧合約程式碼會自動編譯,然後在右邊顯示,如果沒有,說明solidity程式碼語法錯誤
例如,solidity智慧合約程式碼編譯通過
例如,solidity智慧合約程式碼編譯失敗
(2)solidity語言線上編譯器
私有鏈搭建
(1)開啟終端(Ctrl+Alt+T)
(2)開啟測試網控制檯:geth --datadir "~/ethdev" --dev console 2>> geth.log
(3)檢視personal的屬性:personal
(4)建立賬戶: personal.newAccount('123456')
,123456是密碼,0xe9f350a2c250fa26b7eb3db6f28d858668b7e45b
是賬戶地址
(5)檢視賬戶餘額:web3.eth.getBalance(personal.listAccounts[0])
, personal.listAccounts[0]
就是我們第一賬戶,當前賬戶餘額為0
(6)啟動挖礦:miner.start()
, 如果感覺佔用CPU,可以啟動一個CPU挖礦miner.start(1)
(7)開啟另一終端,檢視挖礦資訊(如果一直挖礦,會不斷刷屏,正常,這個終端用來觀察挖礦資訊),檢視挖礦資訊:tail -f geth.log
(8)停止挖礦:miner.stop()
,如果覺得CPU被佔用覺得還行,忽略這一步,後面交易確認需要挖礦一直進行
(9)檢視餘額:web3.eth.getBalance(personal.listAccounts[0])
或者web3.fromWei(eth.getBalance("0xe9f350a2c250fa26b7eb3db6f28d858668b7e45b"), "ether")
(10)解鎖發起智慧合約的賬戶:personal.unlockAccount("0xe9f350a2c250fa26b7eb3db6f28d858668b7e45b")
, 0xe9f350a2c250fa26b7eb3db6f28d858668b7e45b
是我們發起智慧合約賬戶的地址
部署智慧合約
(1)編寫智慧合約:
contract Rating {
function setRating(bytes32 _key, uint256 _value) {
ratings[_key] = _value;
}
mapping (bytes32 => uint256) public ratings;
}
(2)複製編譯後得到Web3 deploy
, 從程式碼上看,定義了2個變數:ratingContract
和rating
var ratingContract = web3.eth.contract([{"constant":false,"inputs":[{"name":"_key","type":"bytes32"},{"name":"_value","type":"uint256"}],"name":"setRating","outputs":[],"type":"function"},{"constant":true,"inputs":[{"name":"","type":"bytes32"}],"name":"ratings","outputs":[{"name":"","type":"uint256"}],"type":"function"}]);
var rating = ratingContract.new(
{
from: web3.eth.accounts[0],
data: '606060405260c88060106000396000f360606040526000357c01000000000000000000000000000000000000000000000000000000009004806350b7b7a21460415780636c71d01d14606057603f565b005b605e6004808035906020019091908035906020019091905050608a565b005b6074600480803590602001909190505060ad565b6040518082815260200191505060405180910390f35b8060006000506000848152602001908152602001600020600050819055505b5050565b6000600050602052806000526040600020600091509050548156',
gas: 3000000
}, function(e, contract){
console.log(e, contract);
if (typeof contract.address != 'undefined') {
console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash);
}
})
(3)複製上面的程式碼到控制檯上,從內容看,裡面是2個變數的定義,所以分開復制更好看一些。
(4)這時,我們可以檢查一下交易池,檢視當前交易的待處理狀況:txpool.status
,如果pending=1,說明我們的合約還沒得到確認,因為我們剛才停止挖礦。
(5)從上面,我們可以看到當前的交易池中有一個交易正在等待確認。然後,我們檢視待確認交易的詳細內容:eth.getBlock("pending",true).transactions
我們從顯示出來的結果可以看出當前交易的一些內容。例如,from資料項就是我們傳送交易的地址,input就是合約編譯完成的位元組碼,這些內容均與我們之前的設定相同。而且,我們可以看到新的交易建立在第2016號區塊中。
與此同時,我們也可以檢視一下剛才在新的終端中建立的挖礦日誌。我們在日誌中找到這樣的一行資訊:
這說明交易已經發送到區塊鏈中了,正在等待礦工的確認。
(6)啟動挖礦:miner.start()
控制檯提示Contract mined
,則合約被建立成功,並返回合約的地址(address)和此次交易的雜湊值。可通過這兩個數值在區塊鏈上尋找合約的資訊。
(7)我們發現交易池已經沒有待確認的交易了。我們使用eth.getBlock(2016)
命令檢視第2016號區塊的資訊:eth.getBlock(2016)
我們發現hash值為0xa20f32030e6114002da1e8c8645023ee02ad43a18dde34f43c916bddc886bc5e
的交易確實在第2016號區塊中。
呼叫智慧合約
(1)在部署合約所使用的控制檯視窗下,可直接使用合約名和函式名呼叫合約。假設一個使用者想為1號商品打3分,需要呼叫rating合約的setRating函式,需要執行以下命令:(我這裡是rating,是因為我上面編譯合約的程式碼賦值給rating,這裡這裡要根據自己編譯完合約的程式碼而定)
rating.setRating.sendTransaction(1, 3, {from: personal.listAccounts[0]})
如果出現下面紅色的錯誤,重新解鎖賬戶
由於使用者需要發起一個交易並改變區塊鏈的狀態,因此需要用到合約物件的sendTransaction()
方法來發起交易。該方法的前幾個引數為setRating
函式的引數,最後一個引數為發起交易的地址,也就是需要為本次交易支付費用的賬戶的地址。這裡personal.listAccounts[0]
代表錢包內的第1個賬戶,即基準賬戶MAIN ACCOUNT
:
"0x3c194bcba9c3b90028fdd22aaad4f4c8973781835c15c57d3879dc5c1c743760"
(2)經過一段時間的確認,該交易被儲存到區塊鏈中,此時可使用rating合約中的ratings陣列來顯示1號商品的打分,其命令如下:rating.ratings(1)
這時將會顯示3,表示1號商品被打了3分。由於此時並不需要改變區塊鏈系統的狀態,因此不需要使用sendTransaction方法,也就不需要支付任何費用。
(3) 如果想在其他以太坊節點通過控制檯呼叫合約,則需知道合約的地址和介面。執行以下命令例項化合約物件:var NewRatingContract = eth.contract(interface).at(“address”)
這裡,interface的資訊可從Solidity線上編輯器上獲得,而address在合約部署之後返回得到。之後,使用NewRatingContract.ratings(1)命令就可查詢到1號商品的打分。例如我的:
var NewRatingContract = eth.contract([{"constant":false,"inputs":[{"name":"_key","type":"bytes32"},{"name":"_value","type":"uint256"}],"name":"setRating","outputs":[],"type":"function"},{"constant":true,"inputs":[{"name":"","type":"bytes32"}],"name":"ratings","outputs":[{"name":"","type":"uint256"}],"type":"function"}]).at("0x133e80139ce46615a777ba26f5ee2a39ee709df1")
找到interface資訊:
找到address資訊:
(3)查詢打分: