0Pricing
Blockchain Smart Contracts with Solidity · 课时

处理链下数据获取

通过 Chainlink 实施从外部 API 请求和接收数据的模式,同时确保数据完整性。

处理链下数据获取 是 CoddyKit 上的免费 Blockchain Smart Contracts with Solidity 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Blockchain Smart Contracts with Solidity 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Blockchain Smart Contracts with Solidity 课程共包含 4 节课。

本课时的部分内容尚未翻译,以英文显示。

Bridging On-chain & Off-chain

Smart contracts live on the blockchain, isolated from the outside world. But what if your contract needs real-time data, like a cryptocurrency price or a weather report?

This is where oracles come in. In this lesson, we'll learn how to implement patterns for requesting and receiving external data from APIs using Chainlink, ensuring the data is secure and reliable.

The Oracle Request-Response Model

Chainlink acts as a bridge, allowing your smart contract to securely interact with off-chain (external) data sources. It works using a request-response cycle:

  • Your smart contract sends a request to a Chainlink oracle network.
  • A Chainlink node fetches the data from the specified API.
  • The Chainlink node then sends a response back to your contract by calling a specific 'callback' function.

Your Contract: A Chainlink Client

To interact with Chainlink, your Solidity contract needs to inherit from the ChainlinkClient contract provided by Chainlink.

This base contract gives you access to essential functions for building and sending data requests, as well as security features for receiving responses.

Initiating a Data Request

To ask for data, you'll use functions like buildChainlinkRequest and sendChainlinkRequestTo.

  • buildChainlinkRequest: Prepares the request, specifying details like the Chainlink job ID, your contract's address, and the callback function the oracle should call.
  • sendChainlinkRequestTo: Sends the prepared request to the Chainlink oracle, along with the LINK token fee.

Code: Requesting Live Price Data

Here's a simplified contract showing how to initiate a Chainlink request for external data, like a cryptocurrency price. This contract would be deployed to a test network.

The requestEthPrice function builds the request, specifies the API to call, and sends it to the oracle.

/*
  This is a simplified example for explanation.
  For a real deployment, replace placeholders like
  oracle address, LINK address, jobId, and fee
  with values for your chosen Chainlink network.
*/
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;

import "@chainlink/contracts/src/v0.8/ChainlinkClient.sol";

contract PriceConsumer is ChainlinkClient {
    bytes32 public lastRequestId; // Stores the ID of our last request
    uint256 public currentPrice; // Where we'll store the fetched price

    address private immutable i_oracle; // Chainlink oracle address
    bytes32 private immutable i_jobId;  // Specific job ID for the data source
    uint256 private immutable i_fee;    // Amount of LINK to pay for the request

    constructor(address _oracle, address _link, bytes32 _jobId, uint256 _fee) {
        setChainlinkToken(_link); // Set the LINK token address
        i_oracle = _oracle;
        i_jobId = _jobId;
        i_fee = _fee;
    }

    // Function to request a price from a Chainlink oracle
    function requestEthPrice() public returns (bytes32) {
        // 1. Build the Chainlink request
        Chainlink.Request memory request = buildChainlinkRequest(
            i_jobId,                      // The job ID for the oracle
            address(this),                // Our contract's address
            this.fulfillEthPrice.selector // The function the oracle will call back
        );

        // 2. Add parameters for the Chainlink node (e.g., API URL, path to data)
        request.add("get", "https://min-api.cryptocompare.com/data/price?fsym=ETH&tsyms=USD");
        request.add("path", "USD"); // Extract the USD value from the JSON response
        request.addInt("times", 100000000); // Multiply by 10^8 for fixed-point math

        // 3. Send the request to the oracle
        lastRequestId = sendChainlinkRequestTo(i_oracle, request, i_fee);
        return lastRequestId;
    }

    // The fulfillEthPrice function will be defined later!
}

Tracking Requests with IDs

When you call sendChainlinkRequestTo, it returns a unique identifier: a bytes32 value called the requestId.

  • This ID acts like a tracking number for your data request.
  • It's essential because multiple requests might be pending, and the requestId ensures that when the data comes back, your contract knows which request it belongs to.

Always store this requestId in a state variable!

Fulfilling the Data Request

Once the Chainlink node successfully fetches the data, it calls the callback function you specified (e.g., fulfillEthPrice) in your contract.

This function's purpose is to:

  • Receive the requestId (to match it with the original request).
  • Receive the actual data fetched by the oracle (e.g., uint256 _price).
  • Process and store the data within your contract's state.

