动手编写一个以太坊智能合约

原创 2017年09月14日 18:38:28

本文节选自图书《区块链开发指南》,本书由 申屠青春 主编,宋波、张鹏、汪晓明、季宙栋、左川民 联合编著。
区块链相关约稿、文章纠错、寻求报道等可邮件联系 jiawd@csdn.net

如何部署、调用智能合约

RPC

之前的章节中讲到了怎么写、部署合约以及与合约互动。现在该讲讲与以太坊网络和智能合约沟通的细节了。

一个以太坊节点提供一个RPC界面。这个界面给Ðapp(去中心化应用)访问以太坊区块链的权限和节点提供的功能,比如编译智能合约代码,它用JSON-RPC 2.0规范(不支持提醒和命名的参数) 的子集作为序列化协议,在HTTP和IPC (linux/OSX上的unix域接口,在Windows上叫pipe’s)上可用。

惯例

RPC界面会使用一些惯例,但它们不是JSON-RPC 2.0规范的一部分,这些惯例如下:

  • 数字是十六进制编码。做这个决定是因为有些语言对运行极大的数字没有或有很少的限制。为了防止这些错误数字类型是十六进制编码,由开发者来分析这些数字并正确处理它们。在维基页百科查看十六进制编码章节查看案例。

  • 默认区块数字。几个RPC 方法接受区块数字。在一些情况下,给出区块数字是不可能的或者不太方便。在那样的情况下,默认区块数字可以是以下字符串中的一个[”earliest”, “latest”, “pending”]。在维基页面可查看使用默认区块参数的RPC方法列表。

部署合约

我们会通过不同的步骤来部署下面的合约,但只用到RPC界面。

contract Multiply7 {
event Print(uint);
function multiply(uint input) returns (uint) {
Print(input
*
7);
return input
*
7;
}
}

要做的第一件事是确保HTTP RPC界面可用。这意味着我们在开始为geth供应—rpc标志,为eth提供-j标志。在这个例子中,用的是私有开发链上的geth节点。通过这种方法,我们就不需要真实网络上的以太币了。

\> geth --rpc --dev --mine --minerthreads 1 --unlock 0 console 2>>geth.log

这会在http://localhost:8545上启动HTTP RPC界面。

注意:geth支持CORS查看—rpccorsdomain标志了解更多。
我们可以通过用curl检索coinbase地址和余额来证明界面正在运行。请注意这些例子中的数据在你本地的节点上会有所不同。如果你想要试试这些参数,视情况替换需要的参数。

\> curl --data '{"jsonrpc":"2.0","method":"eth_coinbase", "id":1}' localhost:8545
{"id":1,"jsonrpc":"2.0","result":["0xeb85a5557e5bdc18ee1934a89d8bb402398ee26a"]}
> curl --data '{"jsonrpc":"2.0","method":"eth_getBalance", "params": ["0xeb85a5557e5bdc18ee1934a89d8bb402398ee26a"], "id":2}' localhost:8545
{"id":2,"jsonrpc":"2.0","result":"0x1639e49bba16280000"}

记不记得前面说过数字是十六进制编码?在这个情况下,余额作为十六进制字符串以Wei的形式返还。如果希望余额作为数字以太币为单位,可以从控制台用web3,示例如下:

\> web3.fromWei("0x1639e49bba16280000", "ether")
"410"

现在我们在私有开发链上有一些以太币,就可以部署合约了。第一步是验证solidity编译器可用,可以用eth_getCompilers RPC method方法来检索可用的编译器,示例如下:

\> curl --data '{"jsonrpc":"2.0","method": "eth_getCompilers", "id": 3}' localhost:8545
{"id":3,"jsonrpc":"2.0","result":["Solidity"]}

我们可以看到solidity编译器可用。

下一步是把Multiply7合约编译到可以发送给以太坊虚拟机的字节代码中,示例如下:

