通过预言机获取任意链下数据 - Chainlink Any API 代码解析

这篇具有很好参考价值的文章主要介绍了通过预言机获取任意链下数据 - Chainlink Any API 代码解析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

智能合约对链下数据的兼容会大大增加开发复杂度,Chainlink 通过 AnyAPI 使开发者的智能合约可以通过去中心化预言机网络(Decentralized Oracle Network:DON)获取外部数据。这样在使用 Chainlink AnyAPI 的时候,开发人员可以投入最少的开发资源,获得最大的自由度,因此可以更加专注在智能合约的功能性上,而非怎么样去获取数据上。

虽然 Chainlink Data Feed 可以给链上智能合约提供由 DON 聚合以后的通证价格,但是在很多场景下,尤其是非 DeFi 应用中,dApp 除了价格以外还需要多种多样的数据来实现自己的业务逻辑。比如在保险领域,智能合约需要天气数据来计算参保方的赔付金额,在合成资产协议中,外部股票市场的数据是必不可少的,除此以外,随着 web3 的场景越来越丰富,会越来越多地依赖于链下数据,比如说链下的交通运输,房地产,身份信息等等多种多样的数据。

如果你的智能合约需要依赖于这些数据,Chainlink AnyAPI 都可以作为一个工具让你从指定的外部数据源获取到特定数据。接下来,就让我们看看 Chainlink AnyAPI 的工作原理是什么。

使用 Chainlink AnyAPI 服务

发送 Chainlink 请求

在从 Chainlink 预言机节点获得数据之前,我们首先需要创建一个用户合约,然后在用户合约中给 Chainlink 预言机节点发送一个请求。下面的代码将展示如何通过用户合约给预言机节点发送请求:

function requestVolumeData() public returns (bytes32 requestId) {
 Chainlink.Request memory req = buildChainlinkRequest(jobId, address(this), this.fulfill.selector);
 req.add('get', 'https://min-api.cryptocompare.com/data/pricemultifull?fsyms=ETH&tsyms=USD');
 req.add('path', 'RAW,ETH,USD,VOLUME24HOUR');
 int256 timesAmount = 10**18;
 req.addInt('times', timesAmount);
 return sendChainlinkRequest(req, fee);
}

Chainlink AnyAPI 获取的数据的方式一般是通过预言机节点给外部数据源发送 RESTful 请求,所以节点在发送请求之前需要知道要请求的数据的 API 和参数。为了给 Any API 提供必要的数据,在智能合约的 ChainlinkRequest 中,我们需要通过函数 buildChainlinkRequest 加入这些相关信息。buildChainlinkRequest 这个函数定义在 ChainlinkClient.sol,代码展示如下:

function buildChainlinkRequest(
 bytes32 specId,
 address callbackAddr,
 bytes4 callbackFunctionSignature)
internal
pure
returns (Chainlink.Request memory)
{
    Chainlink.Request memory req;
    return req.initialize(specId, callbackAddr, callbackFunctionSignature);
}

buildChainlinkRequest 函数中,所有与请求相关的信息都会加入到 Request 这个结构体中,并且调用函数 initialize 来完成初始化。

Struct Request is defined in Chainlink.sol as below:
struct Request {
 bytes32 id;
 address callbackAddress;
 bytes4 callbackFunctionId;
 uint256 nonce;
 BufferChainlink.buffer buf;
}

函数 initialize 也定义在 Chainlink.sol 文件中,代码如下:

function initialize(
 Request memory self,
 bytes32 jobId,
 address callbackAddr,
 bytes4 callbackFunc
)
internal
pure
returns (Chainlink.Request memory)
{
  BufferChainlink.init(self.buf, defaultBufferSize);
  self.id = jobId;
  self.callbackAddress = callbackAddr;
  self.callbackFunctionId = callbackFunc;
  return self;
}

