查看原文
其他

搭车者以太坊智能合约指南(一)

2016-08-28 Manuel Aráoz 以太坊爱好者


我已经智能合约领域工作了4年,主要在比特币区块链上。我参与的一些项目包括存在证明,bitcore(比特核心)以及Streamium. 过去这个月,我探索了在以太坊平台上进行开发。

我决定制作一个简短的指南服务未来想要学习以太坊开发的程序员。手册分为两个部分:如何开始以太坊智能合约开发,智能合约安全简述.

如何开始学习以太坊智能合约

0.基础概念

这个指南假设你已经有了一些密码学货币和区块链的基础技术背景。 如果你没有,我建议快速过一遍Andreas Antonopoulos的《完全掌握比特币》(Mastering Bitcoin),Consensys的《用刚刚够的比特币来搞懂以太坊》(Just Enough Bitcoin for Ethereum),或者至少看看Scott Driscoll的短片。 为了继续读下去你得了解公钥和私钥,为什么区块链需要矿工,如何达成去中心化的共识,以及交易脚本和智能合约的概念。

另外两个在你开始进行以太坊开发之前需要了解的重要的,相关的概念是以太坊虚拟机和汽油(gas)。以太坊的目的在于成为一个智能合约平台。它的起源可以被追溯到Vitalik Buterin对比特币做为智能合约平台具有的局限性的评论。以太坊虚拟机(EVM)是以太坊智能合约执行之处。与比特币相比,它为撰写合约提供了更具表现力和完整性的语言。事实上,它是一个图灵完备的编程语言。一个比较好的比喻是,EVM是一个执行智能合约的分布式的世界电脑。由于智能合约由EVM执行, 必须存在一种限制每个合约占用资源的机制。EVM内运行的每一步操作实际上同时在被所有节点所执行。这是为什么需要有汽油(gas)存在。一个以太坊合约代码交易可以引发数据读写,密码学原语,调动(发送信息给)其他合约等等昂贵的运算。每个此类运算都有用汽油计量的价格,每笔交易所耗费的汽油单元需要用以太币来支付,根据随时变化的汽油和以太币的汇率计算。相应的价格会从提交交易请求的以太坊账户中扣除。同时每笔交易对可使用的汽油会设置上限参数,用以防止编程错误导致耗干账户中资金。点击这里阅读更多关于汽油。

1.设置你的环境

好了,你已经知道了那些基础的,让我们赶紧把环境搞起来写代码吧。为了开始开发以太坊app(或者dapp,去中心化应用的简称,许多人喜欢这样叫),你需要安装一个客户端来接入主网。它会成为你进入这个分布式网络的窗口,提供一个观察区块链的方法,那里所有EVM(以太坊虚拟机)状态被显示出来。有很多与条款兼容的客户端,最受欢迎的是geth,用Go语言实现。但它并不是最开发者友好的客户端。我目前找到最好的选择是testrpc节点(是的,名字起得很糟糕)。相信我,它会节省你很多时间。安装它,运行它:

$ sudo npm install -g ethereumjs-testrpc $ testrpc

你应该在一个新的终端中运行‘testrpc’,并且在你开发的过程中一直让它运行。每次你运行testrpc,它会生成10个包涵模拟测试资金的新地址供你使用。这个不是真钱,你可以安全得用这些进行任何实验,不会有损失资金的风险。在以太坊中撰写智能合约最受欢迎的语言是Solidity,因此我们会使用这个语言。我们也会用Truffle开发框架,它会帮助创造智能合约,编译,部署以及测试。让我们开始吧:

# First, let's install truffle 首先,让我们安装truffle $ sudo npm install -g truffle# let's setup our project $ mkdir solidity-experiments $ cd solidity-experiments/ $ truffle init

Truffle 会生成一个示范项目所需要的文件,包括MetaCoin,一个token合约的例子。你应该能够通过运行truffle compile指令来编译示范合约。然后,你需要通过我们在运行的testrpc节点用‘truffle migrate’指令来在模拟网络部署合约。

Compiling ConvertLib.sol... Compiling MetaCoin.sol... Compiling Migrations.sol... Writing artifacts to ./build/contracts$ truffle migrate Running migration: 1_initial_migration.js  Deploying Migrations...  Migrations: 0x78102b69114dbb846200a6a55c2fce8b16f61a5d Saving successful migration to network... Saving artifacts... Running migration: 2_deploy_contracts.js  Deploying ConvertLib...  ConvertLib: 0xaa708272521f972b9ceced7e4b0dae92c77a49ad  Linking ConvertLib to MetaCoin  Deploying MetaCoin...  MetaCoin: 0xdd14d0691ca607d9a38f303501c5b0cf6c843fa1 Saving successful migration to network... Saving artifacts...Note to Mac OS X users: Truffle is sometimes confused by .DS_Store files. If you get an error mentioning one of those files, just delete it.

我们刚刚往测试节点上部署了我们的示范合约。哇!很简单,对吧?是时候写我们自己的合约了!

2.撰写你的第一个以太坊只能合约

在这个指南里面,我们会写一个存在证明只能合约。就是创造一个存有用于证明存在的文件哈希的电子公正机关。用‘truffle create:contract’来开始:

