以太坊预言机(Oracle)是连接区块链与外部世界的关键基础设施,为智能合约提供链下数据。以下是预言机的详细解析:
预言机的基本概念
预言机是一种将链下数据传输到链上智能合约的机制。由于智能合约无法直接访问外部数据(如API、网站等),预言机成为必要的桥梁。
预言机类型
1. 中心化预言机
由单一实体提供数据服务。
优点:
- 实现简单
- 响应快速
- 成本较低
缺点:
- 单点故障风险
- 数据可被操纵
- 缺乏去中心化
示例:
soliditycontract CentralizedOracle { address public oracle; mapping(bytes32 => uint256) public prices; constructor(address _oracle) { oracle = _oracle; } modifier onlyOracle() { require(msg.sender == oracle, "Not oracle"); _; } function updatePrice(bytes32 symbol, uint256 price) public onlyOracle { prices[symbol] = price; } function getPrice(bytes32 symbol) public view returns (uint256) { return prices[symbol]; } }
2. 去中心化预言机
由多个数据源聚合数据,提高可靠性和安全性。
优点:
- 数据更可靠
- 抗操纵能力强
- 去中心化
缺点:
- 实现复杂
- 成本较高
- 响应较慢
Chainlink预言机
1. Chainlink架构
Chainlink是最流行的去中心化预言机网络。
组件:
- 节点:提供数据服务的独立节点
- 聚合合约:聚合多个节点的数据
- 喂价合约:存储聚合后的数据
2. 使用Chainlink喂价
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(address _priceFeed) { priceFeed = AggregatorV3Interface(_priceFeed); } function getLatestPrice() public view returns (int) { ( /* uint80 roundID */, int price, /* uint startedAt */, /* uint timeStamp */, /* uint80 answeredInRound */ ) = priceFeed.latestRoundData(); return price; } function getDecimals() public view returns (uint8) { return priceFeed.decimals(); } }
3. Chainlink VRF(可验证随机函数)
solidityimport "@chainlink/contracts/src/v0.8/VRFConsumerBase.sol"; contract RandomNumberConsumer is VRFConsumerBase { bytes32 internal keyHash; uint256 internal fee; uint256 public randomResult; constructor(address _vrfCoordinator, address _link) VRFConsumerBase(_vrfCoordinator, _link) { keyHash = 0x2ed0feb11e87f9216304401f82428c1c32c086868a395eb09f70d1a7804939f2; fee = 0.1 * 10**18; // 0.1 LINK } function getRandomNumber() public returns (bytes32 requestId) { require(LINK.balanceOf(address(this)) >= fee, "Not enough LINK"); return requestRandomness(keyHash, fee); } function fulfillRandomness(bytes32 requestId, uint256 randomness) internal override { randomResult = randomness; } }
预言机数据聚合
1. 简单平均
soliditycontract SimpleAggregator { address[] public oracles; mapping(bytes32 => uint256[]) public priceUpdates; function updatePrice(bytes32 symbol, uint256 price) public { bool isOracle = false; for (uint256 i = 0; i < oracles.length; i++) { if (oracles[i] == msg.sender) { isOracle = true; break; } } require(isOracle, "Not oracle"); priceUpdates[symbol].push(price); } function getAggregatedPrice(bytes32 symbol) public view returns (uint256) { uint256[] memory prices = priceUpdates[symbol]; require(prices.length > 0, "No prices"); uint256 sum = 0; for (uint256 i = 0; i < prices.length; i++) { sum += prices[i]; } return sum / prices.length; } }
2. 中位数聚合
soliditycontract MedianAggregator { function getMedian(uint256[] memory data) public pure returns (uint256) { require(data.length > 0, "Empty data"); // 简单排序 for (uint256 i = 0; i < data.length - 1; i++) { for (uint256 j = 0; j < data.length - i - 1; j++) { if (data[j] > data[j + 1]) { uint256 temp = data[j]; data[j] = data[j + 1]; data[j + 1] = temp; } } } return data[data.length / 2]; } }
预言机安全
1. 数据验证
soliditycontract SecureOracle { mapping(address => bool) public trustedOracles; mapping(bytes32 => uint256) public prices; mapping(bytes32 => uint256) public lastUpdateTime; uint256 public maxPriceAge = 1 hours; function updatePrice(bytes32 symbol, uint256 price) public { require(trustedOracles[msg.sender], "Not trusted oracle"); prices[symbol] = price; lastUpdateTime[symbol] = block.timestamp; } function getPrice(bytes32 symbol) public view returns (uint256) { require( block.timestamp - lastUpdateTime[symbol] < maxPriceAge, "Price too old" ); return prices[symbol]; } }
2. 乐观预言机
soliditycontract OptimisticOracle { struct PriceUpdate { uint256 price; uint256 timestamp; bool disputed; bool finalized; } mapping(bytes32 => PriceUpdate) public priceUpdates; uint256 public disputePeriod = 1 hours; function proposePrice(bytes32 symbol, uint256 price) public { priceUpdates[symbol] = PriceUpdate({ price: price, timestamp: block.timestamp, disputed: false, finalized: false }); } function disputePrice(bytes32 symbol) public { PriceUpdate storage update = priceUpdates[symbol]; require( block.timestamp - update.timestamp < disputePeriod, "Dispute period over" ); require(!update.disputed, "Already disputed"); update.disputed = true; } function finalizePrice(bytes32 symbol) public { PriceUpdate storage update = priceUpdates[symbol]; require( block.timestamp - update.timestamp >= disputePeriod, "Dispute period not over" ); require(!update.disputed, "Price disputed"); update.finalized = true; } }
预言机应用场景
1. DeFi价格数据
soliditycontract DeFiProtocol { AggregatorV3Interface public ethUsdPriceFeed; AggregatorV3Interface public btcUsdPriceFeed; function calculateCollateralValue(uint256 ethAmount, uint256 btcAmount) public view returns (uint256) { int256 ethPrice = ethUsdPriceFeed.latestRoundData().price; int256 btcPrice = btcUsdPriceFeed.latestRoundData().price; uint256 ethValue = uint256(ethPrice) * ethAmount / 10**8; uint256 btcValue = uint256(btcPrice) * btcAmount / 10**8; return ethValue + btcValue; } }
2. 体育博彩
soliditycontract SportsBetting { struct Match { string homeTeam; string awayTeam; uint256 startTime; bool finished; uint256 homeScore; uint256 awayScore; } mapping(uint256 => Match) public matches; address public oracle; function reportMatchResult( uint256 matchId, uint256 homeScore, uint256 awayScore ) public { require(msg.sender == oracle, "Not oracle"); Match storage match = matches[matchId]; match.finished = true; match.homeScore = homeScore; match.awayScore = awayScore; } }
3. 保险合约
soliditycontract FlightInsurance { struct Flight { string flightNumber; uint256 departureTime; bool delayed; bool claimed; } mapping(bytes32 => Flight) public flights; address public oracle; function reportDelay(bytes32 flightId, bool isDelayed) public { require(msg.sender == oracle, "Not oracle"); Flight storage flight = flights[flightId]; flight.delayed = isDelayed; } function claimInsurance(bytes32 flightId) public { Flight storage flight = flights[flightId]; require(flight.delayed, "Flight not delayed"); require(!flight.claimed, "Already claimed"); flight.claimed = true; payable(msg.sender).transfer(1 ether); } }
预言机最佳实践
- 使用去中心化预言机:提高数据可靠性
- 数据验证:验证数据来源和时效性
- 多数据源:使用多个数据源降低风险
- 更新频率:根据应用需求设置合理的更新频率
- 成本控制:优化Gas使用,降低成本
- 故障处理:设计故障恢复机制
- 安全审计:对预言机合约进行安全审计
常见预言机项目
- Chainlink:最流行的去中心化预言机网络
- Band Protocol:跨链预言机解决方案
- UMA:乐观预言机
- API3:去中心化API服务
- Tellor:基于挖矿的预言机
预言机是连接区块链与现实世界的关键基础设施,对于构建复杂的去中心化应用至关重要。