在函数 buildChainlinkRequest 中,会接受 3 个参数:

  • jobId: 预言机节点需要执行的 job 的 ID。
  • callbackAddr:用户合约地址,这个参数是预言机节点将会将返回数据的合约地址。
  • callbackFunc:这个是预言机节点需要回调的函数签名。

在这三个参数设置好以后,还需要加入 URL 和数据路径,因为我们需要告诉预言机节点通过哪个 API 获取数据,并且在获取数据以后,如何在返回的数据中找到我们所需要的有效数据。

req.add('get', 'https://min-api.cryptocompare.com/data/pricemultifull?fsyms=ETH&tsyms=USD');
req.add('path', 'RAW,ETH,USD,VOLUME24HOUR');

这里的 path 参数很重要,因为预言机通常会通过用户提供的 URL 获得庞大而杂乱的数据,下面的 JSON 数据就是一个例子。

{"RAW":
  {"ETH":
    {"USD":
     {"TYPE":"5",
      "MARKET":"CCCAGG",
      "FROMSYMBOL":"ETH",
      "TOSYMBOL":"USD",
      "FLAGS":"2049",
      "PRICE":1083.43,
      "LASTUPDATE":1655472805,
      "MEDIAN":1083.49,
      "LASTVOLUME":0.01152796,
      "LASTVOLUMETO":12.488815466,
      "LASTTRADEID":"298687546",
      "VOLUMEDAY":279647.314121829,
      "VOLUMEDAYTO":304661021.9293905,
      "VOLUME24HOUR":617393.32461219,
      .......
      .......
      "TOTALTOPTIERVOLUME24HTO":"$ 5.47B",
      "IMAGEURL":"/media/37746238/eth.png"}
     }
   }
}

通过在 request 中的 path 数据,预言机节点才可以获取到我们所想要的数据。所以在 URL 和路径被设置好以后,这个 chainlinkRequest 就完成并且可以被发送了。
return sendChainlinkRequest(req, fee);
这里的调用顺序是:
终端用户会在用户合约中调用函数 requestVolumeData,然后用户合约会调用 ChainlinkClient.sol 中的函数 sendChainlinkRequest
然后 sendChainlinkRequest 会调用函数 sendChainlinkRequestTo,这个函数会接受的参数是预言机的地址,函数签名和其他相关信息,然后 encode 所有的信息,转化为 bytes 数据。
接下来,_rawRequest 会调用 Link 通证合约的中的 transferAndCall 函数,transferAndCall 是 ERC-677 标准中所定义的函数。transferAndCall会把要执行的代码(上一步中的 encode 数据)发送给预言机合约,然后要求该合约执行 代码逻辑。
最后,预言机合约 OperatorInterface.sol中的函数 operatorRequest 会被上一步中的 transferAndCall调用,然后该函数会将函数签名,requestId 等信息写到 event 中,以便链下预言机发现。
让我们看一个具体的例子,Chainlink 官方在测试网 Kovan 中所部署了一个预言机合约。这个合约的代码可以在这里看到。

 function operatorRequest(
    address sender,
    uint256 payment,
    bytes32 specId,
    bytes4 callbackFunctionId,
    uint256 nonce,
    uint256 dataVersion,
    bytes calldata data
  ) external override validateFromLINK {
    (bytes32 requestId, uint256 expiration) = _verifyAndProcessOracleRequest(
      sender,
      payment,
      sender,
      callbackFunctionId,
      nonce,
      dataVersion
    );
    emit OracleRequest(specId, sender, requestId, payment, sender, callbackFunctionId, expiration, dataVersion, data);
  }

在代码中,可以很容易看到,这个函数就是把所有的信息写到了 event log 中,然后等待链下的预言机节点检测。

返回请求数据

返回数据的函数 fulfillOracleRequest2 也被定义在 OperatorInterface.sol 文件中。

function fulfillOracleRequest2(
bytes32 requestId,
uint256 payment,
address callbackAddress,
bytes4 callbackFunctionId,
uint256 expiration,
bytes calldata data
) external returns (bool);

