乐闻世界logo
搜索文章和话题

What are Ethereum Oracles? Please explain Chainlink and oracle attack protection

2月21日 14:13

Ethereum oracles are important bridges connecting blockchain with the outside world. Here's a comprehensive analysis of oracles:

Basic Concepts of Oracles

Blockchain is a closed system that cannot directly access external data. Oracles act as an intermediate layer, securely transmitting external data (such as prices, weather, sports results, etc.) to the blockchain.

Oracle Types

1. Centralized Oracles

Data services provided by a single entity.

Features:

  • Simple and easy to use
  • Fast response
  • Single point of failure risk

Representative Projects:

  • Provable: Formerly Oraclize

2. Decentralized Oracles

Data provided by multiple nodes together, ensuring data accuracy through consensus mechanisms.

Features:

  • Decentralized
  • Censorship-resistant
  • More reliable data

Representative Projects:

  • Chainlink: Decentralized oracle network
  • Band Protocol: Cross-chain oracle

3. First-Party Oracles

Data providers directly publish data to blockchain.

Features:

  • Direct data source
  • High credibility
  • Requires technical capability from data providers

Examples:

  • UMA: Optimistic oracle
  • Tellor: Decentralized oracle

1. Basic Usage

solidity
// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol"; contract PriceConsumer { AggregatorV3Interface internal priceFeed; constructor() { // ETH/USD price feed address (Ethereum mainnet) priceFeed = AggregatorV3Interface(0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419); } function getLatestPrice() public view returns (int) { ( uint80 roundID, int price, uint startedAt, uint timeStamp, uint80 answeredInRound ) = priceFeed.latestRoundData(); require(timeStamp > 0, "No data available"); return price; } function getPriceInUSD(uint256 ethAmount) public view returns (uint256) { int256 price = getLatestPrice(); require(price > 0, "Invalid price"); // Chainlink price has 8 decimal places return (uint256(price) * ethAmount) / 1e8; } }

2. Request-Response Pattern

solidity
import "@chainlink/contracts/src/v0.8/ChainlinkClient.sol"; contract APIConsumer is ChainlinkClient { using Chainlink for Chainlink.Request; uint256 public volume; bytes32 public jobId; uint256 public fee; event RequestVolume(bytes32 indexed requestId, uint256 volume); constructor() { setChainlinkToken(0x514910771AF9Ca656af840dff83E8264EcF986CA); // LINK token address setChainlinkOracle(0x2f90A640D781587C2fA963d6184B9e9c5f3840B4); // Oracle address jobId = "7da2702f37fd48e5b1b9a5715e3509b6"; fee = 0.1 * 10**18; // 0.1 LINK } 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"); req.addInt("times", 100); return sendChainlinkRequestTo(req, fee); } function fulfill(bytes32 _requestId, uint256 _volume) public recordChainlinkFulfillment(_requestId) { volume = _volume; emit RequestVolume(_requestId, _volume); } }

Oracle Attacks and Protection

1. Flash Loan Attack

solidity
contract FlashLoanAttack { IERC20 public token; AggregatorV3Interface public priceFeed; function attack(uint256 borrowAmount) external { // Borrow token.transferFrom(msg.sender, address(this), borrowAmount); // Manipulate price manipulatePrice(); // Exploit with wrong price exploit(); // Repay token.transfer(msg.sender, borrowAmount); } function manipulatePrice() internal { // Manipulate price through large transactions // ... } function exploit() internal { // Exploit manipulated price // ... } }

2. Oracle Protection

solidity
contract OracleProtection { AggregatorV3Interface public priceFeed; uint256 public maxPriceDeviation = 5; // 5% max deviation uint256 public lastPrice; uint256 public lastUpdateTime; uint256 public maxPriceAge = 1 hours; event PriceUpdated(uint256 newPrice, uint256 oldPrice); function getSafePrice() public returns (uint256) { (, int256 price, , uint256 timestamp, ) = priceFeed.latestRoundData(); require(price > 0, "Invalid price"); require(timestamp > block.timestamp - maxPriceAge, "Price too old"); uint256 newPrice = uint256(price); if (lastPrice > 0) { uint256 deviation = (newPrice > lastPrice) ? ((newPrice - lastPrice) * 100 / lastPrice) : ((lastPrice - newPrice) * 100 / lastPrice); require(deviation <= maxPriceDeviation, "Price deviation too high"); } lastPrice = newPrice; lastUpdateTime = timestamp; emit PriceUpdated(newPrice, lastPrice); return newPrice; } }

Custom Oracles

1. Simple Oracle

solidity
contract SimpleOracle { address public owner; mapping(bytes32 => int256) public data; mapping(bytes32 => bool) public requested; event DataRequested(bytes32 indexed requestId, bytes32 key); event DataProvided(bytes32 indexed requestId, bytes32 key, int256 value); modifier onlyOwner() { require(msg.sender == owner, "Not owner"); _; } constructor() { owner = msg.sender; } function requestData(bytes32 key) public { bytes32 requestId = keccak256(abi.encodePacked(key, block.timestamp)); requested[requestId] = true; emit DataRequested(requestId, key); } function provideData(bytes32 requestId, bytes32 key, int256 value) public onlyOwner { require(requested[requestId], "Not requested"); data[key] = value; emit DataProvided(requestId, key, value); } function getData(bytes32 key) public view returns (int256) { return data[key]; } }

2. Multi-Source Oracle

solidity
contract MultiSourceOracle { struct Source { address oracle; uint256 weight; } Source[] public sources; mapping(bytes32 => int256) public aggregatedData; uint256 public totalWeight; event SourceAdded(address indexed oracle, uint256 weight); event DataAggregated(bytes32 indexed key, int256 value); function addSource(address oracle, uint256 weight) public { sources.push(Source({ oracle: oracle, weight: weight })); totalWeight += weight; emit SourceAdded(oracle, weight); } function aggregateData(bytes32 key) public { int256 weightedSum = 0; uint256 validSources = 0; for (uint256 i = 0; i < sources.length; i++) { Source memory source = sources[i]; int256 value = ISimpleOracle(source.oracle).getData(key); if (value != 0) { weightedSum += value * int256(source.weight); validSources += source.weight; } } require(validSources > 0, "No valid data"); int256 aggregatedValue = weightedSum / int256(validSources); aggregatedData[key] = aggregatedValue; emit DataAggregated(key, aggregatedValue); } function getAggregatedData(bytes32 key) public view returns (int256) { return aggregatedData[key]; } } interface ISimpleOracle { function getData(bytes32 key) external view returns (int256); }

Oracle Best Practices

1. Data Validation

  • Use multiple data sources
  • Validate data reasonableness
  • Set price deviation limits
  • Check data freshness

2. Security Measures

  • Implement access control
  • Use multi-signature
  • Set timelocks
  • Regular audits

3. Performance Optimization

  • Cache commonly used data
  • Batch request data
  • Use decentralized oracles
  • Optimize gas consumption

Famous Oracle Projects

  1. Chainlink: Decentralized oracle network
  2. Band Protocol: Cross-chain oracle
  3. UMA: Optimistic oracle
  4. Tellor: Decentralized oracle
  5. API3: First-party oracle

Oracles are key infrastructure connecting blockchain with the real world, providing reliable data support for DeFi, NFTs, insurance, and other applications.

标签:以太坊