前言
本文主要介绍智能合约的工作原理及其部署过程。
合约部署流程
一般来说,部署智能合约的步骤为1:
- 启动一个以太坊节点 (例如geth或者testrpc)。
- 使用solc编译智能合约。 => 获得二进制代码。
- 将编译好的合约部署到网络。(这一步会消耗以太币,还需要使用你的节点的默认地址或者指定地址来给合约签名。) => 获得合约的区块链地址和ABI(合约接口的JSON表示,包括变量,事件和可以调用的方法)。(译注:作者在这里把ABI与合约接口弄混了。ABI是合约接口的二进制表示。)
- 用web3.js提供的JavaScript API来调用合约。(根据调用的类型有可能会消耗以太币。)
下图表示了部署流程:
你的DApp可以给用户提供一个界面先部署所需合约再使用之(如图1到4步),也可以假设合约已经部署了(常见方法),直接从使用合约(如图第6步)的界面开始。
智能合约实例
接下来我们将使用geth的控制台开发一个简单的智能合约并编译部署在私链上,最后与之交互。完成这些后,我们就能对智能合约的运行机制理解得更加深刻。本例子结合了汪晓明关于以太坊的开发的演示视频和以太坊项目有关交易和合约的wiki。
打开测试网络的控制台
输入以下命令:
geth --datadir "~/ethdev" --dev console 2>> geth.log
显示如下:
zcc@ubuntu:~$ geth --datadir "~/ethdev" --dev console 2>> geth.log
Welcome to the Geth JavaScript console!
instance: Geth/v1.4.18-stable/linux/go1.6.2
coinbase: 0xb005804a49e73acb17d1e7645dfd0a33dde6eb0e
at block: 217 (Tue, 01 Nov 2016 05:21:38 PDT)
datadir: /home/zcc/ethdev
modules: admin:1.0 debug:1.0 eth:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 shh:1.0 txpool:1.0 web3:1.0
>
这样我们就打开了测试网的控制台,之后的步骤如无特别说明都将在控制台中完成。
检查编译器
我们接下来的智能合约的例子是使用solidity语言开发的。因此,至此之前我们要确保solidity编译器已经正确安装了。输入以下命令检查:
> eth.getCompilers()
["Solidity"]
我们发现solidity的编译器已经正确安装了。如果返回值为空数组,那么输入以下命令安装:
sudo add-apt-repository ppa:ethereum/ethereum
sudo apt-get update
sudo apt-get install solc
如果输入第一条命令的时候返回错误,请尝试重启系统。
编写智能合约
我们编写一个求解与7相乘结果的函数,即输入一个值a
,返回a*7
的值。
> source = "contract test { function multiply(uint a) returns(uint d) { return a * 7; }}"
"contract test { function multiply(uint a) returns(uint d) { return a * 7; }}"
编译智能合约
> contract = eth.compile.solidity(source).test
{
code: "0x606060405260388060106000396000f3606060405260e060020a6000350463c6888fa18114601c575b6002565b3460025760076004350260408051918252519081900360200190f3",
info: {
abiDefinition: [{
constant: false,
inputs: [...],
name: "multiply",
outputs: [...],
payable: false,
type: "function"
}],
compilerOptions: "--bin --abi --userdoc --devdoc --add-std --optimize -o /tmp/solc359648392",
compilerVersion: "0.4.3",
developerDoc: {
methods: {}
},
language: "Solidity",
languageVersion: "0.4.3",
source: "contract test { function multiply(uint a) returns(uint d) { return a * 7; }}",
userDoc: {
methods: {}
}
}
}
准备一个创建合约的账户
在以太坊上创建智能合约就是使用一个外部账户(EOA)向区块链中发送一个交易。因此,我们需要准备一个有余额并被激活的以太坊外部账户。
查看是否有可用账户:
> personal.listAccounts
[]
返回为空,说明没有可用账户。创建一个外部账户:
> personal.newAccount('123456')
"0x62b1746767522b36f6421e630fa0198151d72964"
注意:personal.newAccount()
函数里的参数是账号密码,返回值是创建的新账号地址。
这个时候,我们再次使用personal.listAccounts
命令查看可用账户:
> personal.listAccounts
["0x62b1746767522b36f6421e630fa0198151d72964"]
我们看到函数返回值为一个数组,数组目前只有一个元素,就是我们刚才创建的账号。
我们查看一下刚才创建的账户余额:
> web3.eth.getBalance(personal.listAccounts[0])
0
返回值为0,说明新创建的账户没有以太币。这个时候我们就可以开启挖矿来获得以太币。
首先开启挖矿:
> miner.start()
true
为了检测挖矿的状态,我们可以再另开起一个终端用于检测挖矿的状态。在新开起的终端中输入以下命令实时显示挖矿的状态:
tail -f geth.log
这样我们就能看到如下所示的挖矿状态:
zcc@ubuntu:~$ tail -f geth.log
I1102 10:10:21.382666 eth/backend.go:201] Blockchain DB Version: 3
I1102 10:10:21.382691 eth/backend.go:226] ethash used in test mode
I1102 10:10:21.384471 core/blockchain.go:214] Last header: #219 [7a2335e9…] TD=28838912
I1102 10:10:21.384501 core/blockchain.go:215] Last block: #219 [7a2335e9…] TD=28838912
I1102 10:10:21.384507 core/blockchain.go:216] Fast block: #219 [7a2335e9…] TD=28838912
I1102 10: