Preskoči na glavno vsebino
Change page

Oracles

Nazadnje urejeno: @zajko(opens in a new tab), 15. november 2023

Oraklji so viri podatkov, ki povezujejo Ethereum s podatki izven verige iz resničnega sveta, da lahko poizvedujete o teh podatkih v svoji pametni pogodbi. Na primer, dappi napovednih trgov uporabljajo oraklje za poravnavo plačil, ki temeljijo na dogodkih. Napovedni trg lahko od vas zahteva, da stavite svoj ETH na to, kdo bo postal naslednji predsednik Združenih držav Amerike. Oraklje bodo uporabili za potrditev izida in izplačilo zmagovalcem.

Predpogoji

Prepričajte se, da ste seznanjeni z vozlišči, mehanizmi za soglasje in anatomijo pametnih pogodb, specifično za dogodke.

Kaj je orakelj

Orakelj je most med blokovno verigo in resničnim svetom. Delujejo kot API-ji na verigi, od katerih lahko poizvedujete, da prejmete informacije v svoje pametne pogodbe. To je lahko karkoli od informacij o ceni do vremenskih poročil. Oraklji so lahko tudi dvosmerni in se uporabljajo za "pošiljanje" podatkov v resnični svet.

Oglejte si Patricka, ki pojasnjuje oraklje:

Zakaj so potrebni?

Pri blokovni verigi, kot je Ethereum, je potrebno, da vsako vozlišče v omrežju vrne vsako transakcijo in ima na koncu zagotovo enak rezultat. API-ji predstavijo potencialno variabilne podatke. Če bi pošiljali ETH na podlagi dogovorjene vrednosti $USD z uporabo cenovnega API-ja, bi poizvedba vsak dan vrnila različen rezultat. Da ne omenjamo, da je lahko API napaden ali zastarel. V tem primeru se vozlišča v omrežju ne bi mogla strinjati o Ethereumovem trenutnem stanju, kar bi efektivno prelomilo soglasje.

Oraklji rešijo ta problem z objavo podatkov na blokovni verigi. Tako lahko katerokoli vozlišče uporablja iste nespremenljive podatke, ki so objavljeni na očeh vseh. Za to je orakelj po navadi sestavljen iz pametne pogodbe in nekaj komponent izven verige, ki lahko poizvedujejo prek API-jev ter nato periodično pošiljajo transakcije za posodobitev podatkov pametne pogodbe.

Problem oraklja

Kot smo omenili, transakcije Ethereum ne morejo neposredno dostopati do podatkov izven verige. Obenem je zanašanje na le en vir resnice za zagotavljanje podatkov nevarno in izpodbija decentralizacijo pametne pogodbe. To poznamo kot problem oraklja.

Problemu oraklja se lahko izognemo z decentraliziranim orakljem, ki podatke vleče iz različnih virov; če je en podatkovni vir napaden ali mu spodleti, bo pametna pogodba še vedno delovala tako, kot je bil njen namen.

Varnost

Orakelj je varen le toliko, kot so varni njegovi podatkovni viri. Če dapp kot orakelj za svoj vir cene ETH/DAI uporablja Uniswap, lahko napadalec premakne ceno na Uniswapu, da manipulira z dappovim razumevanjem trenutne cene. Primer, kako se boriti proti temu, je sistem virov(opens in a new tab), kot je tisti, ki ga uporablja MakerDAO, ki podatke o cenah zbira od več zunanjih cenovnih virov, namesto da bi se zanašal le na en vir.

Arhitektura

To je primer preproste arhitekture oraklja, ampak obstaja še več drugih načinov za sprožitev računanja izven verige.

  1. Oddajte dnevnik s svojim dogodkom pametne pogodbe
  2. Storitev izven verige se je naročila (navadno z uporabo nečesa, kot je ukaz JSON-RPC eth_subscribe) na te specifične dnevnike.
  3. Storitev izven verige nadaljuje z izvedbo nalog, kot so opredeljene v dnevniku.
  4. Storitev izven verige se odzove s podatki, zahtevanimi v sekundarni transakciji, na pametno pogodbo.

To je način za pridobitev podatkov po načelu 1 na 1, čeprav bi za izboljšanje varnosti morda želeli decentralizirati način zbiranja svojih podatkov izven verige.

Naslednji korak bi lahko bil, da omrežje teh vozlišč izvede te klice na različne API-je in vire ter zbere podatke na verigi.

Poročanje Chainlink izven verige(opens in a new tab) (Chainlink OCR) se je na podlagi te metodologije izboljšalo s tem, da oraklji v omrežju izven verige med seboj komunicirajo, kriptografsko podpišejo svoje odzive, združijo svoje odzive izven verige in na verigo pošljejo le eno transakcijo z rezultatom. Na ta način se porabi manj goriva, ampak še vedno lahko dobite zagotovilo decentraliziranih podatkov, saj je vsako vozlišče podpisalo svoj del transakcije, kar jo je za vozlišča, ki jo pošiljajo, naredilo nespremenljivo. Politika stopnjevanja se uveljavi, če vozlišče ne opravi transakcije in transakcijo pošlje naslednje vozlišče.

Uporaba

