當前位置:首頁 > 物聯(lián)網(wǎng) > 區(qū)塊鏈
[導讀] Chainlink基本原理 本文我們來從技術(shù)上簡述一下Chainlink的基本原理。如果用最短的一句話解釋什么是Chainlink,可以說Chainlink一個去中心化的預言機項目,所以

Chainlink基本原理

本文我們來從技術(shù)上簡述一下Chainlink的基本原理。如果用最短的一句話解釋什么是Chainlink,可以說Chainlink一個去中心化的預言機項目,所以為了理解Chainlink的工作原理,我們首先要明白什么是預言機。

預言機

預言機的英文為Oracle,和著名的數(shù)據(jù)庫服務(wù)提供商Oracle(甲骨文)重名,但是兩者除了名字相同以為并沒有任何關(guān)系。Oracle這個單詞是什么意思,下面是我在vocabulary.com上查到的Oracle的含義:

Back in ancient times, an oracle was someone who offered advice or a prophecy thought to have come directly from a divine source. In modern usage, any good source of informaTIon can be called an oracle.

中文的大概意思是:在古代,oracle是一個提出建議或預言的人,他的建議或預言被認為是直接來自于神。在現(xiàn)代用法中,任何好的信息來源都可以稱為oracle。

這樣就不難理解了,Oracle傳達了萬能全知的神的旨意,而甲骨文最初就是用來占卜吉兇時的記錄,也在當時也被認為是神諭,傳達了神的意思。所以不管是“預言機”還是“甲骨文”都表達了“信息源”的意思。

計算機領(lǐng)域內(nèi)的預言機一詞,最早是圖靈提出的。圖靈在圖靈機(Turing Machine)的基礎(chǔ)上,加入了一個稱為預言者(oracle)的黑盒,組成了預言機(Oracle Machine)。所謂預言者,是一個可以回答特定問題集合的實體。即它可以向圖靈機系統(tǒng)內(nèi)部輸入信息,幫助圖靈機完成運算。以太坊的智能合約是“圖靈完備(Turing Complete)”的,某種意義上可以看做一個圖靈機,所以以太坊的設(shè)計者借鑒這個概念,把向“圖靈完備的智能合約”這個圖靈機輸入信息的也被稱為預言機oracle。所以說“預言機”這個名字并不是區(qū)塊鏈技術(shù)領(lǐng)域內(nèi)的獨創(chuàng)概念,它來源于非常早期的計算機抽象設(shè)計,在密碼學等領(lǐng)域內(nèi)也都有類似的概念。

而在區(qū)塊鏈領(lǐng)域,預言機被認為是可以為智能合約提供外部數(shù)據(jù)源的系統(tǒng)。從傳統(tǒng)技術(shù)架構(gòu)方面來看,預言機是連接智能合約與區(qū)塊鏈外部世界的中間件(middleware),是區(qū)塊鏈重要的基礎(chǔ)設(shè)施,它的作用是為區(qū)塊鏈上的智能合約(Smart Contract)提供數(shù)據(jù)信息的。

正如以太坊的定義,區(qū)塊鏈是一個交易驅(qū)動的狀態(tài)機(a transacTIon-based state machine),它能做的事情非常簡單,就是通過向區(qū)塊鏈提交事務(wù)/交易(transacTIon),來將區(qū)塊鏈從一個狀態(tài)轉(zhuǎn)變成另一個狀態(tài)。為了保持共識,EVM的執(zhí)行過程必須完全確定,并且僅基于以太坊狀態(tài)和簽名交易的共享上下文。這產(chǎn)生了兩個特別重要的后果:一個是EVM和智能合約沒有內(nèi)在的隨機性來源;另一個是外部數(shù)據(jù)只能作為交易的數(shù)據(jù)載荷引入。用通俗的話講,區(qū)塊鏈沒有主動獲取數(shù)據(jù)的能力,它能用的只有區(qū)塊鏈自己本身的數(shù)據(jù)。數(shù)據(jù)的缺失導致智能合約的應(yīng)用范圍非常少,目前大部分的應(yīng)用都是圍繞著token來展開的。

區(qū)塊鏈的確定性的意思是,在任何節(jié)點上,只要連入到區(qū)塊鏈的分布式網(wǎng)絡(luò)中,它就可以同步所有的歷史區(qū)塊,回放出一套完全相同的賬本。換句話說:在沒有互聯(lián)網(wǎng)連接的情況下,給定完整的塊,節(jié)點必須能夠從頭開始重新創(chuàng)建區(qū)塊鏈的最終狀態(tài)。如果賬本在形成過程中,依賴于某個外部的API調(diào)用結(jié)果,那在不同時間不同環(huán)境下回放的結(jié)果就會不一樣。這種情況是區(qū)塊鏈所不允許的,所以區(qū)塊鏈在設(shè)計之初就沒有網(wǎng)絡(luò)調(diào)用。

