Oracle系列一: Human Oracle

yaohsin
Taipei Ethereum Meetup
5 min readMar 31, 2017

智能合約如何取得外界資料。

智能合約是在EVM (Ethereum Virtual Machine)中執行的,它是個封閉的環境,所有執行過程都離不開EVM,換句話說,合約沒辦法由EVM內部向外界取得任何資料。以下圖來解釋,外部帳號A1可以呼叫合約C1所提供的功能,合約C1執行的過程中,可以傳送ether給外部帳號A2,或是再呼叫合約C2,但是不管執行過程如何複雜,就是離不開EVM。

黃色圈表示外部帳號(也就是一般的使用者帳號),綠色圈表示合約帳號

這個特性大大限制了Dapp的發展,舉一個最經典的例子『骰子遊戲』,由於Solidity並沒有random number generator功能,所以這遊戲就做不下去了。這時有人引入了Oracle的概念,讓智能合約能夠透過Oracle取得外部資料。Oraclize就是提供這類服務的公司,如下圖,透過他們的服務就可以讓合約呼叫外部Web API取得所需資料。

Oraclize

看起來非常神奇,直覺上好像辦不到,因為違反了EVM的設計,到底是如何辦到的呢?接下來我們將實作一個簡單版本且需要人為操作的HumanOracle智能合約,來示範如何取得外界資料。

其實訣竅很簡單,這跟看魔術一樣,知道原理之後就會有喔~~~原來如此的想法,然後覺得什麼嘛一點也不神奇XD。不過要將Oracle做的好用其實不容易,這道理也跟變魔術一樣。

訣竅就是:透過Event來跟外界Oracle聯繫,再由Oracle主動將資料拋回EVM

Oracle可以透過監聽特定Event來接收合約所發出的Query,處理完成之後,再由Oracle主動呼叫合約的 callback function將資料回傳即可。

本範例的系統架構與執行流程如下圖,總共有三個角色

  • A1: 一般的使用者帳號
  • C1: 智能合約,裏面實作Event以及callback等function
  • Human Oracle: 這邊是工人智慧,需要手動操作的部分,你也可以寫一支程式來自動化處理。

首先是合約內容,為了支援multi-query,所以每次query要給一個特定id,這邊簡單算出一個hash值當作id來使用。query可以接收bytes,也就是說可以傳入字串,如: "Hello" 再依據Human Oracle的規則回傳response data

這邊使用Parity的Kovan網路來測試,透過他的UI來部署合約

部署合約
成功產生合約

接著使用user帳號執行 query("Hello")

現在假設我自己就是Human Oracle本人,在交易成功之後,我可以看到有個Event被傳出來,帶著_id與_query字串,將 0x2248656c6f22 轉換成ascii就是Hello

透過QueryEvent可以取得必要的資訊

接著我將 "Oracle" 字串透過 _queryCallback() 回傳給合約,記得複製_id當成參數一併傳入。

這邊_id顯示有問題,其實是有輸入的

最後User使用 getResponse 取回 0x224f7261636c6522 就是 Oracle的字串

這樣就完成簡單的Oracle示範。

不過這個版本的合約存在一個致命的缺點,因為Event是所有人都可以監聽的,可能會有其他人故意亂回覆,所以需要再加入指定responder是誰的功能,而且只有合約的擁有者可以設定,這樣就可以確保Human Oracle就是我自己啦!

將合約更新如下:

下一篇將介紹如何寫出類似Oraclize一樣的服務架構,可以讓其他合約使用,而不是單機版,敬請期待。

--

--