Wyrocznie
Ostatnia edycja: @wosek_(opens in a new tab), 25 lipca 2024
Wyrocznie to źródła danych łączące Ethereum z informacjami spoza łańcucha, ze świata rzeczywistego, umożliwiające zapytania o dane w inteligentnych kontraktach. Na przykład aplikacje dapp rynków prognostycznych używają wyroczni do rozliczania płatności na podstawie zdarzeń. Rynek prognostyczny może poprosić Cię o postawienie ETH na następnego prezydenta Stanów Zjednoczonych. Użyje wyroczni, aby potwierdzić wynik i wypłacić nagrodę zwycięzcom.
Warunki wstępne
Upewnij się, że wiesz wystarczająco dużo na temat węzłów, mechanizmów konsensusu i anatomii kontraktów inteligentnych, w szczególności zdarzeń.
Co to jest wyrocznia
Wyrocznia jest pomostem między blockchainem a światem rzeczywistym. Wyrocznie działają jako interfejsy API w łańcuchu, do których można wysyłać zapytania, aby uzyskać informacje do inteligentnych kontraktów. Może to być wszystko, od informacji o cenach po prognozy pogody.
Dlaczego są potrzebne?
Z blockchainem takim jak Ethereum potrzebujesz każdego węzła w sieci, aby móc odtworzyć każdą transakcję i uzyskać ten sam wynik, gwarantowany. API wprowadzają potencjalnie zmienne dane. Jeśli wysyłasz komuś kwotę ETH na podstawie uzgodnionej wartości $USD za pomocą interfejsu API ceny, zapytanie zwróci inny wynik każdego dnia. Nie wspominając o tym, że API może zostać zhakowany lub być przestarzały. Jeśli tak się stanie, węzły w sieci nie będą w stanie uzgodnić aktualnego stanu Ethereum, skutecznie łamiąc konsensus.
Wyrocznie rozwiązują ten problem, publikując dane w blockchainie. Tak więc każdy węzeł odtwarzający transakcję wykorzysta te same niezmienne dane, które zostały opublikowane dla wszystkich. W tym celu wyrocznia składa się zazwyczaj z inteligentnego kontraktu i niektórych elementów nieobjętych łańcuchem, które mogą odpytywać API, następnie okresowo wysyłać transakcje, aby zaktualizować dane inteligentnego kontraktu.
Ochrona
Wyrocznia jest tak bezpieczna, jak jej źródła danych. Jeśli aplikacja dapp używa Uniswap jako wyroczni dla swojego kanału cenowego ETH/DAI, atakujący może zmienić cenę na Uniswap w celu manipulowania wiedzą aplikacji na temat bieżącej ceny. Można z tym walczyć, wykorzystując na przykład system kanałów(opens in a new tab) podobny do używanego przez MakerDAO, który porównuje dane cenowe z wielu zewnętrznych źródeł cen, zamiast polegać tylko na jednym.
Wykorzystanie
Wyrocznie jako usługa
Usługi takie jak Chainlink oferują wyrocznie jako usługę, z której możesz korzystać. Dysponują infrastrukturą umożliwiającą użytkownikom podjęcie następujących działań:
- pobieranie źródeł cen kryptowalut do swojego kontraktu(opens in a new tab)
- generowanie weryfikowalnych liczb losowych (przydatne do gry)(opens in a new tab)
- wywoływanie zewnętrznych interfejsów API(opens in a new tab) – jednym z nowatorskich zastosowań jest sprawdzanie rezerw wBTC(opens in a new tab)
Oto przykład możliwości uzyskania ostatniej ceny ETH w inteligentnym kontrakcie za pomocą kanału cenowego Chainlink:
1pragma solidity ^0.6.7;23import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol";45contract PriceConsumerV3 {67 AggregatorV3Interface internal priceFeed;89 /**10 * Sieć: Kovan11 * Agregator: ETH/USD12 * Adress: 0x9326BFA02ADD2366b30bacB125260Af64103133113 */14 constructor() public {15 priceFeed = AggregatorV3Interface(0x9326BFA02ADD2366b30bacB125260Af641031331);16 }1718 /**19 * Zwraca ostatnią cenę20 */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}Pokaż wszystkoKopiuj
Wyświetl dokumenty(opens in a new tab)
Usługi wyroczni
Tworzenie kontraktu inteligentnego z wykorzystaniem wyroczni
Oto przykład kontraktu z wykorzystaniem wyroczni autorstwa Pedro Costa. W artykule znajdziesz kolejną adnotację: Wprowadzanie wyroczni blockchainu w Ethereum(opens in a new tab).
1pragma solidity >=0.4.21 <0.6.0;23contract Oracle {4 Request[] requests; //lista żądań wprowadzonych do kontraktu5 uint currentId = 0; //rosnący id żądania6 uint minQuorum = 2; //minimalna liczba otrzymanych odpowiedzi przed zadeklarowaniem ostatecznego wyniku7 uint totalOracleCount = 3; // liczba wyroczni osadzonych w kodzie źródłowym8 // defines a general api request9 struct Request {10 uint id; // id żądania11 string urlToQuery; //url API12 string attributeToFetch; //atrybut json (klucz) do pobrania w odpowiedzi13 string agreedValue; //wartość z klucza14 mapping(uint => string) anwers; //odpowiedzi dostarczone przez wyrocznie15 mapping(address => uint) quorum; //wyrocznie, które będą odpytywać odpowiedź (1=wyrocznia nie głosowała, 2=wyrocznia głosowała)16 }1718 //zdarzenie wyzwalające wyrocznię poza blockchainem19 event NewRequest (20 uint id,21 string urlToQuery,22 string attributeToFetch23 );2425 //wyzwalane, jeśli jest konsensus co do końcowego wyniku26 event UpdatedRequest (27 uint id,28 string urlToQuery,29 string attributeToFetch,30 string agreedValue31 );3233 function createRequest (34 string memory _urlToQuery,35 string memory _attributeToFetch36 )37 public38 {39 uint length = requests.push(Request(currentId, _urlToQuery, _attributeToFetch, ""));40 Request storage r = requests[length-1];4142 // osadzony adres wyroczni43 r.quorum[address(0x6c2339b46F41a06f09CA0051ddAD54D1e582bA77)] = 1;44 r.quorum[address(0xb5346CF224c02186606e5f89EACC21eC25398077)] = 1;45 r.quorum[address(0xa2997F1CA363D11a0a35bB1Ac0Ff7849bc13e914)] = 1;4647 // uruchomienie zdarzenia do wykrycia poza blockchainem48 emit NewRequest (49 currentId,50 _urlToQuery,51 _attributeToFetch52 );5354 // zwiększanie id żądania55 currentId++;56 }5758 //wywołane przez wyrocznię, aby zarejestrować jej odpowiedź59 function updateRequest (60 uint _id,61 string memory _valueRetrieved62 ) public {6364 Request storage currRequest = requests[_id];6566 //sprawdzenie, czy wyrocznia jest na liście zaufanych wyroczni67 //i czy wyrocznia jeszcze nie głosowała68 if(currRequest.quorum[address(msg.sender)] == 1){6970 //oznaczenie, że ten adres głosował71 currRequest.quorum[msg.sender] = 2;7273 //iteracyjne przejście przez "tablicę" odpowiedzi do czasu uzyskania wolnej pozycji i zapisanie pobranej wartości74 uint tmpI = 0;75 bool found = false;76 while(!found) {77 //find first empty slot78 if(bytes(currRequest.anwers[tmpI]).length == 0){79 found = true;80 currRequest.anwers[tmpI] = _valueRetrieved;81 }82 tmpI++;83 }8485 uint currentQuorum = 0;8687 //iteracyjne przejście przez listę wyroczni i sprawdzenie, czy ich liczba jest wystarczająca(minimalne kworum)88 //głosowały na tę samą odpowiedź jak bieżąca89 for(uint i = 0; i < totalOracleCount; i++){90 bytes memory a = bytes(currRequest.anwers[i]);91 bytes memory b = bytes(_valueRetrieved);9293 if(keccak256(a) == keccak256(b)){94 currentQuorum++;95 if(currentQuorum >= minQuorum){96 currRequest.agreedValue = _valueRetrieved;97 emit UpdatedRequest (98 currRequest.id,99 currRequest.urlToQuery,100 currRequest.attributeToFetch,101 currRequest.agreedValue102 );103 }104 }105 }106 }107 }108}Pokaż wszystkoKopiuj
Ucieszyłaby nas większa ilość dokumentacji dotyczącej tworzenia inteligentnych kontraktów z wykorzystaniem wyroczni. Jeśli możesz pomóc, utwórz PR!
Dalsza lektura
- Zdecentralizowane wyrocznie: kompleksowy przegląd(opens in a new tab) – Julien Thevenard
- Wdrażanie wyroczni blockchainu w Ethereum(opens in a new tab) – Pedro Costa