那么要實現(xiàn)向區(qū)塊鏈提供數(shù)據(jù),應(yīng)該怎么做呢?區(qū)塊鏈能留下的只有賬本,而區(qū)塊鏈所能輸入的只有交易。我們就從這兩個方面入手。

幾乎每一個合約系統(tǒng),都會有事件記錄的功能,比如以太坊中的EventLog功能。

下面我們通過一個例子,來介紹一下預言機的基本原理。我們在以太坊鏈上建立一個用戶合約,它需要獲取到某個城市的氣溫數(shù)據(jù)。當然,智能合約自己是無法獲取到這個發(fā)生于鏈下真實世界中的數(shù)據(jù)信息的,需要借助預言機來實現(xiàn)。智能合約將需要獲取天氣溫度的的城市寫入到EventLog中,鏈下我們會啟動一個進程,監(jiān)聽并訂閱這個事件日志,獲取到智能合約的請求之后,將指定城市的溫度,通過提交transacTIon的方式,調(diào)用合約中的回填方法,提交到智能合約中。

聲明:以下代碼僅供演示預言機原理,沒有做參數(shù)檢測和錯誤處理,請不要在生產(chǎn)環(huán)境中使用。

消費者合約:

contract WeatherOracle {

// 用戶存儲預言機提交的天氣數(shù)值

uint256 public temperature;

// 定義事件

event RequestTemperature (bytes city);

// 發(fā)出獲取請求,即發(fā)出一個事件日志

function requestTemperature (string memory _city) public {

emit RequestTemperature(bytes(_city));

}

// 預言機回調(diào)方法,預言機獲取到數(shù)據(jù)后通過這個方法將數(shù)據(jù)提交到鏈上

function updateWeather (uint256 _temperature) public {

temperature = _temperature;

}

}

上面的代碼非常簡單,定義了一個變量用來存儲結(jié)果,一個方法用于發(fā)出請求,一個方法用于接收結(jié)果。

鏈下,我們啟動一個進程,以訂閱topic的方式獲取日志信息,之后通過構(gòu)建一個transaction,提交一個結(jié)果到合約中。

func SubscribeEventLog() {

topic := crypto.Keccak256([]byte(“RequestTemperature(bytes)”))

query := ethereum.FilterQuery{

Topics: [][]common.Hash{

{

common.BytesToHash(topic),

},

},

}

// 訂閱相關(guān)主題的日志事件

events := make(chan types.Log)

sub, err := EthClient.SubscribeFilterLogs(ctx, query, events)

// 加載合約的ABI文件

ta, err := abi.JSON(strings.NewReader(AbiJsonStr))

// 監(jiān)聽事件訂閱

for {

select {

case err := 《-sub.Err():

log.Error(err)

break

case ev := 《-events:

// 獲取到訂閱的消息

ej, _ := ev.MarshalJSON()

log.Info(string(ej))

// 解析數(shù)據(jù)

var sampleEvent struct {

City []byte

}

err = ta.Unpack(&sampleEvent, “RequestTemperature”, ev.Data)

log.Info(string(sampleEvent.City))

// 構(gòu)建交易提交結(jié)果,需要提供私鑰用于簽署交易

CallContract(“b7b502b.。.164b42c”)

}

}

}

func CallContract(keyStr string) {

addr := PrivateKeyToAddress(keyStr)

nonce, err := EthClient.PendingNonceAt(ctx, addr)

gasPrice, err := EthClient.SuggestGasPrice(ctx)

privateKey, err := crypto.HexToECDSA(keyStr)

auth := bind.NewKeyedTransactor(privateKey)

auth.Nonce = big.NewInt(int64(nonce))

auth.Value = big.NewInt(0)

auth.GasLimit = uint64(300000)

auth.GasPrice = gasPrice

instance, err := event.NewEvent(common.HexToAddress(“0x8A421906e9562AA1c71e5a32De1cf75161C5A463”), EthClient)

// 調(diào)用合約中的updateWeather方法,回填數(shù)據(jù)“29”

tx, err := instance.UpdateWeather(auth, big.NewInt(29))

log.Info(tx.Hash().Hex())

}

用一個圖來展示這個過程:

Chainlink