$ truffle create:contract ProofOfExistence1

从你的编译器里面打开合约/ProofOfExistnece1.sol(我用的是带Soilidity语法高亮显示的vim)

// Proof of Existence contract, version 1 contract ProofOfExistence1 {  // state  bytes32 public proof;  // calculate and store the proof for a document  // *transactional function*  function notarize(string document) {    proof = calculateProof(document);  }// helper function to get a document's sha256  // *read-only function*  function calculateProof(string document) constant returns (bytes32) {    return sha256(document);  } }

我们将从一段简单但是有错误的代码开始向一个更好的解决方案靠近。这是一份Solidity合约定义,有点像其他语言中的类别(class)。合约中有状态(state)和函数(functions)。区分合约中可能出现的两种函数非常重要。

  • 只读(常数)函数:这些函数不对任何状态(state)进行改变。他们只读取状态,进行计算,并且返回数值。因为这些函数可以在每一个节点内本地解决,他们不回花费任何的汽油(gas)。他们被用‘contant’关键词标出。

  • 交易函数:这些函数对状态进行改变,转移资金。因为这些变化需要在区块链中被反应出来,执行交易函数需要向网络提交交易,这会消耗汽油(gas)。

我们的合约中两种函数各有一个,已在注释中标注。下一段我们将会看到我们使用函数的类型会如何改变我们与智能合约交互。这个简单的版本每次只储存一个证明,用数据类型bytes32或者32bytes,跟sha256哈希的大小一样。交易函数‘notarize’允许我们在合约的状态变量‘proof’里存储一个文件的哈希。这个变量是个公开变量,是我们合约的用户认证一个文件是否被公正的唯一途径。我们一会就会自己做一下,但是首先。。。
让我们把ProofOfExistence1部署到网络上!这次,你需要通过编辑移动文档(migration file)(migrations/2_deploy_contracts.js)让Truffle部署我们的新合约。用以下的来代替内容:

/* * migrations/2_deploy_contracts.js: */ module.exports = function(deployer) {  deployer.deploy(ConvertLib);  deployer.autolink();  deployer.deploy(MetaCoin);  // add this line  deployer.deploy(ProofOfExistence1); };

你也可以选择性的删除有关ConvertLib和MetaCoin的语句,这些我们不会再用了。为了再次运行这个移动,你需要使用重启标签确保它再次运行。

truffle migrate --reset

更多的关于Truffle移动如何工作的内容可以看这里。

3. 与你的智能合约互动

现在我们已经将智能合约部署好了,让我们摆弄摆弄它!我们可以通过函数调用来给它发信息或者读取它的公开状态。我们通过Truffle操纵台来完成:

$ truffle console // get the deployed version of our contract truffle(default)> var poe = ProofOfExistence1.deployed()// and print its address truffle(default)> console.log(poe.address) 0x3d3bce79cccc331e9e095e8985def13651a86004// let's register our first "document" truffle(default)> poe.notarize('An amazing idea') Promise { <pending> }// let's now get the proof for that document truffle(default)> poe.calculateProof('An amazing idea').then(console.log) Promise { <pending> } 0xa3287ff8d1abde95498962c4e1dd2f50a9f75bd8810bd591a64a387b93580ee7// To check if the contract's state was correctly changed: truffle(default)> poe.proof().then(console.log) 0xa3287ff8d1abde95498962c4e1dd2f50a9f75bd8810bd591a64a387b93580ee7 // The hash matches the one we previously calculated

注意所有函数调用都会返回一个Promise,当Promise被解决如果我们想要检验它我们可以通过‘.then(console.log)’来输出。
我们要做的第一件事是获得一个我们部署合约的表达,并把它存储在一个叫做‘poe’的变量之中。
然后我们调用交易方程‘notarize’,这会涉及一个状态改变。当我们调用一个交易方程,我们得到的是一个被转化为交易id的Promise,而不是函数返回的值。记住为了改变EVM状态我们需要消耗汽油(gas)并且向网络提交一个交易。这是为什么我们会得到交易id做为Promise的结果,从改变状态的那项交易那里得到。在这里,我们对交易id不感兴趣,所以我们可以把Promise丢掉。不过当我们真正写app时,我们会想要把它存起来用以检查相应的交易,捕捉错误。

接下来,我们调用只读(常数)函数‘calculateProof‘. 记得用’constant‘关键词来标记你的只读函数,否则Truffle会试着创造一个交易来执行这个函数。这个是我们告诉Truffle,我们并没有跟区块链交互而只是在读取。通过这个只读函数,我们会得到’An amazing idea‘文件的sha256。

我们现在需要把这个和我们智能合约的状态进行对比。为了检查状态的改变是否正确,我们需要读取‘Proof’这个公开状态变量。要获得一个公开状态变量的值,我们得调用具有同样名字的一个函数,它会返回一个Promise。我们这次,输出的哈希值是一致的,所以一切都如我们所料得进行了 :)

像你从上面的片段看到的,我们第一版存在证明智能合约似乎可以工作!干得好!但是它每次只可以注册一个文件。让我们做一版更好的。


翻译:Toya
声明:转载须附本文链接,违者必究

原文链接:


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存