Przejdź do głównej zawartości
Change page

Wyrocznie

Ostatnia edycja: @Beas(opens in a new tab), 15 listopada 2023

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ń:

Oto przykład możliwości uzyskania ostatniej ceny ETH w inteligentnym kontrakcie za pomocą kanału cenowego 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 * Sieć: Kovan
11 * Agregator: ETH/USD
12 * Adress: 0x9326BFA02ADD2366b30bacB125260Af641031331
13 */
14 constructor() public {
15 priceFeed = AggregatorV3Interface(0x9326BFA02ADD2366b30bacB125260Af641031331);
16 }
17
18 /**
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 answeredInRound
28 ) = priceFeed.latestRoundData();
29 return price;
30 }
31}
Pokaż wszystko
Kopiuj

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;
2
3contract Oracle {
4 Request[] requests; //lista żądań wprowadzonych do kontraktu
5 uint currentId = 0; //rosnący id żądania
6 uint minQuorum = 2; //minimalna liczba otrzymanych odpowiedzi przed zadeklarowaniem ostatecznego wyniku
7 uint totalOracleCount = 3; // liczba wyroczni osadzonych w kodzie źródłowym
8 // defines a general api request
9 struct Request {
10 uint id; // id żądania
11 string urlToQuery; //url API
12 string attributeToFetch; //atrybut json (klucz) do pobrania w odpowiedzi
13 string agreedValue; //wartość z klucza
14 mapping(uint => string) anwers; //odpowiedzi dostarczone przez wyrocznie
15 mapping(address => uint) quorum; //wyrocznie, które będą odpytywać odpowiedź (1=wyrocznia nie głosowała, 2=wyrocznia głosowała)
16 }
17
18 //zdarzenie wyzwalające wyrocznię poza blockchainem
19 event NewRequest (
20 uint id,
21 string urlToQuery,
22 string attributeToFetch
23 );
24
25 //wyzwalane, jeśli jest konsensus co do końcowego wyniku
26 event UpdatedRequest (
27 uint id,
28 string urlToQuery,
29 string attributeToFetch,
30 string agreedValue
31 );
32
33 function createRequest (
34 string memory _urlToQuery,
35 string memory _attributeToFetch
36 )
37 public
38 {
39 uint length = requests.push(Request(currentId, _urlToQuery, _attributeToFetch, ""));
40 Request storage r = requests[length-1];
41
42 // osadzony adres wyroczni
43 r.quorum[address(0x6c2339b46F41a06f09CA0051ddAD54D1e582bA77)] = 1;
44 r.quorum[address(0xb5346CF224c02186606e5f89EACC21eC25398077)] = 1;
45 r.quorum[address(0xa2997F1CA363D11a0a35bB1Ac0Ff7849bc13e914)] = 1;
46
47 // uruchomienie zdarzenia do wykrycia poza blockchainem
48 emit NewRequest (
49 currentId,
50 _urlToQuery,
51 _attributeToFetch
52 );
53
54 // zwiększanie id żądania
55 currentId++;
56 }
57
58 //wywołane przez wyrocznię, aby zarejestrować jej odpowiedź
59 function updateRequest (
60 uint _id,
61 string memory _valueRetrieved
62 ) public {
63
64 Request storage currRequest = requests[_id];
65
66 //sprawdzenie, czy wyrocznia jest na liście zaufanych wyroczni
67 //i czy wyrocznia jeszcze nie głosowała
68 if(currRequest.quorum[address(msg.sender)] == 1){
69
70 //oznaczenie, że ten adres głosował
71 currRequest.quorum[msg.sender] = 2;
72
73 //iteracyjne przejście przez "tablicę" odpowiedzi do czasu uzyskania wolnej pozycji i zapisanie pobranej wartości
74 uint tmpI = 0;
75 bool found = false;
76 while(!found) {
77 //find first empty slot
78 if(bytes(currRequest.anwers[tmpI]).length == 0){
79 found = true;
80 currRequest.anwers[tmpI] = _valueRetrieved;
81 }
82 tmpI++;
83 }
84
85 uint currentQuorum = 0;
86
87 //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żąca
89 for(uint i = 0; i < totalOracleCount; i++){
90 bytes memory a = bytes(currRequest.anwers[i]);
91 bytes memory b = bytes(_valueRetrieved);
92
93 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.agreedValue
102 );
103 }
104 }
105 }
106 }
107 }
108}
Pokaż wszystko
Kopiuj

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

Czy ten artykuł był pomocny?