Chainlink 是一个去中心化的预言机网络,它可以让区块链中的智能合约安全地 访问外部世界的数据。在这个文章中,我们将探索 chainlink 预言机网络的搭建,并学习如何使用预置或自定义的适配器实现智能合约与外部世界数据的桥接。 智能合约被锁定在区块链里,与外部世界隔离开来。然而在许多应用中,智能合约的运行需要依赖于外部真实世界的信息。 以 Ocean 协议为例:只有当提供的数据被证明是可以使用时,数据提供商才可以得到代币奖励。因此一个可以桥接区块链和现实世界的预言机(Oracle)网络 就非常必要了。 Chainlink 是一个去中心化的 Oracle 网络,它可以让区块链中的智能合约安全地访问外部世界的数据: 在这个教程中,我们将探索 chainlink 网络的搭建以及其适配器的使用方法,我们 在 Kovan 测试链搭建了一个用于概念验证的演示环境,所有的代码可以从?这里[1]下载。我们使用 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 值得指出的是,每个来自请求器合约的请求都必须包含一个任务 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:特定作业流水线的唯一标识符。可以在这里查看内置适配器的完整清单:https://docs.chain.link/docs/addresses-and-job-specs ? URL:可以返回 JSON 数据的 Web API 的访问端结点 ? path:JSON 数据字段选择路径,用来声明使用数据中的哪一部分 ? times:数据倍乘系数。该操作将浮点数转换为整数,因为 solidity 智能合约仅接受整数 2.3 在 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.4 向请求器合约存入 LINK 代币 Chainlink 官方提供了一些代币 faucet。在 Kovan 测试链上可以访问 https://kovan.chain.link/ 获取一些测试用的 LINK 代币。 只需要输入合约地址或钱包地址,Chainlink 的 faucet 就会转 100 个 LINK 代币进去: 2.5 从合约请求数据 我们创建了一个 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 秒钟来执行该请求,其中包含区块确认的时间。 3、使用自定义的 Chainlink 适配器 前面的部分看起来干净简洁。但是,Chainlink 内置的适配器很有限,不能 满足各种区块链应用的要求。因此,需要为不同的应用场景创建定制的适配器。 在这一部分,我们学习如何开发自己的适配器,并学习如何将其嵌入 Chainlink 体系中。可以在这里[2]找到一些外部适配器 的参考实现,或者查看这里的指南[3]。 下图展示了包含外部适配器的 Chainlink 网络架构: 区块链开发者需要完成以下工作: ? 将预言机合约部署到区块链网络 ? 开发定制适配器并部署到 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: 为这个外部适配器生成的 URL 访问端结点需要提供给 chainlink 节点: https://us-central1-macro-mercury-234919.cloudfunctions.net/coinmarketcap-adapter 现在使用 Google Cloud Functions 的控制台,我们可以测试适配器以确保它可以 正常运行: 现在,外部适配器已经在 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/ 1.创建 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") 1.创建 Chainlink 节点的配置信息 echo?"ROOT=/chainlinkLOG_LEVEL=debugETH_URL=ws://eth:8546?ETH_CHAIN_ID=42MIN_OUTGOING_CONFIRMATIONS=2MIN_INCOMING_CONFIRMATIONS=0LINK_CONTRACT_ADDRESS=0xa36085F69e2889c224210F603D836748e7dC0088TLS_CERT_PATH=/chainlink/tls/server.crtTLS_KEY_PATH=/chainlink/tls/server.keyALLOW_ORIGINS=*"?>?.env 1.运行 chainlink 节点 $?docker?run?--link?eth?-p?6689:6689?-v?~/.chainlink-kovan:/chainlink?-it?--env-file=.env?smartcontract/chainlink?n 访问 https://localhost:6689 打开 Chainlink 节点的 GUI 配置界面,使用 前面创建的管理账号登入,仪表盘看起来像这样: 1.在 chainlink 节点中注册外部适配器 在 Bridges 选项卡,我们需要创建一个新的桥接器并填写桥接 url: 结果看起来是这样: 3.4 为外部适配器创建任务描述 在 chainlink 节点上,很重要的一个步骤是创建一个新的任务描述,参考:https://docs.chain.link/docs/job-specifications 有了任务描述,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 节点的账户地址: 我们使用一个 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?kovanUsing?network?'kovan'???Contract:?Oracle???????should?register?chainlink?nodeChainlink?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 节点的交易历史中找到该交易: 也可以在 Google cloud functions 的仪表盘中找到该交易: 4、结语 Chainlink 是一个重要的桥接区块链与现实世界的去中心化预言机网络。许多 区块链应用可能都需要通过 chainlink 网络来访问现实世界中的数据流。 原文链接:Bridging Blockchain to the Real World using Chainlink[4] References [1]?这里:?https://github.com/oceanprotocol/Nautilus/tree/master/4-chainlink —- 编译者/作者:深入浅出区块链技 玩币族申明:玩币族作为开放的资讯翻译/分享平台,所提供的所有资讯仅代表作者个人观点,与玩币族平台立场无关,且不构成任何投资理财建议。文章版权归原作者所有。 |
Chainlink去中心化预言机桥接区块链与现实世界
2020-02-07 深入浅出区块链技 来源:区块链网络
LOADING...
相关阅读:
- DeFi平台Opyn智能合约漏洞详解:攻击者空手套白狼!2020-08-06
- 苏哲社区:8.6比特币午间行情分析btc又将冲击12000大关?2020-08-06
- 文轩论币:8.6比特币行情分析比特币多头情绪浓烈,日内能否突破12000?2020-08-06
- 美国国会议员希望国税局在加密货币领域平衡税收和创新2020-08-06
- 火币朱嘉伟:DeFi和CeFi的目标一致但二者的实现路径不同2020-08-06