Oracle(预言机)
预言机是将以太坊连接到链外、真实世界信息的数据源,以便您可以在智能合约中查询数据。 例如,预测市场的 dapp 使用预言机来根据事件进行结算。 预测市场可能要求您使用 ETH 来打赌下一任美国总统是谁。 他们将使用一个预言机来确认结果并向获胜者付款。
前置要求
什么是预言机
预言机是区块链与真实世界之间的桥梁。 他们充当在链上的 API,你可以查询以获取信息到你的智能合约。 可以是任何信息,从价格信息到天气预报。
为什么需要预言机?
使用以太坊这样的区块链,你需要确保:网络中的每个节点都能够重放每个交易并最终产生同样的结果。 API 引入潜在的变量数据。 如果你正在使用一个价格 API 根据一个商定的 $USD 值向某人发送一定数量的 ETH,查询将在不同日期返回不同的结果。 不言而喻,API 可能会被破解或废弃。 一旦发生这种情况,网络中的节点不会接受当前状态,导致打破共识。
预言机通过发布数据到区块链来解决这个问题, 以便任何重放交易的节点使用所有人都能看到的、相同的、不可变的数据。 要做到这一点,预言机通常由智能合约和某些可以查询 API 的链外组件组成,然后定期发送交易以更新智能合约的数据。
安全性
预言机的安全性等同于其数据源。 如果一个 dapp 使用 Uniswap 作为其 ETH/DAI 价格的预言机,攻击者就可能在 Uniswap 上篡改价格,以操纵 dapp 对当前价格的理解。 如何对付这个隐患的一个例子是 MakerDAO 所使用的 price feed oracles 。它将来自若干外部数据源的价格数据相互核对,而不是仅仅依靠单一来源。
使用方法
预言机即服务
Chainlink 等服务提供预言机即服务供你使用。 他们已经具备了基础设施,你可以做以下事情:
- 在你的合约中获取加密货币价格
- 生成可验证的随机数字(对游戏有用)
- 调用外部 API – 一个新颖的使用方法是 检查 wBTC 储备
这是如何在智能合约中获取最新的 ETH 价格的一个例子:
1pragma solidity ^0.6.7;23import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol";45contract PriceConsumerV3 {67 AggregatorV3Interface internal priceFeed;89 /**10 * Network: Kovan11 * Aggregator: ETH/USD12 * Address: 0x9326BFA02ADD2366b30bacB125260Af64103133113 */14 constructor() public {15 priceFeed = AggregatorV3Interface(0x9326BFA02ADD2366b30bacB125260Af641031331);16 }1718 /**19 * Returns the latest price20 */21 function getLatestPrice() public view returns (int) {22 (23 uint80 roundID,24 int price,25 uint startedAt,26 uint timeStamp,27 uint80 answeredInRound28 ) = priceFeed.latestRoundData();29 return price;30 }31}32显示全部复制
预言机服务
构建一个预言机智能合约
这是 Pedro Costa 编写的一个预言机智能合约范例。 你可以在他的文章中找到更多注释: Implementing a Blockchain Oracle on Ethereum。
1pragma solidity >=0.4.21 <0.6.0;23contract Oracle {4 Request[] requests; //list of requests made to the contract5 uint currentId = 0; //increasing request id6 uint minQuorum = 2; //minimum number of responses to receive before declaring final result7 uint totalOracleCount = 3; // Hardcoded oracle count89 // defines a general api request10 struct Request {11 uint id; //request id12 string urlToQuery; //API url13 string attributeToFetch; //json attribute (key) to retrieve in the response14 string agreedValue; //value from key15 mapping(uint => string) anwers; //answers provided by the oracles16 mapping(address => uint) quorum; //oracles which will query the answer (1=oracle hasn't voted, 2=oracle has voted)17 }1819 //event that triggers oracle outside of the blockchain20 event NewRequest (21 uint id,22 string urlToQuery,23 string attributeToFetch24 );2526 //triggered when there's a consensus on the final result27 event UpdatedRequest (28 uint id,29 string urlToQuery,30 string attributeToFetch,31 string agreedValue32 );3334 function createRequest (35 string memory _urlToQuery,36 string memory _attributeToFetch37 )38 public39 {40 uint lenght = requests.push(Request(currentId, _urlToQuery, _attributeToFetch, ""));41 Request storage r = requests[lenght-1];4243 // Hardcoded oracles address44 r.quorum[address(0x6c2339b46F41a06f09CA0051ddAD54D1e582bA77)] = 1;45 r.quorum[address(0xb5346CF224c02186606e5f89EACC21eC25398077)] = 1;46 r.quorum[address(0xa2997F1CA363D11a0a35bB1Ac0Ff7849bc13e914)] = 1;4748 // launch an event to be detected by oracle outside of blockchain49 emit NewRequest (50 currentId,51 _urlToQuery,52 _attributeToFetch53 );5455 // increase request id56 currentId++;57 }5859 //called by the oracle to record its answer60 function updateRequest (61 uint _id,62 string memory _valueRetrieved63 ) public {6465 Request storage currRequest = requests[_id];6667 //check if oracle is in the list of trusted oracles68 //and if the oracle hasn't voted yet69 if(currRequest.quorum[address(msg.sender)] == 1){7071 //marking that this address has voted72 currRequest.quorum[msg.sender] = 2;7374 //iterate through "array" of answers until a position if free and save the retrieved value75 uint tmpI = 0;76 bool found = false;77 while(!found) {78 //find first empty slot79 if(bytes(currRequest.anwers[tmpI]).length == 0){80 found = true;81 currRequest.anwers[tmpI] = _valueRetrieved;82 }83 tmpI++;84 }8586 uint currentQuorum = 0;8788 //iterate through oracle list and check if enough oracles(minimum quorum)89 //have voted the same answer has the current one90 for(uint i = 0; i < totalOracleCount; i++){91 bytes memory a = bytes(currRequest.anwers[i]);92 bytes memory b = bytes(_valueRetrieved);9394 if(keccak256(a) == keccak256(b)){95 currentQuorum++;96 if(currentQuorum >= minQuorum){97 currRequest.agreedValue = _valueRetrieved;98 emit UpdatedRequest (99 currRequest.id,100 currRequest.urlToQuery,101 currRequest.attributeToFetch,102 currRequest.agreedValue103 );104 }105 }106 }107 }108 }109}110显示全部复制
我们希望有更多关于构建预言机智能合约的文档。 如果你能帮助我们,就创建一个 PR 吧!
延伸阅读
- Decentralised Oracles: a comprehensive overview –Julien Thevenard
- Implementing a Blockchain Oracle on Ethereum –Pedro Costa
- Oracles –EthHub
帮助我们处理此页面
如果您是这方面的专家,并想发表意见,那么编辑此页分享您的智慧。
您将获得褒奖并会为以太坊社区提供帮助!
自由发挥 文档模板
有任何疑问? 请在我们的频道中进行询问 Discord服务器
编辑页面