让我们看看刚才的合约中,这个函数中的逻辑是什么样的:

function fulfillOracleRequest2(
   bytes32 requestId,
   uint256 payment,
   address callbackAddress,
   bytes4 callbackFunctionId,
   uint256 expiration,
   bytes calldata data
 )
   external
   override
   validateAuthorizedSender
   validateRequestId(requestId)
   validateCallbackAddress(callbackAddress)
   validateMultiWordResponseId(requestId, data)
   returns (bool)
 {
   _verifyOracleRequestAndProcessPayment(requestId, payment, callbackAddress, callbackFunctionId, expiration, 2);
   emit OracleResponse(requestId);
   require(gasleft() >= MINIMUM_CONSUMER_GAS_LIMIT, "Must provide consumer enough gas");
 
   (bool success, ) = callbackAddress.call(abi.encodePacked(callbackFunctionId, data));
   return success;
 }

通过上面的代码,我们看到这个函数调用了 callbackAddress 地址合约中的一个函数,这个地址就是之前传给预言机合约的用户合约地址。用户合约中 fullfill 函数被调用了:

function fulfill(bytes32 _requestId, uint256 _volume) public recordChainlinkFulfillment(_requestId) {
       emit RequestVolume(_requestId, _volume);
       volume = _volume;
   }

这个展示合约中的 fulfill 函数非常简单,就是将 requestId 和 volume 的数据写入 event log,然后将 volume 写入到本地变量 _volume 中。

运行 Chainlink 节点提供 Any API 服务

在上一章节,我们了解了如何在用户合约中使用 Chainlink AnyAPI服务,以获取到多种多样的数据。接下来,我们来看看如何去运行 Chainlink AnyAPI 的“后端”,来看看如何运行一个预言机节点来帮助链上合约获取它们所需要的各种数据。

运行自己的 Chainlink 节点

新建节点有很多种方式,如果你是一个运维人员并且自身有足够的硬件资源,可以根据官方文档中的教程新建一个节点。如果你不想要自己运维节点,那么可以选择使用 naas.link(node as a service),只需要点几个按钮就可以新建一个节点,并且是免费的。另外,Chainlink 官方开发者关系团队也在不同的链上维护了一些 Chainlink 节点,可以在这里查看关于这些节点的 JobId,合约地址和其他相关信息。
如果你需要一些特殊的数据,比如说天气数据,股票数据,体育比赛数据等等,可以在 Chainlink 提供的数据市场 market.link 中搜索。

如果你对于Chainlink 节点所提供的数据有更个性化的要求,可以登陆 Chainlink 的 Discord,Chainlink 团队会帮你在社区中联系节点运营商,以满足你的需求。华语开发者也可以直接联系 Chainlink 中国团队,获得更快的响应。

在上一章节,我们了解了如何去写一个用户合约来使用 Chainlink AnyAPI ,从而获取到多种多样的数据。接下来,我们可以学习一下如何去运行 AnyAPI 的“后端”,来看看如何运行一个预言机节点来帮助链上合约获取它们所需要的各种数据。

预言机节点的 job 和 task pipeline (TOML)

TOML(Tom’s Obviously Minimal Language)是一种配置文件的格式,因为 sematics 比较清晰,所以更容易阅读,被很多项目所使用。Chainlink 节点就是使用 TOML 来定义节点所提供的 API 服务所对应的 job 的详细信息。

在 Chainlink 节点中,每一个 jobId 都会代表一个在节点中运行的 job。比如说在 API 样例代码中,jobId 代表的 job 是获取 BTC 昨天的市场数据的。Chainlink 节点使用 TOML 来定义怎么样从 API 中获取数据,并且将这个数据进行标准化,使其可以被用户合约使用。

