Chainlink区块链Oracle网络使用指南

Stella981
• 阅读 799

Chainlink是一个去中心化的预言机网络,它可以让区块链中的智能合约安全地访问外部世界的数据。在这个教程中,我们将探索chainlink预言机网络的搭建,并学习如何使用预置或自定义的适配器实现智能合约与外部世界数据的桥接。

以太坊教程链接: Dapp入门 | 电商Dapp实战 | ERC721实战 | Php对接 | Java对接 | Python对接 | C#对接 | Dart对接

智能合约被锁定在区块链里,与外部世界隔离开来。然而在许多应用中,智能合约的 运行需要依赖于外部真实世界的信息。

以Ocean协议为例:只有当提供的数据被证明是可以使用时,数据提供商才可以得到代币奖励。因此一个可以桥接区块链和现实世界的语言机(Oracle)网络就非常必要了。

Chainlink是一个去中心化的oracle网络,它可以让区块链中的智能合约安全地访问外部世界的数据:

Chainlink区块链Oracle网络使用指南

在这个教程中,我们将探索chainlink网络的搭建以及其适配器的使用方法,我们在Kovan测试链搭建了一个用于概念验证的演示环境,所有的代码可以从这里下载。我们使用truffle v5.0.3和Node.js v8.11.1。

1、Chainlink架构概述

Chainlink网络的主要组成部分如下:

  • Chainlink预言机合约:预言机智能合约部署在区块链网络上,它接收来自合约的 Link代币支付并向Chainlink节点分发事件
  • Chainlink节点:Chainlink节点是运行在区块链和外部数据源之间的链下中间件, 它提供真实世界的数据,执行来自请求器合约的请求
  • Chainlink适配器:适配器是应用相关的软件,它负责与数据源交互并执行特定的任务。 chainlink适配器可以部署在serverless平台,例如amazon lambda或google cloud functions

Chainlink区块链Oracle网络使用指南

值得指出的是,每个来自请求器合约的请求都必须包含一个任务ID,用来唯一的标识一个特定的工作流水线。Chainlink节点依赖于任务ID来识别与数据源交互所需的适配器以及处理数据所需的工作流。

2、使用Chainlink内置的适配器

在这一部分,我们使用Chainlinkg预置的适配器来展示如何集成Chainlink并向其提交请求。

2.1 安装Chainlink包

在项目根目录,执行如下命令安装chainlink包:

$ npm install github:smartcontractkit/chainlink --save

另外,Chainlink官方最近增加了一个新的NPM包用于Chainlink合约,可以如下命令安装:

$ npm install chainlink.js — save

2.2 在Kovan测试链部署请求器合约

要访问Chainlink的预言机合约,需要构造一个用于发送Link代币并提交请求的请求器合约。

我们创建了一个请求器合约示例,可以在这里下载。

constructor() public {
    // Set the address for the LINK token in Kovan network.
    setLinkToken(0xa36085F69e2889c224210F603D836748e7dC0088);
    // Set the address of the Oracle contract in Kovan network.
    setOracle(0x2f90A6D021db21e1B2A077c5a37B3C7E75D15b7e); 
}...

   /*
   * Create a request and send it to default Oracle contract
   */
  function createRequest(
    bytes32 _jobId,
    string _url,
    string _path,
    int256 _times
  )
    public
    onlyOwner
    returns (bytes32 requestId)
  {
    // create request instance
    Chainlink.Request memory req = newRequest(_jobId, this, this.fulfill.selector);
    // fill in the pass-in parameters
    req.add("url", _url);
    req.add("path", _path);
    req.addInt("times", _times);
    // send request & payment to Chainlink oracle
    requestId = chainlinkRequestTo(getOracle(), req, ORACLE_PAYMENT);
    // emit event message
    emit requestCreated(msg.sender, _jobId, requestId);
  }

请求器合约中的关键函数是createRequest函数,它创建请求并设置必要的参数:

  • Job Id:特定作业流水线的唯一标识符。可以在这里查看内置适配器的完整清单:
  • URL:可以返回JSON数据的web api的访问端结点
  • path:JSON数据字段选择路径,用来声明使用数据中的哪一部分
  • times:数据倍乘系数。该操作将浮点数转换为整数,因为solidity智能合约仅接受整数

