在本章中,我們將討論預(yù)言機(jī)(oracle),它是可以為以太坊智能合約提供外部數(shù)據(jù)源的系統(tǒng)。 “oracle”一詞來自希臘神話,代表能夠與神靈交流的人,他們可以看到未來的愿景。在區(qū)塊鏈的上下文中,預(yù)言機(jī)是一個(gè)可以回答以太坊外部問題的系統(tǒng)。在理想情況下,預(yù)言機(jī)是無信任的系統(tǒng),這意味著它們不需要被信任,因?yàn)樗鼈兪前凑杖?a target="_blank">中心化的原則運(yùn)行的。
?
為什么需要預(yù)言機(jī)?
以太坊平臺(tái)的一個(gè)關(guān)鍵組件是EVM,它能夠在分散網(wǎng)絡(luò)中的任何節(jié)點(diǎn)上執(zhí)行程序并更新受共識(shí)規(guī)則約束的以太坊狀態(tài)。為了保持共識(shí),EVM的執(zhí)行過程必須完全確定,并且僅基于以太坊狀態(tài)和簽名交易的共享上下文。這產(chǎn)生了兩個(gè)特別重要的后果:一個(gè)是EVM和智能合約沒有內(nèi)在的隨機(jī)性來源;另一個(gè)是外部數(shù)據(jù)只能作為交易的數(shù)據(jù)載荷引入。
讓我們進(jìn)一步分析這兩個(gè)后果。首先我們要理解為什么在EVM中需要禁止真正的隨機(jī)函數(shù),不讓它們?yōu)橹悄芎霞s提供隨機(jī)性。請(qǐng)考慮在執(zhí)行此類函數(shù)后對(duì)嘗試達(dá)成共識(shí)的影響:節(jié)點(diǎn)A將執(zhí)行命令并代表智能合約存儲(chǔ)3在其存儲(chǔ)中,而節(jié)點(diǎn)B執(zhí)行相同的智能合約,將存儲(chǔ)7。因此,節(jié)點(diǎn)A和節(jié)點(diǎn)B就結(jié)果狀態(tài)應(yīng)該是什么將得出不同的結(jié)論,盡管在相同的上下文中運(yùn)行完全相同的代碼。實(shí)際上,每次評(píng)估智能合約時(shí),可能會(huì)達(dá)到不同的結(jié)果狀態(tài)。因此,由于其眾多節(jié)點(diǎn)在世界各地獨(dú)立運(yùn)行,網(wǎng)絡(luò)將無法就結(jié)果狀態(tài)應(yīng)該是什么達(dá)成去中心化的共識(shí)。在實(shí)踐中,它會(huì)比這個(gè)例子復(fù)雜得多,因?yàn)榘ㄒ蕴珟呸D(zhuǎn)移在內(nèi)的連鎖效應(yīng)會(huì)以指數(shù)方式增長(zhǎng)。
注意,偽隨機(jī)函數(shù),例如加密安全哈希函數(shù)(它們是確定性的,因此實(shí)際上也是EVM的一部分),對(duì)于許多應(yīng)用來說是不夠的。假想一個(gè)猜硬幣決勝負(fù)的游戲場(chǎng)景,這個(gè)游戲依賴于扔硬幣正反面的隨意性。礦工可以輕易破解這個(gè)游戲:他們只需要打包那些對(duì)其有利的隨機(jī)結(jié)果即可。那么我們?nèi)绾谓鉀Q這個(gè)問題呢?既然所有節(jié)點(diǎn)都可以就簽名交易的內(nèi)容達(dá)成一致,那么我們就可以引入外部信息,包括隨機(jī)性、價(jià)格信息、天氣預(yù)報(bào)等,作為發(fā)送到網(wǎng)絡(luò)的交易的數(shù)據(jù)部分。但是,這些數(shù)據(jù)本身無法信任,因?yàn)樗膩碓礋o法核實(shí)。因此,我們剛剛并沒有完全解決這個(gè)問題。我們使用預(yù)言機(jī)嘗試解決這些問題,在本章的其余部分將詳細(xì)討論這些問題。
預(yù)言機(jī)的應(yīng)用場(chǎng)景和示例
理想情況下,預(yù)言機(jī)提供了一種無信任(或至少近乎無信任)的方式來獲取外在的(即“真實(shí)世界”或“鏈外”)信息,例如足球比賽的結(jié)果、黃金的價(jià)格或真正的隨機(jī)數(shù)字,用于以太坊平臺(tái)上的智能合約。它們還可用于直接將數(shù)據(jù)安全地中繼到DApp前端。因此,可以將預(yù)言機(jī)視為彌合鏈外世界與智能合約之間差距的機(jī)制。允許智能合約基于真實(shí)世界的事件和數(shù)據(jù)來強(qiáng)制執(zhí)行合約關(guān)系,從而大大擴(kuò)展了它們的范圍。但是,這也會(huì)給以太坊的安全模型帶來外部風(fēng)險(xiǎn)。考慮一個(gè)“智能遺囑”合約——當(dāng)一個(gè)人去世時(shí)分配資產(chǎn)。這是智能合約領(lǐng)域中經(jīng)常討論的內(nèi)容,并突出了可信任的預(yù)言機(jī)的風(fēng)險(xiǎn)。如果由這樣的合約控制的繼承金額足夠高,那么在所有者死亡之前攻擊預(yù)言機(jī)(發(fā)出假的死訊)并觸發(fā)資產(chǎn)分配的動(dòng)機(jī)是非常強(qiáng)烈的。
請(qǐng)注意,某些預(yù)言機(jī)提供針對(duì)特定私有數(shù)據(jù)源的數(shù)據(jù),例如學(xué)術(shù)證書或政府ID。這些數(shù)據(jù)的來源,如大學(xué)或政府部門,是完全可信的,數(shù)據(jù)的真實(shí)性是主觀的(真相只能通過來源的權(quán)威來確定)。因此,不能無信地提供這樣的數(shù)據(jù),即不信任來源,因?yàn)闆]有獨(dú)立可驗(yàn)證的客觀事實(shí)。因此,我們將這些數(shù)據(jù)源包含在我們對(duì)預(yù)言機(jī)的定義中,因?yàn)樗鼈冞€為智能合約提供了數(shù)據(jù)橋梁。它們提供的數(shù)據(jù)通常采用證明的形式,如護(hù)照或成就記錄。“證言”將成為未來區(qū)塊鏈平臺(tái)成功的重要組成部分,特別是在驗(yàn)證身份或聲譽(yù)的相關(guān)問題方面,因此探索區(qū)塊鏈平臺(tái)如何為其提供服務(wù)非常重要。
可能由預(yù)言機(jī)提供的更多數(shù)據(jù)示例包括:
· 物理隨機(jī)數(shù)源或熵源(例如量子現(xiàn)象或熱現(xiàn)象):如在彩票智能合約中公平地選出獲獎(jiǎng)?wù)摺?/p>
· 與自然災(zāi)害相關(guān)的參數(shù)觸發(fā)器:觸發(fā)大型自然災(zāi)害債券智能合約(例如地震的里氏震級(jí)測(cè)量債券)。
· 匯率數(shù)據(jù):例如讓加密貨幣與法定貨幣精確掛鉤。
· 資本市場(chǎng)數(shù)據(jù):例如為一攬子代幣化資產(chǎn)或證券定價(jià)。
· 指標(biāo)引用數(shù)據(jù):例如將利率納入智能金融衍生品合約。
· 統(tǒng)計(jì)與準(zhǔn)統(tǒng)計(jì)數(shù)據(jù):安全標(biāo)識(shí)、國(guó)家代號(hào)、貨幣代號(hào)等。
· 時(shí)間和間隔數(shù)據(jù):基于精準(zhǔn)的SI(國(guó)際單位制)時(shí)間度量的事件觸發(fā)器。·天氣數(shù)據(jù):例如基于天氣預(yù)報(bào)的保險(xiǎn)費(fèi)計(jì)算器。
· 政治事件:預(yù)測(cè)市場(chǎng)的走勢(shì)。·運(yùn)動(dòng)事件:預(yù)測(cè)市場(chǎng)走勢(shì)以及體育博彩相關(guān)的合約。·地理定位數(shù)據(jù):例如供應(yīng)鏈跟蹤。
· 損壞程度核驗(yàn):保險(xiǎn)合約。
· 其他區(qū)塊鏈上發(fā)生的事件:可互操作函數(shù)。
· 以太幣市場(chǎng)價(jià)格:例如gas價(jià)格預(yù)言機(jī)。
· 航班統(tǒng)計(jì)數(shù)據(jù):例如用于團(tuán)體和俱樂部的機(jī)票合同。
在接下來的部分,我們將研究可以實(shí)現(xiàn)預(yù)言機(jī)的一些方法,包括基本的預(yù)言機(jī)的設(shè)計(jì)模式、計(jì)算性預(yù)言機(jī)、去中心化的預(yù)言機(jī)以及Solidity中的預(yù)言機(jī)客戶端實(shí)現(xiàn)。
預(yù)言機(jī)的設(shè)計(jì)模式
根據(jù)定義,所有的預(yù)言機(jī)都提供了一些關(guān)鍵功能。這些能力包括:
從鏈外的數(shù)據(jù)源收集數(shù)據(jù)。
使用簽名消息在鏈上傳輸數(shù)據(jù)。
將數(shù)據(jù)放入智能合約的存儲(chǔ)空間,使數(shù)據(jù)可用。
一旦數(shù)據(jù)在智能合約的存儲(chǔ)中可用,其他智能合約就可以通過調(diào)用預(yù)言機(jī)智能合約的“檢索”功能來訪問它;它也可以通過“查看”預(yù)言機(jī)的存儲(chǔ)直接由以太坊節(jié)點(diǎn)或支持網(wǎng)絡(luò)的客戶端訪問。
設(shè)置預(yù)言機(jī)的三種主要方式可以分為請(qǐng)求與響應(yīng)、發(fā)布與訂閱和立即讀取。
讓我們從最簡(jiǎn)單的“立即讀取”式預(yù)言機(jī)開始,這種預(yù)言機(jī)提供即時(shí)決策所需的數(shù)據(jù),例如“ethereumbook.info的地址是什么”或“這個(gè)人是否超過18歲”。那些希望查詢此類數(shù)據(jù)的人傾向于在“即時(shí)”的基礎(chǔ)上這樣做;查找是在需要信息時(shí)完成的,可能永遠(yuǎn)不會(huì)再次查找。這種預(yù)言機(jī)的例子包括那些持有組織數(shù)據(jù)或由組織發(fā)布數(shù)據(jù)(例如學(xué)術(shù)證書、撥號(hào)代碼、機(jī)構(gòu)會(huì)員資格、機(jī)場(chǎng)標(biāo)識(shí)符、自主ID等)的預(yù)言機(jī)。這種類型的預(yù)言機(jī)一旦將數(shù)據(jù)存儲(chǔ)在其合約存儲(chǔ)中,其他智能合約就可以使用對(duì)預(yù)言機(jī)合約的請(qǐng)求調(diào)用來查找。它可能會(huì)更新。預(yù)言機(jī)存儲(chǔ)中的數(shù)據(jù)也可用于通過區(qū)塊鏈啟用(即,以太坊客戶端連接)應(yīng)用程序直接查找,而無須通過調(diào)整并產(chǎn)生發(fā)布交易的gas成本。想要檢查買酒顧客年齡的商店可以這樣使用預(yù)言機(jī)。這種類型的預(yù)言機(jī)對(duì)于可能需要運(yùn)行和維護(hù)服務(wù)器來回答此類數(shù)據(jù)請(qǐng)求的組織或公司具有吸引力。注意:由預(yù)言機(jī)存儲(chǔ)的數(shù)據(jù)可能不是預(yù)言機(jī)正在服務(wù)的原始數(shù)據(jù),例如,出于效率或隱私原因,大學(xué)可能會(huì)為過去學(xué)生的學(xué)業(yè)成績(jī)證書設(shè)立一個(gè)預(yù)言機(jī)。但是,存儲(chǔ)證書的完整詳細(xì)信息(細(xì)致到所修的課程和達(dá)到的成績(jī))是多余的。相反,證書的哈希就足夠了。同樣,政府可能希望將公民身份證放入以太坊平臺(tái),其中顯然包含的細(xì)節(jié)需要保密。再次,散列數(shù)據(jù)(更仔細(xì)的做法是,在默爾克樹中使用Salt)并且僅將根哈希存儲(chǔ)在智能合約的存儲(chǔ)中將是組織這種服務(wù)的有效方式。
下一個(gè)設(shè)置方式是發(fā)布與訂閱,在這種預(yù)言機(jī)中,要對(duì)預(yù)期改變的數(shù)據(jù)(可能是定期和頻繁地)提供有效的廣播服務(wù),預(yù)言機(jī)要么由鏈上的智能合約輪詢,要么由鏈外守護(hù)進(jìn)程監(jiān)視和更新。此類別具有類似于RSS摘要或WebSub的模式,其中預(yù)言機(jī)使用新信息進(jìn)行更新,并用標(biāo)記表示新數(shù)據(jù)可供“訂閱”的人使用。感興趣的人必須將預(yù)言機(jī)輪詢到檢查最新信息是否已更改,或監(jiān)聽預(yù)言機(jī)合約的更新并在發(fā)生時(shí)采取行動(dòng)。示例包括價(jià)格饋送、天氣信息、經(jīng)濟(jì)或社會(huì)統(tǒng)計(jì)、交通數(shù)據(jù)等。在Web服務(wù)器領(lǐng)域,輪詢效率非常低,但在區(qū)塊鏈平臺(tái)的對(duì)等環(huán)境中卻不是這樣:以太坊客戶必須跟上所有狀態(tài)更改,包括對(duì)合約存儲(chǔ)的更改,因此輪詢數(shù)據(jù)更改是對(duì)同步客戶端的本地調(diào)用。以太坊事件日志使應(yīng)用程序特別容易注意預(yù)言機(jī)更新,因此這種模式在某些方面甚至可以被視為“推送”服務(wù)。但是,如果輪詢是通過智能合約完成的——這對(duì)于某些去中心化的應(yīng)用可能是必要的(例如,在無法激活激勵(lì)的情況下),則可能產(chǎn)生大量的gas支出。
“請(qǐng)求/響應(yīng)”類別是最復(fù)雜的:這是數(shù)據(jù)空間太大而無法存儲(chǔ)在智能合約中的情況,并且用戶每次只需要整個(gè)數(shù)據(jù)集的一小部分。它也是數(shù)據(jù)提供商業(yè)務(wù)的適用模型。實(shí)際上,這樣的預(yù)言機(jī)可以實(shí)現(xiàn)為鏈上智能合約系統(tǒng),以及用于監(jiān)視請(qǐng)求和檢索、返回?cái)?shù)據(jù)的鏈外基礎(chǔ)結(jié)構(gòu)。來自去中心化應(yīng)用的數(shù)據(jù)請(qǐng)求通常是涉及許多步驟的異步過程。在這種模式中,首先,EOA與去中心化應(yīng)用進(jìn)行交互,從而與預(yù)言機(jī)智能合約中定義的功能進(jìn)行交互。此函數(shù)啟動(dòng)對(duì)預(yù)言機(jī)的請(qǐng)求,除了可能包含回調(diào)函數(shù)和調(diào)度參數(shù)的補(bǔ)充信息之外,還使用相關(guān)參數(shù)詳細(xì)說明所請(qǐng)求的數(shù)據(jù)。一旦驗(yàn)證了此事務(wù),就可以將預(yù)言機(jī)請(qǐng)求視為預(yù)言機(jī)合約發(fā)出的EVM事件,或者作為狀態(tài)更改;可以檢索參數(shù)并用于執(zhí)行鏈外數(shù)據(jù)源的實(shí)際查詢。預(yù)言機(jī)可能還需要付款來處理請(qǐng)求,回調(diào)的gas支付以及訪問所請(qǐng)求數(shù)據(jù)的權(quán)限。最后,結(jié)果數(shù)據(jù)由預(yù)言機(jī)所有者簽名,證明在給定時(shí)間內(nèi)的數(shù)據(jù)有效性,并在事務(wù)中傳遞給直接或通過預(yù)言機(jī)合約發(fā)出請(qǐng)求的去中心化應(yīng)用。根據(jù)調(diào)度參數(shù),預(yù)言機(jī)可以定期廣播進(jìn)一步更新數(shù)據(jù)的事務(wù)(例如,日終定價(jià)信息)。
請(qǐng)求與響應(yīng)預(yù)言機(jī)的步驟可以總結(jié)如下:
· 接收來自DApp的查詢。
· 解析查詢。
· 檢查是否提供了付款和數(shù)據(jù)訪問權(quán)限。
· 從鏈外數(shù)據(jù)源檢索相關(guān)數(shù)據(jù)(并在必要時(shí)加密)。
· 使用包含的數(shù)據(jù)對(duì)事務(wù)進(jìn)行簽名。
· 將事務(wù)廣播到網(wǎng)絡(luò)。
· 安排任何進(jìn)一步必要的交易,例如通知等。
一系列其他方案也是可能的,例如,可以從EOA請(qǐng)求數(shù)據(jù)并直接返回?cái)?shù)據(jù),從而無須使用預(yù)言機(jī)智能合約。
類似地,可以向支持物聯(lián)網(wǎng)的硬件傳感器發(fā)出請(qǐng)求和響應(yīng)。因此,預(yù)言機(jī)可以是人、軟件或硬件。此處描述的請(qǐng)求與響應(yīng)模式常見于客戶端與服務(wù)器體系結(jié)構(gòu)。雖然這是一種有用的消息傳遞模式,允許應(yīng)用程序進(jìn)行雙向?qū)υ挘谀承┣闆r下這可能是不合適的。例如,在請(qǐng)求與響應(yīng)模式下,需要預(yù)言機(jī)利率的智能債券可能必須每天請(qǐng)求數(shù)據(jù),以確保利率始終是正確的。鑒于利率不經(jīng)常變化,發(fā)布與訂閱模式可能更合適這種情況,尤其是考慮到以太坊的有限帶寬。
在發(fā)布與訂閱模式中,發(fā)布者(在此上下文中是指預(yù)言機(jī))不直接向接收者發(fā)送消息,而是將發(fā)布的消息分類到不同的類中。訂閱者能夠表達(dá)對(duì)一個(gè)或多個(gè)類的興趣并僅檢索那些感興趣的消息。在這種模式下,預(yù)言機(jī)可能會(huì)在每次更改時(shí)將利率寫入其自己的內(nèi)部存儲(chǔ)。多個(gè)訂閱的DApp可以簡(jiǎn)單地從預(yù)言機(jī)合約中讀取它,從而減少對(duì)網(wǎng)絡(luò)帶寬的影響,同時(shí)最大限度地降低存儲(chǔ)成本。
在廣播或多播模式中,預(yù)言機(jī)會(huì)將所有消息發(fā)布到信道,訂閱合約將在各種訂閱模式下收聽信道。例如,預(yù)言機(jī)可能會(huì)將消息發(fā)布到加密貨幣匯率信道。訂閱智能合約如果需要時(shí)間序列,例如移動(dòng)平均計(jì)算,則可以請(qǐng)求信道的全部?jī)?nèi)容;另一個(gè)可能只需要現(xiàn)貨價(jià)格計(jì)算最新利率。在預(yù)言機(jī)不需要知道訂閱合約的身份的情況下,廣播模式是合適的。
數(shù)據(jù)認(rèn)證
即便我們假設(shè)被去中心化應(yīng)用查詢的數(shù)據(jù)源是權(quán)威的和值得信任的,仍然存在一個(gè)突出的問題:鑒于預(yù)言機(jī)以及“請(qǐng)求/響應(yīng)”機(jī)制可能由多個(gè)實(shí)體來操作,我們?nèi)绾尾拍苄湃芜@個(gè)機(jī)制呢?數(shù)據(jù)在傳輸過程中被篡改的可能性顯然是存在的,所以,讓鏈外方法可以證明返回?cái)?shù)據(jù)的完整性是非常關(guān)鍵的。兩種常見的數(shù)據(jù)認(rèn)證方法是真實(shí)性證明(authenticity proof)以及可信執(zhí)行環(huán)境(Trusted Execution Environment,TEE)。
真實(shí)性證明是用密碼學(xué)證據(jù)證明數(shù)據(jù)沒有被篡改過。基于許多證明技術(shù)(例如,數(shù)字簽名證明),它們將需要的信任從數(shù)據(jù)傳輸者高效地轉(zhuǎn)移到證明人(證明方法的提供者)。通過鏈上驗(yàn)證證據(jù),智能合約可以在使用數(shù)據(jù)前驗(yàn)證數(shù)據(jù)的完整性。Oraclize(現(xiàn)已加入Chainlink網(wǎng)絡(luò))http://www.oraclize.it/就是一個(gè)利用多種真實(shí)性證明的預(yù)言機(jī)服務(wù)的例子。現(xiàn)在以太坊主網(wǎng)查詢數(shù)據(jù)時(shí)可以使用的其中一種證明方式是TLSNotary Proof。TLSNotary Proof允許客戶端向第三方提交證據(jù),證明客戶端與某服務(wù)器之間發(fā)生了HTTPS網(wǎng)絡(luò)流量。雖然HTTPS自身是安全的,但它并不支持?jǐn)?shù)據(jù)簽名。因此,TLSNotaryProof依賴于TLSNotary簽名方案(通過PageSigner)。TLSNotaryProof利用了傳輸層安全協(xié)議(Transport Layer Security,TLS),這讓TLS可以掌控密鑰,在獲取數(shù)據(jù)后給數(shù)據(jù)簽名,并將數(shù)據(jù)分配給三方:服務(wù)器(預(yù)言機(jī))、受審單位(Oraclize)以及審計(jì)方。Oraclize使用亞馬遜網(wǎng)絡(luò)服務(wù)器(AWS)虛擬機(jī)實(shí)例作為審計(jì)方,可以驗(yàn)證自實(shí)例化以來它沒有被修改過。這一AWS實(shí)例存儲(chǔ)著TLSNotary密文,密文讓它可以提供誠(chéng)實(shí)性證明。雖然這套方案在數(shù)據(jù)篡改上提供了比純粹的“請(qǐng)求/響應(yīng)”機(jī)制更高的安全保證,我們?nèi)匀恍枰僭O(shè)亞馬遜自己不會(huì)篡改虛擬機(jī)實(shí)例。
Town Crier(http://www.towncrier.org/)是一個(gè)基于可信執(zhí)行環(huán)境的驗(yàn)證數(shù)據(jù)饋送預(yù)言機(jī)系統(tǒng);這些方法采用基于硬件的安全區(qū)(security enclave)來驗(yàn)證數(shù)據(jù)完整性。Town Crier使用英特爾的SGX(Software Guard eXtensions)來保證對(duì)HTTPS查詢的響應(yīng)可以被驗(yàn)證為可信的。SGX也提供了完整性保證,使得在安全區(qū)中運(yùn)行的應(yīng)用受到CPU保護(hù),不被其他進(jìn)程篡改。它也提供了機(jī)密性,保證應(yīng)用程序在安全區(qū)中運(yùn)行時(shí),其狀態(tài)對(duì)其他進(jìn)程來說是不可知的。最后,SGX通過生成應(yīng)用程序確定在安全區(qū)中運(yùn)行的數(shù)字簽名(通過其構(gòu)建結(jié)果的哈希值來安全地確定),讓證明成為可能。通過驗(yàn)證這一數(shù)字簽名,去中心化應(yīng)用就可以證明Town Crier實(shí)例正在SGX安全區(qū)內(nèi)安全地運(yùn)行。這樣就反過來證明了該實(shí)例沒有被篡改過,由Town Crier發(fā)出的數(shù)據(jù)是可信的。此外,這種機(jī)密屬性還讓Town Crier可以處理隱私數(shù)據(jù):使用Town Crier實(shí)例的公鑰來加密數(shù)據(jù)查詢請(qǐng)求。在安全區(qū)(如SGX)中運(yùn)行預(yù)言機(jī)的“請(qǐng)求/響應(yīng)”機(jī)制,我們完全可以認(rèn)為Town Crier是在可信第三方硬件中安全地運(yùn)行,保證了所請(qǐng)求的數(shù)據(jù)不受篡改地返回(假設(shè)我們相信Intel/SGX)。
計(jì)算機(jī)性的預(yù)言機(jī)
迄今為止,我們只討論請(qǐng)求和分發(fā)數(shù)據(jù)情境下的預(yù)言機(jī)。但是,預(yù)言機(jī)也可以用來執(zhí)行任意計(jì)算。給定以太坊內(nèi)在的區(qū)塊gas上限和相對(duì)較貴的計(jì)算成本,是一個(gè)特別有用的功能。不只是傳遞數(shù)據(jù)請(qǐng)求的結(jié)果,計(jì)算預(yù)言機(jī)也可以用來執(zhí)行帶有一組輸入的相關(guān)計(jì)算并返回計(jì)算結(jié)果,而這種計(jì)算可能無法在鏈上進(jìn)行。舉個(gè)例子,我們可以使用計(jì)算預(yù)言機(jī)來執(zhí)行計(jì)算密集型的回歸計(jì)算,以估計(jì)某個(gè)債券智能合約的收益。
如果你愿意信任集中而可審計(jì)的服務(wù),你可以再次訪問Oraclize。它們提供的服務(wù)允許去中心化應(yīng)用請(qǐng)求在沙盒AWS虛擬機(jī)中執(zhí)行的計(jì)算結(jié)果。AWS實(shí)例從包含在存檔中的用戶配置的Dockerfile創(chuàng)建可執(zhí)行容器,該存檔上載到星際文件系統(tǒng)(IPFS,參見第12章“數(shù)據(jù)存儲(chǔ)”一節(jié))。根據(jù)請(qǐng)求,Oraclize使用其哈希檢索此存檔,然后在AWS上初始化并執(zhí)行Docker容器,傳遞將作為環(huán)境變量提供給應(yīng)用程序的任何參數(shù)。容器化應(yīng)用程序根據(jù)時(shí)間限制執(zhí)行計(jì)算,并將結(jié)果寫入標(biāo)準(zhǔn)輸出,Oraclize可以對(duì)其進(jìn)行檢索并返回到去中心化應(yīng)用。Oraclize目前在可審計(jì)的t2.microAWS實(shí)例上提供此服務(wù),因此如果計(jì)算具有一些非常重要的值,則可以檢查是否執(zhí)行了正確的Docker容器。盡管如此,這不是一個(gè)真正去中心化的解決方案。
作為可驗(yàn)證預(yù)言機(jī)事實(shí)上的標(biāo)準(zhǔn),“Cryptlet”的概念已經(jīng)被規(guī)范化為微軟更廣泛的ESC框架的一部分。Cryptlet在一個(gè)密封安全區(qū)中運(yùn)行,該密封安全區(qū)是從基礎(chǔ)設(shè)施比如I/O中抽象出來的,并且附加上了CryptoDelegate,所以輸入和輸出消息都會(huì)自動(dòng)簽名、驗(yàn)證和證明。Cryptlet支持分布式交易,所以合約邏輯可以用具備ACID屬性的方式來處理復(fù)雜的多步驟、多區(qū)塊鏈交易以及外部系統(tǒng)交易。開發(fā)者因此可以創(chuàng)建用于智能合約中的可移植的、獨(dú)立且具隱私性的事實(shí)解析。Cryptlet遵循下列格式:
public class SampleContractCryptlet : Cryptlet
{
public SampleContractCryptlet(Guid id, Guid bindingId, string name,
string address, IContainerServices hostContainer, bool contract)
: base(id, bindingId, name, address, hostContainer, contract)
{
MessageApi = new CryptletMessageApi(GetType().FullName,
new SampleContractConstructor())
TrueBit(https://truebit.io)是一個(gè)可擴(kuò)展和可驗(yàn)證的鏈外計(jì)算解決方案。它引入了一個(gè)解決者和驗(yàn)證者系統(tǒng),它們被激勵(lì)各自執(zhí)行計(jì)算和驗(yàn)證這些計(jì)算。如果一個(gè)計(jì)算結(jié)果受到挑戰(zhàn),鏈上就會(huì)相應(yīng)執(zhí)行對(duì)該計(jì)算子集的迭代驗(yàn)證進(jìn)程——這是一種類型的“驗(yàn)證游戲”。驗(yàn)證游戲會(huì)進(jìn)行幾輪,每一輪都會(huì)遞歸地查驗(yàn)相關(guān)計(jì)算的更小子集。挑戰(zhàn)充分細(xì)分之后,游戲的終局便到來,法官(以太坊礦工)便可在鏈上最終裁定相關(guān)挑戰(zhàn)是否合理。實(shí)際上,TrueBit是計(jì)算市場(chǎng)的一種實(shí)現(xiàn),去中心化應(yīng)用因此可以為可驗(yàn)證計(jì)算支付;計(jì)算雖然是在鏈外執(zhí)行的,但依靠以太坊來強(qiáng)制執(zhí)行驗(yàn)證者游戲的規(guī)則。理論上來說,這讓免信任型智能合約安全地執(zhí)行任意計(jì)算任務(wù)。
像TrueBit這樣的系統(tǒng)有很多應(yīng)用,從機(jī)器學(xué)習(xí)到任意工作量證明的驗(yàn)證。后者的其中一個(gè)例子是Doge Ethereum橋接,它利用TrueBit來驗(yàn)證狗狗幣(Dogecoin)的工作量證明算法Scrypt,這是一種強(qiáng)內(nèi)存需求且計(jì)算密集的函數(shù),它不可能在以太坊區(qū)塊gas上限內(nèi)計(jì)算完成。通過在TrueBit執(zhí)行這種驗(yàn)證,在以太坊Rinkeby測(cè)試網(wǎng)絡(luò)上用智能合約安全地驗(yàn)證狗狗幣交易便成為可能。
去中心化預(yù)言機(jī)
上面列舉出的所有機(jī)制描述的都是中心化的預(yù)言機(jī)系統(tǒng),都需要依賴可信的權(quán)威。雖然它們可以為許多應(yīng)用服務(wù),它們的存在仍然意味著以太坊網(wǎng)絡(luò)中的單點(diǎn)故障。圍繞著去中心化預(yù)言機(jī),人們已經(jīng)提出了很多計(jì)劃:去中心化預(yù)言機(jī)可以用于保證數(shù)據(jù)可得性,還可搭配鏈上數(shù)據(jù)匯總系統(tǒng)創(chuàng)建獨(dú)立數(shù)據(jù)提供者網(wǎng)絡(luò)。
Chainlink(https://chain.link)已經(jīng)提出了一種去中心化預(yù)言機(jī)網(wǎng)絡(luò),由三個(gè)關(guān)鍵智能合約(聲譽(yù)合約、訂單匹配合約、數(shù)據(jù)匯總合約)以及數(shù)據(jù)提供者的鏈外注冊(cè)表組成。聲譽(yù)合約用來跟蹤數(shù)據(jù)提供者的表現(xiàn)。聲譽(yù)合約中的分?jǐn)?shù)會(huì)更新到鏈外注冊(cè)表中。訂單匹配合約會(huì)從使用聲譽(yù)合約的預(yù)言機(jī)中選擇競(jìng)標(biāo)者,并最終確定服務(wù)層級(jí)要約(Service Level Agreement,SLA),其中包含了查詢參數(shù)和要求的預(yù)言機(jī)數(shù)量。這也意味著數(shù)據(jù)購(gòu)買者不會(huì)直接與個(gè)體預(yù)言機(jī)交易。數(shù)據(jù)匯總合約會(huì)從多個(gè)預(yù)言機(jī)處收集響應(yīng)(使用“commit reveal”模式提交),計(jì)算查詢的最終總結(jié)果,然后將結(jié)果反饋回聲譽(yù)合約。
這樣的去中心化方案要面臨的其中一個(gè)重大挑戰(zhàn)是:構(gòu)建數(shù)據(jù)匯總函數(shù)。Chainlink提議計(jì)算響應(yīng)附加權(quán)重,這樣就可以為每一個(gè)預(yù)言機(jī)響應(yīng)記錄有效性分?jǐn)?shù)。此處,發(fā)現(xiàn)一個(gè)“無效”的分?jǐn)?shù)并不是毫無價(jià)值的,因?yàn)樗⒃冢海ㄒ詫?duì)統(tǒng)計(jì)提供的響應(yīng)的偏離來度量)過于偏遠(yuǎn)的數(shù)據(jù)點(diǎn)是不正確的這一前提之上。基于某一預(yù)言機(jī)響應(yīng)圍繞響應(yīng)分布的位置來計(jì)算有效性分?jǐn)?shù)有一定風(fēng)險(xiǎn),具體表現(xiàn)為懲罰偏離平均值的正確答案。因此,Chainlink提供匯總函數(shù)的標(biāo)準(zhǔn)集合,但也支持使用定制化的匯總合約。
一個(gè)相關(guān)的想法是謝林幣協(xié)議。其中,多個(gè)參與者記錄數(shù)值,這些數(shù)值的中位數(shù)會(huì)被當(dāng)成“正確”答案。記錄者必須先質(zhì)押保證金,這些保證金會(huì)根據(jù)它與中位數(shù)的接近程度重新分配,由此可以激勵(lì)人們記錄與其他人提供的值相近的值。這樣共同的數(shù)值,也就是所謂的“謝林點(diǎn)”,預(yù)計(jì)會(huì)接近真實(shí)值,因?yàn)檎鎸?shí)數(shù)值是響應(yīng)者協(xié)作中所圍繞的自然而明顯的目標(biāo)。
Jason Teutsch最近提出一種新型的去中心化鏈外數(shù)據(jù)可得性預(yù)言機(jī)。這種設(shè)計(jì)利用了一條專用的工作量證明區(qū)塊鏈,后者可以在給定時(shí)間內(nèi)正確地記錄登記過的數(shù)據(jù)是否可得。礦工會(huì)嘗試下載、存儲(chǔ)和傳播所有新近登記的數(shù)據(jù),因此保證數(shù)據(jù)在本地是可得的。這樣的系統(tǒng)是昂貴的,因?yàn)槊恳粋€(gè)挖礦節(jié)點(diǎn)都要存儲(chǔ)和傳播所有登記過的數(shù)據(jù)。該系統(tǒng)可以通過在登記期結(jié)束后釋放數(shù)據(jù)來重復(fù)利用存儲(chǔ)空間。
Solidity中的預(yù)言機(jī)客戶端接口
代碼11-1是一個(gè)Solidity示例,展示了Oraclize如何從API不斷獲取ETH/USD價(jià)格并以可用的方式存儲(chǔ)結(jié)果。
代碼11-1:使用Oraclize從外部來源更新ETH/USD匯率
/*
ETH/USD price ticker leveraging CryptoCompare API
This contract keeps in storage an updated ETH/USD price,
which is updated every 10 minutes.
*/
pragma solidity ^0.4.1;
import “github.com/oraclize/ethereum-api/oraclizeAPI.sol”;
/*
“oraclize_” prepended methods indicate inheritance from “usingOraclize”
*/
contract EthUsdPriceTicker is usingOraclize {
uint public ethUsd;
event newOraclizeQuery(string description);
event newCallbackResult(string result);
function EthUsdPriceTicker() payable {
// signals TLSN proof generation and storage on IPFS
oraclize_setProof(proofType_TLSNotary | proofStorage_IPFS);
// requests query
queryTicker();
}
function __callback(bytes32 _queryId, string _result, bytes _proof) public {
if (msg.sender != oraclize_cbAddress()) throw;
newCallbackResult(_result);
/*
* Parse the result string into an unsigned integer for on-chain use.
* Uses inherited “parseInt” helper from “usingOraclize”, allowing for
* a string result such as “123.45” to be converted to uint 12345.
*/
ethUsd = parseInt(_result, 2);
// called from callback since we‘re polling the price
queryTicker();
}
function queryTicker() public payable {
if (oraclize_getPrice(“URL”) 》 this.balance) {
newOraclizeQuery(“Oraclize query was NOT sent, please add some ETH
to cover for the query fee”);
} else {
newOraclizeQuery(“Oraclize query was sent, standing by for the
answer.。.”);
// query params are (delay in seconds, datasource type,
// datasource argument)
// specifies JSONPath, to fetch specific portion of JSON API result
oraclize_query(60 * 10, “URL”,
“json(https://min-api.cryptocompare.com/data/price?\
fsym=ETH&tsyms=USD,EUR,GBP).USD”);
}
}
}
為結(jié)合Oraclize,EthUsdPriceTicker合約必須是usingOraclize合約的子合約;后者是在oraclizeAPI文件中定義好的。數(shù)據(jù)請(qǐng)求會(huì)由usingOraclize合約內(nèi)置的oraclize_query函數(shù)發(fā)起。這是一個(gè)重載函數(shù),預(yù)計(jì)至少需要兩個(gè)參數(shù):
支持使用的數(shù)據(jù)源,如URL、WolframAlpha、IPFS或計(jì)算。
為給定數(shù)據(jù)源設(shè)定的參數(shù),可能包括JSON或XML解析助手的使用。
數(shù)據(jù)查詢的價(jià)格會(huì)由queryTicker函數(shù)執(zhí)行。為執(zhí)行數(shù)據(jù)查詢請(qǐng)求,Oraclize要求用支付一小筆費(fèi)用,用于補(bǔ)償傳輸和處理結(jié)果到_callback函數(shù)過程中發(fā)生的gas費(fèi)用以及為服務(wù)支付的額外費(fèi)用。費(fèi)用的數(shù)額視數(shù)據(jù)源和要求的可信證明類型(如果有所指定的話)而定。一旦檢索了數(shù)據(jù),_callback函數(shù)就會(huì)由Oraclize控制的許可賬戶調(diào)用;這一過程會(huì)傳入響應(yīng)值和唯一的queryId參數(shù),后者可以用于處理和跟蹤來自O(shè)raclize的多個(gè)待定的回調(diào)。
金融數(shù)據(jù)提供者ThomsonReuters也為以太坊提供了一項(xiàng)名為“BlockOneIQ”的預(yù)言機(jī)服務(wù),讓運(yùn)行在私有或許可網(wǎng)絡(luò)上的智能合約可以請(qǐng)求市場(chǎng)和參考數(shù)據(jù)。代碼112是該預(yù)言機(jī)的交互接口,以及用于發(fā)起請(qǐng)求的客戶端智能合約。
代碼11-2:合約調(diào)用BlockOneIQ服務(wù)以獲取市場(chǎng)數(shù)據(jù)
pragma solidity ^0.4.11;
contract Oracle {
uint256 public divisor;
function initRequest(
uint256 queryType, function(uint256) external onSuccess,
function(uint256
) external onFailure) public returns (uint256 id);
function addArgumentToRequestUint(uint256 id, bytes32 name, uint256 arg) public;
function addArgumentToRequestString(uint256 id, bytes32 name, bytes32 arg)
public;
function executeRequest(uint256 id) public;
function getResponseUint(uint256 id, bytes32 name) public constant
returns(uint256);
function getResponseString(uint256 id, bytes32 name) public constant
returns(bytes32);
function getResponseError(uint256 id) public constant returns(bytes32);
function deleteResponse(uint256 id) public constant;
}
contract OracleB1IQClient {
Oracle private oracle;
event LogError(bytes32 description);
function OracleB1IQClient(address addr) public payable {
oracle = Oracle(addr);
getIntraday(“IBM”, now);
}
function getIntraday(bytes32 ric, uint256 timestamp) public {
uint256 id = oracle.initRequest(0, this.handleSuccess, this.handleFailure);
oracle.addArgumentToRequestString(id, “symbol”, ric);
oracle.addArgumentToRequestUint(id, “timestamp”, timestamp);
oracle.executeRequest(id);
}
function handleSuccess(uint256 id) public {
assert(msg.sender == address(oracle));
bytes32 ric = oracle.getResponseString(id, “symbol”);
uint256 open = oracle.getResponseUint(id, “open”);
uint256 high = oracle.getResponseUint(id, “high”);
uint256 low = oracle.getResponseUint(id, “l(fā)ow”);
uint256 close = oracle.getResponseUint(id, “close”);
uint256 bid = oracle.getResponseUint(id, “bid”);
uint256 ask = oracle.getResponseUint(id, “ask”);
uint256 timestamp = oracle.getResponseUint(id, “timestamp”);
oracle.deleteResponse(id);
// Do something with the price data
}
function handleFailure(uint256 id) public {
assert(msg.sender == address(oracle));
bytes32 error = oracle.getResponseError(id);
oracle.deleteResponse(id);
emit LogError(error);
}
}
使用initRequest函數(shù)啟動(dòng)數(shù)據(jù)請(qǐng)求,該函數(shù)允許指定查詢類型(在此示例中是對(duì)日內(nèi)價(jià)格的請(qǐng)求)以及兩個(gè)回調(diào)函數(shù)。這將返回一個(gè)uint256標(biāo)識(shí)符,然后可用于提供其他參數(shù)。addArgumentToRequestString函數(shù)用于指定路透代碼表(RIC),此處為IBM庫(kù)存,addArgumentToRequestUint允許指定時(shí)間戳。現(xiàn)在,傳入block.timestamp的別名將檢索IBM的當(dāng)前價(jià)格。然后由executeRequest函數(shù)執(zhí)行該請(qǐng)求。處理完請(qǐng)求后,預(yù)言機(jī)合約將使用查詢標(biāo)識(shí)符調(diào)用onSuccess回調(diào)函數(shù),從而允許檢索結(jié)果數(shù)據(jù);如果檢索失敗,onFailure回調(diào)函數(shù)將返回錯(cuò)誤代碼。成功檢索的可用字段包括open(開盤價(jià))、high(最高價(jià))、low(最低價(jià))、close(收盤價(jià))和bid/ask(買/賣價(jià))。
總結(jié)
正如你所看到的,預(yù)言機(jī)為智能合約提供了至關(guān)重要的服務(wù):它們將外部事實(shí)帶入合約執(zhí)行。當(dāng)然,預(yù)言機(jī)也會(huì)帶來很大的風(fēng)險(xiǎn):如果它們是受信任的來源并且可能受到損害,可能導(dǎo)致它們提供的智能合約的執(zhí)行受損。
一般來說,在考慮使用預(yù)言機(jī)時(shí)要非常小心信任模型。如果你認(rèn)為預(yù)言機(jī)可以信任,那么你可能會(huì)通過將其暴露給潛在的錯(cuò)誤輸入來破壞智能合約的安全性。也就是說,如果仔細(xì)考慮安全假設(shè),那么預(yù)言機(jī)會(huì)非常有用。
去中心化的預(yù)言機(jī)可以解決其中一些問題,并為以太坊智能合約提供無信任的外部數(shù)據(jù)。謹(jǐn)慎選擇,你就可以開始探索以太坊與預(yù)言機(jī)提供的“真實(shí)世界”之間的橋梁。
責(zé)任編輯;zl
評(píng)論