首页 > 世链号 > 撸一个预言机(Oracle)服务,真香
币小葱  

撸一个预言机(Oracle)服务,真香

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

一、文章结构

本文将通过上、中、下三篇文章带领大家一步步开发实现一个中心化的 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 合约传递的数据,继续自己的业务。

整体流程如下图所示。

撸一个预言机(Oracle)服务,真香!— 上篇Chainlinkfundamental2.png

图片来源于文章《Chainlink 预言机基本原理》:

https://learnblockchain.cn/article/587

三、Oracle 合约

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

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

  • 能够回调用户合约的方法

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

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

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

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

需要说明的地方:

  • 用户合约会多次请求 Oracle 服务,获取数据, queryId 请求 ID 参数可以让用户合约对请求做标识。

  • 让用户传 callbackAddr 回调地址参数,而不是直接通过 msg.sender 获取调用者地址,是考虑到调用 Oracle 合约 (付费方) 和接收数据方有可能不是一个地址。

  • 对于用户请求的数据类型,本文目前实现了 uint256 和 bytes 两种类型的回调。

  • 考虑到通用性,用户请求的数据来源由用户自定义。如果是一个专类的 Oracle 服务(如只提供随机数服务),可以不需要请求数据字段。

  • 考虑到节省用户的请求费用,加之本身就是一个中心化的 Oracle 服务,不存在作弊问题,因此 query 方法并没有更改任何状态变量,用户请求数据直接写入到日志中。

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

 1/** 2 * @dev 将查询得到的结果(bytes 类型)发送给客户端 3 * @param queryId 查询请求 id 4 * @param callbackAddr 回调的合约地址 5 * @param callbackFUN 回调合约的方法及参数 6 * @param stateCode 查询结果状态码,1 表示查询成功,0 表示失败 7 * @param respData 查询结果 8 * @return bool true 请求成功,false 请求失败 9 */ 10function responseBytes(bytes32 queryId, address callbackAddr, string calldata callbackFUN, uint64 stateCode, bytes calldata respData) payable external isOwner returns(bool) { 11 require(address(this).balance > CALLBACK_GAS, "Insufficient balance!"); 12 (bool success,) = callbackAddr.call.gas(CALLBACK_GAS)(abi.encodeWithSignature(callbackFUN, queryId, stateCode, respData)); 13 require(success,"call back failed!"); 14} 15 16/** 17 * @dev 将查询得到的结果(uint256 类型)发送给客户端 18 */ 19function responseUint256(bytes32 queryId, address callbackAddr, string calldata callbackFUN, uint64 stateCode, uint256 respData) payable external isOwner returns(bool) { 20 require(address(this).balance > CALLBACK_GAS, "Insufficient balance!"); 21 (bool success,) = callbackAddr.call.gas(CALLBACK_GAS)(abi.encodeWithSignature(callbackFUN, queryId, stateCode, respData)); 22 require(success); 23} 

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

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

 1// 查询事件,oracle 后端服务会订阅该事件 2event QueryInfo(bytes32 queryId, address requester, uint fee, address callbackAddr, string callbackFUN, bytes queryData); 

完整代码地址:

https://github.com/six-days/ethereum-contracts/blob/master/oracle/Oracle.sol

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


本文作者:六天

来源链接:mp.weixin.qq.com

免责声明
世链财经作为开放的信息发布平台,所有资讯仅代表作者个人观点,与世链财经无关。如文章、图片、音频或视频出现侵权、违规及其他不当言论,请提供相关材料,发送到:2785592653@qq.com。
风险提示:本站所提供的资讯不代表任何投资暗示。投资有风险,入市须谨慎。
世链粉丝群:提供最新热点新闻,空投糖果、红包等福利,微信:juu3644。