使用solidity語(yǔ)言撰寫(xiě)智能合約
Ethereum上的智能合約需要使用solidity語(yǔ)言來(lái)撰寫(xiě)迎卤。雖然還有其他能用來(lái)撰寫(xiě)智能合約的語(yǔ)言如Serpent(類(lèi)Python)墩弯、lll(類(lèi)Fortran)
但目前看到所有公開(kāi)的智能合約都是使用solidity撰寫(xiě)。
solidity還是比較像Java或C#展融。因?yàn)楹蚃avascript不同窖认,solidity與Java或C#同屬于強(qiáng)類(lèi)型(Strong Type,在定義變數(shù)時(shí)需要指定類(lèi)型)語(yǔ)言愈污、在定義函式(function)時(shí)同樣需指定回傳的類(lèi)型(type)耀态、同樣也需要先編譯才能執(zhí)行。這些特性都是Javascript所不具備的暂雹。
關(guān)于solidity編寫(xiě)智能合約的具體語(yǔ)法參見(jiàn)筆者專(zhuān)題
開(kāi)發(fā)前的準(zhǔn)備
本文將使用當(dāng)前最活躍的智能合約開(kāi)發(fā)框架truffle為基礎(chǔ)來(lái)開(kāi)發(fā)首装。ENS(Ethereum Name Service)也是采用truffle框架。其他選擇還有embark等杭跪。
測(cè)試網(wǎng):test rpc仙逻。 畢竟真實(shí)網(wǎng)絡(luò)需要以太幣,且操作需要等待十幾秒涧尿,性價(jià)比不高系奉。testrpc中也包含了Javascript版本的Ethereum虛擬機(jī)(Ethereum Virtual Machine),因此可以完整地執(zhí)行智能合約姑廉。
-編譯器: atom缺亮,好處之前說(shuō)過(guò)
環(huán)境準(zhǔn)備
- node.js (自行安卓)
- 安裝truffle
$ npm install -g ethereumjs-testrpc truffle
- 啟動(dòng)testrpc
luoxuedeMBP:~ luoxue$ testrpc
EthereumJS TestRPC v6.0.3 (ganache-core: 2.0.2)
Available Accounts
==================
(0) 0x48e9abd440ff12f0f5bd457d0205d64a2c047973
(1) 0x14692d8b82328f29016db341c15f59585531ab58
(2) 0x0ff04903afd3dc4791ea5b747804de6cd6c4c513
(3) 0x4d77b3d7cadee90f4c90af72be75bd2ac88a72b5
(4) 0xc66ad1ee63b457047e7102425e657b70105f5eb9
(5) 0xfab642ee1cbacd8fc678c83e821f7d8beda61fec
(6) 0xf76e1c57250b88c1628430d0c04e3b4ecb111c0e
(7) 0xf4994bfce769c16f1631f0609867858a96885917
(8) 0xf31105aee2b095265ea46c51e2644eacbab96cb7
(9) 0x51213b5aa72783e7216b55fc2ecb3104dfd5f465
Private Keys
==================
(0) 77b92fa8bdf4bec94f3ebf67f44fb11ff660911ca64d3aa2c729b689aa8c807b
(1) e1b555743af9cc58fb094349776f944b76ff85663b51d5d6bc4802da2e92c54c
(2) c5180d4154bb2d89eb89335766070dcc8210b25374ef8d71c26f50d002f3c450
(3) 61acc2eaf3fdcecad846cf0507ae8cc07fa03a9bf00a581974c268c6bcba0afd
(4) 7f384dad1148c73257c596bc875ca492e8c6e99bb5f7de6958ea4cfe82a5b9a3
(5) 9796225e8d81a3f72e4fccfe3a562838bf589d4c40fcadbdc85c9b9ad5d5ad4c
(6) b858608913552368f4bdbc33a01f7fc7ec98684b013eab2d8dcb696246cbea56
(7) 3b581c0f56aa9937706cd0e27e7a1ccd45513c71d845ab5b18ff5039c20e9d8a
(8) f5d548c0b0c9974711814937b2d0d8373e244aa265ac2e0174b2b9ec35faa134
(9) 22cb6ad0b97dda82426c04485fca580f25746602bc94950efcb13d10528bf622
HD Wallet
==================
Mnemonic: marriage artwork corn dentist other feel decrease pride brass flash wire since
Base HD Path: m/44'/60'/0'/0/{account_index}
Listening on localhost:8545
- testrpc啟動(dòng)后自動(dòng)建立了10個(gè)帳號(hào)(Accounts),與每個(gè)帳號(hào)對(duì)應(yīng)的私鑰(Private Key)桥言。
- 每個(gè)帳號(hào)中都有100個(gè)測(cè)試用的以太幣(Ether)萌踱。
- 要注意testrpc僅運(yùn)行在內(nèi)存中,因此每次重開(kāi)時(shí)都會(huì)回到全新的狀態(tài)号阿。
建立項(xiàng)目
輸入以下命令
luoxuedeMBP:~ luoxue$ cd desktop
luoxuedeMBP:desktop luoxue$ mkdir SmartContractDemo
luoxuedeMBP:desktop luoxue$ cd SmartContractDemo
luoxuedeMBP:SmartContractDemo luoxue$ mkdir hello
luoxuedeMBP:SmartContractDemo luoxue$ cd hello
luoxuedeMBP:hello luoxue$ truffle init
Downloading...
Unpacking...
Setting up...
Unbox successful. Sweet!
Commands:
Compile: truffle compile
Migrate: truffle migrate
Test contracts: truffle test
luoxuedeMBP:hello luoxue$ ls
目錄結(jié)構(gòu):
- /contracts:存放智能合約原始代碼的地方
- /migrations:這是 Truffle用來(lái)部署智能合約的功能并鸵,待會(huì)兒我們會(huì)修改2_deploy_contracts.js來(lái)部署 HelloWorld.sol。
- /test: 測(cè)試智能合約的代碼放在這里扔涧,支持js 與 sol 測(cè)試园担。
- truffle.js: Truffle 的設(shè)置文檔
新建HelloWorld.sol
放在contracts里届谈,代碼如下
pragma solidity ^0.4.4;
contract HelloWorld {
function sayHello() returns (string) {
return ("Hello World");
}
}
編譯
現(xiàn)在執(zhí)行truffle compile命令,我們可以將HelloWorld.sol原始碼編譯成Ethereum bytecode弯汰。
luoxuedeMBP:hello luoxue$ cd build
luoxuedeMBP:build luoxue$ ls
contracts
luoxuedeMBP:build luoxue$ cd contracts
luoxuedeMBP:contracts luoxue$ ls
HelloWorld.json Migrations.json
-
編譯成功艰山,新增了build文件夾,會(huì)在HelloWorld文件夾下面的build/contracts文件夾下面看見(jiàn)HelloWorld.json文件咏闪。
image.png
部署
- 復(fù)制migration文件夾中的init文件程剥,創(chuàng)建名為2_deploy_contracts.js的文件,代碼如下:
var HelloWorld = artifacts.require("HelloWorld");
module.exports = function(deployer) {
deployer.deploy(HelloWorld);
};
使用artifacts.require語(yǔ)句來(lái)取得準(zhǔn)備部署的合約汤踏。使用deployer.deploy語(yǔ)句將合約部署到區(qū)塊鏈上。這邊HelloWorld是contract的名稱(chēng)而不是文件名舔腾。因此可以用此語(yǔ)法讀入任一.sol文件中的任一合約溪胶。
現(xiàn)在執(zhí)行truffle migrate命令
注意!N瘸稀哗脖!需要切換到truffle develop 網(wǎng)絡(luò)下編譯和部署,并且部署文件需要在編譯前寫(xiě)對(duì)扳还,因?yàn)榫幾g即產(chǎn)生一個(gè)合約地址才避,錯(cuò)誤的部署文件會(huì)對(duì)不上
姿勢(shì)如下:
luoxuedeMBP:HelloWorld luoxue$ truffle develop
省略
truffle(develop)> compile
Compiling ./contracts/HelloWorld.sol...
Compiling ./contracts/Migrations.sol...
Writing artifacts to ./build/contracts
truffle(develop)> migrate
Using network 'develop'.
Running migration: 1_initial_migration.js
Deploying Migrations...
... 0xad8b447607866b32b1c115156a97f9d247a125d35c14585ac3ed3f9eaa06a528
Migrations: 0x8cdaf0cd259887258bc13a92c0a6da92698644c0
Saving successful migration to network...
... 0xd7bc86d31bee32fa3988f1c1eabce403a1b5d570340a3a9cdba53a472ee8c956
Saving artifacts...
Running migration: 2_deploy_contracts.js
Deploying HelloWorld...
... 0xae7215511d62acedac6c4880d8578240e73913373eaaf6d0e86253197b35261b
HelloWorld: 0x345ca3e014aaf5dca488057592ee47305d9b3e10
Saving successful migration to network...
... 0xf36163615f41ef7ed8f4a8f192149a0bf633fe1a2398ce001bf44c43dc7bdda0
Saving artifacts...
truffle(develop)>
獲取合約對(duì)象
- 通過(guò)web3 來(lái)獲取合約對(duì)象
- 輸入
// 聲明一個(gè)對(duì)象
truffle(develop)> let contract;
undefined
// 實(shí)例化
// truffle console
truffle(develop)> HelloWorld.deployed().then(instance => contract = instance)
解釋?zhuān)簍ruffle console中預(yù)載了truffle-contract函數(shù)庫(kù),以方便操作部署到區(qū)塊鏈上的合約氨距。
這邊使用HelloWorld.deployed().then語(yǔ)句來(lái)取得HelloWorld合約的Instance(實(shí)例)桑逝,并存到contract變量中,以方便后續(xù)的調(diào)用俏让。
使用的是js es6+語(yǔ)句
調(diào)用合約函數(shù)
truffle(develop)> contract.sayHello()
'Hello World'
- 注意如果該函數(shù)沒(méi)有constant 或者pure 楞遏,需要.call()
如將代碼增加一個(gè)函數(shù)無(wú)pure/constant如下:
pragma solidity ^0.4.4;
contract HelloWorld {
// 能直接調(diào)用
function sayHello() pure public returns (string) {
return ("Hello World");
}
// 需要依靠.call調(diào)用
function test() public returns (string) {
return ("Hello World");
}
}
- 重新編譯與部署, 注意部署時(shí)候需要加上-- reset
// 編譯
truffle(develop)> compile
Compiling ./contracts/HelloWorld.sol...
Compilation warnings encountered:
/Users/luoxue/Desktop/SmartContractDemo/HelloWorld/contracts/HelloWorld.sol:9:3: Warning: Function state mutability can be restricted to pure
function test() public returns (string) {
^ (Relevant source part starts here and spans across multiple lines).
Writing artifacts to ./build/contracts
// 部署
truffle(develop)> migrate
Using network 'develop'.
Network up to date.
truffle(develop)> migrate --reset
正確的調(diào)用姿勢(shì)
truffle(develop)> contract.sayHello()
'Hello World'
truffle(develop)> contract.test.call()
'Hello World'
truffle(develop)>
- 輸入與輸出,在代碼里面加入一個(gè)echo函數(shù)首昔,輸入字符串寡喝,返回輸出
function echo(string s) public returns (string) {
return s;
}
truffle(develop)> contract.echo.call("melody")
'melody'