oracle自取一条,撸一个预言机(Oracle)服务,真香!—下篇

本篇是下篇,主要介绍如果通过一个抽奖合约调用我们上篇开发的Oracle服务

# 一、文章结构

本文将通过上、中、下三篇文章带领大家一步步开发实现一个中心化的Oracle服务,并通过一个抽奖合约演示如何使用我们的Oracle服务。文章内容安排如下:

- 上篇:[Oracle简介及合约实现](https://learnblockchain.cn/article/1150)

- 中篇:[使用go语言开发Oracle服务](https://learnblockchain.cn/article/1157)

- 下篇:**抽奖合约调用Oracle服务示例**

前两篇文章中,我们实现了Oracle合约,开发了Oracle服务,在这边文章中,我们以一个抽奖合约为例,介绍在抽奖合约中,怎么通过Oracle服务获取一个随机数(中奖数)。

# 二、联调准备

首先我们需要搭建测试环境、部署合约、运行服务。我是在本地进行联调测试的,可以参考我的环境。

## 1、区块链网络

我使用的是ganache,在本地创建了一个以太坊私链。

ganache的按照和使用详见官方文档:[https://www.trufflesuite.com/ganache](https://www.trufflesuite.com/ganache)

## 2、部署合约

区块链网络创建好后,需要把我们的Oracle合约和抽奖合约部署到网络上。我用的是Remix,链接到本地网络进行部署的。

如下图所示。

![445b3f96b38eeb4c73df632e6f6f5063.png](https://img.learnblockchain.cn/attachments/2020/06/7Nc8txNA5eec6e6652794.png)

> 大家也可以使用Truffle工具进行合约的自动化部署

### 2.1 部署Oracle合约

Oracle合约源码地址:[https://github.com/six-days/ethereum-contracts/blob/master/oracle/Oracle.sol](https://github.com/six-days/ethereum-contracts/blob/master/oracle/Oracle.sol)

这里我部署后的合约地址为:`0xcb6a9baeb203a19d391d5f3db7040fe2ac4f8b82`

### 2.2 部署抽奖合约

抽奖合约源码地址:[https://github.com/six-days/ethereum-contracts/blob/master/oracle/Lottery.sol](https://github.com/six-days/ethereum-contracts/blob/master/oracle/Lottery.sol)

这里我部署后的合约地址为:`0x7058f4f12ba53a13617de57d2271f64f2621e503`

### 2.3 初始化抽奖合约

调用`setOracle`方法,将我们的Oracle合约地址配置到抽奖合约中。

![0ee43a48e5f8d12715629a024c5ff4b5.png](https://img.learnblockchain.cn/attachments/2020/06/04eJqKKq5eec6e78ca113.png)

## 3、 运行Oracle服务

合约部署完成后,就可以配置我们的Oracle服务并启动了。

Oracle服务源码地址:[https://github.com/six-days/ethereum-oracle-service](https://github.com/six-days/ethereum-oracle-service)

将源码下载下来后,按照说明进行编译。

### 3.1 修改服务配置文件

配置文件需要有三项,分别是:

- ` OracleContractAddress` Oracle合约地址

- `NetworkWS` 以太坊网络的ws地址

- `PrivateKey` Oracle合约的部署(owner)以太坊账户私钥

编辑好配置信息后,保存到文件中。如下图所示。

![644e6d39fcb8649f4598ae092bc3a295.png](https://img.learnblockchain.cn/attachments/2020/06/pEM8O01S5eec6e8714c08.png)

### 3.2 运行Oracle服务

服务启动命令:

```

./oracle-service -c ./conf/app.conf -l logs/

```

其中:

- `-c`表示配置文件地址

- `-l`表示日志存储目录

启动后如下图所示。

![975c1405ab9534d0bae408f311202f12.png](https://img.learnblockchain.cn/attachments/2020/06/TIitSMcX5eec6e92bd17e.png)

此时我们的Oracle服务已经开始监控Oracle合约的事件了。

# 三、抽奖合约

在联调前,我先简单介绍下抽奖合约。

玩法是每个用户向合约提交一个数字(默认>=0,<=30,根据每轮中运行的下注个数决定),调用`enterNumber`投注。

当下注的数字个数超过每一轮允许的个数后(默认3个),管理员就可以调用`runRound`方法进行开奖。

```

/**

* @dev 开奖

*/

function runRound(uint256 _roundTimes) public onlyOwner {

require(oracleRequests[_roundTimes] == -3, "oracle random request has send or not ready!");

bytes memory requestData = bytes("{\"url\":\"https://www.random.org/integers/?num=1&min=0&max=30&col=1&base=10&format=plain&rnd=new\",\"responseParams\":[]}");

oracle.query.value(ORACLE_FEE)(bytes32(_roundTimes), address(this), "getOracelRandom(bytes32,uint64,uint256)", requestData);

oracleRequests[_roundTimes] = -2; // 表示已请求oracle服务,等待返回结果

}

```

在`runRound`方法中,会调用Oracle合约,请求一个随机数。这里随机数是通过www.random.org网站获取。

Oracle服务获取到随机数后,回调抽奖合约的`getOracelRandom`方法。代码如下。

```

/**

* @dev oracle服务回调函数

*/

function getOracelRandom(bytes32 _reqId, uint64 _stateCode, uint256 _randomNum) external onlyOracle returns(bool) {

emit OracleResponse(_reqId, _stateCode, _randomNum);

uint256 _roundTimes = uint256(_reqId);

require(numbers.length >= _roundTimes*oneRoundPlayers, "invalid reqId!");

require(oracleRequests[_roundTimes] == -2, "not ready to get oracle random response!");

if (_stateCode == 1) {

oracleRequests[_roundTimes] = int256(_randomNum);

for (uint256 i = (_roundTimes-1)*oneRoundPlayers; i < _roundTimes*oneRoundPlayers; i++) {

if (numbers[i] == _randomNum) {

roundWinner[_roundTimes].push(i);

}

}

} else {

oracleRequests[_roundTimes] = -1;

}

}

```

`getOracelRandom`方法会根据Oracle服务返回的随机数,判断中奖者。这里我只是标识了中奖者,并没有给中奖者发奖。

# 四、联调

## 1、向抽奖合约提交数字

在remix里调用抽奖合约的`enterNumber`方法,提交时除了数字外,需要最少100 szabo的以太币。

如下图所示。

![e131251b39b4b9cf823e95c3cd953424.png](https://img.learnblockchain.cn/attachments/2020/06/VodHiFp35eec6ea28c14c.png)

## 2、调用Oracle合约

当向抽奖合约发送至少3个数字后,查看`roundTimes`(表示第几轮)已经大于0。这时调用`runRound`方法进行开奖。

## 3、查看Oracle服务

调用开奖方法后,会向我们的Oracle合约请求一个随机数。这时回到Oracle服务中,可以看到请求日志。如下图所示。

![dd8615c764279b2be46cc77a7be13cd6.png](https://img.learnblockchain.cn/attachments/2020/06/1KRdJXqE5eec6ead757df.png)

从上图可以看到,我们的Oracle服务已经获取到Oracle合约中的事件,并且根据用户查询信息查询到一个随机数11,并且把这个随机数回调给了用户,交易hash是`0x3060d0ebcb61666199379dc7f8ad7cf06e6b306fbf172d7d0d44871b02ce73c8` 。

## 4、抽奖合约中验证

抽奖合约的`oracleRequests`变量中保存这Oracle合约的请求id和对应的结果。我们通过调用该方法进行验证,如下图所示。

![7e0f2aebc0994043df5e306604d17f6e.png](https://img.learnblockchain.cn/attachments/2020/06/WMCgNSVq5eec6eb6dae06.png)

至此,我们抽奖合约和Oracle服务联调完毕,可以愉快的使用了。

相关的代码都已放到github上,如有需要请自取。自取时记得点个`star`,感谢!

Oracle服务代码:[https://github.com/six-days/ethereum-oracle-service](https://github.com/six-days/ethereum-oracle-service)

Oracle合约代码:[https://github.com/six-days/ethereum-contracts](https://github.com/six-days/ethereum-contracts)

一、文章结构

本文将通过上、中、下三篇文章带领大家一步步开发实现一个中心化的Oracle服务,并通过一个抽奖合约演示如何使用我们的Oracle服务。文章内容安排如下:

前两篇文章中,我们实现了Oracle合约,开发了Oracle服务,在这边文章中,我们以一个抽奖合约为例,介绍在抽奖合约中,怎么通过Oracle服务获取一个随机数(中奖数)。

二、联调准备

首先我们需要搭建测试环境、部署合约、运行服务。我是在本地进行联调测试的,可以参考我的环境。

1、区块链网络

我使用的是ganache,在本地创建了一个以太坊私链。

ganache的按照和使用详见官方文档:https://www.trufflesuite.com/ganache

2、部署合约

区块链网络创建好后,需要把我们的Oracle合约和抽奖合约部署到网络上。我用的是Remix,链接到本地网络进行部署的。

如下图所示。

ec68aed5278e6f30ee8b56e0528a5afe.png

大家也可以使用Truffle工具进行合约的自动化部署

2.1 部署Oracle合约

这里我部署后的合约地址为:0xcb6a9baeb203a19d391d5f3db7040fe2ac4f8b82

2.2 部署抽奖合约

这里我部署后的合约地址为:0x7058f4f12ba53a13617de57d2271f64f2621e503

2.3 初始化抽奖合约

调用setOracle方法,将我们的Oracle合约地址配置到抽奖合约中。

8dc69a54ee54caf6c2dba55768d624fa.png

3、 运行Oracle服务

合约部署完成后,就可以配置我们的Oracle服务并启动了。

将源码下载下来后,按照说明进行编译。

3.1 修改服务配置文件

配置文件需要有三项,分别是:

OracleContractAddress Oracle合约地址

NetworkWS 以太坊网络的ws地址

PrivateKey Oracle合约的部署(owner)以太坊账户私钥

编辑好配置信息后,保存到文件中。如下图所示。

34f71a7f132788d5cf11886fd2232253.png

3.2 运行Oracle服务

服务启动命令:

./oracle-service -c ./conf/app.conf -l logs/

其中:

-c表示配置文件地址

-l表示日志存储目录

启动后如下图所示。

b19bf528f2bd1fc1e8f541cafb92b5ba.png

此时我们的Oracle服务已经开始监控Oracle合约的事件了。

三、抽奖合约

在联调前,我先简单介绍下抽奖合约。

玩法是每个用户向合约提交一个数字(默认>=0,<=30,根据每轮中运行的下注个数决定),调用enterNumber投注。

当下注的数字个数超过每一轮允许的个数后(默认3个),管理员就可以调用runRound方法进行开奖。

/**

* @dev 开奖

*/

function runRound(uint256 _roundTimes) public onlyOwner {

require(oracleRequests[_roundTimes] == -3, "oracle random request has send or not ready!");

bytes memory requestData = bytes("{\"url\":\"https://www.random.org/integers/?num=1&min=0&max=30&col=1&base=10&format=plain&rnd=new\",\"responseParams\":[]}");

oracle.query.value(ORACLE_FEE)(bytes32(_roundTimes), address(this), "getOracelRandom(bytes32,uint64,uint256)", requestData);

oracleRequests[_roundTimes] = -2; // 表示已请求oracle服务,等待返回结果

}

在runRound方法中,会调用Oracle合约,请求一个随机数。这里随机数是通过www.random.org网站获取。

Oracle服务获取到随机数后,回调抽奖合约的getOracelRandom方法。代码如下。

/**

* @dev oracle服务回调函数

*/

function getOracelRandom(bytes32 _reqId, uint64 _stateCode, uint256 _randomNum) external onlyOracle returns(bool) {

emit OracleResponse(_reqId, _stateCode, _randomNum);

uint256 _roundTimes = uint256(_reqId);

require(numbers.length >= _roundTimes*oneRoundPlayers, "invalid reqId!");

require(oracleRequests[_roundTimes] == -2, "not ready to get oracle random response!");

if (_stateCode == 1) {

oracleRequests[_roundTimes] = int256(_randomNum);

for (uint256 i = (_roundTimes-1)*oneRoundPlayers; i < _roundTimes*oneRoundPlayers; i++) {

if (numbers[i] == _randomNum) {

roundWinner[_roundTimes].push(i);

}

}

} else {

oracleRequests[_roundTimes] = -1;

}

}

getOracelRandom方法会根据Oracle服务返回的随机数,判断中奖者。这里我只是标识了中奖者,并没有给中奖者发奖。

四、联调

1、向抽奖合约提交数字

在remix里调用抽奖合约的enterNumber方法,提交时除了数字外,需要最少100 szabo的以太币。

如下图所示。

c72c9fe5bf59bb82cde031d63e595ead.png

2、调用Oracle合约

当向抽奖合约发送至少3个数字后,查看roundTimes(表示第几轮)已经大于0。这时调用runRound方法进行开奖。

3、查看Oracle服务

调用开奖方法后,会向我们的Oracle合约请求一个随机数。这时回到Oracle服务中,可以看到请求日志。如下图所示。

bc6bc6b72e5e35bd86d33d3ed4d29014.png

从上图可以看到,我们的Oracle服务已经获取到Oracle合约中的事件,并且根据用户查询信息查询到一个随机数11,并且把这个随机数回调给了用户,交易hash是0x3060d0ebcb61666199379dc7f8ad7cf06e6b306fbf172d7d0d44871b02ce73c8 。

4、抽奖合约中验证

抽奖合约的oracleRequests变量中保存这Oracle合约的请求id和对应的结果。我们通过调用该方法进行验证,如下图所示。

46aa7fdf0ab736da304a0b0d2606b560.png

至此,我们抽奖合约和Oracle服务联调完毕,可以愉快的使用了。

相关的代码都已放到github上,如有需要请自取。自取时记得点个star,感谢!

本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

发表于 2020-06-19 15:45

阅读 ( 2064 )

学分 ( 316 )

分类:以太坊

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值