23

撸一个预言机(Oracle)服务,真香!—下篇 | 登链社区 | 深入浅出区块链技术

 3 years ago
source link: https://learnblockchain.cn/article/1162?
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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

一、文章结构

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

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

二、联调准备

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

1、区块链网络

我使用的是 ganache,在本地创建了一个以太坊私链。
ganache 的按照和使用详见官方文档:https://www.trufflesuite.com/ganache

2、部署合约

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

如下图所示。

445b3f96b38eeb4c73df632e6f6f5063.png

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

2.1 部署 Oracle 合约

Oracle 合约源码地址: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

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

2.3 初始化抽奖合约

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

0ee43a48e5f8d12715629a024c5ff4b5.png

3、 运行 Oracle 服务

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

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

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

3.1 修改服务配置文件

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

  • OracleContractAddress Oracle 合约地址
  • NetworkWS 以太坊网络的 ws 地址
  • PrivateKey Oracle 合约的部署(owner)以太坊账户私钥

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

644e6d39fcb8649f4598ae092bc3a295.png

3.2 运行 Oracle 服务

服务启动命令:

./oracle-service -c ./conf/app.conf -l logs/
  • -c 表示配置文件地址
  • -l 表示日志存储目录

启动后如下图所示。

975c1405ab9534d0bae408f311202f12.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

2、调用 Oracle 合约

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

3、查看 Oracle 服务

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

dd8615c764279b2be46cc77a7be13cd6.png

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

4、抽奖合约中验证

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

7e0f2aebc0994043df5e306604d17f6e.png

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

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

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

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

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

  • 发表于 2020-06-19 15:45
  • 阅读 ( 1008 )
  • 学分 ( 246 )
  • 分类:以太坊

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK