在本章中,我們將討論預言機(oracle),它是可以為以太坊智能合約提供外部數據源的系統。 “oracle”一詞來自希臘神話,代表能夠與神靈交流的人,他們可以看到未來的愿景。在區塊鏈的上下文中,預言機是一個可以回答以太坊外部問題的系統。在理想情況下,預言機是無信任的系統,這意味著它們不需要被信任,因為它們是按照去中心化的原則運行的。
?
為什么需要預言機?
以太坊平臺的一個關鍵組件是EVM,它能夠在分散網絡中的任何節點上執行程序并更新受共識規則約束的以太坊狀態。為了保持共識,EVM的執行過程必須完全確定,并且僅基于以太坊狀態和簽名交易的共享上下文。這產生了兩個特別重要的后果:一個是EVM和智能合約沒有內在的隨機性來源;另一個是外部數據只能作為交易的數據載荷引入。
讓我們進一步分析這兩個后果。首先我們要理解為什么在EVM中需要禁止真正的隨機函數,不讓它們為智能合約提供隨機性。請考慮在執行此類函數后對嘗試達成共識的影響:節點A將執行命令并代表智能合約存儲3在其存儲中,而節點B執行相同的智能合約,將存儲7。因此,節點A和節點B就結果狀態應該是什么將得出不同的結論,盡管在相同的上下文中運行完全相同的代碼。實際上,每次評估智能合約時,可能會達到不同的結果狀態。因此,由于其眾多節點在世界各地獨立運行,網絡將無法就結果狀態應該是什么達成去中心化的共識。在實踐中,它會比這個例子復雜得多,因為包括以太幣轉移在內的連鎖效應會以指數方式增長。
注意,偽隨機函數,例如加密安全哈希函數(它們是確定性的,因此實際上也是EVM的一部分),對于許多應用來說是不夠的。假想一個猜硬幣決勝負的游戲場景,這個游戲依賴于扔硬幣正反面的隨意性。礦工可以輕易破解這個游戲:他們只需要打包那些對其有利的隨機結果即可。那么我們如何解決這個問題呢?既然所有節點都可以就簽名交易的內容達成一致,那么我們就可以引入外部信息,包括隨機性、價格信息、天氣預報等,作為發送到網絡的交易的數據部分。但是,這些數據本身無法信任,因為它的來源無法核實。因此,我們剛剛并沒有完全解決這個問題。我們使用預言機嘗試解決這些問題,在本章的其余部分將詳細討論這些問題。
預言機的應用場景和示例
理想情況下,預言機提供了一種無信任(或至少近乎無信任)的方式來獲取外在的(即“真實世界”或“鏈外”)信息,例如足球比賽的結果、黃金的價格或真正的隨機數字,用于以太坊平臺上的智能合約。它們還可用于直接將數據安全地中繼到DApp前端。因此,可以將預言機視為彌合鏈外世界與智能合約之間差距的機制。允許智能合約基于真實世界的事件和數據來強制執行合約關系,從而大大擴展了它們的范圍。但是,這也會給以太坊的安全模型帶來外部風險。考慮一個“智能遺囑”合約——當一個人去世時分配資產。這是智能合約領域中經常討論的內容,并突出了可信任的預言機的風險。如果由這樣的合約控制的繼承金額足夠高,那么在所有者死亡之前攻擊預言機(發出假的死訊)并觸發資產分配的動機是非常強烈的。
請注意,某些預言機提供針對特定私有數據源的數據,例如學術證書或政府ID。這些數據的來源,如大學或政府部門,是完全可信的,數據的真實性是主觀的(真相只能通過來源的權威來確定)。因此,不能無信地提供這樣的數據,即不信任來源,因為沒有獨立可驗證的客觀事實。因此,我們將這些數據源包含在我們對預言機的定義中,因為它們還為智能合約提供了數據橋梁。它們提供的數據通常采用證明的形式,如護照或成就記錄。“證言”將成為未來區塊鏈平臺成功的重要組成部分,特別是在驗證身份或聲譽的相關問題方面,因此探索區塊鏈平臺如何為其提供服務非常重要。
可能由預言機提供的更多數據示例包括:
· 物理隨機數源或熵源(例如量子現象或熱現象):如在彩票智能合約中公平地選出獲獎者。
· 與自然災害相關的參數觸發器:觸發大型自然災害債券智能合約(例如地震的里氏震級測量債券)。
· 匯率數據:例如讓加密貨幣與法定貨幣精確掛鉤。
· 資本市場數據:例如為一攬子代幣化資產或證券定價。
· 指標引用數據:例如將利率納入智能金融衍生品合約。
· 統計與準統計數據:安全標識、國家代號、貨幣代號等。
· 時間和間隔數據:基于精準的SI(國際單位制)時間度量的事件觸發器。·天氣數據:例如基于天氣預報的保險費計算器。
· 政治事件:預測市場的走勢。·運動事件:預測市場走勢以及體育博彩相關的合約。·地理定位數據:例如供應鏈跟蹤。
· 損壞程度核驗:保險合約。
· 其他區塊鏈上發生的事件:可互操作函數。
· 以太幣市場價格:例如gas價格預言機。
· 航班統計數據:例如用于團體和俱樂部的機票合同。
在接下來的部分,我們將研究可以實現預言機的一些方法,包括基本的預言機的設計模式、計算性預言機、去中心化的預言機以及Solidity中的預言機客戶端實現。
預言機的設計模式
根據定義,所有的預言機都提供了一些關鍵功能。這些能力包括:
從鏈外的數據源收集數據。
使用簽名消息在鏈上傳輸數據。
將數據放入智能合約的存儲空間,使數據可用。
一旦數據在智能合約的存儲中可用,其他智能合約就可以通過調用預言機智能合約的“檢索”功能來訪問它;它也可以通過“查看”預言機的存儲直接由以太坊節點或支持網絡的客戶端訪問。
設置預言機的三種主要方式可以分為請求與響應、發布與訂閱和立即讀取。
讓我們從最簡單的“立即讀取”式預言機開始,這種預言機提供即時決策所需的數據,例如“ethereumbook.info的地址是什么”或“這個人是否超過18歲”。那些希望查詢此類數據的人傾向于在“即時”的基礎上這樣做;查找是在需要信息時完成的,可能永遠不會再次查找。這種預言機的例子包括那些持有組織數據或由組織發布數據(例如學術證書、撥號代碼、機構會員資格、機場標識符、自主ID等)的預言機。這種類型的預言機一旦將數據存儲在其合約存儲中,其他智能合約就可以使用對預言機合約的請求調用來查找。它可能會更新。預言機存儲中的數據也可用于通過區塊鏈啟用(即,以太坊客戶端連接)應用程序直接查找,而無須通過調整并產生發布交易的gas成本。想要檢查買酒顧客年齡的商店可以這樣使用預言機。這種類型的預言機對于可能需要運行和維護服務器來回答此類數據請求的組織或公司具有吸引力。注意:由預言機存儲的數據可能不是預言機正在服務的原始數據,例如,出于效率或隱私原因,大學可能會為過去學生的學業成績證書設立一個預言機。但是,存儲證書的完整詳細信息(細致到所修的課程和達到的成績)是多余的。相反,證書的哈希就足夠了。同樣,政府可能希望將公民身份證放入以太坊平臺,其中顯然包含的細節需要保密。再次,散列數據(更仔細的做法是,在默爾克樹中使用Salt)并且僅將根哈希存儲在智能合約的存儲中將是組織這種服務的有效方式。
下一個設置方式是發布與訂閱,在這種預言機中,要對預期改變的數據(可能是定期和頻繁地)提供有效的廣播服務,預言機要么由鏈上的智能合約輪詢,要么由鏈外守護進程監視和更新。此類別具有類似于RSS摘要或WebSub的模式,其中預言機使用新信息進行更新,并用標記表示新數據可供“訂閱”的人使用。感興趣的人必須將預言機輪詢到檢查最新信息是否已更改,或監聽預言機合約的更新并在發生時采取行動。示例包括價格饋送、天氣信息、經濟或社會統計、交通數據等。在Web服務器領域,輪詢效率非常低,但在區塊鏈平臺的對等環境中卻不是這樣:以太坊客戶必須跟上所有狀態更改,包括對合約存儲的更改,因此輪詢數據更改是對同步客戶端的本地調用。以太坊事件日志使應用程序特別容易注意預言機更新,因此這種模式在某些方面甚至可以被視為“推送”服務。但是,如果輪詢是通過智能合約完成的——這對于某些去中心化的應用可能是必要的(例如,在無法激活激勵的情況下),則可能產生大量的gas支出。
“請求/響應”類別是最復雜的:這是數據空間太大而無法存儲在智能合約中的情況,并且用戶每次只需要整個數據集的一小部分。它也是數據提供商業務的適用模型。實際上,這樣的預言機可以實現為鏈上智能合約系統,以及用于監視請求和檢索、返回數據的鏈外基礎結構。來自去中心化應用的數據請求通常是涉及許多步驟的異步過程。在這種模式中,首先,EOA與去中心化應用進行交互,從而與預言機智能合約中定義的功能進行交互。此函數啟動對預言機的請求,除了可能包含回調函數和調度參數的補充信息之外,還使用相關參數詳細說明所請求的數據。一旦驗證了此事務,就可以將預言機請求視為預言機合約發出的EVM事件,或者作為狀態更改;可以檢索參數并用于執行鏈外數據源的實際查詢。預言機可能還需要付款來處理請求,回調的gas支付以及訪問所請求數據的權限。最后,結果數據由預言機所有者簽名,證明在給定時間內的數據有效性,并在事務中傳遞給直接或通過預言機合約發出請求的去中心化應用。根據調度參數,預言機可以定期廣播進一步更新數據的事務(例如,日終定價信息)。
請求與響應預言機的步驟可以總結如下:
· 接收來自DApp的查詢。
· 解析查詢。
· 檢查是否提供了付款和數據訪問權限。
· 從鏈外數據源檢索相關數據(并在必要時加密)。
· 使用包含的數據對事務進行簽名。
· 將事務廣播到網絡。
· 安排任何進一步必要的交易,例如通知等。
一系列其他方案也是可能的,例如,可以從EOA請求數據并直接返回數據,從而無須使用預言機智能合約。
類似地,可以向支持物聯網的硬件傳感器發出請求和響應。因此,預言機可以是人、軟件或硬件。此處描述的請求與響應模式常見于客戶端與服務器體系結構。雖然這是一種有用的消息傳遞模式,允許應用程序進行雙向對話,但在某些情況下這可能是不合適的。例如,在請求與響應模式下,需要預言機利率的智能債券可能必須每天請求數據,以確保利率始終是正確的。鑒于利率不經常變化,發布與訂閱模式可能更合適這種情況,尤其是考慮到以太坊的有限帶寬。
在發布與訂閱模式中,發布者(在此上下文中是指預言機)不直接向接收者發送消息,而是將發布的消息分類到不同的類中。訂閱者能夠表達對一個或多個類的興趣并僅檢索那些感興趣的消息。在這種模式下,預言機可能會在每次更改時將利率寫入其自己的內部存儲。多個訂閱的DApp可以簡單地從預言機合約中讀取它,從而減少對網絡帶寬的影響,同時最大限度地降低存儲成本。
在廣播或多播模式中,預言機會將所有消息發布到信道,訂閱合約將在各種訂閱模式下收聽信道。例如,預言機可能會將消息發布到加密貨幣匯率信道。訂閱智能合約如果需要時間序列,例如移動平均計算,則可以請求信道的全部內容;另一個可能只需要現貨價格計算最新利率。在預言機不需要知道訂閱合約的身份的情況下,廣播模式是合適的。
數據認證
即便我們假設被去中心化應用查詢的數據源是權威的和值得信任的,仍然存在一個突出的問題:鑒于預言機以及“請求/響應”機制可能由多個實體來操作,我們如何才能信任這個機制呢?數據在傳輸過程中被篡改的可能性顯然是存在的,所以,讓鏈外方法可以證明返回數據的完整性是非常關鍵的。兩種常見的數據認證方法是真實性證明(authenticity proof)以及可信執行環境(Trusted Execution Environment,TEE)。
真實性證明是用密碼學證據證明數據沒有被篡改過。基于許多證明技術(例如,數字簽名證明),它們將需要的信任從數據傳輸者高效地轉移到證明人(證明方法的提供者)。通過鏈上驗證證據,智能合約可以在使用數據前驗證數據的完整性。Oraclize(現已加入Chainlink網絡)http://www.oraclize.it/就是一個利用多種真實性證明的預言機服務的例子。現在以太坊主網查詢數據時可以使用的其中一種證明方式是TLSNotary Proof。TLSNotary Proof允許客戶端向第三方提交證據,證明客戶端與某服務器之間發生了HTTPS網絡流量。雖然HTTPS自身是安全的,但它并不支持數據簽名。因此,TLSNotaryProof依賴于TLSNotary簽名方案(通過PageSigner)。TLSNotaryProof利用了傳輸層安全協議(Transport Layer Security,TLS),這讓TLS可以掌控密鑰,在獲取數據后給數據簽名,并將數據分配給三方:服務器(預言機)、受審單位(Oraclize)以及審計方。Oraclize使用亞馬遜網絡服務器(AWS)虛擬機實例作為審計方,可以驗證自實例化以來它沒有被修改過。這一AWS實例存儲著TLSNotary密文,密文讓它可以提供誠實性證明。雖然這套方案在數據篡改上提供了比純粹的“請求/響應”機制更高的安全保證,我們仍然需要假設亞馬遜自己不會篡改虛擬機實例。
Town Crier(http://www.towncrier.org/)是一個基于可信執行環境的驗證數據饋送預言機系統;這些方法采用基于硬件的安全區(security enclave)來驗證數據完整性。Town Crier使用英特爾的SGX(Software Guard eXtensions)來保證對HTTPS查詢的響應可以被驗證為可信的。SGX也提供了完整性保證,使得在安全區中運行的應用受到CPU保護,不被其他進程篡改。它也提供了機密性,保證應用程序在安全區中運行時,其狀態對其他進程來說是不可知的。最后,SGX通過生成應用程序確定在安全區中運行的數字簽名(通過其構建結果的哈希值來安全地確定),讓證明成為可能。通過驗證這一數字簽名,去中心化應用就可以證明Town Crier實例正在SGX安全區內安全地運行。這樣就反過來證明了該實例沒有被篡改過,由Town Crier發出的數據是可信的。此外,這種機密屬性還讓Town Crier可以處理隱私數據:使用Town Crier實例的公鑰來加密數據查詢請求。在安全區(如SGX)中運行預言機的“請求/響應”機制,我們完全可以認為Town Crier是在可信第三方硬件中安全地運行,保證了所請求的數據不受篡改地返回(假設我們相信Intel/SGX)。
計算機性的預言機
迄今為止,我們只討論請求和分發數據情境下的預言機。但是,預言機也可以用來執行任意計算。給定以太坊內在的區塊gas上限和相對較貴的計算成本,是一個特別有用的功能。不只是傳遞數據請求的結果,計算預言機也可以用來執行帶有一組輸入的相關計算并返回計算結果,而這種計算可能無法在鏈上進行。舉個例子,我們可以使用計算預言機來執行計算密集型的回歸計算,以估計某個債券智能合約的收益。
如果你愿意信任集中而可審計的服務,你可以再次訪問Oraclize。它們提供的服務允許去中心化應用請求在沙盒AWS虛擬機中執行的計算結果。AWS實例從包含在存檔中的用戶配置的Dockerfile創建可執行容器,該存檔上載到星際文件系統(IPFS,參見第12章“數據存儲”一節)。根據請求,Oraclize使用其哈希檢索此存檔,然后在AWS上初始化并執行Docker容器,傳遞將作為環境變量提供給應用程序的任何參數。容器化應用程序根據時間限制執行計算,并將結果寫入標準輸出,Oraclize可以對其進行檢索并返回到去中心化應用。Oraclize目前在可審計的t2.microAWS實例上提供此服務,因此如果計算具有一些非常重要的值,則可以檢查是否執行了正確的Docker容器。盡管如此,這不是一個真正去中心化的解決方案。
作為可驗證預言機事實上的標準,“Cryptlet”的概念已經被規范化為微軟更廣泛的ESC框架的一部分。Cryptlet在一個密封安全區中運行,該密封安全區是從基礎設施比如I/O中抽象出來的,并且附加上了CryptoDelegate,所以輸入和輸出消息都會自動簽名、驗證和證明。Cryptlet支持分布式交易,所以合約邏輯可以用具備ACID屬性的方式來處理復雜的多步驟、多區塊鏈交易以及外部系統交易。開發者因此可以創建用于智能合約中的可移植的、獨立且具隱私性的事實解析。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)是一個可擴展和可驗證的鏈外計算解決方案。它引入了一個解決者和驗證者系統,它們被激勵各自執行計算和驗證這些計算。如果一個計算結果受到挑戰,鏈上就會相應執行對該計算子集的迭代驗證進程——這是一種類型的“驗證游戲”。驗證游戲會進行幾輪,每一輪都會遞歸地查驗相關計算的更小子集。挑戰充分細分之后,游戲的終局便到來,法官(以太坊礦工)便可在鏈上最終裁定相關挑戰是否合理。實際上,TrueBit是計算市場的一種實現,去中心化應用因此可以為可驗證計算支付;計算雖然是在鏈外執行的,但依靠以太坊來強制執行驗證者游戲的規則。理論上來說,這讓免信任型智能合約安全地執行任意計算任務。
像TrueBit這樣的系統有很多應用,從機器學習到任意工作量證明的驗證。后者的其中一個例子是Doge Ethereum橋接,它利用TrueBit來驗證狗狗幣(Dogecoin)的工作量證明算法Scrypt,這是一種強內存需求且計算密集的函數,它不可能在以太坊區塊gas上限內計算完成。通過在TrueBit執行這種驗證,在以太坊Rinkeby測試網絡上用智能合約安全地驗證狗狗幣交易便成為可能。
去中心化預言機
上面列舉出的所有機制描述的都是中心化的預言機系統,都需要依賴可信的權威。雖然它們可以為許多應用服務,它們的存在仍然意味著以太坊網絡中的單點故障。圍繞著去中心化預言機,人們已經提出了很多計劃:去中心化預言機可以用于保證數據可得性,還可搭配鏈上數據匯總系統創建獨立數據提供者網絡。
Chainlink(https://chain.link)已經提出了一種去中心化預言機網絡,由三個關鍵智能合約(聲譽合約、訂單匹配合約、數據匯總合約)以及數據提供者的鏈外注冊表組成。聲譽合約用來跟蹤數據提供者的表現。聲譽合約中的分數會更新到鏈外注冊表中。訂單匹配合約會從使用聲譽合約的預言機中選擇競標者,并最終確定服務層級要約(Service Level Agreement,SLA),其中包含了查詢參數和要求的預言機數量。這也意味著數據購買者不會直接與個體預言機交易。數據匯總合約會從多個預言機處收集響應(使用“commit reveal”模式提交),計算查詢的最終總結果,然后將結果反饋回聲譽合約。
這樣的去中心化方案要面臨的其中一個重大挑戰是:構建數據匯總函數。Chainlink提議計算響應附加權重,這樣就可以為每一個預言機響應記錄有效性分數。此處,發現一個“無效”的分數并不是毫無價值的,因為它建立在:(以對統計提供的響應的偏離來度量)過于偏遠的數據點是不正確的這一前提之上。基于某一預言機響應圍繞響應分布的位置來計算有效性分數有一定風險,具體表現為懲罰偏離平均值的正確答案。因此,Chainlink提供匯總函數的標準集合,但也支持使用定制化的匯總合約。
一個相關的想法是謝林幣協議。其中,多個參與者記錄數值,這些數值的中位數會被當成“正確”答案。記錄者必須先質押保證金,這些保證金會根據它與中位數的接近程度重新分配,由此可以激勵人們記錄與其他人提供的值相近的值。這樣共同的數值,也就是所謂的“謝林點”,預計會接近真實值,因為真實數值是響應者協作中所圍繞的自然而明顯的目標。
Jason Teutsch最近提出一種新型的去中心化鏈外數據可得性預言機。這種設計利用了一條專用的工作量證明區塊鏈,后者可以在給定時間內正確地記錄登記過的數據是否可得。礦工會嘗試下載、存儲和傳播所有新近登記的數據,因此保證數據在本地是可得的。這樣的系統是昂貴的,因為每一個挖礦節點都要存儲和傳播所有登記過的數據。該系統可以通過在登記期結束后釋放數據來重復利用存儲空間。
Solidity中的預言機客戶端接口
代碼11-1是一個Solidity示例,展示了Oraclize如何從API不斷獲取ETH/USD價格并以可用的方式存儲結果。
代碼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”);
}
}
}
為結合Oraclize,EthUsdPriceTicker合約必須是usingOraclize合約的子合約;后者是在oraclizeAPI文件中定義好的。數據請求會由usingOraclize合約內置的oraclize_query函數發起。這是一個重載函數,預計至少需要兩個參數:
支持使用的數據源,如URL、WolframAlpha、IPFS或計算。
為給定數據源設定的參數,可能包括JSON或XML解析助手的使用。
數據查詢的價格會由queryTicker函數執行。為執行數據查詢請求,Oraclize要求用支付一小筆費用,用于補償傳輸和處理結果到_callback函數過程中發生的gas費用以及為服務支付的額外費用。費用的數額視數據源和要求的可信證明類型(如果有所指定的話)而定。一旦檢索了數據,_callback函數就會由Oraclize控制的許可賬戶調用;這一過程會傳入響應值和唯一的queryId參數,后者可以用于處理和跟蹤來自Oraclize的多個待定的回調。
金融數據提供者ThomsonReuters也為以太坊提供了一項名為“BlockOneIQ”的預言機服務,讓運行在私有或許可網絡上的智能合約可以請求市場和參考數據。代碼112是該預言機的交互接口,以及用于發起請求的客戶端智能合約。
代碼11-2:合約調用BlockOneIQ服務以獲取市場數據
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, “low”);
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函數啟動數據請求,該函數允許指定查詢類型(在此示例中是對日內價格的請求)以及兩個回調函數。這將返回一個uint256標識符,然后可用于提供其他參數。addArgumentToRequestString函數用于指定路透代碼表(RIC),此處為IBM庫存,addArgumentToRequestUint允許指定時間戳。現在,傳入block.timestamp的別名將檢索IBM的當前價格。然后由executeRequest函數執行該請求。處理完請求后,預言機合約將使用查詢標識符調用onSuccess回調函數,從而允許檢索結果數據;如果檢索失敗,onFailure回調函數將返回錯誤代碼。成功檢索的可用字段包括open(開盤價)、high(最高價)、low(最低價)、close(收盤價)和bid/ask(買/賣價)。
總結
正如你所看到的,預言機為智能合約提供了至關重要的服務:它們將外部事實帶入合約執行。當然,預言機也會帶來很大的風險:如果它們是受信任的來源并且可能受到損害,可能導致它們提供的智能合約的執行受損。
一般來說,在考慮使用預言機時要非常小心信任模型。如果你認為預言機可以信任,那么你可能會通過將其暴露給潛在的錯誤輸入來破壞智能合約的安全性。也就是說,如果仔細考慮安全假設,那么預言機會非常有用。
去中心化的預言機可以解決其中一些問題,并為以太坊智能合約提供無信任的外部數據。謹慎選擇,你就可以開始探索以太坊與預言機提供的“真實世界”之間的橋梁。
責任編輯;zl
評論
查看更多