Chainlink是一個去中心化的預言機項目,它的作用就是以最安全的方式向區(qū)塊鏈提供現(xiàn)實世界中產(chǎn)生的數(shù)據(jù)。Chainlink在基本的預言機原理的實現(xiàn)方式之上,圍繞LINK token通過經(jīng)濟激勵建立了一個良性循環(huán)的生態(tài)系統(tǒng)。Chainlink預言機需要通過LINK token的轉(zhuǎn)賬來實現(xiàn)觸發(fā)。

LINK是以太坊網(wǎng)絡(luò)上的ERC677合約,關(guān)于各類ERC token的區(qū)別,請參考這篇文章。

在《精通以太坊(Matering Ethereum)》一書中,提出了三種預言機的設(shè)計模式,分別是

· 立即讀取(immediate-read)

· 發(fā)布/訂閱(publish–subscribe)

· 請求/響應(yīng)(request–response)

而基于LINK ERC677 token完成的預言機功能,就屬于其中的請求/響應(yīng)模式。這是一種較為復雜的模式,上圖中展示的是一個不含有聚合過程的簡單請求/相應(yīng)流程。

我們以Chainlink提供的TestnetConsumer合約中的一個requestEthereumPrice 方法為例來簡單講一下請求響應(yīng)的流程。這個函數(shù)定義如下:

function requestEthereumPrice(address _oracle, string _jobId)

public

onlyOwner

