# 陀飛鏈 (續) --- ### 其實,本專案就是一個時間的 oracle 服務 --- ### 這是它的架構設計 ![](https://i.imgur.com/zSyBA7t.png) --- ### 每個元件的說明如下 --- ### Crown (錶冠/龍頭) 負責與以太坊介接,監控事件的傳回並發送時間與簽章 --- ### Calibre (機芯) 負責與 NTP 介接,即時查詢標準時間值 --- ### Mainspring (發條) 負責儲存時間與存證資料內容 --- ### Surface (錶面) 負責提供操作介面,供 Bob 看到目前已有的時間存證紀錄 --- ### 關於 oracle 服務的科普 --- ### oracle 服務的作法,其實就是不斷地監控以太坊的特定事件 --- ### 一旦捕捉到 Alice 呼叫合約,觸發事件之後,就將資料從外部傳入合約 --- ### 因此,有兩大關鍵 --- ### 第一是在 Crown 的監控服務 --- ### 首先設定 filter ```python event_filter = tourb.events\ .WhatTimeIsIt\ .createFilter(fromBlock=0, toBlock='latest') ``` --- ### 再用 Thread 把它封裝起來 ```python monitor = Thread(target=listen_event, args=(event_filter, 1, tourb, w3, priv_key), daemon=True) ``` --- ### Thread 的內容 ```python while True: for event in event_filter.get_new_entries(): handle_event(event, contract, target_net, owner_priv_key) time.sleep(sleep_time) ``` --- ### 最後設計 event handler ```python ... result = contract\ .functions\ .timeIsIt(time, sig, addr, serial)\ .transact() receipt = target_net\ .eth\ .waitForTransactionReceipt(result) ... ``` --- ### 第二個關鍵在合約 --- ### 原先,我使用了 proxy 的合約機制來設計 --- ### But! 卻發現捕捉不到合約的事件 --- ### 只好換成用 Mediator 模式來設計合約 --- ### 先設定語言版本 ```solidity pragma solidity ^0.6.0; ``` --- ### 這回使用的是最新的 0.6.0,而且強迫 compiler 固定在特定版本進行編譯 --- ### 再設定 interface ```solidity abstract contract Tourbillon { function saveMyTreasure(address addr, string memory digest, string memory sign) public virtual returns (uint); ... } ``` --- ### 介面語法由原先的 `interface` 改為 `abstract`,並在函式後方加上 `virtual` --- ### 前導合約實作 interface ```solidity contract Breguet is Tourbillon { ... } ``` --- ### 前導合約建構子傳入合約實體位址 ```solidity Tourbillon private tourbillon; address private owner; constructor (address _tourbillon) public { owner = msg.sender; tourbillon = Tourbillon(_tourbillon); } ``` --- ### 在一個合約裡,呼叫另一個合約,就是將它的實體位址傳入它的介面或合約定義的建構子 --- ### 每一個呼叫的動作,都是呼叫實體合約 ```solidity function saveMyTreasure(address addr, string memory digest, string memory sign) public override returns (uint){ return tourbillon.saveMyTreasure(addr, digest, sign); } ``` --- ### 而這樣的呼叫,也使得我們可以正確拿到合約執行時的事件 --- ### 實作合約實體 ```solidity contract Tourbillon { ... } ``` --- ### 其實 Tourbillon 的介面應該獨立出來作一個檔案,但這次並沒有做得很確實 --- ### 兩個主要的結構性資料 ```solidity struct TimestampAuthorization { string timestamp; string signature; } struct Treasure { string myDigest; string mySign; } ``` --- ### `TimestampAuthorization` - ### 儲存時間驗證資訊 --- ### `Treasure` - ### 儲存存證資訊 --- ### 負責儲存的資料結構 ```solidity mapping(address => mapping(uint => Treasure)) private myArchive; mapping(address => mapping(uint => TimestampAuthorization)) private tsArchive; mapping(address => uint) private mySerial; ``` --- ### 呼叫後端的事件 ```solidity event WhatTimeIsIt(address myAddr, uint serial, string digest, string sign); ``` --- ### 主要的函式 - saveMyTreasure ```solidity function saveMyTreasure(address addr, string memory digest, string memory sign) public returns (uint){ require(addr != address(0)); uint serial = mySerial[addr] + 1; myArchive[addr][serial] = Treasure(digest, sign); mySerial[addr] = serial; emit WhatTimeIsIt(addr, serial, digest, sign); return serial; } ``` --- ### 檢討與發想 --- ### 1. 其實區塊鏈的網路很廣,當事件被傳播到 Bob 的服務時,可能已經過了很久 #### 因此建議提供 WebAPI 給 Alice 呼叫,以縮短完全使用區塊鏈所造成的時間差 --- ### 2. 在以太坊上進行合約操作,是件錙銖必較的事 #### 因此在合約開發、服務定價上需要再深入設計 --- ### 3. 後端介接的 NTP Server 為預設的固定主機 #### 建議合約可以供傳入 NTP 位址,以強化使用者對這服務的信任
{"metaMigratedAt":"2023-06-15T03:43:41.861Z","metaMigratedFrom":"Content","title":"陀飛鏈 (續)","breaks":true,"contributors":"[{\"id\":\"5a30c4d4-f84e-40a1-9cb4-119dc1d40dc8\",\"add\":4011,\"del\":115}]"}
    221 views