Code: Implementing the Callback

Let's complete our PriceConsumer contract by adding the fulfillEthPrice function. This is the function that the Chainlink oracle will call back to with the fetched price.

The recordChainlinkFulfillment modifier and the requestId check are crucial for security and data integrity.

/*
  This is a simplified example for explanation.
  For a real deployment, replace placeholders like
  oracle address, LINK address, jobId, and fee
  with values for your chosen Chainlink network.
*/
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;

import "@chainlink/contracts/src/v0.8/ChainlinkClient.sol";

contract PriceConsumer is ChainlinkClient {
    bytes32 public lastRequestId; // Stores the ID of our last request
    uint256 public currentPrice; // Where we'll store the fetched price

    address private immutable i_oracle; // Chainlink oracle address
    bytes32 private immutable i_jobId;  // Specific job ID for the data source
    uint256 private immutable i_fee;    // Amount of LINK to pay for the request

    constructor(address _oracle, address _link, bytes32 _jobId, uint256 _fee) {
        setChainlinkToken(_link); // Set the LINK token address
        i_oracle = _oracle;
        i_jobId = _jobId;
        i_fee = _fee;
    }

    // Function to request a price from a Chainlink oracle
    function requestEthPrice() public returns (bytes32) {
        Chainlink.Request memory request = buildChainlinkRequest(
            i_jobId,
            address(this),
            this.fulfillEthPrice.selector // Callback function
        );
        request.add("get", "https://min-api.cryptocompare.com/data/price?fsym=ETH&tsyms=USD");
        request.add("path", "USD");
        request.addInt("times", 100000000); // Multiply by 10^8
        lastRequestId = sendChainlinkRequestTo(i_oracle, request, i_fee);
        return lastRequestId;
    }

    // This is the callback function called by the Chainlink oracle
    function fulfillEthPrice(bytes32 _requestId, uint256 _price)
        public
        recordChainlinkFulfillment(_requestId) // Security modifier
    {
        // Crucial: Check if the requestId matches our last sent request
        require(lastRequestId == _requestId, "Request ID mismatch!");
        currentPrice = _price; // Store the fetched price
    }
}

Enhancing Data Integrity

Ensuring the integrity of off-chain data is paramount. Chainlink employs several mechanisms, and you should use them:

  • recordChainlinkFulfillment(_requestId): This modifier (from ChainlinkClient) verifies that the caller is the authorized Chainlink oracle for that specific requestId.
  • requestId Matching: Always include a require(lastRequestId == _requestId, ...) check in your callback. This prevents accidental or malicious fulfillment of an old or unrelated request.
  • Error Handling: Consider what happens if the oracle fails or returns invalid data. Implement checks and revert if necessary.

Quick Check: Oracle Flow

You've learned about requesting and receiving data from Chainlink oracles.

Consider the following steps involved in a Chainlink request-response cycle:

Recap: Off-chain Data Retrieval

In this lesson, we explored how to enable your smart contracts to interact with external data using Chainlink oracles.

  • We learned about the request-response model, where your contract requests data and an oracle node delivers it.
  • You saw how to use the ChainlinkClient base contract to build and send requests.
  • We implemented a callback function (e.g., fulfillEthPrice) to receive the data.
  • Finally, we discussed the importance of requestId matching and the recordChainlinkFulfillment modifier for data integrity and security.

You can now build contracts that react to real-world events!

常见问题解答

「处理链下数据获取」课时是免费的吗?

是的 — 「处理链下数据获取」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Blockchain Smart Contracts with Solidity 课程的其余内容,请升级到 CoddyKit PRO。 Blockchain Smart Contracts with Solidity 课程共包含 4 节课。

「处理链下数据获取」这节课中我会学到什么?

通过 Chainlink 实施从外部 API 请求和接收数据的模式,同时确保数据完整性。 你通过在浏览器中直接运行的动手代码来练习 Blockchain Smart Contracts with Solidity,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Blockchain Smart Contracts with Solidity 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Blockchain Smart Contracts with Solidity 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。

「处理链下数据获取」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Blockchain Smart Contracts with Solidity 课中编写并运行代码吗?

能。每节 Blockchain Smart Contracts with Solidity 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 预言机问题解析
  2. 集成 Chainlink 预言机
  3. 处理链下数据获取
  4. 构建自定义预言机合约
← 返回 Blockchain Smart Contracts with Solidity