Passer au contenu principal

Aider à mettre à jour cette page

🌏

Il existe une nouvelle version de cette page, mais seulement en anglais pour le moment. Aidez-nous à traduire la dernière version.

Traduire la page
Voir l'anglais

Aucun bogue ici !🐛

Cette page n'est pas traduite. Nous laissons volontairement cette page en anglais pour le moment.

Cette page est incomplète et nous aimerions votre aide. Modifiez cette page et ajoutez tout ce que vous pensez être utile aux autres.

Oracles

Dernière modification: , Invalid DateTime
Modifier la page

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.

  1. Émettre un journal avec votre événement de contrat intelligent
  2. Un service hors chaîne s'abonne (généralement en utilisant quelque chose comme la commande JSON-RPC eth_subscribe) à ce journal.
  3. Le service hors chaîne procède à certaines tâches telles que définies dans le journal.
  4. 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 :

Voici un exemple pour obtenir le dernier prix de l'ETH dans votre contrat intelligent en utilisant un flux de prix Chainlink :

1pragma solidity ^0.6.7;
2
3import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol";
4
5contract PriceConsumerV3 {
6
7 AggregatorV3Interface internal priceFeed;
8
9 /**
10 * Network: Kovan
11 * Aggregator: ETH/USD
12 * Address: 0x9326BFA02ADD2366b30bacB125260Af641031331
13 */
14 constructor() public {
15 priceFeed = AggregatorV3Interface(0x9326BFA02ADD2366b30bacB125260Af641031331);
16 }
17
18 /**
19 * Returns the latest price
20 */
21 function getLatestPrice() public view returns (int) {
22 (
23 uint80 roundID,
24 int price,
25 uint startedAt,
26 uint timeStamp,
27 uint80 answeredInRound
28 ) = priceFeed.latestRoundData();
29 return price;
30 }
31}
32
Afficher tout
📋 Copier

Vous pouvez tester cela dans Remix avec ce lien

Voir la documentation

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.

