自我学习ChainLink 1 记录

本文为学习,整理其他大佬们的资料。重新整理出方便自己学习,理解的顺序。加深我对ChianLink 的基础概念了解。 如果有整理,总结出错误的地方,希望各位大大能告诉我,谢谢!

学习来源:

  1. ChainLinkDevelopers
    https://docs.chain.link/docs/available-oracles
  2. Chainlink预言机基本原理(一)
    https://blog.csdn.net/ChainlinkO/article/details/103671006.
  3. Chainlink预言机基本原理(二)
    https://blog.csdn.net/ChainlinkO/article/details/103723133?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.nonecase.
  4. Chainlink预言机基本原理(三)
    https://blog.csdn.net/ChainlinkO/article/details/103784697.

总体概念

每一个合约系统,都会有事件记录的功能,比如以太坊中的EventLog功能。利用事件记录的功能,oracle可以从外界获取数据,从而达到将外界数据传递到smart contract。
在这里插入图片描述

数据获取例子

  1. smartcontract将需要获取天气温度的的城市写入到EventLog中
  2. 链下我们会启动一个进程,监听并订阅这个事件日志
  3. 获取到smartcontract的请求之后,将指定城市的温度,通过提交transaction的方式,调用合约中的回填方法,提交到智能合约中

smartcontract部分:在这里插入图片描述

流程讲解例子

在这里插入图片描述

Step 1

目标:
* @notice 向指定的oracle地址创建一个请求
* @dev 创建并存储一个请求ID, 增加本地的nonce值, 并使用transferAndCall 方法发送LINK,
* 创建到目标oracle合约地址的请求
* 发出 ChainlinkRequested 事件.

参数解释:
* @param _oracle 发送请求至的oracle地址
* @param _req 完成初始化的Chainlink请求
* @param _payment 请求发送的LINK数量
* @return 请求 ID

代码

function requestEthereumPrice(address _oracle, string_jobId)
        public
        onlyOwner
      {
        Chainlink.Request memory req = buildChainlinkRequest(stringToBytes32(_jobId), this, this.fulfillEthereumPrice.selector);
        req.add("get", "https://min-api.cryptocompare.com/data/price?fsym=ETH&tsyms=USD");
        req.add("path", "USD");
        req.addInt("times", 100);
        sendChainlinkRequestTo(_oracle, req, ORACLE_PAYMENT);
      }

Step 2

目标:
* @dev 将token和额外数据一起转移给一个合约地址

参数解释:
* @param _to 转移到的目的地址
* @param _value 转移数量
* @param _data 传递给接收合约的额外数据

方法说明:
1. transferAndCall 方法将之前打包好的请求数据放在了data字段,跟随转账一起发送到了oracle合约
link.transferAndCall方法即是ERC677定义的token转账方法,与ERC20的transfer方法相比,它多了一个data字段,可以在转账的同时携带数据
2. Transfer(msg.sender, _to, _value, _data);是发出一个事件日志
event Transfer(address indexed from, address indexed to, uint value, bytes data);将这次转账的详细信息(发送方、接收方、金额、数据)记录到日志中

代码:

 function transferAndCall(address _to, uint _value, bytes_data)
        public
        returns (bool success)
      {
        super.transfer(_to, _value);
        Transfer(msg.sender, _to, _value, _data);
        if (isContract(_to)) {
          contractFallback(_to, _value, _data);
        }
        return true;
      }

Oracle合约在收到转账之后,会触发onTokenTransfer方法,该方法会检查转账的有效性,并通过发出OracleRequest事件记录更为详细的数据信息

代码:

event OracleRequest(
        bytes32 indexed specId,
        address requester,
        bytes32 requestId,
        uint256 payment,
        address callbackAddr,
        bytes4 callbackFunctionId,
        uint256 cancelExpiration,
        uint256 dataVersion,
        bytes data
      );

Step 3

这个日志会在oracle合约的日志中找到,链下的节点会订阅该主题的日志,在获取到记录的日志信息之后,节点会解析出请求的具体信息,通过网络的API调用,获取到请求的结果


Step 4

通过提交事务的方式,调用Oracle合约中的fulfillOracleRequest方法,将数据提交到链上

目标:
* @notice 由Chainlink节点调用来完成请求
* @dev 提交的参数必须是oracleRequest方法所记录的哈希参数
* 将会调用回调地址的回调函数,require检查时不会报错,以便节点可以获得报酬

参数解释:
* @param _requestId 请求ID必须与请求者所匹配
* @param _payment 为Oracle发放付款金额 (以wei为单位)
* @param _callbackAddress 完成方法的回调地址
* @param _callbackFunctionId 完成方法的回调函数
* @param _expiration 请求者可以取消之前节点应响应的到期时间
* @param _data 返回给消费者合约的数据
* @return 外部调用成功的状态值

代码:

function fulfillOracleRequest(
        bytes32 _requestId,
        uint256 _payment,
        address _callbackAddress,
        bytes4 _callbackFunctionId,
        uint256 _expiration,
        bytes32 _data
      )
        external
        onlyAuthorizedNode
        isValidRequest(_requestId)
        returns (bool)
      {
        bytes32 paramsHash = keccak256(
          abi.encodePacked(
            _payment,
            _callbackAddress,
            _callbackFunctionId,
            _expiration
          )
        );
        
        require(commitments[_requestId] == paramsHash, "Params do not match request ID");
        withdrawableTokens = withdrawableTokens.add(_payment);
        delete commitments[_requestId];
        require(gasleft() >= MINIMUM_CONSUMER_GAS_LIMIT, "Must provide consumer enough gas");
        
        return _callbackAddress.call(_callbackFunctionId, _requestId, _data); // solhint-disable-line avoid-low-level-calls
      }

Step 4

进行一系列的检验之后,会将结果通过之前记录的回调地址与回调函数,返回给消费者合约

_callbackAddress.call(_callbackFunctionId, _requestId, _data);

这样一次请求就全部完成了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值