Ana içeriğe geç

Oracles

Son düzenleme: , Invalid DateTime

Kâhinler, akıllı sözleşmelerinizdeki verileri sorgulayabilmeniz için Ethereum'u zincir dışı ve gerçek dünya bilgilerine bağlayan veri akışlarıdır. Örneğin, tahmin piyasası uygulamaları, olaylara dayalı olarak ödemeleri tamamlamak için kâhinleri kullanır. Bir tahmin piyasası, Amerika Birleşik Devletleri'nin bir sonraki başkanına ETH'nize bahse girmenizi isteyebilir. Sonucu onaylamak ve kazananlara ödeme yapmak için bir kâhin kullanırlar.

Ön koşullar

Düğümlere, mutabakat mekanizmalarına ve özellikle olaylar olmak üzere akıllı sözleşme anatomisine aşina olduğunuzdan emin olun.

Kâhin nedir

Kâhin, blok zinciri ile gerçek dünya arasında bir köprüdür. Akıllı sözleşmelerinize bilgi almak için sorgulayabileceğiniz zincir üstü API görevi görürler. Bu, fiyat bilgisinden hava durumu raporlarına kadar her şey olabilir. Kâhinler, verileri gerçek dünyaya "göndermek" için iki yönlü olarak da kullanılabilir.

Patrick'in Kâhinler hakkındaki açıklamasını izleyin:

Bunlar neden gereklidir?

Ethereum gibi bir blok zinciri ile her işlemi tekrar yapmak ve aynı sonucu garanti etmek için ağdaki her düğüme ihtiyacınız vardır. API'ler potansiyel olarak değişken veriler sunar. Bir fiyat API'si kullanarak kabul edilmiş bir $USD değerine dayalı olarak ETH gönderiyorsanız, sorgu bir günden diğerine farklı bir sonuç döndürür. Ayrıca API hack'lenebilir veya kullanımdan kaldırılabilir. Bu olursa, ağdaki düğümler Ethereum'un mevcut durumu üzerinde anlaşamaz ve mutabakatı etkin bir şekilde bozar.

Kâhinler, bu sorunu verileri blok zincirine göndererek çözer. Bu nedenle, işlemi yeniden yürüten herhangi bir düğüm, herkesin görmesi için gönderilen aynı değişmez verileri kullanacaktır. Bunu yapmak için, bir kâhin tipik olarak bir akıllı sözleşmeden ve API'leri sorgulayabilen ve ardından akıllı sözleşmenin verilerini güncellemek için periyodik olarak işlemler gönderebilen bazı zincir dışı bileşenlerden oluşur.

Kâhin sorunu

Bahsettiğimiz gibi, Ethereum işlemleri zincir dışı verilere doğrudan erişemez. Aynı zamanda, veri sağlamak için tek bir gerçek kaynağına güvenmek güvenli değildir ve akıllı bir sözleşmenin merkeziyetsizliğini geçersiz kılar. Bu, kâhin problemi olarak bilinir.

Birden çok veri kaynağından veri alan merkeziyetsiz bir kâhin kullanarak Kâhin probleminden kaçınabiliriz; bir veri kaynağı saldırıya uğrarsa veya başarısız olursa, akıllı sözleşme amaçlandığı gibi çalışmaya devam eder.

Güvenlik

Bir kâhin, yalnızca kendi veri kaynakları kadar güvenlidir. Bir dapp, ETH/DAI fiyat beslemesi için bir kâhin olarak Uniswap'i kullanırsa bir saldırgan, dapp'in mevcut fiyat anlayışını manipüle etmek için Uniswap'teki fiyatı hareket ettirebilir. Bununla nasıl mücadele edileceğine dair bir örnek, MakerDAO tarafından kullanılan, sadece tek bir kaynağa güvenmek yerine birçok harici fiyat beslemelerinden fiyat verilerini toplayan bir besleme sistemidir(opens in a new tab).

Mimari

