使用Web3.js 1.0构建以太坊Oracle

以太坊oracle:一个人们可能会在Meetups听到或其他技术活动中被抛出的非常模糊的术语。如果你不了解,你可能没有意识到区块链oracle只是一个离线数据源的专门案例,它通过响应合约中的链上事件与以太坊EVM进行交互。这可能听起来似乎挺复杂,但实际上并非如此——只需坚持几分钟。

oracle的主要关注点是在合约要求时将外部数据返回合约。这些数据可以是合约开展业务所需的任何数据:存储在数据库中的客户数量,由40年历史的大型机计算的精算风险评估。在本文中,我们将关注通过易于使用的Dark Sky weather forecast API获得的请求洛杉矶温度时的数据。

Chatty合约

人们需要开始与外界联系,以太坊虚拟机也不例外。否则,它只会是另一个孤立的书呆子,坐在周围,害羞只与自己说话。EVM是一种社交动物,它让你知道它想要聊天的方式是发射一个事件(希望有人在听)。在oracle的情况下,该事件会告诉你合约想要谈论的内容,你要提供的信息以及有时你如何加入对话。如果正在运行的合约是礼貌的话,如果你想知道,它甚至可以通过让你知道你做了什么来完成对话。然而,就像脱衣舞娘和律师一样,对EVM的讨厌会花钱,所以我们将不必要的调情保持在最低限度。

无论如何,让我们开始构建我们的Weather oracle。我们使用的是Web3.js 1.0,它的工作方式与0.2.x版本略有不同。我们还使用Ganache作为testnet,它可以很好地处理Websockets连接和事件。除了Node和Javascript之外,你不需要Truffle或Embark或其他工具——oracle将为你编译和部署合约。

确保安装了最新的Solidity编译器以及solc npm软件包。并且不要忘记安装针对Dark Sky的出站HTTP调用的请求包。

如果你想在家里玩,oracle和测试客户端的完整代码位于https://github.com/robinagist/EthereumWeatherOracle。为了清楚起见,有一些冗余。(注意:我在Javascript和Node上有一点菜鸟,但不是软件,所以请原谅我可能已经Python化了你心爱的Javascript,Python和Go是我的主要语言。)

你还需要在https://darksky.net上获得一个Dark Sky API帐户。

细节

过程很简单:

  • 一个帐户(EOA或合约)调用主合约上的方法,询问一些离线数据,然后回归其业务。
  • 合约方法与在执行期间发出的事件相关联。
  • 将通知oracle(已在合约地址处在线监听此特定事件),并开始处理数据请求。
  • 处理完毕后,oracle在合约地址上运行另一种方法,完成调用帐户/合约的数据请求。有时,会从此方法发出一个事件,以便通知调用者。

合约

我们的合约很简单。除了通常的潜在交互者(与构造函数的合约)之外,我们有两种方法和两种事件。第一个被调用的方法是request。请求没有参数,并且它的唯一目的是在被调用时发出一个TempRequest事件,希望它被oracle选中。如果我们的oracle选择事件,它会调用Dark Sky获取最新数据,然后使用当前温度调用fill方法。fill方法需要无符号整数作为参数,将合约变量temp设置为传递的值并以当前温度作为参数触发FilledRequest事件。(注意:这里不需要返回值 - 我们只是为了控制台输出而在这里传递它们。)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
pragma solidity ^0.4.21;

contract WeatherOracle {

address public owner;
uint public temp;
uint public timestamp;

event TempRequest(address sender);
event FilledRequest(uint rtemp);

function constructor() public {
temp = 0;
owner = msg.sender;
}

function request() public returns (string) {
emit TempRequest(msg.sender);
return "sent";
}

function fill(uint rtemp) public returns (uint){
temp = rtemp;
emit FilledRequest(rtemp);
return temp;
}


}

代码

只是一个标准的设置。我们宣布abi以便以后分配。该帐户是Ganache帐户。

要注意的一件事(特别是如果你使用过Web3.js的早期版本)是我们现在正在使用Websockets。这为我们提供了真正的点对点功能,并且无需轮询即可捕获事件通知。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// SETUP //
let Web3 = require('web3')
let fs = require('fs')
let request = require('request')

// using Websockets URL. Ganache works w/ Web3 1.0 and Websockets
const testNetWS = "ws://127.0.0.1:7545"

// create a WebsocketProvider
const web3 = new Web3(new Web3.providers.WebsocketProvider(testNetWS))

// account address
const account = "0xf17f52151EbEF6C7334FAD080c5704D77216b732"

// we're using the Dark Sky API - get your API key at darksky.net
const apiKey = "GetYourOwnKey"
// using the Dark Sky API - getting the forecast, centered on LA
let url= "https://api.darksky.net/forecast/"+apiKey+"/37.8267,-122.4233"
// store the ABI for the contract so we can use it later
let abi = null

下一段代码编译和部署合约,该合约应该与oracle位于同一目录中。成功部署和挖掘合约(返回合约地址)后,将在该地址上启动事件监听器。

1
2
3
4
5
6
7
8
// LOAD, COMPILE, DEPLOY //
// load, compile and deploy the included contract (contract.sol)
let c = loadCompileDeploy("contract.sol", ":WeatherOracle").then(function(address) {
console.log("contract address: " + address)
startListener(address)
}, function(err) {
console.log("didn't work. here's why: " + err)
})