Z uporabo storitev, kot je Chainlink, se lahko sklicujete na decentralizirane podatke na verigi, ki so že bili povlečeni in združeni iz resničnega sveta. Nekako tako kot javna skupna dobrina, vendar za decentralizirane podatke. Prav tako lahko za pridobitev katerihkoli podatkov po meri, ki jih iščete, razvijete svoja lastna modularna omrežja orakljev. Dodatno lahko izvedete računanje izven verige in prav tako pošljete informacije v resnični svet. Chainlink ima vzpostavljeno infrastrukturo za:

Tukaj je primer pridobivanja aktualne cene ETH v vaši pametni pogodbi z uporabo cenovnega vira 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}
Prikaži vse
Kopiraj

To lahko testirate v remiksu prek te povezave(opens in a new tab)

Oglejte si dokumentacijo(opens in a new tab)

Chainlink VRF (potrdljiva naključna funkcija) je dokazano pravičen in potrdljiv vir naključnosti, oblikovan za pametne pogodbe. Razvijalci pametnih pogodb lahko uporabijo Chainlink VRF za naključno generiranje številk (RNG), odporno na posege, da razvijejo zanesljive pametne pogodbe za katerekoli aplikacije, ki se zanašajo na nepredvidljive izide:

  • Igre na blokovnih verigah in NFT-je
  • Naključno dodeljevanje zadolžitev in virov (recimo naključno dodeljevanje sodnikov primerom)
  • Izbiro reprezentativnega vzorca za mehanizme za soglasje

Naključne številke so težke, saj so blokovne verige deterministične.

Delo z oraklji Chainlink zunaj podatkovnih virov sledi ciklu zahtevaj in prejmi(opens in a new tab) dela s Chainlinkom. Za pošiljanje goriva ponudnikom orakljev za vračanje odzivov uporabljajo žeton LINK. Žeton LINK je specifično oblikovan za delo z oraklji in temelji na nadgrajenem žetonu ERC-677, ki je vzvratno kompatibilen z ERC-20. Naslednja koda, če je uveljavljena na testnem omrežju Kovan, bo pridobila kriptografsko dokazano naključno številko. Za izvršitev zahteve na pogodbo nakažite nekaj žetonov LINK testnega omrežja, ki jih lahko dobite iz pipe Kovan LINK(opens in a new tab).

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}
Prikaži vse

Pametne pogodbe ne morejo sprožiti ali iniciirati svojih lastnih funkcij v arbitrarnem času ali pod arbitrarnimi pogoji. Spremembe stanja se bodo pojavile, ko nek drug račun iniciira transakcijo (recimo uporabnik, orakelj ali pogodba). Omrežje Chainlink Keeper(opens in a new tab) zagotavlja možnosti, da pametne pogodbe sprotno vzdrževanje predajo zunanjim izvajalcem na način minimiziranega zaupanja in decentralizacije.

Za uporabo Chainlink Keeperjev mora pametna pogodba implementirati KeeperCompatibleInterface(opens in a new tab), ki je sestavljena iz dveh funkcij:

  • checkUpkeep – preveri, če pogodba zahteva delo, ki ga je treba opraviti.
  • performUpkeep – izvede delo na pogodbi, če tako naroči checkUpkeep.

Spodnji primer je preprosta kontra pogodba. Kontra spremenljivka je povečana za ena z vsakim klicem performUpkeep. Lahko si ogledate naslednjo kodo z uporabo Remixa(opens in a new tab)

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. Funkcija checkData je definirana, ko je bil registriran Upkeep.
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. Funkcija performData je ustvarjena s strani Keeper klica na vašo funkcijo checkUpkeep
36 }
37}
Prikaži vse

Po uveljavitvi pogodbe, kompatibilne s Keeper, morate pogodbo registrirati za Upkeep(opens in a new tab) in nanjo položiti LINK, da omrežje Keeper obvestite o svoji pogodbi in da je vaše delo izvedeno neprekinjeno.

Projekti Keepers

Klici Chainlink API(opens in a new tab) so najenostavnejši način za pridobivanje podatkov iz sveta izven verige na tradicionalen način, po katerem deluje splet: klici API. Enkratna izvedba in razpolaganje le z enim orakljem sta po naravi centralizirana. Da bi jo ohranili resnično decentralizirano, bi morala platforma pametnih pogodb uporabljati številna vozlišča, najdena na zunanjem podatkovnem trgu(opens in a new tab).

Za testiranje uveljavite naslednjo kodo v remiksu na omrežju Kovan(opens in a new tab)

To prav tako sledi zahtevi in prejme cikel orakljev ter za to potrebuje pogodbo, da se lahko za delovanje financira s Kovan LINK (gorivom oraklja).

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}
Prikaži vse

Več o aplikacijah Chainlink lahko izveste z branjem razvijalskega bloga Chainlink(opens in a new tab).

Storitve orakljev

Razvijte orakeljsko pametno pogodbo

Tukaj najdete primer orakeljske pogodbe Pedra Coste. Nadaljnje opombe lahko najdete v njegovem članku: Implementacija oraklja blokovne verige na Ethereumu(opens in a new tab).

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 length = requests.push(Request(currentId, _urlToQuery, _attributeToFetch, ""));
41 Request storage r = requests[length-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}
Prikaži vse
Kopiraj

Želeli bi si več dokumentacije o ustvarjanju orakeljskih pametnih pogodb. Če lahko pomagate, ustvarite PR!

Nadaljnje branje

Članki

Videoposnetki

Vadnice

Je bil ta članek uporaben?