{

Chainlink.Request memory req = buildChainlinkRequest(stringToBytes32(_jobId), this, this.fulfillEthereumPrice.selector);

req.add(“get”, “https://min-api.cryptocompare.com/data/price?fsym=ETH&tsyms=USD”);

req.add(“path”, “USD”);

req.addInt(“times”, 100);

sendChainlinkRequestTo(_oracle, req, ORACLE_PAYMENT);

}

它所實現(xiàn)的功能就是從指定的API(cryptocompare)獲取ETH/USD的交易價格。函數(shù)傳入的參數(shù)是指定的oracle地址和jobId。

將一些列的請求參數(shù)組好后,調(diào)用sendChainlinkRequestTo 方法將請求發(fā)出。sendChainlinkRequestTo是定義在Chainlink提供的庫中的一個接口方法,定義如下:

/**

* @notice 向指定的oracle地址創(chuàng)建一個請求

* @dev 創(chuàng)建并存儲一個請求ID, 增加本地的nonce值, 并使用`transferAndCall` 方法發(fā)送LINK,

* 創(chuàng)建到目標oracle合約地址的請求

* 發(fā)出 ChainlinkRequested 事件。

* @param _oracle 發(fā)送請求至的oracle地址

* @param _req 完成初始化的Chainlink請求

* @param _payment 請求發(fā)送的LINK數(shù)量

* @return 請求 ID

*/

function sendChainlinkRequestTo(address _oracle, Chainlink.Request memory _req, uint256 _payment)

internal

returns (bytes32 requestId)

{

requestId = keccak256(abi.encodePacked(this, requests));

_req.nonce = requests;

pendingRequests[requestId] = _oracle;

emit ChainlinkRequested(requestId);

require(link.transferAndCall(_oracle, _payment, encodeRequest(_req)), “unable to transferAndCall to oracle”);

requests += 1;

return requestId;

}

其中l(wèi)ink.transferAndCall方法即是ERC677定義的token轉(zhuǎn)賬方法,與ERC20的transfer方法相比,它多了一個data字段,可以在轉(zhuǎn)賬的同時攜帶數(shù)據(jù)。這里就將之前打包好的請求數(shù)據(jù)放在了data字段,跟隨轉(zhuǎn)賬一起發(fā)送到了oracle合約。transferAndCall 方法定義如下:

/**

* @dev 將token和額外數(shù)據(jù)一起轉(zhuǎn)移給一個合約地址

* @param _to 轉(zhuǎn)移到的目的地址

* @param _value 轉(zhuǎn)移數(shù)量

* @param _data 傳遞給接收合約的額外數(shù)據(jù)

*/

function transferAndCall(address _to, uint _value, bytes _data)

public

returns (bool success)

{

super.transfer(_to, _value);

Transfer(msg.sender, _to, _value, _data);

if (isContract(_to)) {

contractFallback(_to, _value, _data);

}

return true;

}

其中的Transfer(msg.sender, _to, _value, _data);是發(fā)出一個事件日志:

event Transfer(address indexed from, address indexed to, uint value, bytes data);

將這次轉(zhuǎn)賬的詳細信息(發(fā)送方、接收方、金額、數(shù)據(jù))記錄到日志中。

Oracle合約在收到轉(zhuǎn)賬之后,會觸發(fā)onTokenTransfer方法,該方法會檢查轉(zhuǎn)賬的有效性,并通過發(fā)出OracleRequest事件記錄更為詳細的數(shù)據(jù)信息:

event OracleRequest(

bytes32 indexed specId,

address requester,

bytes32 requestId,

uint256 payment,

address callbackAddr,

bytes4 callbackFunctionId,

uint256 cancelExpiration,

uint256 dataVersion,

bytes data

);

這個日志會在oracle合約的日志中找到,如圖中下方所示。鏈下的節(jié)點會訂閱該主題的日志,在獲取到記錄的日志信息之后,節(jié)點會解析出請求的具體信息,通過網(wǎng)絡(luò)的API調(diào)用,獲取到請求的結(jié)果。之后通過提交事務(wù)的方式,調(diào)用Oracle合約中的fulfillOracleRequest方法,將數(shù)據(jù)提交到鏈上。fulfillOracleRequest定義如下:

/**

* @notice 由Chainlink節(jié)點調(diào)用來完成請求

* @dev 提交的參數(shù)必須是`oracleRequest`方法所記錄的哈希參數(shù)

* 將會調(diào)用回調(diào)地址的回調(diào)函數(shù),`require`檢查時不會報錯,以便節(jié)點可以獲得報酬

* @param _requestId 請求ID必須與請求者所匹配

* @param _payment 為Oracle發(fā)放付款金額 (以wei為單位)

* @param _callbackAddress 完成方法的回調(diào)地址

* @param _callbackFunctionId 完成方法的回調(diào)函數(shù)

* @param _expiration 請求者可以取消之前節(jié)點應(yīng)響應(yīng)的到期時間

* @param _data 返回給消費者合約的數(shù)據(jù)

* @return 外部調(diào)用成功的狀態(tài)值

*/

function fulfillOracleRequest(

bytes32 _requestId,

uint256 _payment,

address _callbackAddress,

bytes4 _callbackFunctionId,

uint256 _expiration,

bytes32 _data

external

onlyAuthorizedNode

isValidRequest(_requestId)

returns (bool)

{

bytes32 paramsHash = keccak256(

abi.encodePacked(

_payment,

_callbackAddress,

_callbackFunctionId,

_expiration

);

require(commitments[_requestId] == paramsHash, “Params do not match request ID”);

withdrawableTokens = withdrawableTokens.add(_payment);

delete commitments[_requestId];

require(gasleft() 》= MINIMUM_CONSUMER_GAS_LIMIT, “Must provide consumer enough gas”);

// All updates to the oracle‘s fulfillment should come before calling the

// callback(addr+functionId) as it is untrusted.

// See: https://solidity.readthedocs.io/en/develop/security-considerations.html#use-the-checks-effects-interactions-pattern

return _callbackAddress.call(_callbackFunctionId, _requestId, _data); // solhint-disable-line avoid-low-level-calls

}

這個方法會在進行一系列的檢驗之后,會將結(jié)果通過之前記錄的回調(diào)地址與回調(diào)函數(shù),返回給消費者合約:

_callbackAddress.call(_callbackFunctionId, _requestId, _data);

這樣一次請求就全部完成了。

總結(jié)

本文從預言機的概念開始,通過一個簡單的獲取ETH價格的例子,講解了請求/響應(yīng)模式的Chainlink預言機的基本過程,希望對你理解預言機與Chainlink的運行原理有所幫助。

本站聲明: 本文章由作者或相關(guān)機構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內(nèi)容真實性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫毥谦F公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

加利福尼亞州圣克拉拉縣2024年8月30日 /美通社/ -- 數(shù)字化轉(zhuǎn)型技術(shù)解決方案公司Trianz今天宣布,該公司與Amazon Web Services (AWS)簽訂了...

關(guān)鍵字: AWS AN BSP 數(shù)字化

倫敦2024年8月29日 /美通社/ -- 英國汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動 BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運行,同時企業(yè)卻面臨越來越多業(yè)務(wù)中斷的風險,如企業(yè)系統(tǒng)復雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報道,騰訊和網(wǎng)易近期正在縮減他們對日本游戲市場的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會開幕式在貴陽舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導體

8月28日消息,在2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機 衛(wèi)星通信

要點: 有效應(yīng)對環(huán)境變化,經(jīng)營業(yè)績穩(wěn)中有升 落實提質(zhì)增效舉措,毛利潤率延續(xù)升勢 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競爭力 堅持高質(zhì)量發(fā)展策略,塑強核心競爭優(yōu)勢...

關(guān)鍵字: 通信 BSP 電信運營商 數(shù)字經(jīng)濟

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺與中國電影電視技術(shù)學會聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會上宣布正式成立。 活動現(xiàn)場 NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會上,軟通動力信息技術(shù)(集團)股份有限公司(以下簡稱"軟通動力")與長三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