Bu, basit bir Kâhin mimarisinin bir örneğidir, ancak zincir dışı hesaplamayı tetiklemek için bundan daha fazla yol vardır.

  1. Akıllı sözleşme olayınızla bir kayıt yayınlayın
  2. Zincir dışı bir hizmet (genellikle JSON-RPC eth_subscribe komutu gibi bir şey kullanarak) bu belirli günlüklere abone olmuştur.
  3. Zincir dışı hizmet, kayıtlarda tanımlanan bazı görevleri yerine getirmeye devam eder.
  4. Zincir dışı hizmet, akıllı sözleşmeye ikincil bir işlemde istenen verilerle yanıt verir.

Verileri 1'e 1 şeklinde böyle alabilirsiniz ancak güvenliği artırmak için zincir dışı verileri toplama şeklinizi merkeziyetsizleştirmek isteyebilirsiniz.

Bir sonraki adım, farklı API'lere ve kaynaklara bu çağrıları yapan ve zincirdeki verileri toplayan bu düğümlerden oluşan bir ağa sahip olmak olabilir.

Chainlink Zincir Dışı Raporlaması(opens in a new tab) (Chainlink OCR), zincir dışı kâhin ağının birbirleriyle iletişim kurması, yanıtlarını kriptografik olarak imzalaması, yanıtlarını zincir dışı olarak toplaması ve sonuçta zincir üstünde yalnızca bir işlem göndermesi ile bu metodolojiyi geliştirdi. Bu şekilde daha az gaz harcanmasının yanı sıra her düğüm, işlemin kendi bölümünü imzaladığı ve işlemi gönderen düğüm tarafından değiştirilemez hâle getirdiği için merkeziyetsiz veri garantisine sahip olursunuz. Düğüm işlem yapmazsa yükseltme politikası devreye girer ve sonraki düğüm işlemi gönderir.

Kullanım

Chainlink gibi hizmetleri kullanarak, halihazırda gerçek dünyadan alınmış ve bir araya getirilmiş zincir üzerindeki merkeziyetsiz verileri referans verebilirsiniz. Merkeziyetsiz veriler için bir tür ortak ortak alan gibidir. Aradığınız herhangi bir özelleştirilmiş veriyi elde etmek için kendi modüler kâhin ağlarınızı da oluşturabilirsiniz. Ek olarak, zincir dışı hesaplama yapabilir ve gerçek dünyaya da bilgi gönderebilirsiniz. Chainlink şunları yapabilmeniz için altyapılara sahiptir:

Bir Chainlink fiyat beslemesi kullanarak akıllı sözleşmenizde en son ETH fiyatını nasıl alacağınıza dair bir örnek:

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
Tümünü göster
📋 Kopyala

Bunu, bu bağlantı ile remix'te test edebilirsiniz(opens in a new tab)

Belgeleri görüntüle(opens in a new tab)

Chainlink VRF (Doğrulanabilir Rastgele İşlev), akıllı sözleşmeler için tasarlanmış, kanıtlanabilir şekilde adil ve doğrulanabilir bir rastgelelik kaynağıdır. Akıllı sözleşme geliştiricileri, öngörülemeyen sonuçlara dayanan herhangi bir uygulama için güvenilir akıllı sözleşmeler oluşturmak üzere kurcalamaya karşı korumalı rastgele sayı oluşturma (RNG) olarak Chainlink VRF'yi kullanabilir:

  • Blok zinciri oyunları ve NFT'ler
  • Görevlerin ve kaynakların rastgele atanması (örneğin yargıçların davalara rastgele atanması)
  • Mutabakat mekanizmaları için temsili bir örnek seçme

Blok zincirleri deterministik olduğu için Rrastgele sayılar zordur.

