什么是以太坊预言机?智能合约就其性质而言,可以运行各类算法并存储查询数据。预言机能够监控以太坊区块链事件并能将监控结果发回智能合约。由于每一个节点每次都须要大量计算,因此从Ethereum智能合约开发中进行频繁的网络请求是切不实际的。这样,智能合约就能够与链外的世界进行互动了。前端
可是这样有一个明显的信任问题。与信任单一外部数据源的分布式智能合约有些矛盾。不过这能够经过让多个独立的预言机来响应相同的查询最终造成共识来缓解这个问题。node
有关预言机的更多信息,请查看在分布式应用程序之间提供“可靠链接”的FinTech公司Oraclize。 他们对预言机的解释很不错。git
Tinypay的预言机作了三件简单的事情:github
我经历了几回迭代,最终实现了,我但愿经过它们来引导您了解以太坊的发展。web
我第一次写预言机,我用了Go-Ethereum。我想直接使用RPC API与Ethereum节点进行全部通讯。算法
这颇有趣,由于我可以学习不少关于以太坊协议如何进行存储和数据编码等较底层的内容。我必须手动从新在代码中建立ABI(应用程序二进制接口),并使用它来发送和解密消息。 ABI对于定义合约如何交互以及如何从线上的原始字节中提取数据是必需的。json
从事件中实际提取数据证实比我想象的要复杂得多。Go-Ethereum的处理事件没完成。我被迫手动轮询RPC端点,并找出如何未来自原始事件的二进制数据解码。Go-Ethereum固然彷佛是以太坊团队关注的焦点,他们应该很清楚Go-Ethereum在观看和解码事件方面的问题。我但愿他们能很快有所提高,这会使得Go-Ethereum成为编写预言机和其余以太坊客户端应用程序的更好选择。网络
低级别的RPC API和解码API被证实是很是低效率的,而且他们正在更快地进行迭代,因此...oracle
对于第二次迭代,我切换到node.js并使用web3库与geth节点进行通讯。 这给了我内置的抽象了的事件查询,数据提取和格式化,并且明显使开发变得更容易。框架
我开始使用Alex Beregszaszi很是有用的'tinyoracle'指南,这让我在第二版中得到了不错的成果
下面的代码是通过选择编辑的,完整的代码能够在github存储库中找到(本次迭代的标签为v0.0.2)
var Web3 = require('web3'); var web3 = new Web3(); var contracts = require(path.join(__dirname, 'gen_contracts.json')); // First we instruct web3 to use the RPC provider //首先咱们指定web3使用RPC接口 web3.setProvider( new web3.providers.HttpProvider( 'http://' + opts.rpc_host + ':' + opts.rpc_port)); // This isn't strictly necessary here, but goes to show the step // required to "unlock" the account before sending transactions. // 这并非严格须要的,但它显示了在发送交易以前“解锁”账户所需的步骤。 if (!web3.personal.unlockAccount( web3.eth.coinbase, opts.wallet_password)) { console.error('Could not unlock'); process.exit(); } //Here we register the filter with the ethereum node, //and then begin polling for updates. //在这里,咱们用以太坊节点注册过滤器,而后开始轮询更新 function runLoop(o) { var filter = web3.eth.filter({address: o.contract_address}); filter.watch(function (err, results) { if (err) { console.log('WATCH ERROR: ', err); process.exit(); } console.debug(results); }); } // If the contract isn't deployed yet, we deploy it here //若是尚未部署合约,咱们在这里部署它。 if (!opts.contract_address) { // This block of code loads the ABI for interpreting contract data. // 该代码块加载ABI来解释合约数据。 var dmC = web3.eth.contract(JSON.parse(contracts.DomainMicropay.abi)); var x = { from: web3.eth.coinbase, data: contracts.DomainMicropay.bin, gas: 1000000 }; // send the transaction for installing the contract. //发送用于部署合约的交易。 dmC.new(x, function (err, resp) { if (err) { console.error('Loading contract', err); process.exit(); } var addr = resp.address; if (!addr) { console.log('Pending tx: ', resp.transactionHash); } else { console.log('Deployed Address: ', addr); opts.contract_address = addr; runLoop(opts); } }); } else { runLoop(opts); // in either case, start the polling event loop. //在任一种状况下,启动轮询事件循环 }
最后,在第三次迭代中,我放弃了本身搞的这一切。 咱们已经在咱们的网络前端使用ConsenSys的优秀工具Truffle。 我只是将生成的构件复制到个人node.js项目中,并直接将其包含在内,而后就开始工做。
使用Truffle,咱们可以将咱们的Solidity合约编译成的一个JavaScript库,它能够确认各类重要的细节,如合同的部署地址,并彻底代替低级RPC通讯。 查看事件,发送交易和查询数据变成了直接从咱们的合同中生成的简单API调用。
// This code extract shows the whole event loop abstracted behind the actual event name: ClientConfirmed and ClientCreated. // 这段代码显示了整个事件循环中的抽象后的实际事件:ClientConfirmed 和 ClientCreated。 startWatcher: function (rpcUrl, unlockPass) { password = unlockPass || password; web3.setProvider(new web3.providers.HttpProvider(rpcUrl)); DomainMicropay.setProvider(web3.currentProvider); contract.ClientConfirmed({}, eventOpts(), function (err, data) { if (err) { console.log('Error ClientConfirmed: ', err); return; } console.log('Event ClientConfirmed: ', data.args.domain); }); contract.ClientCreated({}, eventOpts(), function (err, data) { if (err) { console.log('Error ClientCreated: ', err); return; } console.log('Event ClientCreated: ', data.args.domain); contract.getPaymentContractForDomain .call(data.args.domain) .then(beginDomainVerification(data)) .catch(errFn('Unhandled Error: ')); }); }
正如您所看到的,Truffle为使用智能合约并与之交互提供了一些很是好的抽象。这并不完美,也不能解决合约版本问题等问题。可是咱们须要在其余文章中再介绍这些内容。
但愿赢得你喜欢,并能够帮助你开发下一个“DApp”。 若是您正在寻求帮助理解或利用区块链技术,请联系 we@mustwin.com 并参考本文。
原文:medium.com/@mustwin/building-an-oracle-for-an-ethereum-contract-6096d3e39551
安利两个教程:1.以太坊入门实战 2.以太坊电商DApp实战