# 陀飛鏈 (續)
---
### 其實,本專案就是一個時間的 oracle 服務
---
### 這是它的架構設計

---
### 每個元件的說明如下
---
### 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}]"}