溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

區(qū)塊鏈Oracle預(yù)言機(jī)實(shí)現(xiàn)方法是什么

發(fā)布時(shí)間:2021-12-29 14:18:03 來源:億速云 閱讀:151 作者:iii 欄目:互聯(lián)網(wǎng)科技

本篇內(nèi)容主要講解“區(qū)塊鏈Oracle預(yù)言機(jī)實(shí)現(xiàn)方法是什么”,感興趣的朋友不妨來看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“區(qū)塊鏈Oracle預(yù)言機(jī)實(shí)現(xiàn)方法是什么”吧!

1、為什么智能合約需要預(yù)言機(jī)/Oracle?

在智能合約中執(zhí)行的邏輯不可以執(zhí)行區(qū)塊鏈之外的任何操作,例如它不可以訪問互聯(lián)網(wǎng)上的web服務(wù)。外部數(shù)據(jù)進(jìn)入智能合約的唯一方法是將其置入一個(gè)交易中,通過向系統(tǒng)發(fā)送一個(gè)新的交易來觸發(fā)區(qū)塊鏈狀態(tài)的更新。

試著考慮一下,如果智能合約在執(zhí)行時(shí)可以訪問外部的一個(gè)API來獲取數(shù)據(jù),會(huì)出現(xiàn)什么情況?

如果今天部署這個(gè)合約,那么API可能會(huì)返回如下的數(shù)據(jù):

{ "foo": "bar" }

但是明天再部署時(shí),API可能就會(huì)返回新的數(shù)據(jù),例如:

{ "foo": "baz" }

那么可以想像,一個(gè)月以后如果有人進(jìn)行以太坊區(qū)塊鏈的同步,這個(gè)智能合約就會(huì)被執(zhí)行,但是API的響應(yīng)數(shù)據(jù)是和一個(gè)月之前不同的,這就會(huì)導(dǎo)致新同步的 區(qū)塊鏈狀態(tài)不同于之前已經(jīng)存在的節(jié)點(diǎn)狀態(tài)。

這就不再是完全自確定的區(qū)塊鏈了。經(jīng)歷相同的同步過程,我的區(qū)塊鏈和你的區(qū)塊鏈卻不一樣!

讓我們?cè)贀Q個(gè)說法:給定一組區(qū)塊,一個(gè)節(jié)點(diǎn)必須能夠從零開始重現(xiàn)區(qū)塊鏈的最終狀態(tài),而無需互聯(lián)網(wǎng)連接。

那么這一點(diǎn)對(duì)于智能合約的開發(fā)者意味著什么?Oralce(預(yù)言機(jī)),開發(fā)者必須構(gòu)造一個(gè)預(yù)言機(jī)來和實(shí)現(xiàn)智能合約與外部世界的交互。

2、如何實(shí)現(xiàn)一個(gè)簡(jiǎn)單的預(yù)言機(jī)/Oracle?

現(xiàn)在讓我們創(chuàng)建一個(gè)簡(jiǎn)單的預(yù)言機(jī)/Oracle,來將外部的天氣數(shù)據(jù)傳入智能合約:

區(qū)塊鏈Oracle預(yù)言機(jī)實(shí)現(xiàn)方法是什么

在最底層的區(qū)塊鏈平臺(tái),我們需要部署一個(gè)智能合約,這個(gè)合約有一個(gè)方法updateWeather()用來更新天氣狀態(tài),只有在合約白名單里的地址才可以調(diào)用這個(gè)方法。updateWeather方法接受天氣數(shù)據(jù)作為參數(shù),同時(shí)觸發(fā)一個(gè)以太坊合約事件并將天氣數(shù)據(jù)作為事件的參數(shù),這樣JavaScript應(yīng)用就可以訂閱這個(gè)事件并獲得異步通知了。

同時(shí)我們將創(chuàng)建兩個(gè)nodejs進(jìn)程,其中之一就是預(yù)言機(jī)/Oracle,它的實(shí)現(xiàn)邏輯就是周期性地輪詢第三方天氣API來獲取天氣數(shù)據(jù),然后將天氣數(shù)據(jù)提交給智能合約以便進(jìn)行歷史審計(jì)。

另一個(gè)nodejs進(jìn)程則負(fù)責(zé)訂閱智能合約的天氣事件,然后在控制臺(tái)輸出事件參數(shù)。正如之前所述,每當(dāng)預(yù)言機(jī)/Oracle調(diào)用合約的updateWeather()方法時(shí),都會(huì)觸發(fā)天氣事件。

需要指出的是,為了便于理解預(yù)言機(jī)的核心實(shí)現(xiàn)思路,下面的代碼進(jìn)行了簡(jiǎn)化,剔除了必要的錯(cuò)誤處理,因此并不適用于生產(chǎn)環(huán)境。

源代碼在這里:

  • 預(yù)言機(jī)合約 - https://github.com/decentorganization/weather-oracle-contract

  • 預(yù)言機(jī)服務(wù) - https://github.com/decentorganization/weather-oracle-service

接下來我們?cè)敿?xì)講解這個(gè)簡(jiǎn)單的預(yù)言機(jī)的實(shí)現(xiàn)。

3、預(yù)言機(jī)智能合約實(shí)現(xiàn)