1
2pragma solidity 0.6.6;
3
4import "@chainlink/contracts/src/v0.6/VRFConsumerBase.sol";
5
6contract RandomNumberConsumer is VRFConsumerBase {
7
8 bytes32 internal keyHash;
9 uint256 internal fee;
10
11 uint256 public randomResult;
12
13 /**
14 * Constructor inherits VRFConsumerBase
15 *
16 * Network: Kovan
17 * Chainlink VRF Coordinator address: 0xdD3782915140c8f3b190B5D67eAc6dc5760C46E9
18 * LINK token address: 0xa36085F69e2889c224210F603D836748e7dC0088
19 * Key Hash: 0x6c3699283bda56ad74f6b855546325b68d482e983852a7a82979cc4807b641f4
20 */
21 constructor()
22 VRFConsumerBase(
23 0xdD3782915140c8f3b190B5D67eAc6dc5760C46E9, // VRF Coordinator
24 0xa36085F69e2889c224210F603D836748e7dC0088 // LINK Token
25 ) public
26 {
27 keyHash = 0x6c3699283bda56ad74f6b855546325b68d482e983852a7a82979cc4807b641f4;
28 fee = 0.1 * 10 ** 18; // 0.1 LINK (varies by network)
29 }
30
31 /**
32 * Requests randomness from a user-provided seed
33 */
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 }
38
39 /**
40 * Callback function used by VRF Coordinator
41 */
42 function fulfillRandomness(bytes32 requestId, uint256 randomness) internal override {
43 randomResult = randomness;
44 }
45}
46
Afficher tout

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: MIT
2pragma solidity ^0.7.0;
3
4// KeeperCompatible.sol imports the functions from both ./KeeperBase.sol and
5// ./interfaces/KeeperCompatibleInterface.sol
6import "@chainlink/contracts/src/v0.7/KeeperCompatible.sol";
7
8contract Counter is KeeperCompatibleInterface {
9 /**
10 * Public counter variable
11 */
12 uint public counter;
13
14 /**
15 * Use an interval in seconds and a timestamp to slow execution of Upkeep
16 */
17 uint public immutable interval;
18 uint public lastTimeStamp;
19
20 constructor(uint updateInterval) {
21 interval = updateInterval;
22 lastTimeStamp = block.timestamp;
23
24 counter = 0;
25 }
26
27 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 }
31
32 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 function
36 }
37}
38
Afficher 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

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;
2
3import "@chainlink/contracts/src/v0.6/ChainlinkClient.sol";
4
5contract APIConsumer is ChainlinkClient {
6
7 uint256 public volume;
8
9 address private oracle;
10 bytes32 private jobId;
11 uint256 private fee;
12
13 /**
14 * Network: Kovan
15 * Oracle: 0x2f90A6D021db21e1B2A077c5a37B3C7E75D15b7e
16 * Job ID: 29fa9aa13bf1468788b7cc4a500a45b8
17 * Fee: 0.1 LINK
18 */
19 constructor() public {
20 setPublicChainlinkToken();
21 oracle = 0x2f90A6D021db21e1B2A077c5a37B3C7E75D15b7e;
22 jobId = "29fa9aa13bf1468788b7cc4a500a45b8";
23 fee = 0.1 * 10 ** 18; // 0.1 LINK
24 }
25
26 /**
27 * Create a Chainlink request to retrieve API response, find the target
28 * 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);
33
34 // Set the URL to perform the GET request on
35 request.add("get", "https://min-api.cryptocompare.com/data/pricemultifull?fsyms=ETH&tsyms=USD");
36
37 // 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");
48
49 // Multiply the result by 1000000000000000000 to remove decimals
50 int timesAmount = 10**18;
51 request.addInt("times", timesAmount);
52
53 // Sends the request
54 return sendChainlinkRequestTo(oracle, request, fee);
55 }
56
57 /**
58 * Receive the response in the form of uint256
59 */
60 function fulfill(bytes32 _requestId, uint256 _volume) public recordChainlinkFulfillment(_requestId)
61 {
62 volume = _volume;
63 }
64}
65
Afficher 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;
2
3contract Oracle {
4 Request[] requests; //list of requests made to the contract
5 uint currentId = 0; //increasing request id
6 uint minQuorum = 2; //minimum number of responses to receive before declaring final result
7 uint totalOracleCount = 3; // Hardcoded oracle count
8
9 // defines a general api request
10 struct Request {
11 uint id; //request id
12 string urlToQuery; //API url
13 string attributeToFetch; //json attribute (key) to retrieve in the response
14 string agreedValue; //value from key
15 mapping(uint => string) anwers; //answers provided by the oracles
16 mapping(address => uint) quorum; //oracles which will query the answer (1=oracle hasn't voted, 2=oracle has voted)
17 }
18
19 //event that triggers oracle outside of the blockchain
20 event NewRequest (
21 uint id,
22 string urlToQuery,
23 string attributeToFetch
24 );
25
26 //triggered when there's a consensus on the final result
27 event UpdatedRequest (
28 uint id,
29 string urlToQuery,
30 string attributeToFetch,
31 string agreedValue
32 );
33
34 function createRequest (
35 string memory _urlToQuery,
36 string memory _attributeToFetch
37 )
38 public
39 {
40 uint lenght = requests.push(Request(currentId, _urlToQuery, _attributeToFetch, ""));
41 Request storage r = requests[lenght-1];
42
43 // Hardcoded oracles address
44 r.quorum[address(0x6c2339b46F41a06f09CA0051ddAD54D1e582bA77)] = 1;
45 r.quorum[address(0xb5346CF224c02186606e5f89EACC21eC25398077)] = 1;
46 r.quorum[address(0xa2997F1CA363D11a0a35bB1Ac0Ff7849bc13e914)] = 1;
47
48 // launch an event to be detected by oracle outside of blockchain
49 emit NewRequest (
50 currentId,
51 _urlToQuery,
52 _attributeToFetch
53 );
54
55 // increase request id
56 currentId++;
57 }
58
59 //called by the oracle to record its answer
60 function updateRequest (
61 uint _id,
62 string memory _valueRetrieved
63 ) public {
64
65 Request storage currRequest = requests[_id];
66
67 //check if oracle is in the list of trusted oracles
68 //and if the oracle hasn't voted yet
69 if(currRequest.quorum[address(msg.sender)] == 1){
70
71 //marking that this address has voted
72 currRequest.quorum[msg.sender] = 2;
73
74 //iterate through "array" of answers until a position if free and save the retrieved value
75 uint tmpI = 0;
76 bool found = false;
77 while(!found) {
78 //find first empty slot
79 if(bytes(currRequest.anwers[tmpI]).length == 0){
80 found = true;
81 currRequest.anwers[tmpI] = _valueRetrieved;
82 }
83 tmpI++;
84 }
85
86 uint currentQuorum = 0;
87
88 //iterate through oracle list and check if enough oracles(minimum quorum)
89 //have voted the same answer has the current one
90 for(uint i = 0; i < totalOracleCount; i++){
91 bytes memory a = bytes(currRequest.anwers[i]);
92 bytes memory b = bytes(_valueRetrieved);
93
94 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.agreedValue
103 );
104 }
105 }
106 }
107 }
108 }
109}
110
111Text
112Xpath: /pre[2]/code
113
Afficher tout
📋 Copier

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

Vidéos

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

Cet article vous a été utile ?