\> curl --data '{"jsonrpc":"2.0","method": "eth_compileSolidity", "params": ["contract Multiply7 { event Print(uint); function multiply(uint input) returns (uint) { Print(input
{"id":4,"jsonrpc":"2.0","result":{"Multiply7":{"code":"0x6060604052605f8060106000396000f360606040

现在我们有了编译代码,需要决定花多少gas去部署它。RPC界面有eth_estimateGas方法,会给我们一个预估数量,如下:

\> curl --data '{"jsonrpc":"2.0","method": "eth_estimateGas", "params": [{"from": "0xeb85a5557e5bdc18ee1934a89d8bb402398ee26a", "data": "0x6060604052605f8060106000396000f3606060405260e060020a6000350463c6888fa18114601a575b005b60586004356007810260609081526000907f24abdb5865df5079dcc5ac590ff6f01d5c16edbc5fab4e195d9febd1114503da90602090a15060070290565b5060206060f3"}], "id": 5}' localhost:8545
{"id":5,"jsonrpc":"2.0","result":"0xb8a9"}

最后部署合约。

\> curl --data '{"jsonrpc":"2.0","method": "eth_sendTransaction", "params": [{"from": "0xeb85a5557e5bdc18ee1934a89d8bb402398ee26a", "gas": "0xb8a9", "data": "0x6060604052605f8060106000396000f3606060405260e060020a6000350463c6888fa18114601a575b005b60586004356007810260609081526000907f24abdb5865df5079dcc5ac590ff6f01d5c16edbc5fab4e195d9febd1114503da90602090a15060070290565b5060206060f3"}], "id": 6}' localhost:8545
{"id":6,"jsonrpc":"2.0","result":"0x3a90b5face52c4c5f30d507ccf51b0209ca628c6824d0532bcd6283df7c08

交易由节点接受,交易散表被返还。我们可以用这个散表来跟踪交易。

下一步是决定部署合约的地址。每个执行的交易都会创建一个接收。这个接收包含交易的各种信息,比如交易被包含在哪个区块,以太坊虚拟机用掉多少gas。如果交易创建了一个合约,它也会包含合约地址。我们可以用eth_getTransactionReceipt RPC方法检索接收,示例如下:

\> curl --data '{"jsonrpc":"2.0","method": "eth_getTransactionReceipt", "params": ["0x3a90b5face52c4c5f30d507ccf51b0209ca628c6824d0532bcd6283df7c08a7c"], "id": 7}' localhost:8545
{"id":7,"jsonrpc":"2.0","result":{"transactionHash":"0x3a90b5face52c4c5f30d507ccf51b0209ca628c682

可以看到,合约在0x6ff93b4b46b41c0c3c9baee01c255d3b4675963d上被创建。如果你得到了零而不是接收,说明还没有被纳入区块。这时,要检查看看你的矿工是否在运行,然后重新试一遍。

和智能合约互动

现在已经部署了合约,我们可以和它互动了。有两种方法进行互动,即发送交易或调用。在本节的例子中,将会发送交易到合约的multiply方法里。

在我们的实例中,需要具体说明from、to 和data参数。From是我们账户的公共地址,to是合约地址,Data参数有一点复杂,它包括了规定调用哪个方法和哪个参数的负载量。这就需要ABI发挥作用了,ABI规定了如何为以太坊虚拟机规定和编码数据。

负载量的字节是功能选择符,规定了调用哪个方法。它取Keccak散表的头4个字节,涵盖功能名称参数类型,并进行十六进制编码。multiply功能接受一个参数。示例如下:

\> web3.sha3("multiply(uint256)").substring(0, 8)
"c6888fa1"

下一步是编码参数。我们只有一个unit256,假定提供了值6。ABI有一个章节规定了编码uint字节的方法,如下:

int<M>: enc(X) is the big-endian two’s complement encoding of X, padded on the higher-oder (left) side with 0xff for negative X and with zero 字节s for positive X such that the length is a multiple of 32 bytes.

它会编码到
0000000000000000000000000000000000000000000000000000000000000006。
将功能选择符和编码参数结合起来,数据就会变成0xc6888fa10000000000000000000000000000000000000000000000000000000000000006。

我们来试一下:

\> curl --data '{"jsonrpc":"2.0","method": "eth_sendTransaction", "params": [{"from": "0xeb85a5557e5bdc18ee1934a89d8bb402398ee26a", "to": "0x6ff93b4b46b41c0c3c9baee01c255d3b4675963d", "data": "0xc6888fa10000000000000000000000000000000000000000000000000000000000000006"}], "id": 8}' localhost:8545
{"id":8,"jsonrpc":"2.0","result":"0x759cf065cbc22e9d779748dc53763854e5376eea07409e590c990eafc0869

由于我们发送了交易,于是有交易散表返回。如果检索接收,可以看到一些新内容,如下:

{
blockHash: "0xbf0a347307b8c63dd8c1d3d7cbdc0b463e6e7c9bf0a35be40393588242f01d55",
blockNumber: 268,
contractAddress: null,
cumulativeGasUsed: 22631,
gasUsed: 22631,
logs: [{
address: "0x6ff93b4b46b41c0c3c9baee01c255d3b4675963d",
blockHash: "0xbf0a347307b8c63dd8c1d3d7cbdc0b463e6e7c9bf0a35be40393588242f01d55",
blockNumber: 268,
data: "0x000000000000000000000000000000000000000000000000000000000000002a",
logIndex: 0,
topics: ["0x24abdb5865df5079dcc5ac590ff6f01d5c16edbc5fab4e195d9febd1114503da"],
transactionHash: "0x759cf065cbc22e9d779748dc53763854e5376eea07409e590c990eafc0869d74",
transactionIndex: 0
}],
transactionHash: "0x759cf065cbc22e9d779748dc53763854e5376eea07409e590c990eafc0869d74",
transactionIndex: 0
}

接收包含一个日志。日志由以太坊虚拟机在交易执行时生成,包含接收。如果我们看Multiply功能,可以看到打印事件和输入次数7一起被提出。由于打印事件的参数是uint256,因此可以根据ABI规则对它进行编码,这样就会得到预期的十进制42。

\> web3.sha3("Print(uint256)")
"24abdb5865df5079dcc5ac590ff6f01d5c16edbc5fab4e195d9febd1114503da"

这只是对一些最常见任务的简单介绍。在RPC维基页面查看可用RPC方法的完整列表。

Web3.js

正如在之前的案例所见,使用JSON-RPC界面相当单调乏味且容易出错,尤其是在处理ABI的时候。Web3.js是Javascript库,它的目标是提供更友好的界面,减少出错机会。

用web3部署Multiply7合约看起来是这样:

var source = 'contract Multiply7 { event Print(uint); function multiply(uint input) returns (uint) { Print(input
var compiled = web3.eth.compile.solidity(source);
var code = compiled.Multiply7.code;
var abi = compiled.Multiply7.info.abiDefinition;
web3.eth.contract(abi).new({from: "0xeb85a5557e5bdc18ee1934a89d8bb402398ee26a", data: code}, function (err, contract) {
if (!err && contract.address)
console.log("deployed on:", contract.address);
}
);
deployed on: 0x0ab60714033847ad7f0677cc7514db48313976e2

装载一个部署的合约,发送交易:

var source = 'contract Multiply7 { event Print(uint); function multiply(uint input) returns (uint) { Print(input
var compiled = web3.eth.compile.solidity(source);
var Multiply7 = web3.eth.contract(compiled.Multiply7.info.abiDefinition);
var multi = Multiply7.at("0x0ab60714033847ad7f0677cc7514db48313976e2")
multi.multiply.sendTransaction(6, {from: "0xeb85a5557e5bdc18ee1934a89d8bb402398ee26a"})

注册一个回调,打印事件创建日志的时候会被调用。

multi.Print(function(err, data) { console.log(JSON.stringify(data)) })
{"address":"0x0ab60714033847ad7f0677cc7514db48313976e2","args": {"":"21"},"blockHash":"0x259c7dc0

在web3.js维基页面可查看更多信息。

控制台

geth控制台提供命令行界面和Javascript执行时间。它可以连接到本地或远程的geth或eth节点。它会装载用户能使用的web3.js库,从而方便用户从控制台通过web3.js部署智能合约,并和智能合约互动。实际上Web3.js章节的例子可以被复制进控制台并且调用。

查看合约与交易

有几个可用的在线区块链浏览器,能让你查询以太坊区块链,它们分别是:

  • EtherChain
  • EtherCamp
  • EtherScan

其他可查看节点或交易的资源

  • EtherNodes :节点的地理分配,由客户端区分。
  • EtherListen:实时以太坊交易可视器和可听器。

智能合约案例实战

以太坊是区块链开发领域最好的编程平台,而truffle是以太坊(Ethereum)最受欢迎的一个开发框架,这也是介绍truffle的原因。实战是最重要的事情,这篇文章不讲原理,只搭建环境,运行第一个区块链程序(Dapp)。

1. 安装truffle

安装truffle的命令如下:

$ npm install -g truffle

2. 依赖环境

可用的系统包括:Windows、Linux和Mac OS X,推荐Mac OS X,不建议使用Windows,会碰到各种各样的问题,很可能导致放弃。首先,访问https://nodejs.org 官方网站下载安装NodeJS。

此外,需要安装Ethereum客户端,来支持JSON RPC API调用。

至于开发环境,推荐使用EthereumJS TestRPC,地址为: https://github.com/ethereumjs/testrpc

安装命令如下:

$ npm install -g ethereumjs-testrpc

3. 新建第一个项目

通过以下命令新建一个项目:

$ mkdir zhaoxi
$ cd zhaoxi
$ truffle init

默认会生成一个MetaCoin的demo,可以从这个demo中学习truffle的架构。

项目的目录结构如图5-3所示。

这里写图片描述
图5-3 项目的目录结构

项目所有文件的目录如图5-4所示。

这里写图片描述
图5-4 项目文件目录目录结构

现在,通过以下命令编译项目。

$ truffle compile

图5-5是运行以上命令后的结果。

这里写图片描述
图5-5 Truffle compile执行结果图

下面介绍部署项目的方式。

部署之前先启动TestRPC,命令如下:

$ testrpc 
$ truffle deploy(在Truffle 2.0以上版本中,命令变成了:truffle migrate)

图5-6是运行truffle deploy后的结果。

这里写图片描述
图5-6 truffle deploy执行结果图

$ truffle migrate migrate的执行结果见图5-7。

这里写图片描述
图5-7 truffle migrate migrate执行结果图

现在,可以启动服务了,命令如下:

$ truffle serve

图5-8是truffle serve执行结果图

这里写图片描述
图5-8 truffle serve执行结果图

启动服务后,可以在浏览器访问项目了,地址是:http://localhost:8080/ ,网页界面如图5-9所示。

这里写图片描述
图5-9智能合约运行界面

好了,第一个区块链程序跑起来了,后面可以不断地实践深入学习了。

这里写图片描述

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

以太坊开发--geth的使用入门

geth的全称是Go-ethereum,是一个以太坊客户端,用go语言编写,应该是目前最常用的客户端。当然以太坊客户端还有用C++,Ruby,Python,Java等其他多种语言编写的,不同类型的客户...

搭建以太坊开发环境的曲折之路

在这个“雪中送炭”的日子里,终于搭建好了以太坊开发环境,非常感谢二师兄ⅡⅩⅠⅤ的帮助,在这里结合二师兄ⅡⅩⅠⅤ的博客回顾一下我的搭建过程。一、为了和教程保持最大程度的一致,重装了腾讯云主机系统,使用x...
  • ler_123
  • ler_123
  • 2017年01月09日 09:50
  • 1931

建立以太坊开发环境

Window 安装 https://github.com/ethereum/mist/releases 下载Ethereum-Wallet-xxx,或者下载Mist 下载后解压,运行Ethereu...
  • fd_mas
  • fd_mas
  • 2016年07月14日 17:27
  • 4693

以太坊go-ethereum常见问题汇总

(1)什么是 Ethereum? 以太坊是一个分散的智能合同平台,由Ether的加密货币提供支持。 (2) 听说过以太坊,但什么是Geth,Mist,Ethminer,Mix? Ge...

以太坊开发--使用geth搭建私有链

我在上一篇博客中《以太坊开发--geth的使用入门》中使用的是geth的开发环境,准确来说和私链还是不同的。今天我们就学习来搭建一个以太坊私链。我们知道区块链有三种:公有链、联盟链、私有链。我会在之后...

怎么验证交易是否成功

一般是通过event来查看的 event mylog(uint code); function test() { … mylog(0); } 发起交易后,根据eth.getTransactio...
  • DDFFR
  • DDFFR
  • 2017年07月10日 09:17
  • 491

Gnome shell修改顶栏透明度方法

首先我们需要用gedit打开gnome-shell.css进行编译。 sudo gedit /usr/share/gnome-shell/theme/gnome-shell.css 先改变顶部...

深入浅出谈以太坊智能合约

什么是合约?合约是代码(它的功能)和数据(它的状态)的集合,存在于以太坊区块链的特定地址。 合约账户能够在彼此之间传递信息,进行图灵完备的运算。...

区块链开发(三)编写调试第一个以太坊智能合约

李赫 2016年9月10日 一、       智能合约IDE简介     目前以太坊上支持三种语言编写智能合约,     Solidity:类似JavaScript,这是以太坊官方推荐语言,也是最流行...

区块链开发(三)编写调试第一个以太坊智能合约

一、        智能合约IDE简介     目前以太坊上支持三种语言编写智能合约,     Solidity:类似JavaScript,这是以太坊官方推荐语言,也是最流行的智能合约语言。具体用...
  • fidelhl
  • fidelhl
  • 2016年09月13日 11:31
  • 3914
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:动手编写一个以太坊智能合约
举报原因:
原因补充:

(最多只允许输入30个字)