智能合約有一個(gè)公開的oracleAddress狀態(tài)變量,用來表示允許調(diào)用智能合約的updateWeather方法的賬戶地址,我們?cè)跇?gòu)造函數(shù)中對(duì)其進(jìn)行賦值:

contract WeatherOracle {  
  address public oracleAddress;
  
  constructor (address _oracleAddress) public {
    oracleAddress = _oracleAddress;
  }
  
  // ...
}

接下來我們要定義天氣事件,這個(gè)事件將在weatherUpdate()調(diào)用成功時(shí)觸發(fā)。同樣為了簡(jiǎn)化,我們讓這個(gè)事件簡(jiǎn)單的附帶一個(gè)表示溫度的字符串參數(shù)。

event WeatherUpdate (string temperature);

最后我們要實(shí)現(xiàn)updateWeather()方法。它的可見性為public,意思是可以從外部調(diào)用這個(gè)方法:

function updateWeather (string temperature) public {
    require(msg.sender == oracleAddress);
    emit WeatherUpdate (temperature);
  }

請(qǐng)注意require語句。只有當(dāng)調(diào)用地址(msg.sender)和白名單地址(oracleAddress)一致時(shí)才允許繼續(xù)執(zhí)行該方法,否則將回滾交易。

好了,就這么簡(jiǎn)單。

4、預(yù)言機(jī)服務(wù)

我們的預(yù)言機(jī)就是一個(gè)簡(jiǎn)單的nodejs服務(wù)。它使用request庫來調(diào)用外部天氣API,解析API的響應(yīng),然后構(gòu)造并提交交易給智能合約,然后等一會(huì)兒,重復(fù)上面的工作,如此 周而復(fù)始。

讓我們從訪問API開始,我們將API的地址放在一個(gè)環(huán)境變量里,以便在開發(fā)/生產(chǎn)環(huán)境切換時(shí)避免修改源代碼:

const options = { uri: process.env.WEATHER_URL, json: true };
const start = () => {
  request(options)
  .then(parseData)
  .then(updateWeather)
  .then(restart)
  .catch(error);
};

下面的代碼用來解析API的響應(yīng)結(jié)果:

const parseData = (body) => {
  return new Promise((resolve, reject) => {
    const temperature = body.main.temp.toString();
    resolve({ temperature });
  });
};

現(xiàn)在要做的就是構(gòu)造一個(gè)調(diào)用智能合約的updateWeather()方法的以太坊交易。注意account()是一個(gè)異步方法,它的作用是載入一個(gè)以太坊賬戶,contract是一個(gè)js 對(duì)象,它包含了之前部署的WeatherOracle智能合約的部署地址和ABI接口數(shù)據(jù)。這些與智能合約相關(guān)的函數(shù)都來自于著名的web3開發(fā)包:)

const updateWeather = ({ temperature }) => {
  return new Promise((resolve, reject) => {
    account().then(account => {
      contract.updateWeather(temperature, { from: account }, (err, res) => {
        resolve(res);
      });
    });
  });
};

最后,我們只需要在指定超時(shí)后重新啟動(dòng)這個(gè)過程即可。 wait()函數(shù)將在指定的超時(shí)時(shí)間之后解析。

const restart = () => {
  wait(process.env.TIMEOUT).then(start);
};

搞定了!上面的代碼實(shí)現(xiàn)了一個(gè)簡(jiǎn)單服務(wù),它可以從API獲取數(shù)據(jù),然后再輸入智能合約。

注意:

  • 當(dāng)我們構(gòu)造以太坊交易時(shí),我們使用{from:account}來指定調(diào)用賬戶,account所指向的這個(gè)賬戶需要有一些以太幣來支付交易的手續(xù)費(fèi)。

  • 我們使用環(huán)境變量來配置一個(gè)私鑰,用來實(shí)例化account對(duì)象。這個(gè)私鑰必須是用來部署WeatherOracle智能合約時(shí)傳入的那個(gè)白名單地址所對(duì)應(yīng)的私鑰。

5、天氣事件的利用服務(wù)

這是另一個(gè)簡(jiǎn)單的nodejs服務(wù)。同樣,contract是一個(gè)包含了合約的部署地址和ABI信息的js對(duì)象,調(diào)用WeatherUpdate并傳入一個(gè)回調(diào)就是我們訂閱天氣事件的所有代碼:

const consume = () => {
  contract.WeatherUpdate((error, result) => {
    console.log("NEW WEATHER DATA EVENT ON SMART CONTRACT");
    console.log("BLOCK NUMBER: ");
    console.log("  " + result.blockNumber)
    console.log("WEATHER DATA: ");
    console.log(result.args);
    console.log("\n");
  });
}

當(dāng)這個(gè)服務(wù)運(yùn)行時(shí),隨著交易成功入塊上鏈,它將會(huì)周期性地向控制臺(tái)輸出數(shù)據(jù):

NEW WEATHER DATA EVENT ON SMART CONTRACT
BLOCK NUMBER:
  3424586
WEATHER DATA:
{ temperature: '74.75' }

到此,相信大家對(duì)“區(qū)塊鏈Oracle預(yù)言機(jī)實(shí)現(xiàn)方法是什么”有了更深的了解,不妨來實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細(xì)節(jié)
AI