没有oracle服务_撸一个预言机(Oracle)服务,真香!—上篇

本文详细介绍了如何开发一个中心化的Oracle服务,包括Oracle的基本概念、服务流程和合约实现。作者提出Oracle作为链上链下的桥梁,允许区块链获取链下数据。文中提到的Oracle合约包含接收请求、回调用户合约和事件订阅等关键方法,并提供了合约代码示例。下篇将讲述Oracle服务的后台实现。
摘要由CSDN通过智能技术生成

34b5b25866c6d6f73623bc805a1b7eb0.png

本文作者:六天

一、文章结构

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

  • 上篇:Oracle 简介及合约实现
  • 中篇:使用 go 语言开发 Oracle 服务
  • 下篇:抽奖合约调用 Oracle 服务示例

一、Oracle 简介

Oracle(预言机)是链接链上与链下的桥梁,能够将链下数据推送给链上。正是由于 Oracle 的存在,使得区块链从封闭走向开放,充满无限可能。

如需了解 Oracle 基础知识,这里推荐阅读孙孝虎的《什么是区块链预言机(BlockChain Oracle)》

Oracle 服务分为中心化和去中心化,其核心区别是对数据的获取和审核上。去中心化的 Oracle 服务会有一套机制能够保障推送给用户合约的数据是可信的。而无论是中心化还是去中心化,用户合约调用 Oracle 合约和 Oracle 服务将获取到的结果数据推送给用户合约的底层逻辑都是一样的。

一个完整的中心化 Oracle 服务请求流程为:

  1. 用户合约调用 Oracle 合约的查询方法
  2. Oracle 合约接收到用户查询请求后将相关数据写入 Event 事件中
  3. Oracle 服务(后台服务)通过订阅 Oracle 合约的 Event 事件,获取到用户的请求
  4. Oracle 服务根据用户请求获取外部数据
  5. Oracle 服务调用 Oracle 合约响应方法,传入获取的外部数据
  6. Oracle 合约响应方法调用用户合约的回调方法,将数据传递给用户合约
  7. 用户合约收到 Oracle 合约传递的数据,继续自己的业务。

整体流程如下图所示。

d57515888d518835cc7041cb007e325b.png
图片来源于文章《Chainlink 预言机基本原理》: https:// learnblockchain.cn/arti cle/587

三、Oracle 合约

通过上面对 Oracle 服务流程的分析,总结到一个 Oracle 合约至少需要包含两个方法和一个事件:

  • 能够接收用户合约请求的方法
  • 能够回调用户合约的方法
  • 能够供 Oracle 服务订阅的用户请求事件

接下来,我将实现一个通用的 Oracle 合约。

1. 能够接收用户合约请求的方法

/**
 * @dev 接收客户端请求
 * @param queryId 请求id,回调时原值返回
 * @param callbackAddr 回调的合约地址
 * @param callbackFUN 回调合约的方法及参数,如getResponse(bytes32,uint64,uint256/bytes),
 *        其中getResponse表示回调方法名,可自定义;
 *        bytes32类型参数指请求id,回调时会原值返回;
 *        uint64类型参数表示oracle服务状态码,1表示成功,0表示失败;
 *        第三个参数表示Oracle服务回调支持uint256/bytes两种类型的参数
 * @param queryData 请求数据,json格式,如{"url":"https://ethgasstation.info/api/ethgasAPI.json","responseParams":["fast"]}
 * @return bool true请求成功,false请求失败
 */
function query(bytes32 queryId, address callbackAddr, string calldata callbackFUN, bytes calldata queryData) external payable returns(bool) {
    require(msg.value >= MIN_FEE, "Insufficient handling fee!");
    require(bytes(callbackFUN).length > 0, "Invalid callbackFUN!");
    require(queryData.length > 0, "Invalid queryData!");
    // 记录日志
    emit QueryInfo(queryId, msg.sender, msg.value, callbackAddr, callbackFUN, queryData);
    return true;
}

需要说明的地方:

  • 用户合约会多次请求 Oracle 服务,获取数据, queryId 请求 ID 参数可以让用户合约对请求做标识。
  • 让用户传 callbackAddr 回调地址参数,而不是直接通过 msg.sender 获取调用者地址,是考虑到调用 Oracle 合约(付费方)和接收数据方有可能不是一个地址。
  • 对于用户请求的数据类型,本文目前实现了 uint256 和 bytes 两种类型的回调。
  • 考虑到通用性,用户请求的数据来源由用户自定义。如果是一个专类的 Oracle 服务(如只提供随机数服务),可以不需要请求数据字段。
  • 考虑到节省用户的请求费用,加之本身就是一个中心化的 Oracle 服务,不存在作弊问题,因此 query 方法并没有更改任何状态变量,用户请求数据直接写入到日志中。

2. 能够回调用户合约的方法

/**
 * @dev 将查询得到的结果(bytes类型)发送给客户端
 * @param queryId 查询请求id
 * @param callbackAddr 回调的合约地址
 * @param callbackFUN 回调合约的方法及参数
 * @param stateCode 查询结果状态码,1表示查询成功,0表示失败
 * @param respData 查询结果
 * @return bool true请求成功,false请求失败
 */
function responseBytes(bytes32 queryId, address callbackAddr, string calldata callbackFUN, uint64 stateCode, bytes calldata respData) payable external isOwner returns(bool) {
    require(address(this).balance > CALLBACK_GAS, "Insufficient balance!");
    (bool success,) = callbackAddr.call.gas(CALLBACK_GAS)(abi.encodeWithSignature(callbackFUN, queryId, stateCode, respData));
    require(success,"call back failed!");
}

/**
 * @dev 将查询得到的结果(uint256类型)发送给客户端
 */
function responseUint256(bytes32 queryId, address callbackAddr, string calldata callbackFUN, uint64 stateCode, uint256 respData) payable external isOwner returns(bool) {
    require(address(this).balance > CALLBACK_GAS, "Insufficient balance!");
    (bool success,) = callbackAddr.call.gas(CALLBACK_GAS)(abi.encodeWithSignature(callbackFUN, queryId, stateCode, respData));
    require(success);
}

3. 能够供 Oracle 服务订阅的用户请求事件

事件将用户请求的相关参数都记录下来,Oracle 服务通过订阅该事件,一旦有用户请求时,Oracle 服务就能够获取到用户的请求数据。

// 查询事件,oracle后端服务会订阅该事件
event QueryInfo(bytes32 queryId, address requester, uint fee, address callbackAddr, string callbackFUN, bytes queryData);
完整代码地址: https:// github.com/six-days/eth ereum-contracts/blob/master/oracle/Oracle.sol

下篇我们将介绍 Oracle 服务(后端服务)如何订阅查询事件以及将获取到的数据返回给合约,具体实现代码将以 golang 语言给出。


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

作者主页: 六天 的个人主页 - 登链社区 | 深入浅出区块链技术,欢迎阅读作者更多好文

登链社区 - 区块链技术爱好者的家园

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值