Chainlink 节点做的任何操作都会依赖于 job,现在支持以下 6 种 job:

  1. Cron:根据一个时间表而非外部触发来执行一个 job。
  2. Direct request job:根据一个用户所发出的请求的 receipt 来执行一个 job。预言机合约会在被 emit 的 log 中发现用户的请求。这个方式和以前 ethlog/runlog 执行 job 的方式类似。
  3. Flux monitor job:根据不同的预言机节点所返回的数据来更新 data feed 中的数据。更新会在波动率足够大,或者是 heartbeat 超出时间限制的时候触发。
  4. Keeper job:根据链上合约中的状态进行判断,判断成功以后会执行智能合约中的函数,可以非定期地调用合约中的函数。
  5. Off-chain reporting job:Off-chain reporting(OCR)和 Flux monitor job 非常类似,OCR job 会根据多个 Chainlink 预言机节点聚合以后的数据更新 data feed。OCR 和 Flux monitor job 的区别是 OCR 使用了由密码学保证的链下协议,可以让单个节点在一个 round 中将所有其他节点中的数据提交上来。通过这个方式,可以节省大量的gas。
  6. Webhook job: Webhook 可以由 HTTP 请求所触发,HTTP 请求可以由用户或者其他外部触发器所触发。

在 job 中,需要定义以下变量:

  1. name: 在 Chainlink 节点 UI 中所现实的 job 的名字。
  2. type: job 的类型,可以是上述 job 类型中的任何一个。
  3. schemaVersion: 现在都需要设置为 1,这个设置是为了让 job 的格式向前兼容。
  4. observationSource: 这个参数定义 job 具体要做的操作。
  5. maxTaskDuration: 任何一个任务能够运行的最长事件默认值。如果一个任务达到了最长时间,这个任务就会报错。
  6. externalJobID: 提供了一种可选方法,用户可以通过这个参数直接定义 job 的。

除了上述参数以外,你还需要定义 job 中的任务(task),让我们看看一个 job 的 TOML 文件的例子:

type                = "directrequest"
schemaVersion       = 1
evmChainID          = 1
name                = "example eth request event spec"
contractAddress     = "0x613a38AC1659769640aaE063C651F48E0250454C"
 