2.4 在Kovan测试链部署请求器合约

执行如下命令在以太坊Kovan测试链部署请求器合约:

$ truffle migrate --network kovan
    ...
   Deploying 'OceanRequester'
   --------------------------
   > transaction hash:    0x6e228163e73828c58c8287fec72c551289516a1d8e9300aab5dcc99d848f6146
   > Blocks: 0            Seconds: 16
   > contract address:    0x04E4b02EA2662F5BF0189912e6092d317d6388F3
   > account:             0x0E364EB0Ad6EB5a4fC30FC3D2C2aE8EBe75F245c
   > balance:             2.703082875853937168
   > gas used:            1439461
   > gas price:           10 gwei
   > value sent:          0 ETH
   > total cost:          0.01439461 ETH

   > Saving artifacts
   -------------------------------------
   > Total cost:          0.01439461 ETH

2.6 向请求器合约存入LINK代币

Chainlink官方提供了一些代币faucet。在Kovan测试链上可以访问这里 获取一些测试用的LINK代币。

只需要输入合约地址或钱包地址,Chainlink的faucet就会转100个LINK代币进去:

Chainlink区块链Oracle网络使用指南

2.7 从合约请求数据

我们创建了一个JavaScript脚本来与请求器合约交互,以便创建并提交请求给Chainlink网络。可以在这里下载JavaScript脚本。

contract("OceanRequester", (accounts) => {
  const LinkToken = artifacts.require("LinkToken.sol");
  const OceanRequester = artifacts.require("OceanRequester.sol");
  const jobId = web3.utils.toHex("2c6578f488c843588954be403aba2deb");
  const url = "https://min-api.cryptocompare.com/data/price?fsym=ETH&tsyms=USD,EUR,JPY";
  const path = "USD";
  const times = 100;
  let link, ocean;

  beforeEach(async () => {
    link = await LinkToken.at("0xa36085F69e2889c224210F603D836748e7dC0088");
    ocean = await OceanRequester.at("0x04E4b02EA2662F5BF0189912e6092d317d6388F3");
  });

  describe("query the initial token balance", () => {
    it("create a request and send to Chainlink", async () => {
      let tx = await ocean.createRequest(jobId, url, path, times);
      request = h.decodeRunRequest(tx.receipt.rawLogs[3]);
      ...
      data = await ocean.getRequestResult(request.id)
      console.log("Request is fulfilled. data := " + data)
       ...
     });
   });
});

上面的代码中,关键参数已经加粗显式。任务ID“2c6578f488c843588954be403aba2deb”标识了用于从URL提取JSON数据、拷贝指定字段值并转换化为SOlidity支持的uint256类型的Chainlink适配器。

例如,返回的JSON格式数据看起来像这样:

{USD":142.33,"EUR":126.69,"JPY":15765.39}

path参数设置为USD表示该字段的值需要提供给请求器合约。

我们可以运行该脚本像Chainlinkg网络提交请求并从指定的URL提取数据。Chainlinkg节点大概需要2秒钟来执行该请求,其中包含区块确认的时间。

Chainlink区块链Oracle网络使用指南

3、使用自定义的Chainlink适配器

前面的部分看起来干净简洁。但是,Chainlink内置的适配器很有限,不能满足各种区块链应用的要求。因此,需要为不同的应用场景创建定制的适配器。

在这一部分,我们学习如何开发自己的适配器,并学习如何将其嵌入Chainlink体系中。可以在这里找到一些外部适配器的参考实现,或者查看这里的指南

下图展示了包含外部适配器的Chainlink网络架构:

Chainlink区块链Oracle网络使用指南

区块链开发者需要完成以下工作:

  • 将预言机合约部署到区块链网络
  • 开发定制适配器并部署到AWS lambda或GCP functions,提供用于交互的URL端结点
  • 运行一个新的CHainlink节点并在该节点的配置中注册定制的适配器的URL端结点
  • 在Chainlink节点中为该任务创建一个任务描述,以便其监听预言机合约并触发正确 的工作流水线
  • 在链上预言机合约中注册新的CHainlink节点
  • 创建一个新的请求器合约来提交请求

下面我们逐步来实现。

3.1 在Kovan测试链部署预言机合约

在我们的概念验证系统中,需要一个预言机合约与Chainlinkg节点交互。为此,我们在Kovan测试链上部署这个合约:https://github.com/oceanprotocol/Nautilus/blob/master/4-chainlink。

3_oracle_migration.js
=====================

   Deploying 'Oracle'
   ------------------
   > transaction hash:    0xd281b18c4be0be9b2bdbfed4bae090aab5c86027564f048785b1f971cf0b6f2c
   > Blocks: 0            Seconds: 8
   > contract address:    0x698EFB00F79E858724633e297d5188705512e506
   > account:             0x0E364EB0Ad6EB5a4fC30FC3D2C2aE8EBe75F245c
   > balance:             2.262907885853937168
   > gas used:            1311430
   > gas price:           10 gwei
   > value sent:          0 ETH
   > total cost:          0.0131143 ETH

   > Saving artifacts
   -------------------------------------
   > Total cost:           0.0131143 ETH

3.2 创建一个新的外部适配器

在这个概念验证系统中,我们使用一个由OracleFinder开发的外部适配器CryptoCompareExternalAdapter。对应更一般性的应用,Thomas Hodges创建了一个用NodeJS开发的外部适配器模板:https://github.com/thodges-gh/CL-EA-NodeJS-Template

$ git clone https://github.com/OracleFinder/CryptoCompareExternalAdapter.git
$ cd CryptoCompareExternalAdapter/
$ npm install
$ zip -r chainlink-cloud-adapter.zip .

压缩文件chainlink-cloud-adapter.zip创建后就可以部署了。作为示例,我们将这个外部适配器部署到Google Cloud Functions。在登录之后,参考下图创建一个新的函数并上传chainlink-cloud-adapter.zip:

Chainlink区块链Oracle网络使用指南

为这个外部适配器生成的URL访问端结点需要提供给chainlink节点:

https://us-central1-macro-mercury-234919.cloudfunctions.net/coinmarketcap-adapter

现在使用Google Cloud Functions的控制台,我们可以测试适配器以确保它可以正常运行:

Chainlink区块链Oracle网络使用指南

现在,外部适配器已经在Google Cloud平台运行起来,它等待执行来自Chainlink节点的请求。

3.3 在新的chainlink节点中注册适配器url

我们需要运行一个新的chainlink节点,以便可以访问外部适配器,步骤如下:

  1. 安装Parity并接入Kovan网络:

    $ docker pull parity/parity:stable $ mkdir ~/.parity-kovan $ docker run -h eth --name eth -p 8546:8546
    -v ~/.parity-kovan:/home/parity/.local/share/io.parity.ethereum/
    -it parity/parity:stable --chain=kovan
    --ws-interface=all --ws-origins="all" --light
    --base-path /home/parity/.local/share/io.parity.ethereum/

  2. 创建Chainlink节点的管理账号

    $ docker pull smartcontract/chainlink:latest $ mkdir -p ~/.chainlink-kovan/tls $ openssl req -x509 -out ~/.chainlink-kovan/tls/server.crt -keyout ~/.chainlink-kovan/tls/server.key
    -newkey rsa:2048 -nodes -sha256
    -subj '/CN=localhost' -extensions EXT -config <(
    printf "[dn]\nCN=localhost\n[req]\ndistinguished_name = dn\n[EXT]\nsubjectAltName=DNS:localhost\nkeyUsage=digitalSignature\nextendedKeyUsage=serverAuth")

  3. 创建Chainlink节点的配置信息

    echo "ROOT=/chainlink LOG_LEVEL=debug ETH_URL=ws://eth:8546 ETH_CHAIN_ID=42 MIN_OUTGOING_CONFIRMATIONS=2 MIN_INCOMING_CONFIRMATIONS=0 LINK_CONTRACT_ADDRESS=0xa36085F69e2889c224210F603D836748e7dC0088 TLS_CERT_PATH=/chainlink/tls/server.crt TLS_KEY_PATH=/chainlink/tls/server.key ALLOW_ORIGINS=*" > .env

  4. 运行chainlink节点

    $ docker run --link eth -p 6689:6689 -v ~/.chainlink-kovan:/chainlink -it --env-file=.env smartcontract/chainlink n

访问https://localhost:6689 打开Chainlink节点的GUI配置界面,使用前面创建的管理账号登入,仪表盘看起来像这样:

Chainlink区块链Oracle网络使用指南

  1. 在chainlink节点中注册外部适配器

在Bridges选项卡,我们需要创建一个新的桥接器并填写桥接url:

Chainlink区块链Oracle网络使用指南

结果看起来是这样:

Chainlink区块链Oracle网络使用指南

3.4 为外部适配器创建任务描述

在chainlink节点上,很重要的一个步骤是创建一个新的任务描述,参考这里

有了任务描述,Chainlink节点可以监听来自预言机合约的事件消息并触发在任务描述中定义的流水线。我们的任务描述看起来是这样:

{
  "initiators": [
    {
      "type": "RunLog",
      "params": { "address": "0x698efb00f79e858724633e297d5188705512e506" }
    }
  ],
  "tasks": [
    {
      "type": "coinmarketcap",
      "confirmations": 0,
      "params": {}
    },
    {
      "type": "Copy",
      "params": {}
    },
    {
      "type": "Multiply",
      "params": { "times": 100 }
    },
    { "type": "EthUint256" },
    { "type": "EthTx" }
  ]
}

initiators用来设置触发chainlink节点的合约地址,tasks定义了该任务的作业流水线。

3.5 在预言机合约中注册Chainlink节点

新的Chainlink节点必须要在之前部署的预言机合约中注册,这样它才能接受请求并执行任务。

可以在Chainlink节点的配置页面找到新的chainlink节点的账户地址:

Chainlink区块链Oracle网络使用指南

我们使用一个JavaScript文件来注册该Chainlink节点:

const Web3 = require('web3')

const web3 = new Web3(new Web3.providers.HttpProvider('https://kovan.infura.io/'))


const h = require("chainlink-test-helpers");
const scale = 1e18;

contract("Oracle", (accounts) => {
  const Oracle = artifacts.require("Oracle.sol");
  const chainlinkNode ='0x79B80f3b6B06FD5516146af22E10df26dfDc5455';
  let oracle;

  beforeEach(async () => {
    oracle = await Oracle.at("0x698EFB00F79E858724633e297d5188705512e506");
  });

  describe("should register chainlink node", () => {

    it("register chainlink node", async () => {
      await oracle.setFulfillmentPermission(chainlinkNode, true)
      let status = await oracle.getAuthorizationStatus(chainlinkNode)
      console.log("Chainlink node's status is := " + status)
    });
  });
});

使用truffle运行上述脚本:

$ truffle test test/Oracle.Test.js --network kovan
Using network 'kovan'   Contract: Oracle
       should register chainlink node
Chainlink node's status is := true

状态为true表示chainlink节点已经注册成功,并被授予执行任务的权限。

3.6 创建请求器合约以提交请求

为了向外部适配器提交请求,我们创建一个请求器合约contracts/requestGCP.sol来测试整个工作流。

function createRequest(
    bytes32 _jobId,
    string _coin,
    string _market
  )
    public
    onlyOwner
    returns (bytes32 requestId)
  {
    // create request instance
    Chainlink.Request memory req = newRequest(_jobId, this, this.fulfill.selector);
    // fill in the pass-in parameters
    req.add("endpoint", "price");
    req.add("fsym", _coin);
    req.add("tsyms", _market);
    req.add("copyPath", _market);
    // send request & payment to Chainlink oracle (Requester Contract sends the payment)
    requestId = chainlinkRequestTo(getOracle(), req, ORACLE_PAYMENT);
    // emit event message
    emit requestCreated(msg.sender, _jobId, requestId);
  }

同样部署到Kovan测试链:

4_requestGCP_migration.js
=========================

   Replacing 'requestGCP'
   ----------------------
   > transaction hash:    0x978974b43d843606c42ce15c87fcc560a5c625497bf074f5ec0f337347438fdf
   > Blocks: 0            Seconds: 16
   > contract address:    0x6f73E784253aD72F0BA4164101860992dFC17Fe1
   > account:             0x0E364EB0Ad6EB5a4fC30FC3D2C2aE8EBe75F245c
   > balance:             2.248942845853937168
   > gas used:            1396504
   > gas price:           10 gwei
   > value sent:          0 ETH
   > total cost:          0.01396504 ETH

   > Saving artifacts
   -------------------------------------
   > Total cost:          0.01396504 ETH

利用faucet充值一些link代币:https://kovan.chain.link/

现在,我们可以请求外部适配器来访问链下数据。可以使用如下脚本:

const Web3 = require('web3')

const web3 = new Web3(new Web3.providers.WebsocketProvider('ws://eth:8546'))

const h = require("chainlink-test-helpers");
const scale = 1e18;

contract("requestGCP", (accounts) => {
  const LinkToken = artifacts.require("LinkToken.sol");
  const RequestGCP = artifacts.require("requestGCP.sol");
  const jobId = web3.utils.toHex("80c7e6908e714bf4a73170c287b9a18c");
  const coin = "ETH"
  const market = "USD";
  const defaultAccount =0x0e364eb0ad6eb5a4fc30fc3d2c2ae8ebe75f245c;
  let link, ocean;

  beforeEach(async () => {
    link = await LinkToken.at("0xa36085F69e2889c224210F603D836748e7dC0088");
    ocean = await RequestGCP.at("0x6f73E784253aD72F0BA4164101860992dFC17Fe1");
  });

  describe("should request data and receive callback", () => {
    let request;    ...
    it("create a request and send to Chainlink", async () => {
      let tx = await ocean.createRequest(jobId, coin, market);
      request = h.decodeRunRequest(tx.receipt.rawLogs[3]);
      console.log("request has been sent. request id :=" + request.id)

      let data = 0
      let timer = 0
      while(data == 0){
        data = await ocean.getRequestResult(request.id)
        if(data != 0) {
          console.log("Request is fulfilled. data := " + data)
        }
        wait(1000)
        timer = timer + 1
        console.log("waiting for " + timer + " second")
      }

    });
  });
});

用truffle运行该脚本:

$ truffle test test/requestGCP.Test.js --network kovan

运行了大约10秒钟,外部适配器完成该任务:

Chainlink区块链Oracle网络使用指南

可以在chainlink节点的交易历史中找到该交易:

Chainlink区块链Oracle网络使用指南

也可以在Google cloud functions的仪表盘中找到该交易:

Chainlink区块链Oracle网络使用指南

4、结语

Chainlink是一个重要的桥接区块链与现实世界的去中心化预言机网络。许多区块链应用可能都需要通过chainlink网络来访问现实世界中的数据流。


原文链接:Chainlink去中心化预言机网络搭建与定制教程 — 汇智网

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
可莉 可莉
3年前
10个开源的Python区块链项目
Python不是主流的区块链底层平台开发语言,但是在DApp开发、区块链仿真与数据分析、智能合约安全分析等领域,Python依然是不错的选择。本文介绍了10个最流行的Python区块链项并提供了相应的源代码下载地址。<!more区块链开发教程链接:以太坊(https://www.oschina.net/action/GoToLink
Stella981 Stella981
3年前
Defi数据引擎The Graph调用方法【含源码】
当你尝试访问以太坊智能合约以及DApp产生的区块链数据时,可能会发现很难将数据转换为一种可读的格式。TheGraph提供了一种用于查询以太坊和IPFS网络数据的索引协议,任何人都可以基于其提供的开放API创建并发布索引数据,即subgraph,这使得区块链数据更容易访问。在这个教程中,我们将学习如何使用TheGraph来查询Aave协议数据,使用的技术
Stella981 Stella981
3年前
Chainlink指南【77个应用场景】
Chainlink提供了构建去中心化预言机网络所需的必要开发人员工具,对外部数据的访问为智能合约开启了全新的功能浪潮。本文汇总了77种使用Chainlink预言机网络的方法与实际应用场景,涵盖去中心化金融、外部支付、游戏、保险、企业系统、供应链、工具、身份授权、政府等诸多领域,相信有助于加深学习者对预言机潜力的理解并激发探索的兴趣。用自己熟悉的语言学
Wesley13 Wesley13
3年前
NEO从源码分析看UTXO交易
_0x00前言_社区大佬:“交易是操作区块链的唯一方式。”_0x01交易类型_在NEO中,几乎除了共识之外的所有的对区块链的操作都是一种“交易”,甚至在“交易”面前,合约都只是一个小弟。交易类型的定义在Core中的TransactionType中:源码位置:neo/Core/TransactionType
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这