Chainlink Kâhinleri ile veri akışlarının dışında çalışmak, Chainlink ile çalışmanın talep ve alma döngüsünü(opens in a new tab) takip eder. Yanıtları döndürmek için Kâhin sağlayıcılarına Kâhin gazı göndermek için LINK token'ını kullanırlar. LINK token, özellikle kâhinlerle çalışmak üzere tasarlanmıştır ve ERC-20 ile geriye dönük uyumlu olan yükseltilmiş ERC-677 token'ı temel alır. Aşağıdaki kod, Kovan test ağında dağıtılırsa kriptografik olarak kanıtlanmış bir rastgele sayı alır. Talepte bulunmak için sözleşmeyi, Kovan LINK Faucet(opens in a new tab)'ten alabileceğiniz bir test ağı LINK token'ı ile finanse edin.

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
Tümünü göster

Akıllı sözleşmeler, keyfi zamanlarda veya keyfi koşullar altında kendi işlevlerini tetikleyemez veya başlatamaz. Durum değişiklikleri, yalnızca başka bir hesap bir işlem (bir kullanıcı, kâhin veya sözleşme gibi) başlattığında gerçekleşir. Chainlink Keeper Network(opens in a new tab), düzenli bakım görevlerini güvenle en aza indirilmiş ve merkeziyetsiz bir şekilde dışarıdan temin etmek için akıllı sözleşmeler için seçenekler sunar.

Chainlink Keepers'ı kullanmak için, bir akıllı sözleşme KeeperCompatibleInterface(opens in a new tab) arayüzünü sağlamalıdır, bu arayüz iki fonksiyondan oluşur:

  • checkUpkeep - Sözleşmede iş yapılmasının gerekip gerekmediğini kontrol eder.
  • performUpkeep - checkUpkeep tarafından emir verilirse işi sözleşme üzerinde gerçekleştirir.

Aşağıdaki örnek basit bir sayaç sözleşmesidir. counter değişkeni, performUpkeep öğesine yapılan her çağrıda birer birer artırılır. Sıradaki kodu Remix kullanarak deneyebilirsiniz(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. CheckData, Upkeep kaydedildiğinde tanımlanır.
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. PerformData, Keeper'ın checkUpkeep işlevinize yaptığı çağrıyla oluşturulur.
36 }
37}
38
Tümünü göster

Keeper uyumlu bir sözleşmeyi dağıttıktan sonra, sözleşmeyi Bakım(opens in a new tab) için kaydettirmeli ve sözleşmeniz hakkında Keeper Network'ü bilgilendirmek amacıyla LINK ile bunu finans etmelisiniz, böylece işiniz sürekli olarak yapılır.

Keepers projeleri

Chainlink API Çağrıları(opens in a new tab), web'in geleneksel şekilde çalıştığı şekilde zincir dışı dünyadan veri almanın en kolay yoludur: API çağrıları. Bunun tek bir örneğini yapmak ve tek bir kâhine sahip olmak, bunu doğası gereği merkezileştirir. Bir akıllı sözleşme platformunun, gerçekten merkeziyetsiz şekilde kalmak için bir harici veri pazarında(opens in a new tab) bulunan çok sayıda düğümü kullanması gerekir.

Test etmek için aşağıdaki kodu kovan ağında remix'te dağıtın(opens in a new tab)

Bu aynı zamanda kâhinlerin talep ve alma döngüsünü de takip eder ve çalışması için Kovan LINK (kâhin gazı) ile finanse edilecek sözleşmeye ihtiyaç duyar.

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
Tümünü göster

Chainlink geliştiricileri bloğunu(opens in a new tab) okuyarak Chainlink uygulamaları hakkında daha fazla bilgi edinebilirsiniz.

Kâhin hizmetleri

Bir Kâhin akıllı sözleşmesi oluşturun

İşte Pedro Costa'nın örnek bir kâhin sözleşmesi. Ethereum'da Blok Zinciri Kâhin Uygulaması(opens in a new tab) makalesinde daha fazla açıklama bulabilirsiniz.

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}
110
Tümünü göster
📋 Kopyala

Bir Kâhin akıllı sözleşmesi oluşturmaya ilişkin daha fazla belgeye sahip olmak istiyoruz. Yardım edebilecekseniz, bir PR oluşturun!

Daha fazla bilgi

Makaleler

Videolar

Öğreticiler

Bu makale yararlı oldu mu?