1偿荷,摘要
本文主要講解外部預(yù)言機(jī)ORACLE定義和原理,并講解螞蟻BAAS系統(tǒng)如何通過ORACLE預(yù)言機(jī)方式使用外部數(shù)據(jù)源的方法溉躲。
2星岗,外部預(yù)言機(jī)ORACLE定義和原理
2.1 預(yù)言機(jī)(Oracle)是什么?
2018年11 月 6 日首有,中國(guó)人民銀行發(fā)布的《區(qū)塊鏈能做什么燕垃?不能做什么?》報(bào)告中井联,是這樣對(duì)預(yù)言機(jī)定義的卜壕。
區(qū)塊鏈外信息寫入?yún)^(qū)塊鏈內(nèi)的機(jī)制,一般被稱為預(yù)言機(jī) (oracle mechanism) 烙常。
預(yù)言機(jī)的功能就是將外界信息寫入到區(qū)塊鏈內(nèi)轴捎,完成區(qū)塊鏈與現(xiàn)實(shí)世界的數(shù)據(jù)互通。它允許確定的智能合約對(duì)不確定的外部世界作出反應(yīng)蚕脏,是智能合約與外部進(jìn)行數(shù)據(jù)交互的唯一途徑侦副,也是區(qū)塊鏈與現(xiàn)實(shí)世界進(jìn)行數(shù)據(jù)交互的接口。
聽上去很難理解驼鞭,我們舉例來說秦驯。
大家會(huì)很形象的把公鏈比作操作系統(tǒng)(Windows、IOS挣棕、安卓)译隘,DAPP 類比的話就是 APP,那么預(yù)言機(jī)可以形象的比做 API 接口洛心。API 是一組定義固耘、程序及協(xié)議的集合,通過 API 接口實(shí)現(xiàn)計(jì)算機(jī)軟件之間的相互通信词身。這樣類比雖然不準(zhǔn)確厅目,但意思就是預(yù)言機(jī)是區(qū)塊鏈和現(xiàn)實(shí)世界之間的紐帶,可以實(shí)現(xiàn)數(shù)據(jù)互通的工具法严。
Oracle 為什么被中譯為預(yù)言機(jī)璧瞬?
跟別人提起預(yù)言機(jī),很多人的反應(yīng)都是預(yù)測(cè)市場(chǎng)渐夸,預(yù)言機(jī)這個(gè)名字確實(shí)容易想到預(yù)測(cè)嗤锉。
Oracle 最初是來源于古希臘宗教,意為“神諭墓塌、先知瘟忱、預(yù)言”奥额。而在互聯(lián)網(wǎng)領(lǐng)域,預(yù)言機(jī)(英語:oracle machine)访诱,又稱諭示機(jī)垫挨,是一種抽象電腦,用來研究決定型問題触菜【爬疲可以被視為一個(gè)多了個(gè)黑盒子(預(yù)言者)的圖靈機(jī),這個(gè)黑盒子的功能是可以在單一運(yùn)算之內(nèi)解答特定問題涡相。
也許你會(huì)好奇這跟甲骨文公司有什么關(guān)系嗎哲泊?其實(shí)沒有關(guān)系。
Oracle 在中國(guó)叫甲骨文公司的原因可能是另一個(gè)故事催蝗。在中國(guó)商朝晚期切威,王室把在動(dòng)物骨骼或龜甲上做占卜記事的文字叫甲骨文,甲骨文被英譯為 Oracle bone script丙号,后來 Oracle 公司到中國(guó)中譯為了甲骨文公司先朦。(很有道理的猜測(cè) 哈哈哈??)
2.2 區(qū)塊鏈為什么需要預(yù)言機(jī)?
區(qū)塊鏈?zhǔn)且粋€(gè)確定性的犬缨、封閉的系統(tǒng)環(huán)境喳魏,目前區(qū)塊鏈只能獲取到鏈內(nèi)的數(shù)據(jù),而不能獲取到鏈外真實(shí)世界的數(shù)據(jù)怀薛,區(qū)塊鏈與現(xiàn)實(shí)世界是割裂的刺彩。
一般智能合約的執(zhí)行需要觸發(fā)條件扩氢,當(dāng)智能合約的觸發(fā)條件是外部信息時(shí)(鏈外),就必須需要預(yù)言機(jī)來提供數(shù)據(jù)服務(wù)刨裆,通過預(yù)言機(jī)將現(xiàn)實(shí)世界的數(shù)據(jù)輸入到區(qū)塊鏈上扇住,因?yàn)橹悄芎霞s不支持對(duì)外請(qǐng)求。
具體原因是這樣的怀樟。區(qū)塊鏈?zhǔn)谴_定性的環(huán)境,它不允許不確定的事情或因素,智能合約不管何時(shí)何地運(yùn)行都必須是一致的結(jié)果呐能,所以虛擬機(jī)(VM)不能讓智能合約有 network call(網(wǎng)絡(luò)調(diào)用),不然結(jié)果就是不確定的抑堡。
也就是說智能合約不能進(jìn)行 I/O(Input/Output摆出,即輸入/輸出),所以它是無法主動(dòng)獲取外部數(shù)據(jù)的首妖,只能通過預(yù)言機(jī)將數(shù)據(jù)給到智能合約偎漫。
我們通過一個(gè)例子來說明一下。假設(shè)現(xiàn)在我被關(guān)進(jìn)了一個(gè)小黑屋里(不要多想有缆,只是例子 =-=)象踊,我對(duì)外面的世界發(fā)生了什么幾乎一無所知温亲,不知道外面是否有人,即使呼叫也沒有人回應(yīng)杯矩,只有外面的人在門口把他看到的聽到的都告訴我栈虚,我才可以得知外面的世界。
例子雖然不太恰當(dāng)史隆,但智能合約就像這個(gè)例子中的我一樣魂务,它無論何時(shí)何地,都無法主動(dòng)向外尋求信息泌射,只能外部把消息或數(shù)據(jù)給到里面粘姜。而預(yù)言機(jī)就是這個(gè)在外面輸送消息和數(shù)據(jù)的人。
好像這么看來魄幕,智能合約并不是很智能呀相艇,是的,智能合約其實(shí)是完成的不智能的事情纯陨,即寫好了條件和結(jié)果坛芽,當(dāng)給它條件的時(shí)候,就可以觸發(fā)翼抠,但也不會(huì)馬上執(zhí)行咙轩,還需要合約相關(guān)的人進(jìn)行私鑰簽署才可以執(zhí)行。
所以阴颖,網(wǎng)上很多文章其實(shí)都有水分活喊,比如智能合約某個(gè)時(shí)間或者觸發(fā)某個(gè)條件就可以自動(dòng)執(zhí)行之類的,只能說這樣的句子在邏輯上是有問題的量愧。關(guān)于預(yù)言機(jī)的很多文章也有水分钾菊,描述的并不準(zhǔn)確。
好了偎肃,上面就是區(qū)塊鏈為什么需要預(yù)言機(jī)煞烫,因?yàn)橹悄芎霞s無法主動(dòng)去獲取鏈外的數(shù)據(jù),只能被動(dòng)接受數(shù)據(jù)累颂。
2.3 預(yù)言機(jī)怎么解決這個(gè)問題
這就是理想中預(yù)言機(jī)的工作流程滞详,即用戶的智能合約把請(qǐng)求給鏈上 Oracle 合約,通過鏈下的 API 接口獲得外部數(shù)據(jù)紊馏,更確切的說是外部把數(shù)據(jù)給鏈上的 Oracle 合約料饥,然后 Oracle 合約再把數(shù)據(jù)給用戶的智能合約。
或許很難理解朱监,因?yàn)樵诨ヂ?lián)網(wǎng)中岸啡,調(diào)用數(shù)據(jù)是非常容易的,只需要在程序中寫調(diào)用的代碼就可以了赫编。但是區(qū)塊鏈與外部世界的數(shù)據(jù)交互凰狞,確實(shí)不能進(jìn)行這樣的操作篇裁。
2.4 預(yù)言機(jī)的應(yīng)用場(chǎng)景有哪些?
預(yù)言機(jī)作為區(qū)塊鏈與現(xiàn)實(shí)世界進(jìn)行數(shù)據(jù)交互的橋梁赡若,應(yīng)用場(chǎng)景非常多达布,可以說一切需要與鏈下進(jìn)行數(shù)據(jù)交互的DApp都需要預(yù)言機(jī)。比如金融衍生品交易平臺(tái)逾冬、借貸平臺(tái)黍聂、快遞追蹤/IoT、穩(wěn)定幣身腻、博彩游戲产还、保險(xiǎn)、預(yù)測(cè)市場(chǎng)等等嘀趟。
我們還是舉例來說脐区。
先說最近幣圈比較火熱的博彩游戲?yàn)槭裁葱枰A(yù)言機(jī)。博彩游戲的核心是不可預(yù)測(cè)她按、可驗(yàn)證的隨機(jī)數(shù)牛隅,從而決定賭注的最終結(jié)果,但是在鏈上是無法生成隨機(jī)數(shù)的或者說在鏈上的隨機(jī)數(shù)是可以被預(yù)測(cè)和破解的酌泰,這時(shí)候就需要預(yù)言機(jī)從外部給智能合約安全的媒佣、不可預(yù)測(cè)的隨機(jī)數(shù)。
現(xiàn)在的大多數(shù)博彩游戲都是在鏈上生成隨機(jī)數(shù)陵刹,所以很容易被預(yù)測(cè)和破解默伍,導(dǎo)致資產(chǎn)被盜,大家有興趣的可以去看一下DApp被盜的相關(guān)研究報(bào)告衰琐,很多因?yàn)殡S機(jī)數(shù)問題被盜的也糊。比如 BetDice、Dice2Win羡宙。
如果大家很感興趣狸剃,可以看一下我男神 DOS Network 創(chuàng)始人@nrek jonny 關(guān)于《智能合約中的隨機(jī)數(shù)》的分享。
其實(shí)辛辨,早在 Fomo3D 這個(gè)游戲出來之前捕捂,以太坊的 Team Leader 就在推特上說過鏈上是無法生成隨機(jī)數(shù)的瑟枫。Dear devs... you can`t generate random numbers on chain斗搞!
我們?cè)賮砜匆粋€(gè)關(guān)于快遞追蹤的例子。
假設(shè)當(dāng)我通過某個(gè) DApp 購物平臺(tái)購買某件物品快遞過來的時(shí)候慷妙,真實(shí)世界中的快遞寄送或到達(dá)信息僻焚,就可以通過 Oracle 把數(shù)據(jù)傳遞到鏈上,然后觸發(fā)鏈上的智能合約膝擂,我用自己的私鑰確認(rèn)收到了快遞虑啤,并完成付款隙弛。
大家發(fā)現(xiàn)了嗎?這里的智能合約不能自動(dòng)執(zhí)行狞山,而是需要我用自己的私鑰進(jìn)行確認(rèn)全闷,智能合約保證的是沒有第三方機(jī)構(gòu)做擔(dān)保和資金周轉(zhuǎn)(比如支付寶),這就是智能合約的價(jià)值萍启。
其他的案例就不細(xì)說了总珠,比如穩(wěn)定幣需要鏈下的利率,保險(xiǎn)需要鏈下的病例或車況等勘纯,具體可以看這篇文章《Oracle—區(qū)塊鏈與現(xiàn)實(shí)世界的紐帶》局服。
2.5 目前公鏈上的預(yù)言機(jī)項(xiàng)目
目前在預(yù)言機(jī)領(lǐng)域探索的項(xiàng)目還不是很多,每一個(gè)項(xiàng)目的預(yù)言機(jī)解決方案都略有差異驳遵,我找了幾家典型的預(yù)言機(jī)項(xiàng)目淫奔,做一個(gè)簡(jiǎn)單的闡述。
Oraclize:為以太坊提供中心化預(yù)言機(jī)服務(wù)
Oraclize 依托亞馬遜 AWS 服務(wù)和 TLSNotary 技術(shù)堤结,是一個(gè)可證明的誠(chéng)實(shí)的預(yù)言機(jī)服務(wù)唆迁,不過它是中心化的,目前只能在以太坊網(wǎng)絡(luò)使用霍殴,而且gas費(fèi)較高媒惕。但是不妨礙它是目前很受歡迎的預(yù)言機(jī)服務(wù),也可能是因?yàn)檫€沒有更好的選擇吧来庭。這里有 Oraclize 詳細(xì)的使用說明:Oraclize Documentation
ChainLink:以太坊上第一個(gè)去中心化預(yù)言機(jī)解決方案
ChainLink 的解決方案是通過在鏈上的智能合約和鏈下的數(shù)據(jù)節(jié)點(diǎn)妒蔚,通過獎(jiǎng)懲機(jī)制和聚合模型的方式,進(jìn)行數(shù)據(jù)的請(qǐng)求和饋送月弛。不過也有一些不足肴盏,比如鏈?zhǔn)骄酆铣杀据^高,拓展性差帽衙,基于聲譽(yù)系統(tǒng)容易集中化菜皂。他們更關(guān)注支付場(chǎng)景的應(yīng)用,比如幫助銀行與企業(yè)之間建立智能合約厉萝。
歐鏈 OracleChain:EOS 上的第一個(gè)去中心化預(yù)言機(jī)解決方案
歐鏈很早就提出了預(yù)言機(jī)的想法和方案恍飘,采用自主的 PoRD 機(jī)制(Proof-of-Reputation&Deposit),本質(zhì)上是一種抵押代幣獎(jiǎng)懲機(jī)制的聲譽(yù)系統(tǒng)谴垫,獎(jiǎng)勵(lì)數(shù)據(jù)節(jié)點(diǎn)懲罰作惡節(jié)點(diǎn)章母,可以實(shí)現(xiàn) Augur、Gnosis 等預(yù)測(cè)市場(chǎng)應(yīng)用的功能翩剪,還能支撐對(duì)鏈外數(shù)據(jù)有更高頻率訪問需求的智能合約業(yè)務(wù)乳怎。預(yù)測(cè)市場(chǎng)的結(jié)果本身有時(shí)也可以作為 Oracle 的輸入數(shù)據(jù)源,歐鏈更像是預(yù)測(cè)市場(chǎng)前弯,而且不足是單純的聲譽(yù)系統(tǒng)容易集中化蚪缀。目前歐鏈只在 EOS 上開發(fā)秫逝。
DOS Network:支持多條主流公鏈的去中心化預(yù)言機(jī)服務(wù)網(wǎng)絡(luò)
DOS Network 是一個(gè) Layer-2 的預(yù)言機(jī)解決方案,它通過在鏈上部署一個(gè)輕量級(jí)智能合約询枚,鏈下是一個(gè) p2p 網(wǎng)絡(luò)违帆,服務(wù)節(jié)點(diǎn)的選取和數(shù)據(jù)驗(yàn)證采用 VRF+閾值簽名等技術(shù),保證了去中心化和數(shù)據(jù)安全金蜀,并達(dá)到快速反應(yīng)前方。可以適配所有主流公鏈廉油,比如以太坊惠险、EOS、Tron抒线、Thunder班巩。目前已在以太坊測(cè)試網(wǎng)發(fā)布 alpha 版本 https://dosnetwork.github.io/docs。
我們也期待預(yù)言機(jī)技術(shù)的不斷成熟嘶炭,進(jìn)而促進(jìn)更多區(qū)塊鏈與現(xiàn)實(shí)世界進(jìn)行數(shù)據(jù)交互的 DApp 落地抱慌。
3,螞蟻BAAS實(shí)現(xiàn)外部預(yù)言機(jī)的技術(shù)概述
區(qū)塊鏈預(yù)言機(jī)(Oracle)是區(qū)塊鏈與外部世界交互的一種實(shí)現(xiàn)機(jī)制眨猎,它通過可信計(jì)算技術(shù)或者其他建立信任的約束關(guān)系抑进,在區(qū)塊鏈與外部世界間建立一種可信任的橋接機(jī)制,使得外部數(shù)據(jù)可以安全可靠地進(jìn)入?yún)^(qū)塊鏈睡陪。
外部數(shù)據(jù)源服務(wù)是基于可信執(zhí)行環(huán)境(Trusted Execution Environment寺渗,TEE)技術(shù)實(shí)現(xiàn)的區(qū)塊鏈預(yù)言機(jī)服務(wù),該服務(wù)旨在為區(qū)塊鏈智能合約提供可信訪問外部數(shù)據(jù)源能力兰迫。
外部數(shù)據(jù)源服務(wù)會(huì)在智能合約平臺(tái)部署一個(gè)外部數(shù)據(jù)源服務(wù)合約信殊,用戶合約通過調(diào)用該服務(wù)合約發(fā)送外部數(shù)據(jù)源請(qǐng)求,鏈下的 TEE 外部數(shù)據(jù)源服務(wù)對(duì)接該服務(wù)合約汁果,監(jiān)聽用戶的請(qǐng)求涡拘,然后去對(duì)應(yīng)的外部數(shù)據(jù)源取數(shù)據(jù),最后將結(jié)果返回給用戶合約据德。
3.1 實(shí)現(xiàn)原理
外部數(shù)據(jù)源服務(wù)使用 TEE 技術(shù)實(shí)現(xiàn)鳄乏,對(duì)于每筆外部數(shù)據(jù)請(qǐng)求都將在可信硬件環(huán)境中執(zhí)行〖可信硬件環(huán)境會(huì)驗(yàn)證外部數(shù)據(jù)源的 TLS 通訊證書以確認(rèn)數(shù)據(jù)源的身份橱野,通過 TLS 協(xié)議確保拿到的數(shù)據(jù)沒有被第三方篡改∩囊耄可信硬件環(huán)境得到數(shù)據(jù)后仲吏,會(huì)使用硬件私鑰對(duì)數(shù)據(jù)進(jìn)行簽名不铆,并返回給智能合約蝌焚,智能合約將自動(dòng)驗(yàn)證可信硬件的簽名裹唆,確保數(shù)據(jù)是可信硬件執(zhí)行結(jié)果,沒有被第三方篡改只洒,從而安全可靠地獲取來自指定外部數(shù)據(jù)源的數(shù)據(jù)许帐。
3.2 功能特性
數(shù)據(jù)安全可信
區(qū)塊鏈預(yù)言機(jī)底層使用 TEE 技術(shù)實(shí)現(xiàn),TEE 是一個(gè)安全隔離的執(zhí)行環(huán)境毕谴,提供隔離執(zhí)行成畦、可信應(yīng)用的完整性、可信數(shù)據(jù)的機(jī)密性涝开、安全存儲(chǔ)等安全特征循帐,使預(yù)言機(jī)服務(wù)數(shù)據(jù)服務(wù)安全可信。支持 HTTPS 協(xié)議
通過 HTTPS 協(xié)議舀武,區(qū)塊鏈預(yù)言機(jī)會(huì)與目標(biāo)數(shù)據(jù)源建立端到端的安全通行通道拄养,并且可以完成對(duì)數(shù)據(jù)源的證書校驗(yàn)以確定身份,從而安全银舱、可靠地獲取來自指定外部數(shù)據(jù)源的數(shù)據(jù)瘪匿。支持 JSON API
JSON 是一種輕量級(jí)的數(shù)據(jù)交換格式,廣泛地被采用為 API 的數(shù)據(jù)交換格式寻馏。區(qū)塊鏈預(yù)言機(jī)內(nèi)置 JSON 解析器棋弥,如果請(qǐng)求的 URL 響應(yīng)格式是 JSON 格式,可以在請(qǐng)求命令中設(shè)置 jsonpath 命令诚欠,使區(qū)塊鏈預(yù)言機(jī)根據(jù) jsonpath 讀取部分 JSON 數(shù)據(jù)顽染,只返回這部分?jǐn)?shù)據(jù)上鏈。支持訪問要權(quán)限認(rèn)證的 API
一些 API 需要認(rèn)證授權(quán)訪問轰绵,例如使用 OAuth 2.0 協(xié)議實(shí)現(xiàn)的 API家乘,需要在請(qǐng)求中攜帶服務(wù)端認(rèn)證鑒權(quán)需要的參數(shù),但這些參數(shù)屬于私密信息不可泄露藏澳。這種情況下仁锯,利用 TEE 技術(shù)提供的機(jī)密性,與區(qū)塊鏈預(yù)言機(jī)的 TEE 環(huán)境建立端到端的加密信封翔悠,使得請(qǐng)求只在 TEE 硬件可信執(zhí)行環(huán)境里面解密业崖,從而不會(huì)泄露請(qǐng)求機(jī)密。高可用預(yù)言機(jī)集群
區(qū)塊鏈預(yù)言機(jī)服務(wù)使用集群架構(gòu)實(shí)現(xiàn)蓄愁,為合約提供高可用的數(shù)據(jù)訪問服務(wù)双炕。
3.3 使用場(chǎng)景
外部數(shù)據(jù)源服務(wù)適用于以下任意場(chǎng)景:
- 智能合約需要可信訪問 Web 數(shù)據(jù)。
- 智能合約通過調(diào)用 Open API 使用互聯(lián)網(wǎng)服務(wù)撮抓。
- 智能合約需要與外部系統(tǒng)交互妇斤。
- 智能合約依賴公共現(xiàn)實(shí)事件,如天氣、賽事信息站超、航班信息等荸恕。
4,螞蟻BAAS的外部數(shù)據(jù)源服務(wù)(實(shí)現(xiàn)ORACLE預(yù)言機(jī))接口
外部數(shù)據(jù)源服務(wù)在區(qū)塊鏈上部署了區(qū)塊鏈預(yù)言機(jī)(Oracle)合約死相,提供異步查詢互聯(lián)網(wǎng)數(shù)據(jù)接口(CURL)供用戶合約使用融求。正常情況下,用戶合約調(diào)用預(yù)言機(jī)合約發(fā)起查詢請(qǐng)求后算撮,預(yù)言機(jī)合約在 1~3 個(gè)區(qū)塊內(nèi)就能得到外部數(shù)據(jù)源服務(wù)取回的數(shù)據(jù)生宛,然后回調(diào)用戶合約傳入數(shù)據(jù)。
4.1 開發(fā)流程
通過外部數(shù)據(jù)源服務(wù)肮柜,讓智能合約獲取指定外部數(shù)據(jù)源數(shù)據(jù)的開發(fā)流程如下:
- 在 BaaS 平臺(tái)上獲得預(yù)言機(jī)合約 ID(進(jìn)入聯(lián)盟陷舅,選擇 聯(lián)盟內(nèi)的鏈 > 目標(biāo)合約鏈 > 管理 > 跨鏈管理 可查看合約 ID)。
- 獲取合約 API 定義(OracleInterface.sol)审洞。
- 在用戶合約中引入合約 API 定義(OracleInterface.sol)蔑赘。
- 用戶合約實(shí)現(xiàn)回調(diào)接口,用于異步接收請(qǐng)求結(jié)果预明。
- 用戶請(qǐng)求需要使用 CURL 命令構(gòu)建外部數(shù)據(jù)源請(qǐng)求缩赛。
- 用戶合約向預(yù)言機(jī)合約發(fā)送查詢請(qǐng)求,具體參考 合約 API 說明撰糠。
4.2 合約 API 使用流程
用戶的智能合約調(diào)用預(yù)言機(jī)合約的 CURL 接口發(fā)起查詢請(qǐng)求酥馍,預(yù)言機(jī)合約同步返回查詢結(jié)果,即請(qǐng)求單據(jù)號(hào)(reqeust_id)阅酪。預(yù)言機(jī)合約獲取到查詢結(jié)果數(shù)據(jù)后旨袒,會(huì)異步回調(diào)查詢用戶合約的回調(diào)接口。
4.3 合約 API接口詳解
合約 API 定義
OracleInterface.sol 中定義了用戶合約與預(yù)言機(jī)合約的通信接口术辐,其中用戶通過 curlRequest 接口調(diào)用預(yù)言機(jī)合約砚尽。用戶合約需要實(shí)現(xiàn) oracleCallbackCurlResponse 接口,用于接收預(yù)言機(jī)合約的請(qǐng)求結(jié)果回調(diào)辉词。
// OracleInterface.sol
pragma solidity ^0.4.22;
// 使用預(yù)言機(jī) API 需要在用戶合約中開啟 ABIEncoderV2 特性
pragma experimental ABIEncoderV2;
interface OracleInterface {
/**
* function: 發(fā)送 CURL 請(qǐng)求
* parameters:
* _biz_id : 用戶自定義的業(yè)務(wù)請(qǐng)求 ID
* _curl_cmd : CURL 命令必孤,參考 CURL 命令使用文檔進(jìn)行構(gòu)造
* _if_callback : 是否需要預(yù)言機(jī)將請(qǐng)求結(jié)果回調(diào)用戶合約
* _callback_identity : 預(yù)言機(jī)請(qǐng)求結(jié)果回調(diào)的合約 ID,可以是發(fā)送請(qǐng)求的合約瑞躺,也可以是其他合約
* _delay_time : 該特性未激活敷搪,填 0 即可
* return value: : 預(yù)言機(jī)請(qǐng)求 ID,是預(yù)言機(jī)合約為本次請(qǐng)求生成的唯一請(qǐng)求 ID
*/
function curlRequestDefault(bytes32 _biz_id, string _curl_cmd, bool _if_callback, identity _callback_identity, uint256 _delay_time) external returns (bytes32);
/**
* function: oracleCallbackCurlResponse
* parameters:
* _request_id : 預(yù)言機(jī)合約請(qǐng)求 ID(在發(fā)送請(qǐng)求時(shí)預(yù)言機(jī)合約會(huì)返回此 ID)
* _biz_id : 用戶合約的業(yè)務(wù)請(qǐng)求 ID
* _error_code : 請(qǐng)求結(jié)果碼幢哨,如果值是 0赡勘,則表示預(yù)言機(jī)請(qǐng)求處理成功;如果是其他值捞镰,則為請(qǐng)求處理失敗闸与,詳見合約錯(cuò)誤碼表
* _resp_status : HTTP 響應(yīng)的狀態(tài)碼毙替,一般 200 表示 HTTP 請(qǐng)求處理成功,5xx 表示服務(wù)端處理錯(cuò)誤践樱,調(diào)用者可根據(jù)自己的使用場(chǎng)景做判斷
* _resp_header : HTTP 響應(yīng)的 header厂画,如果 CURL 中指定了要返回 HTTP 響應(yīng)的 header,則回調(diào)時(shí)會(huì)返回對(duì)應(yīng)的值
* _resp_body : http 響應(yīng)的 body
* _call_identity : 發(fā)起該請(qǐng)求的合約 ID
* return value : 無
*/
function oracleCallbackCurlResponse (bytes32 _request_id, bytes32 _biz_id, uint32 _error_code, uint32 _resp_status, bytes _resp_header, bytes _resp_body, identity _call_identity) external;
}
請(qǐng)求接口
curlRequestDefault
curlRequestDefault
是業(yè)務(wù)合約向預(yù)言機(jī)合約發(fā)送請(qǐng)求的接口映胁。
函數(shù)原型
function curlRequestDefault(bytes32 _biz_id, string _curl_cmd, bool _if_callback, identity _callback_identity, uint256 _delay_time) external returns (bytes32);
請(qǐng)求參數(shù)
參數(shù) | 必選 | 類型 | 說明 |
---|---|---|---|
_biz_id | true | bytes32 | 用戶自定義的業(yè)務(wù)請(qǐng)求 ID,預(yù)言機(jī)合約回調(diào)結(jié)果時(shí)甲雅,會(huì)回傳此 ID解孙。 |
_curl_cmd | true | string | CURL 命令,參考 CURL 命令使用說明 進(jìn)行構(gòu)造抛人。 |
_if_callback | true | bool | 是否需要預(yù)言機(jī)將請(qǐng)求結(jié)果回調(diào)用戶合約弛姜。 |
_callback_identity | true | identity | 預(yù)言機(jī)請(qǐng)求結(jié)果回調(diào)的合約 ID,可以是發(fā)送請(qǐng)求的合約妖枚,也可以是其他合約廷臼。 |
_delay_time | true | uint256 | 該特性未激活,填 0 即可绝页。 |
返回字段
返回字段 | 字段類型 | 說明 |
---|---|---|
_request_Id | bytes32 | 預(yù)言機(jī)請(qǐng)求 ID荠商,是預(yù)言機(jī)合約為本次請(qǐng)求生成的唯一請(qǐng)求 ID。 |
回調(diào)接口
oracleCallbackCurlResponse
回調(diào)接口需要業(yè)務(wù)合約實(shí)現(xiàn)续誉,用于接收預(yù)言機(jī)合約的請(qǐng)求結(jié)果回調(diào)莱没,如果未能正確實(shí)現(xiàn)該合約,則將無法接收請(qǐng)求結(jié)果酷鸦。
業(yè)務(wù)合約通過 oracleCallbackCurlResponse 來接收預(yù)言機(jī)合約的 CURL 請(qǐng)求結(jié)果回調(diào)饰躲。
函數(shù)原型
function oracleCallbackCurlResponse (bytes32 _request_id, bytes32 _biz_id, uint32 _error_code, uint32 _resp_status, bytes _resp_header, bytes _resp_body, identity _call_identity) external;
請(qǐng)求參數(shù)
參數(shù) | 必選 | 類型 | 說明 |
---|---|---|---|
_request_id | true | bytes32 | 預(yù)言機(jī)合約請(qǐng)求 ID,在發(fā)送請(qǐng)求時(shí)預(yù)言機(jī)合約會(huì)返回此 ID臼隔。 |
_biz_id | true | bytes32 | 用戶合約的業(yè)務(wù)請(qǐng)求 ID |
_error_code | true | uint32 | 請(qǐng)求結(jié)果碼嘹裂,如果值是 0,則表示預(yù)言機(jī)請(qǐng)求處理成功摔握;如果是其他值寄狼,則為請(qǐng)求處理失敗,詳見 合約錯(cuò)誤碼表氨淌。 |
_resp_status | true | uint32 | HTTP 響應(yīng)的狀態(tài)碼例嘱,一般 200 表示 HTTP 請(qǐng)求處理成功,5xx 表示服務(wù)端處理錯(cuò)誤宁舰,調(diào)用者可根據(jù)自己的使用場(chǎng)景做判斷拼卵。 |
_resp_header | true | bytes | HTTP 響應(yīng)的 header,如果 CURL 中指定了要返回 HTTP 響應(yīng)的 header蛮艰,則回調(diào)時(shí)會(huì)返回對(duì)應(yīng)的值腋腮。 |
_resp_body | true | bytes | HTTP 響應(yīng)的 body |
_call_identity | true | identity | 發(fā)起該請(qǐng)求的合約 ID |
返回字段
無返回字段。
示例
pragma solidity ^0.4.22;
// 使用預(yù)言機(jī) API 需要在用戶合約中開啟 ABIEncoderV2 特性
pragma experimental ABIEncoderV2;
import "./OracleInterface.sol";
// 實(shí)現(xiàn)一個(gè)demo合約
contract BizContract {
// 業(yè)務(wù) ID 與預(yù)言機(jī)請(qǐng)求 ID 的關(guān)聯(lián)關(guān)系
mapping(bytes32 => bytes32) request_id;
// 調(diào)用預(yù)言機(jī)合約的 CURL 接口
function rawCURLRequest(identity oracle_address, bytes32 biz_id, string cmd) public{
// 1. 跨合約調(diào)用,需要通過合約 API 定義及合約 ID 生成一個(gè)合約對(duì)象
OracleInterface oracle = OracleInterface(oracle_address);
//
// 2. 發(fā)送 CURL 請(qǐng)求
// (例如查詢股票行情信息即寡,cmd 參數(shù)的值可以是“https://hq.sinajs.cn/list=hk00941”)
bytes32 request_id = oracle.curlRequest(service_id, biz_id, cmd, true, this, 0);
// 3. 記錄預(yù)言機(jī)返回的request id
request_id[biz_id] = request_id;
// 4. 請(qǐng)求階段結(jié)束徊哑,等待回調(diào)
return;
}
// 業(yè)務(wù)合約用于接收預(yù)言機(jī)合約的 CURL 請(qǐng)求結(jié)果回調(diào)
function oracleCallbackCurlResponse (bytes32 _request_id, bytes32 _biz_id, uint32 _error_code, uint32 _web_status, bytes _resp_header, bytes _resp_body, identity _call_identity) external {
// 業(yè)務(wù)處理回調(diào)結(jié)果
}
}
4.4 CURL 命令使用說明
本文主要對(duì)外部數(shù)據(jù)源服務(wù)涉及到的 CURL 命令的用法進(jìn)行說明。
說明:當(dāng)前外部數(shù)據(jù)源服務(wù)版本暫不支持 HTTP 分塊傳輸編碼聪富,即不支持 HTTP 響應(yīng)的 Transfer-Encoding 為 chunked莺丑,后續(xù)版本會(huì)支持該特性。
NAME
curl
VERSION
1.0.0_BETA
SYNOPSIS
curl https://address[:port][/path][?args] [options]
DESCRIPTION
CURL 命令是預(yù)言機(jī)提供的 Web API 接口必要傳入?yún)?shù)之一墩蔓。CURL 命令描述了指定預(yù)言機(jī)訪問目的互聯(lián)網(wǎng)資源的 URI梢莽,以及其他可選配置項(xiàng)。
當(dāng)前外部數(shù)據(jù)源服務(wù)版本暫不支持 HTTP 分塊傳輸編碼奸披,即不支持 HTTP 響應(yīng)的 Transfer-Encoding 為 chunked昏名,后續(xù)版本會(huì)支持該特性。
OPTIONS
--request <GET|POST>
HTTP 訪問的方法阵面,支持 GET 和 POST轻局。缺省使用 GET 方法。
e.g.
--request GET
--request POST
--header <header:value>
指定 HTTP 請(qǐng)求中附帶的 header 信息样刷。
header 名和 header 值使用冒號(hào)分割仑扑。如果 header 名或者值包含空格,應(yīng)該使用單引號(hào)將其作為整體包起來置鼻,譬如 --header 'content-type:plain text'夫壁。
--header 選項(xiàng)可以重復(fù)使用多次來配置多對(duì) header,最多不超過 100 對(duì)沃疮。
以下為保留 header盒让,用戶配置不生效:"Host"、"Accept"司蔬、"User-Agent"邑茄、"Connection"、"Content-Length"俊啼。
e.g.
--header SomeHeader:SomeValue
--header 'Some Header:Some Value' --header k2:v2
--data <value>
HTTP 使用 POST 方法時(shí)附帶的 body 信息肺缕,建議使用單引號(hào)包起來。
e.g.
--data 'Hello world!'
--json-path <value>
指定了對(duì) HTTP 原始響應(yīng) body 進(jìn)行 JSONPath 處理授帕。
JSONPath 語法說明:https://goessner.net/articles/JsonPath/
目前支持:$.[]*
e.g.
--json-path '$.obj' 取子對(duì)象
--json-path '$[0]' 從數(shù)組取下標(biāo)
--json-path "$['obj']" 取子對(duì)象
--json-path '$[0,1].obj' 取多個(gè)對(duì)象
--body-plain-text
指定了返回正文內(nèi)容格式同木,缺省 --body-plain-text。
--resp-header <header>
指定了從 HTTP 原始響應(yīng) header 全集中返回給查詢方的子集跛十。
如果指定的 header 不在原始響應(yīng) header 全集中彤路,則返回 value 為空字符串。
可以指定多次 --resp-header 來指定返回多個(gè) header芥映。
--header-plain-text
指定了返回 HTTP 響應(yīng) header 的格式洲尊,缺省 --header-plain-text远豺。
具體格式為每個(gè)"header:value"占一行,使用 \r\n 換行坞嘀。
--header-to-json
指定了返回 HTTP 響應(yīng) header 使用 JSON 格式組織躯护,每個(gè) header:value 為頂層 kv。
--encrypted-envelope <value>
加密信封字段丽涩,傳遞機(jī)密信息給預(yù)言機(jī) TEE 實(shí)例棺滞。
加密信封為以下 JSON 格式字符串的 BASE64 編碼:
{ "cipher_text": "", // 機(jī)密信息密文,使用 aes-256-gcm 加密
"aes_iv":"", // 對(duì)稱加密 iv
"gcm_aad": "", // 對(duì)稱加密 add
"gcm_tag": "" // 對(duì)稱加密 tag
"encrypted_aes_key": "" // 經(jīng)過 TEE 公鑰加密后的對(duì)稱加密 key
"rsa_key": "", // TEE 實(shí)例的 RSA 公鑰
}
其中 cipher_text 字段為機(jī)密信息矢渊,值為以下固定結(jié)構(gòu)的 JSON 字符串:
{"macro_replacement":{}, "content_hash":"", "nonce_str":"", "timestamp":"", "time_to_live":""}
其中 macro_replacement 存放宏替換內(nèi)容继准,可以在 URL path、body昆淡、header 中嵌入宏锰瘸,然后將替換值寫在macro_replacement 中刽严,只對(duì) TEE 可見昂灵。合法宏只能從 'ORACLE_SUB_MACRO_0' ~ 'ORACLE_SUB_MACRO_4' 選擇,并且替換值中不能包括合法宏舞萄。
content_hash 存放 CURL 命令明文部分內(nèi)容計(jì)算的哈希值眨补,鎖定加密信封只能與鎖定的明文一起使用。
nonce_str倒脓、timestamp撑螺、time_to_live 暫未啟用。
機(jī)密信息使用 AES/GCM/NoPadding 加密崎弃,再用 TEE 的公鑰使用(TEE 的公鑰在跨鏈服務(wù)頁面中查詢)RSA/None/OAEPPadding 加密 AES 密鑰甘晤。
4.5 預(yù)言機(jī)合約錯(cuò)誤碼
錯(cuò)誤碼 | 16 進(jìn)制錯(cuò)誤碼值 | 10 進(jìn)制錯(cuò)誤碼值 | 描述 | 解決方法 |
---|---|---|---|---|
OE_SUCCESS | 0x0000 | 0 | 查詢成功 | |
OE_UNKNOWN_ERROR | 0x0002 | 2 | 未知錯(cuò)誤 | 聯(lián)系管理員。 |
OE_QUERY_COMMAND_PARSE_ERROR | 0x1000 | 4096 | 命令解析錯(cuò)誤 | 檢查命令語法是否正確饲做。 |
OE_REQUEST_QUERY_COMMAND_NONSUPPORT | 0x1001 | 4097 | 非法命令 | 檢查命令线婚,目前僅支持 CURL。 |
OE_TLS_ERROR | 0x1002 | 4098 | 網(wǎng)絡(luò)連接錯(cuò)誤 | 聯(lián)系管理員盆均。 |
OE_UNRECOGNIZED_OPTION | 0x1200 | 4608 | 非法選項(xiàng) | 查命令選項(xiàng)是否拼寫有誤塞弊,檢查命令選項(xiàng)是否存在拼寫錯(cuò)誤或者存在 CURL 命令使用說明 中沒有的選項(xiàng)。 |
OE_OPTION_CONFLICTS | 0x1201 | 4609 | 選項(xiàng)存在沖突 | 檢查是否同時(shí)使用了語義互斥的命令選項(xiàng)泪姨。 |
OE_INVALID_JSONPATH | 0x1202 | 4610 | JSONPath 語法錯(cuò)誤 | 檢查 JSONPath游沿。 |
OE_REQUEST_ENVELOPE_PARSE_ERROR | 0x1203 | 4611 | 信封解析錯(cuò)誤 | 檢查信封字段。 |
OE_REQUEST_ENVELOPE_MISS_FIELD | 0x1204 | 4612 | 信封缺失字段 | 檢查信封是否缺失必要字段肮砾,具體參考 CURL 命令使用說明诀黍。 |
OE_REQUEST_ENVELOPE_DECRYPT_ERROR | 0x1205 | 4613 | 信封解密失敗 | 檢查信封是否使用了規(guī)定的加密算法,具體參考 CURL 命令使用說明仗处。 |
OE_REQUEST_ENVELOPE_CONTENT_PARSE_ERROR | 0x1206 | 4614 | 信封內(nèi)容解析勢(shì)必 | 檢查信封結(jié)構(gòu)是否遵循規(guī)定的結(jié)構(gòu)蔗草,具體參考 CURL 命令使用說明咒彤。 |
OE_REQUEST_ENVELOPE_CONTENT_MISS_FIELD | 0x1207 | 4615 | 信封內(nèi)容缺失字段 | 檢查信封是否缺失必要字段,具體參考 CURL 命令使用說明咒精。 |
OE_REQUEST_ENVELOPE_CONTENT_HASH_CHECK_ERROR | 0x1208 | 4616 | 信封內(nèi)容哈希不一致 | 檢查是否采用了規(guī)定的哈希算法镶柱,具體參考 CURL 命令使用說明。 |
OE_REQUEST_ENVELOPE_CONTENT_MACRO_CHECK_ERROR | 0x1209 | 4617 | 信封內(nèi)容宏錯(cuò)誤 | 檢查信封中關(guān)于宏的使用方法是否正確模叙。 |
OE_CONTENT_EXCEED_LIMIT | 0x1400 | 5120 | 返回原始內(nèi)容超長(zhǎng) | 檢查數(shù)據(jù)源串長(zhǎng)度是否超出限制歇拆。 |
OE_RESPONSE_ERROR | 0x1401 | 5121 | 數(shù)據(jù)源返回失敗 | 遠(yuǎn)端數(shù)據(jù)源返回失敗,需要用戶根據(jù)需求重新發(fā)起請(qǐng)求范咨。 |
OE_JSON_PATH_NOT_IN_CONTENT | 0x1402 | 5122 | 返回內(nèi)容中不存在指定 JSONPath | 檢查數(shù)據(jù)源的返回?cái)?shù)據(jù)格式故觅,根據(jù)實(shí)際情況使用 JSONPath 命令。 |
OE_JSON_PATH_FOR_NON_JSON | 0x1403 | 5123 | 返回內(nèi)容不是 JSON 但指定了 JSONPath渠啊。 | 檢查數(shù)據(jù)源的返回?cái)?shù)據(jù)格式是否為 JSON输吏,否則不能使用 JSONPath 命令。 |
OE_CURL_INVALID_SCHEMA | 0x2000 | 8192 | 非法 URL Schema | 僅支持 HTTPS替蛉。 |
OE_CURL_INVALID_PORT | 0x2001 | 8193 | 非法端口 | 檢查端口是否有效贯溅,可以使用 Linux CURL 工具進(jìn)行測(cè)試。 |
OE_CURL_INVALID_PATH | 0x2002 | 8194 | 非法路徑 | 檢查 path 的語法是否正確躲查,具體參考 CURL 命令使用說明它浅。 |
OE_CURL_HEADER_NUM_EXCEED_LIMIT | 0x2003 | 8195 | —header 選項(xiàng)個(gè)數(shù)過多 | 最多指定 100 個(gè) header。 |
OE_CURL_HTTP_HEADER_PARSE_ERROR | 0x2004 | 8196 | —header 的值格式錯(cuò)誤 | 必須是“key:value”镣煮。 |
OE_CURL_METHOD_NON_SUPPORTED | 0x2005 | 8197 | 非法的請(qǐng)求方法 | 僅支持 GET 和 POST 方法姐霍。 |
REJECT_SYSTEM_ERROR | 0x5000 | 20480 | 服務(wù)處理請(qǐng)求解析失敗,拒絕該請(qǐng)求典唇。 | 預(yù)言機(jī)系統(tǒng)處理該筆請(qǐng)求錯(cuò)誤镊折,需要客戶端重新發(fā)起請(qǐng)求。 |
REJECT_ILLEGAL_REQUEST | 0x5100 | 20736 | 服務(wù)處理請(qǐng)求解析失敗介衔,拒絕該請(qǐng)求恨胚。 | 非法 CURL 語法。檢查 CURL 命令是否按照 CURL 命令使用說明 中的約束構(gòu)建夜牡。 |
REJECT_ILLEGAL_CMD | 0x5101 | 20737 | 服務(wù)處理請(qǐng)求解析失敗与纽,拒絕該請(qǐng)求 | 非法 CURL 語法。檢查 CURL 命令是否按照 CURL 命令使用說明 中的約束構(gòu)建塘装。 |
REJECT_ILLEGAL_SERVICE_ID | 0x5102 | 20738 | 不存在請(qǐng)求指定的 Service ID急迂。 | 使用正確的 Service ID。 |
REJECT_OVERSIZE_CMD | 0x5104 | 20740 | 請(qǐng)求內(nèi)容過大 | CURL 命令不大于 10240 字節(jié)蹦肴。 |
REJECT_ENVELOPE_ILLEGAL_BASE64 | 0x5105 | 20741 | 加密信封 Base64 解碼失敗 | 檢查加密信封 Base64 編碼僚碎。 |
REJECT_ENVELOPE_NOT_EXIST_KEY | 0x5106 | 20742 | 加密信封的 key 不存在 | 檢查加密信封的結(jié)構(gòu)是否正確傳入 key。 |
REJECT_ENVELOPE_UNKNOWN_KEY | 0x5107 | 20743 | 加密信封的 key 未能識(shí)別 | 檢查加密信封的 key 是否使用約定的用法傳入阴幌。 |
REJECT_BY_REQUEST_FILTER | 0x5301 | 21249 | 請(qǐng)求白名單限制 | 配置請(qǐng)求白名單勺阐。 |
REJECT_BY_RESPONSE_FILTER | 0x5302 | 21250 | 請(qǐng)求結(jié)果安全校驗(yàn)失敗 | 請(qǐng)求結(jié)果中內(nèi)容安全處理失敗卷中,檢查數(shù)據(jù)源的安全性。 |
5. 參考
(1)外部數(shù)據(jù)源服務(wù)
https://tech.antfin.com/docs/2/108575
(2)預(yù)言機(jī)(oracle)2.0:用完即走渊抽,為智能合約可信地與外部世界交互提供必要條件(上)
https://zhuanlan.zhihu.com/p/35007714
(3)什么是區(qū)塊鏈預(yù)言機(jī)(BlockChain Oracle)
https://zhuanlan.zhihu.com/p/52369816
截止2019.04.10蟆豫,針對(duì)創(chuàng)新大賽的TEE硬件隱私合約鏈的外部預(yù)言機(jī)功能還未開放出來,但是標(biāo)準(zhǔn)合約鏈的外部預(yù)言機(jī)ORACLE功能已開放懒闷。