Oracles
Les oracles sont des flux de données qui connectent Ethereum aux informations hors chaîne du monde réel pour vous permettre d’interroger les données dans vos contrats intelligents. Par exemple, les DApps de marchés prédictifs utilisent les oracles pour régler des paiements en fonction des événements. Un marché prédictif peut vous demander de miser vos ETH sur le prochain président des États-Unis. Ils utiliseront un oracle pour confirmer le résultat et rémunérer les gagnants.
Prérequis
Assurez-vous d'avoir compris en quoi consistent les nœuds, les mécanismes de consensus et l' anatomie des contrats intelligents, et en particulier les événements.
Qu'est ce qu'un oracle ?
Un oracle est un pont entre la blockchain et le monde réel. Ils agissent sur la blockchain comme des API que vous pouvez interroger pour obtenir des informations dans vos contrats intelligents. Il peut s'agir de n'importe quoi, d'informations de prix aux bulletins météorologiques. Les oracles peuvent également être bidirectionnels, utilisés pour « envoyer » des données hors du monde réel.
Regardez Patrick expliquer les Oracles :
Pourquoi sont-ils nécessaires ?
Avec une blockchain comme Ethereum, tous les nœuds du réseau sont nécessaires pour pouvoir rejouer chaque transaction et finir avec le même résultat garanti. Les APIs introduisent des données potentiellement variables. Si vous envoyez un montant d'ETH basé sur une valeur convenue en $USD via une API de prix, la requête retournera un résultat différent d'un jour sur l'autre. Sans parler du fait que l'API pourrait être piratée ou dépréciée. Dans ce cas, les nœuds du réseau ne pourraient pas se mettre d'accord sur l'état actuel d'Ethereum, brisant ainsi le consensus.
Les oracles résolvent ce problème en publiant les données sur la blockchain. Ainsi, tout nœud rejouant la transaction utilisera les mêmes données immuables qui ont été publiées pour que tout le monde puisse les voir. À cette fin, un oracle comprend généralement un contrat intelligent et des composants hors chaîne qui peuvent interroger les APIs, puis envoyer périodiquement des transactions pour mettre à jour les données du contrat intelligent.
Le problème de l'oracle
Comme nous l'avons mentionné, les transactions Ethereum ne peuvent accéder directement aux données hors chaîne. En même temps, compter sur une seule source de vérité pour fournir des données n'est pas sûr et invalide la décentralisation d'un contrat intelligent. Ceci est connu comme le problème de l'oracle.
Nous pouvons éviter le problème de l'oracle en utilisant un oracle décentralisé qui s'appuie sur de multiples sources de données. Si une source de données est piratée ou échoue, le contrat intelligent fonctionnera toujours comme prévu.
Sécurité
Un oracle est aussi sûr que le sont ses sources de données. Si une dapp utilise Uniswap comme oracle pour son flux de prix ETH/DAI, il est possible pour un attaquant de déplacer le prix sur Uniswap afin de manipuler la compréhension du prix actuel par la dapp. Un exemple de façon de combattre cela est l'utilisation d'un système de flux comme celui de MakerDAO qui rassemble les données de prix à partir d'un certain nombre de flux externes de prix au lieu de dépendre d'une seule source.
Architecture
Voici un exemple d'architecture simple d'Oracle, mais il existe d'autres moyens pour déclencher un calcul hors chaîne.
- Émettre un journal avec votre événement de contrat intelligent
- Un service hors chaîne s'abonne (généralement en utilisant quelque chose comme la commande JSON-RPC
eth_subscribe
) à ce journal. - Le service hors chaîne procède à certaines tâches telles que définies dans le journal.
- Le service hors chaîne répond avec les données demandées dans une transaction secondaire au contrat intelligent.
Voici comment obtenir des données 1 à 1. Cependant, et afin d'améliorer la sécurité, vous pouvez souhaiter décentraliser la façon dont vous collectez vos données hors chaîne.
L'étape suivante pourrait être de disposer d'un réseau de ces nœuds faisant ces appels à différentes APIs et sources, et en agrégeant les données sur la chaîne.
Chainlink Off-Chain Reporting (Chainlink OCR) a amélioré cette méthodologie en faisant communiquer les noeuds du réseau d'oracles hors chaîne les uns avec les autres, en signant cryptographiquement leurs réponses, en agrégeant leurs réponses hors chaîne et en envoyant une seule transaction sur la blockchain avec le résultat. De cette façon, moins de carburant est dépensé, mais on conserve toujours la garantie de décentralisation des données puisque chaque nœud a signé sa partie de la transaction, la rendant non modifiable par le nœud envoyant la transaction. La politique d'escalade se déclenche si le nœud ne finalise pas la transaction et que le nœud suivant envoie la transaction.
Utilisation
En utilisant des services comme Chainlink, vous pouvez référencer des données décentralisées sur la chaîne qui ont déjà été tirées du monde réel et agrégées. Un peu comme des bien publics partagés, mais pour les données décentralisées. Vous pouvez également construire vos propres réseaux d'oracles modulaires pour obtenir tout type de données personnalisées dont vous avez besoin. En outre, vous pouvez faire du calcul hors chaîne et envoyer des informations dans le monde réel. Chainlink a l'infrastructure en place pour :
- Obtenir des flux de prix de cryptomonnaies dans votre contrat
- Générer des nombres aléatoires vérifiables (utile pour les jeux)
- Appeler des API externes - une nouvelle utilisation de ceci est la vérification des réserves WBTC
Voici un exemple pour obtenir le dernier prix de l'ETH dans votre contrat intelligent en utilisant un flux de prix Chainlink :
Flux de données de Chainlink
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}32Afficher toutCopier
Vous pouvez tester cela dans Remix avec ce lien
Chainlink VRF
Chainlink VRF (Verifiable Random Function) est une source d'aléas prouvable et vérifiable conçue pour les contrats intelligents. Les développeurs de contrats intelligents peuvent utiliser Chainlink VRF comme un générateur de numéros aléatoires (RNG) à l'épreuve de la falsification pour créer des contrats intelligents fiables pour toutes les applications qui se basent sur des résultats imprévisibles :
- Jeux Blockchain et NFTs
- Affectation aléatoire de tâches et de ressources (p. ex. assigner aléatoirement des juges à des cas)
- Choisir un échantillon représentatif pour les mécanismes de consensus
Les nombres aléatoires sont difficiles, car les blockchains sont déterministes.
Travailler avec Chainlink Oracles en dehors des flux de données suit le travail du cycle de requête et de réception avec Chainlink. Ils utilisent le jeton LINK pour envoyer du carburant oracle à des fournisseurs oracle pour les réponses retournées. Le jeton LINK est spécifiquement conçu pour fonctionner avec des oracles et est basé sur le jeton ERC-677 mis à jour, qui est rétrocompatible avec ERC-20. Le code suivant, s'il est déployé sur le réseau de test Kovan, récupérera un nombre aléatoire prouvé cryptographiquement. Pour réaliser la requête, financez le contrat avec un jeton de réseau de test LINK que vous pouvez obtenir du robinet Kovan LINK.
12pragma solidity 0.6.6;34import "@chainlink/contracts/src/v0.6/VRFConsumerBase.sol";56contract RandomNumberConsumer is VRFConsumerBase {78 bytes32 internal keyHash;9 uint256 internal fee;1011 uint256 public randomResult;1213 /**14 * Constructor inherits VRFConsumerBase15 *16 * Network: Kovan17 * Chainlink VRF Coordinator address: 0xdD3782915140c8f3b190B5D67eAc6dc5760C46E918 * LINK token address: 0xa36085F69e2889c224210F603D836748e7dC008819 * Key Hash: 0x6c3699283bda56ad74f6b855546325b68d482e983852a7a82979cc4807b641f420 */21 constructor()22 VRFConsumerBase(23 0xdD3782915140c8f3b190B5D67eAc6dc5760C46E9, // VRF Coordinator24 0xa36085F69e2889c224210F603D836748e7dC0088 // LINK Token25 ) public26 {27 keyHash = 0x6c3699283bda56ad74f6b855546325b68d482e983852a7a82979cc4807b641f4;28 fee = 0.1 * 10 ** 18; // 0.1 LINK (varies by network)29 }3031 /**32 * Requests randomness from a user-provided seed33 */34 function getRandomNumber(uint256 userProvidedSeed) public returns (bytes32 requestId) {35 require(LINK.balanceOf(address(this)) >= fee, "Not enough LINK - fill contract with faucet");36 return requestRandomness(keyHash, fee, userProvidedSeed);37 }3839 /**40 * Callback function used by VRF Coordinator41 */42 function fulfillRandomness(bytes32 requestId, uint256 randomness) internal override {43 randomResult = randomness;44 }45}46Afficher tout
Les gardiens Chainlink
Les contrats intelligents ne peuvent pas déclencher ou initier leurs propres fonctions à des moments arbitraires ou dans des conditions arbitraires. Les changements d'état ne se produiront que lorsqu'un autre compte lance une transaction (comme un utilisateur, un oracle ou un contrat). Le réseau de gardien Chainlink fournit des options pour que les contrats intelligents pour externaliser des tâches régulières de maintenance de manière minimisée et décentralisée et en toute confiance.
Pour utiliser les gardiens Chainlink, un contrat intelligent doit implémenter une KeeperCompatibleInterface qui se compose de deux fonctions :
checkUpkeep
- Vérifie si le contrat nécessite de réaliser un travail.performUpkeep
- Effectue le travail sur le contrat, si initié par checkUpkeep.
L'exemple ci-dessous est un simple contrat de comptage. La variable counter
est incrémentée d'un pour chaque appel à performUpkeep
. Vous pouvez vérifier le code suivant en utilisant Remix
1// SPDX-License-Identifier: MIT2pragma solidity ^0.7.0;34// KeeperCompatible.sol imports the functions from both ./KeeperBase.sol and5// ./interfaces/KeeperCompatibleInterface.sol6import "@chainlink/contracts/src/v0.7/KeeperCompatible.sol";78contract Counter is KeeperCompatibleInterface {9 /**10 * Public counter variable11 */12 uint public counter;1314 /**15 * Use an interval in seconds and a timestamp to slow execution of Upkeep16 */17 uint public immutable interval;18 uint public lastTimeStamp;1920 constructor(uint updateInterval) {21 interval = updateInterval;22 lastTimeStamp = block.timestamp;2324 counter = 0;25 }2627 function checkUpkeep(bytes calldata /* checkData */) external override returns (bool upkeepNeeded, bytes memory /* performData */) {28 upkeepNeeded = (block.timestamp - lastTimeStamp) > interval;29 // We don't use the checkData in this example. The checkData is defined when the Upkeep was registered.30 }3132 function performUpkeep(bytes calldata /* performData */) external override {33 lastTimeStamp = block.timestamp;34 counter = counter + 1;35 // We don't use the performData in this example. The performData is generated by the Keeper's call to your checkUpkeep function36 }37}38Afficher tout
Après avoir déployé un contrat compatible avec Keeper, vous devez enregistrer le contrat pour le gardiennage et le financer par LINK, pour informer le réseau de gardiens de votre contrat et afin que votre travail soit effectué en permanence.
Projets Keepers
Appel API Chainlink
Les Appels API Chainlink sont le moyen le plus simple d'obtenir des données hors chaîne suivant la méthode qui fonctionne traditionnellement sur le web : les appels API. Exécuter une seule instance de ceci en ayant qu'un seul oracle la rend centralisée par nature. Pour le maintenir véritablement décentralisé, une plateforme de contrats intelligents devrait utiliser de nombreux nœuds trouvés sur le marché externe de données.
Déployez le code suivant sur remix via le réseau kovan pour le tester
Cela suit également le cycle requête et réception d'oracles et a besoin que le contrat soit financé avec Kovan LINK (le carburant oracle) pour fonctionner.
1pragma solidity ^0.6.0;23import "@chainlink/contracts/src/v0.6/ChainlinkClient.sol";45contract APIConsumer is ChainlinkClient {67 uint256 public volume;89 address private oracle;10 bytes32 private jobId;11 uint256 private fee;1213 /**14 * Network: Kovan15 * Oracle: 0x2f90A6D021db21e1B2A077c5a37B3C7E75D15b7e16 * Job ID: 29fa9aa13bf1468788b7cc4a500a45b817 * Fee: 0.1 LINK18 */19 constructor() public {20 setPublicChainlinkToken();21 oracle = 0x2f90A6D021db21e1B2A077c5a37B3C7E75D15b7e;22 jobId = "29fa9aa13bf1468788b7cc4a500a45b8";23 fee = 0.1 * 10 ** 18; // 0.1 LINK24 }2526 /**27 * Create a Chainlink request to retrieve API response, find the target28 * data, then multiply by 1000000000000000000 (to remove decimal places from data).29 */30 function requestVolumeData() public returns (bytes32 requestId)31 {32 Chainlink.Request memory request = buildChainlinkRequest(jobId, address(this), this.fulfill.selector);3334 // Set the URL to perform the GET request on35 request.add("get", "https://min-api.cryptocompare.com/data/pricemultifull?fsyms=ETH&tsyms=USD");3637 // Set the path to find the desired data in the API response, where the response format is:38 // {"RAW":39 // {"ETH":40 // {"USD":41 // {42 // "VOLUME24HOUR": xxx.xxx,43 // }44 // }45 // }46 // }47 request.add("path", "RAW.ETH.USD.VOLUME24HOUR");4849 // Multiply the result by 1000000000000000000 to remove decimals50 int timesAmount = 10**18;51 request.addInt("times", timesAmount);5253 // Sends the request54 return sendChainlinkRequestTo(oracle, request, fee);55 }5657 /**58 * Receive the response in the form of uint25659 */60 function fulfill(bytes32 _requestId, uint256 _volume) public recordChainlinkFulfillment(_requestId)61 {62 volume = _volume;63 }64}65Afficher tout
Vous pouvez en apprendre plus sur les applications de Chainlink en lisant le blog des développeurs de Chainlink.
Services d'Oracle
Créer un contrat intelligent oracle
Voici un exemple de contrat oracle créé par Pedro Costa. Vous pouvez trouver d'autres annotations dans son article : 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}110111Text112Xpath: /pre[2]/code113Afficher toutCopier
Nous aimerions avoir plus de documentation sur la création d'un contrat intelligent oracle. Si vous pouvez nous aider, créez une PR !
En lire plus
Articles
- Qu'est-ce qu'une Blockchain Oracle ? - Chainlink
- Oracles – EthHub
- Qu'est-ce qu'une Blockchain Oracle ? - Patrick Collins
- Oracles décentralisés : un aperçu complet – Julien Thevenard
- Implémentation d'une Blockchain Oracle sur Ethereum – Pedro Costa
- Pourquoi les contrats intelligents ne peuvent pas générer des appels API ? - StackExchange
- Pourquoi nous avons besoin d'oracles décentralisées - Bankless
- Ainsi, vous souhaitez utiliser un prix oracle -samczsun
Vidéos
- Oracles et l'expansion de l'utilité des Blockchains - Real Vision Finance
Didacticiels
Aidez-nous avec cette page
Si vous êtes un expert sur le sujet et que vous souhaitez contribuer, modifiez cette page et enrichissez-la de votre sagesse.
Vous serez crédité et vous aiderez la communauté Ethereum !
Utilisez la flexibilité de ce Modèle de documentation
Des questions ? Demandez-nous dans le salon #content de notre Serveur Discord
Modifier la page