observationSource   = """
   ds          [type="http" method=GET url="http://example.com"]
   ds_parse    [type="jsonparse" path="USD"]
   ds_multiply [type="multiply" times=100]
 
   ds -> ds_parse -> ds_multiply

ds, ds_parse, ds_multiply 是 job 要执行的 3 个任务,执行顺序通过 ds -> ds_parse -> ds_multiply 这一行定义,语法非常简单,即先给 “http://exmpale.com” 发送 GET 请求,然后使用路径 “USD” 来找到用户在这个JSON 文件中需要的值。这个 JSON 文件如下:

{
  usd: number
}

最后,这个 job 会根据 ds_multiply 这个任务将结果乘以 100。

总结

除了可以通过 Chainlink data feed 获取通证价格以外,开发者还可以通过 Chainlink Any API 获得任何个性化数据。文章讲解了如何新建自己的 Chainlink 节点,并且在合约中使用 Chainlink 节点 AnyAPI 服务获得个性化数据。
您可以关注 Chainlink 预言机并且私信加入开发者社区,有大量关于智能合约的学习资料以及关于区块链的话题!文章来源地址https://www.toymoban.com/news/detail-405388.html

到了这里,关于通过预言机获取任意链下数据 - Chainlink Any API 代码解析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 操作指南 | 如何使用Chainlink喂价功能获取价格数据

    Chainlink的去中心化预言机网络中的智能合约包含由运行商为其他智能合约(DApps)使用或截取所持续更新的实施价格数据。其中有两个主要架构:喂价和基础要求模型。此教程将会展现如何在Moonbeam、Moonriver或是Moonbase Alpha测试网上使用喂价功能。 这些信息仅用于教育目的,永

    2024年02月11日
    浏览(42)
  • 通过python 获取股票数据的API接口

    用法: ContextInfo.get_bar_timetag (index)。 释义:获取当前K线对应时间的时间戳。 参数:number:K线索引号。 返回:number。 示例: 用法:ContextInfo.get_ sector(sector, realtime)。 释义:获取板块成份股,只支持取指数成份股。

    2024年02月11日
    浏览(34)
  • 拼多多商品数据如何通过api接口获取

    要从拼多多获取商品数据,可以使用拼多多提供的API接口。首先需要注册一个拼多多开放平台的开发者账号,然后创建一个应用程序,获取应用程序的app_id和app_secret,以在API请求中进行身份验证。 以下是一些获取拼多多商品数据的常用API接口: 商品搜索API:可以根据

    2024年02月01日
    浏览(40)
  • 淘宝商品API使用示例:如何通过调用外部API来获取淘宝商品价格销量主图详情数据

    淘宝上的商品信息量非常之大,商品的详情信息也很齐全。如何通过调用外部API来实现批量获取商品价格销量主图详情等信息呢?上周刚好完成了一个完整的淘宝商品采集项目,今天特来分享一下。 接口名称:item_get 请求地址:https://api-test.cn/taobao/item_get result_type:[json,jso

    2024年02月10日
    浏览(41)
  • 如何通过 Chainlink Price Feeds获得加密资产的历史价格

    对于 Web3 应用来说,获取加密资产的价格数据是一个很常见的要求,许多协议都需要依赖于高质量且及时更新的数据来运营DeFi 应用并且保证其安全性。除此之外,智能合约开发者有的时候也需要获取加密资产的历史数据。 在这篇文章中,我们将演示如何从 Chainlink Price Feed

    2023年04月24日
    浏览(42)
  • Intel RealSense D435i深度相机通过点云获取图片中任意点三维信息(python实现)

    此时效果(左侧RGB图,右侧深度图)(过近时深度信息几乎显示不出来)  按下p键暂停画面 按下s键保存图片 按下r键读取刚才保存的图片,并通过image_sliced文件将图片裁剪到自己需要的范围 image_sliced.py 按下g键进行图像处理,判断方向,并将三维信息显示在图片上 image_pro

    2023年04月08日
    浏览(40)
  • 链下数据认证

    由于区块链无法自己获取链下数据,也无法向链下系统传输数据,所以才能在安全和可靠性上做到极致,整个网络只需要使用区块链账本中已经存储的数据针对一组简单的true/false问题达成共识即可,比如“公钥持有者是否使用对应的私钥对交易签名?”、“公钥地址中是否有

    2024年01月21日
    浏览(27)
  • Bitbyte.Finance 通过预言机为 Web3 赋能

    如果我们将区块链定义为信任机器,那么预言机器本质上可以被描述为维护和建立信任的机器。事实上,区块链本身并不产生信任,信任的输入来自于预言机。智能合约的模块化增长将带来大量的交互需求和相应的差异数据请求。为此,Bitbyte.Finance 与预言机上线,提供链上协

    2024年02月13日
    浏览(27)
  • Python 使用 win32gui+win32api 通过鼠标获取句柄

    通过python实现某些win相关的自动化操作时,可能需要通过句柄操作. 获取的方法有很多.对此也有相关的可视化的软件实现类似的功能.比如: 通过vs工具获取窗体或者程序句柄 使用按键精灵获取句柄 使用某星小助手等 为此分享的当前的文章介绍的方法也是一种可视化的获取句柄

    2024年02月14日
    浏览(32)
  • 拼多多关键字搜索API-通过关键字获取拼多多商品列表

    pinduoduo.item_search 公共参数 请求地址: pinduoduo/item_search 名称 类型 必须 描述 key String 是 调用key(必须以GET方式拼接在URL中) secret String 是 调用密钥 api_name String 是 API接口名称(包括在请求地址中)[item_search,item_get,item_search_shop等] cache String 否 [yes,no]默认yes,将调用缓存的数据

    2024年02月22日
    浏览(59)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包