我们的监听器设置为从区块链时间开始以来监听任何块上的TempRequest事件。如果调用事件,它会记录事件数据,并使用合约地址调用handler来处理程序 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// EVENT LISTENER //
function startListener(address) {
console.log("starting event monitoring on contract: " + address)
let myContract = new web3.eth.Contract(abi, address);
myContract.events.TempRequest({fromBlock: 0, toBlock: 'latest'
}, function(error, event){ console.log(">>> " + event) })
.on('data', (log) => {
console.log("event data: " + JSON.stringify(log, undefined, 2))
handler(address)
})
.on('changed', (log) => {
console.log(`Changed: ${log}`)
})
.on('error', (log) => {
console.log(`error: ${log}`)
})
}

请求处理程序是从Dark Sky获取温度数据的函数,稍微清理一下数据,并在提供的地址处调用合约上的fill方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// REQUEST HANDLER //
// handles a request event and sends the response to the contract
function handler(address) {
request(url, function(error, response, body) {
if(error)
console.log("error: " + error)

console.log("status code: " + response.statusCode)
let wx = JSON.parse(body)
let temperature = Math.round(wx.currently.temperature)
console.log("temp: " + temperature)

// run the 'fill' method on the contract
let MyContract = new web3.eth.Contract(abi, address);
MyContract.methods.fill(temperature).call()
.then(function(result) {
console.log("call result: " + result)
if (temperature == result)
console.log("+++success+++")
}, function(error) {
console.log("error " + error)
})

})
}

启动Oracle

测试客户端

测试客户端是wxclient.js,与Github repo中的wxoracle.js位于同一目录中。启动oracle后,从控制台输出中复制联系地址,然后将其粘贴,以便将其分配给此代码底部的地址。

此外,从Ganache获取帐户并粘贴帐户。

1
2
3
4
5
6
7
// account address
const account = "0xC5fdf4076b8F3A5357c5E395ab970B5B54098Fef"

'''
'''
// cut and paste the deployed contract address
const address = "contract address here"

运行测试客户端

启动一个新终端,然后在提示符下键入node wxclient

目前,测试客户端编译contract.sol文件以获取ABI,这对于此示例来说是不必要的,但很快。我就不进入测试客户端的工作。这很简单。

如果你正在观看oracle输出,你应该看到如下内容:

在测试客户端上,从另一个终端运行:

你可以从oracle的输出中看到它从Dark Sky获得了200状态代码,并且圆形温度为53(对于LA来说太冷了)。温度存储在合约存储中,并触发另一个事件以通知监听器新的温度可用。

结论

Web3 1.0和Websockets使oracle构建成为一个快照。你不再需要构建轮询事件的系统。

其他oracle教程要么过时,要么太复杂。我试图保持这个简单的,并保持像Truffle和Embark这样的工具,所以你可以看到一切真的如何工作。oracle进行自己的部署,oracle和test客户端都编译并生成自己的ABI(虽然我会优化它,所以没有那么多的编译和剪切和粘贴)。

======================================================================

分享一些以太坊、EOS、比特币等区块链相关的交互式在线编程实战教程:

  • java以太坊开发教程,主要是针对java和android程序员进行区块链以太坊开发的web3j详解。
  • php以太坊,主要是介绍使用php进行智能合约开发交互,进行账号创建、交易、转账、代币开发以及过滤器和交易等内容。
  • python以太坊,主要是针对python工程师使用web3.py进行区块链以太坊开发的详解。
  • 以太坊入门教程,主要介绍智能合约与dapp应用开发,适合入门。
  • 以太坊开发进阶教程,主要是介绍使用node.js、mongodb、区块链、ipfs实现去中心化电商DApp实战,适合进阶。
  • C#以太坊,主要讲解如何使用C#开发基于.Net的以太坊应用,包括账户管理、状态与交易、智能合约开发与交互、过滤器和交易等。
  • EOS教程,本课程帮助你快速入门EOS区块链去中心化应用的开发,内容涵盖EOS工具链、账户与钱包、发行代币、智能合约开发与部署、使用代码与智能合约交互等核心知识点,最后综合运用各知识点完成一个便签DApp的开发。
  • java比特币开发教程,本课程面向初学者,内容即涵盖比特币的核心概念,例如区块链存储、去中心化共识机制、密钥与脚本、交易与UTXO等,同时也详细讲解如何在Java代码中集成比特币支持功能,例如创建地址、管理钱包、构造裸交易等,是Java工程师不可多得的比特币开发学习课程。
  • php比特币开发教程,本课程面向初学者,内容即涵盖比特币的核心概念,例如区块链存储、去中心化共识机制、密钥与脚本、交易与UTXO等,同时也详细讲解如何在Php代码中集成比特币支持功能,例如创建地址、管理钱包、构造裸交易等,是Php工程师不可多得的比特币开发学习课程。
  • tendermint区块链开发详解,本课程适合希望使用tendermint进行区块链开发的工程师,课程内容即包括tendermint应用开发模型中的核心概念,例如ABCI接口、默克尔树、多版本状态库等,也包括代币发行等丰富的实操代码,是go语言工程师快速入门区块链开发的最佳选择。

汇智网原创翻译,转载请标明出处。这里是使用Web3.js 1.0构建以太坊Oracle