智能合约初体验
参考地址: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的事情。以后会进一步讨论。