Oracle系列一: Human Oracle
智能合約如何取得外界資料。
智能合約是在EVM (Ethereum Virtual Machine)中執行的,它是個封閉的環境,所有執行過程都離不開EVM,換句話說,合約沒辦法由EVM內部向外界取得任何資料。以下圖來解釋,外部帳號A1可以呼叫合約C1所提供的功能,合約C1執行的過程中,可以傳送ether給外部帳號A2,或是再呼叫合約C2,但是不管執行過程如何複雜,就是離不開EVM。
這個特性大大限制了Dapp的發展,舉一個最經典的例子『骰子遊戲』,由於Solidity並沒有random number generator功能,所以這遊戲就做不下去了。這時有人引入了Oracle的概念,讓智能合約能夠透過Oracle取得外部資料。Oraclize就是提供這類服務的公司,如下圖,透過他們的服務就可以讓合約呼叫外部Web API取得所需資料。
看起來非常神奇,直覺上好像辦不到,因為違反了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
接著我將 "Oracle"
字串透過 _queryCallback()
回傳給合約,記得複製_id當成參數一併傳入。
最後User使用 getResponse
取回 0x224f7261636c6522
就是 Oracle的字串
這樣就完成簡單的Oracle示範。
不過這個版本的合約存在一個致命的缺點,因為Event是所有人都可以監聽的,可能會有其他人故意亂回覆,所以需要再加入指定responder是誰的功能,而且只有合約的擁有者可以設定,這樣就可以確保Human Oracle就是我自己啦!
將合約更新如下:
下一篇將介紹如何寫出類似Oraclize一樣的服務架構,可以讓其他合約使用,而不是單機版,敬請期待。