# IX. Service Accounts
> [name=Eugene]
> ==TODO: 移動至 Note 4. Overview==
> 前情提要:建議先閱讀 4.9 The Core Model and services
> Ethereum 是使用 *on-chain consensus*, 所有節點都需要對所有的交易進行計算,確保網絡的狀態一致,但效能較差,系統缺乏擴展性。
> JAM 提出一種新的方式 *in-core consensus*, 只有部份的節點進行計算,但由於共識不是所有節點進行驗證,因此透過 *guaranteeing*, *assuring*, *auditing* 以及有可能需要 *judging*, 來讓這個由部份節點所計算結果足夠被相信是有效的。
> 這些在 in-core 計算的結果, 都必須可以在已最終確定的區塊上重新執行,也拿到相同的結果, 將 in-core 設計為 stateless, 將不需要考同步性,並且可以很容易的將計算重現於任何區塊 (只要使用相同的輸入參數即可), 而為了達到這個需求,in-core 的執行需要以下內容:
> - the refinement code (執行邏輯, 處理輸入、產生結果)
> - the code of the authorizer (驗證這一個 in-core 執行是合法的)
> - preimage lookups (可以在執行期間查詢到相關資料)
JAM 中的 service 類似於 Ethereum 的智能合約 (smart contract), Service Accounts 包含以下三個部份
- Code (程式碼)
- Storage (儲存空間)
- Balance (餘額)
相較於 Ethereum, JAM 把程式碼邏輯分為兩個部份:
- Refinement
- Stateless
- in-core (高效能的計算)
- Accumulation
- Stateful (依賴於前面的區塊參數)
- on-chain (涉及狀態更新與儲存)
---
Service Accounts 被儲存於狀態 $\sigma$ (sigma) 中, 記錄為 $\delta$ (delta)
可以使用服務辨識符 (service identifier) $\mathbb{N}_S$ 來映射到一個描述 service 的 $\mathbb{A}$ tuple (包含了數個描述 service 的資訊)
$$
\mathbb{N}_S \equiv \mathbb{N}_{2^{32}}
$$
$$
\delta \in \mathbb{D} \langle {\mathbb{N}_S} \to {\mathbb{A}} \rangle
$$
- $\mathbb{N}_S$ 是 service identifier (index)
- $\mathbb{N}_{2^{32}}$ 是一個 32 位的自然數,表示最多可以定義 $2^{32}$ 個 service account
- $\mathbb{A}$: The set of service accounts
- $\mathbb{D}$: The set of dictionaries
> State $\sigma$ 所儲存的資訊可以參考 4.2. The State.
---
以下定義為一個 service account $\mathbb{A}$ 中所包含的資訊

- $\mathbf{s}$: storage dictionary
- $\mathbf{p}$: preimage lookup dictionary
- $\mathbf{l}$: preimage lookup dictionary
- $c$: code hash
- $b$: balance
- $g$: gas (執行 accumulate 所需的最低 gas)
- $m$: gas (執行 on transfer 所需的最低 gas)
> - $\mathbb{D}$: The set of dictionaries
> - $\mathbb{Y}$: The set of octet strings/blobs
> - $\mathbb{H}$: The set of 32-octet cryptographic values (沒有下標的 $\mathbb{H}$ 通常代表 hash function 的結果)
> - $\mathbb{N}_B$: The set of balance values. Equivalent to $\mathbb{N_{2_{64}}}$. See equation 4.21.
> - $\mathbb{N}_G$: The set of unsigned gas values. Equivalent to $\mathbb{N_{2_{64}}}$. See equation 4.23.
> - $\mathbb{N}_L$: The set of blob length value. Euqivalent to $\mathbb{N}_{2^{32}}$. See equation 3.4.
> - $\mathbb{N}_T$: The set of timeslot values. Equivalent to $\mathbb{N}_{2^{32}}$. See equation 4.28.
因此,你可以透過 service identifier 來取得在 $\mathbb{A}$ 中的相關資訊,例如以下範例:
- $\delta[\mathbf{s}]_b$: 取得 service account $s$ 的 balance
- $\delta[s]_\mathbf{s}[k]$: 取得一個在 service account $s$ 的 storage $\mathbf{s}$ 中,以 $k$ ($k \in \mathbb{H}$) 作為 key 的儲存項目
> :robot_face:
> $\delta[\mathbf{s}]_b$:`service_accounts[service_index].balance`
> $\delta[s]_\mathbf{s}[k]$:`service_accounts[service_index].storage[storage_key]`
---
## 9.1 Code and Gas
- Code $\mathbf{c}$ 在 service account 中會以 hash 進行表示
- 如果一個 service 是可以執行的 (具有 code 資訊), 那麼 code $\mathbf{c}$ 就必須存在於他自己的 preimage lookup 中 (See 9.2 Preimage Lookups)
對於所有屬於 $\mathbb{A}$ 的 service account $\mathbf{a}$, 其 code $\mathbf{c}$ 可以被定義為:


> [name=yu2C] 多出 metadata 讓 fetch 的時候可以由第一個 byte 就知道這些額外 info
>
> - name, author, version, licence/copyright...
> - 左邊為 pre-iamge, 右邊用 code hash 拿到相對應的 pre-image
> - $a_\mathbf{m}$ 只是 accumulation `fetch` 的時候用而已
:::info
- $\mathbf{a}_{\mathbf{c}}$: (**dictionary value**) 儲存於 preimage 中 service account 的 code
- $\mathbf{a}_c$: (**dictionary key**) 儲存於 service account 的 code hash
```python
# 公式想要表達的意思:從 Dictionary 中取值, default None
code = preimage_dict.get(code_hash, None)
```
:::
---
Code 會有三種進入點:
- **0 refine**: Refinement, executed in-core and stateless.
- **1 accumulate**: Accumulation, executed on-chain and stateful.
- **2 on_transfer**: Transfer handler, executed on-chain and stateful.
> 關於 Refine 如何在 in-core 進行計算, 會在 section 14.3 Packages and Items 有更詳細的介紹
---
### 關於 Gas
- JAM 虛擬機中的執行時間,以 *gas* 為單位進行測量
- 可以被表示為小於 $2^{64}$ 的自然數, 被寫為 $\mathbb{N}_G$
- 如果數值可能負值,可以使用 $\mathbb{Z}_G$ 來表示 $\mathbb{Z}_{-2^{63}...2^{63}}$
每個 service account 定義了兩種 *gas* 限制:
- $g$: 執行 *Accumulate* 所需的最低 *gas*
- $m$: 執行 *On Transfer* 所需的最低 *gas*
## 9.2 Preimage Lookups
以下為 preimage lookup dictionary 與 storage 的比較表
| 特性 | Preimage Lookups | Storage |
| --- | --- | --- |
| **映射類型** | 從 hash 映射到 preimage | 任意鍵(Key)映射到值(Value) |
| **資料來源** | 資料由外部(extrinsically)提供 | 資料來自服務的內部累積(accumulation) |
| **移除機制** | 需先標記為不可用 (unavailable),經過一段時間後才能移除 | 可自由移除 |
| **歷史資訊保存** | 保留 preimage 歷史, 提供查詢歷史可用性 | 不會保留歷史資訊 |
| **查詢目的** | 設計為核心(in-core)查詢,供服務代碼的 Refine 邏輯使用 | 通常僅供一般存儲需求 |
Accumulate 與 Refine 的差別:
- Accumulate 階段 (on-chain),驗證者可以透過 State $\sigma$ 中得知相關的靜態資料
- Refine 階段 (in-core), 驗證者無法取得 State $\sigma$ 進行使用, 因此將一個歷史狀態稱做 `lookup anchor` (必須要是最終確定的狀態), 作為一個參考歷史點,讓 Refine 階段的計算結果,也可以正確的累積 (accmulate)
透過保留可用的歷史資料,我們相信任何在最近最終確定範圍內的驗證者,都能夠確定任意的 preimage 是可以在審核期間被存取到
-> 任何一個驗證者,只要他們擁有最近完成最終確認的 view (他們有權限的話), 就能判斷某個特定的 preimage 在審核期間內是否曾經被使用
### *historical lookup function* $\Lambda$ (Lambda)
歷史查詢函數,可以查詢到某一個 service account $\mathbf{a}$ 在某一個時間點 $t$,是否可以使用這一個 preimage hash $h$ 查詢到對應的 preimage
> 以下公式只是簡短的定義, 後續會有詳細版公式


- $\mathbf{a}$: 一個 service account
- $t$: 查詢的時間點
- $\mathcal{H}_{(\mathbf{p})}$: preimage 的 hash value
- $\mathcal{H}$: The Blake 2b 256-bit hash function. See section 3.8.
- $v$: historical lookup function 的輸出結果
- account $\mathbf{a}$ 可以使用,拿回該 preimage $\mathbf{p}$
- 或是 account $\mathbf{a}$ 不可使用,拿到空值 $\varnothing$
> - $\mathbb{A}$: The set of service accounts
> - $\mathbb{N}_{\mathbf{H}_t - C_D...\mathbf{H}_t}$: 一個時間點 (==$C_D$ 找不到定義的地方==)
> - 這邊想要表達從歷史到當前的 time slot index, 可以作為輸入的時間點
> - $\mathsf{D}= 19, 200$: The period in timeslots after which an unreferenced preimage may be expunged.
> - $\mathbb{H}$: The set of 32-octet cryptographic values.
> - $\mathbb{Y}$: The set of octet strings/blobs
- $\delta[s]_\mathbf{p}$: 代表該 service 的 preimage dictionary, 可以透過 preimage hash 查詢 preimage
- $\delta[s]_\mathbf{l}$: 代表該 service 可用的歷史資料,可以透過 hash 以及資料長度作為 dictionary key 進行查詢
### 9.2.1 Invariants
lookup 系統應該具有一些不變特性

$\forall a \in \mathbb{A}, (h \mapsto \mathbf{p}) \in a_{\mathbf{p}}$ : 所有在 service accounts 集合中的 account, preimage dictionary 中存在的 hash 映射 preimage,必須符合以下條件:
1. $h = \mathcal{H}({\mathbf{p}})$ : hash 必須是 preimage hash 的結果
2. $(h, |\mathbf{p}|) \in \mathcal{K}(a_\mathbf{l})$ : hash 以及 preimage 的長度,必須是 account $l$ dictionary 中的其中一個 key
> - $\mathcal{K}(a_{\mathbf{l}})$: 是一個 service account 儲存 preimage 歷史資訊的 Dictionary keys
> - $\mathcal{K}$: 是一個可以拿回 Dictionary keys 的函數
> - $(h, |\mathbf{p}|$): 一個由 preimage hash 以及 preimage length 所組合成的 tuple
> - $\mathbb{H}$: The set of 32-octet cryptographic values (沒有下標的 $\mathbb{H}$ 通常代表 hash function 的結果)
### 9.2.2 Semantics
$h \in [\![\mathbb{N}_T]\!]_{:3}$
- $h$: 歷史狀態 (historical status component)
- $[\mathbb{N}_T]_{:3}$: 最多可以儲存三個時間點(time slot)的序列
這一個歷史狀態 $h$ 序列的長度,會有四種的狀態模式:
- $h = []$
- 表示已經請求 preimage 中, 但是還沒被提供 (還沒被儲存)
- $h \in [\![\mathbb{N}_T]\!]_1$
- 表示從 $h_0$ 這個時間點開始, preimage 可以被存取
- $h \in [\![\mathbb{N}_T]\!]_2$
- 表示之前 ($h_0$) 可以使用的 preimage 自從 $h_1$ 後不可以被存取了 (preimage $h_0$ 到 $h_1$ 之間是可以使用的)
- $h \in [\![\mathbb{N}_T]\!]_3$
- 表示 preiamge 在 $h_0$ 到 $h_1$ 的時間內可以使用,但是後來無法存取,直到 $h_2$ 後,再次可以被存取。
透過以上的定義,historical lookup function $\Lambda$ (Lambda) 可以被定義為以下:

==h 如何更新, 如果更多歷史出現==
:::info
**historical lookup funciton 參數**
$\Lambda(\mathbf{a}, t, h)$ 是一個歷史查詢函數,需要以下三種輸入參數:
- $\mathbf{a}$: 一個 service account
- $t$: 想要查詢的時間點
- $h$: preimage hash
:::
:::info
**historical lookup funciton 邏輯**
若符合以下兩個條件, 代表 account 能夠在 $t$ 時間點使用該 preimage
- $h \in \mathcal{K}(\mathbf{a}_{\mathbf{p}})$
- hash 屬於 account preimage dictionary 的 keys 之一
- $I (\mathbf{a}_{\mathbf{l}}[h, |\mathbf{a}_{\mathbf{p}}[h]|], t)$
- $I$: 是一個函數,可以判斷 account $\mathbf{a}$ 在某個時間點 $t$ 是否可以取用 preimage $\mathbf{p}$
- $\mathbf{a}_{\mathbf{l}}[h, |\mathbf{a}_{\mathbf{p}}[h]|]$
- $\mathbf{a}_{\mathbf{l}}$ : account 儲存 preimage 歷史資訊的 dictionary
- 該 dictionary 的 key 是由 preimage hash 及 preimage length 所組成
- $\mathbf{a_{\mathbf{p}}}$ : account 的 preimage dictionary
- $h$ : preimage hash
- $t$ : 查詢時間點
- 回傳 boolean: True or False
- 在這個時間點,該 service account 是否可以存取該 preimage
- $I$ 函數回傳 boolean,取決於上面描述的四種狀態模式 (不同時間點該 preimage 是否可以被使用)
:::
:::info
**historical lookup function 輸出**
如果 account $a$ 可以在 $t$ 時間點取用以 preimage hash $h$ 所拿到的 preimage $\mathbf{p}$
那麼將會取得該 preimage, 否則拿到 $\varnothing$
:::
:::spoiler historical lookup function - pseudo code
```python
def historical_lookup_function(account, time, hash):
if hash_is_preimage_dict_key and is_available_time:
return account.preimage[hash]
else:
return None
def hash_is_preimage_dict_key(hash, preimage_dict):
if hash in list(preimage_dict.keys())
return True
return False
def is_available_time(history, lookup_time):
if len(history) == 0:
return False
if len(history) == 1:
x = history[0]
return x <= t
if len(history) == 2:
x = history[0]
y = history[1]
return x <= t < y
if len(history) == 3:
x = history[0]
y = history[1]
z = history[2]
return (x <= t < y) || z <= t
```
:::
### 9.3. Account Footprint and Threshold Balance
只要 service's storage 有所改變,這兩個變數都需要被更新
- $i$: the number of items in storage (儲存項目的數量)
- $l$: the total number of octets used in storage (octets 儲存的總大小)
> 這兩個資訊在 serialization function 也會用到
- $t$: 根據該 service account 的儲存項目與空間,所需要的最低餘額數量 (儲存東西要付錢)


- $\forall a \in \mathcal{V}(\delta)$: 所有的 service account 都會屬於 service accounts dictionary $\delta$ 的 value 之一
:::info
#### $a_i$ (儲存項目的數量)
$$
a_i \in \mathbb{N}_{2^{32}} \equiv 2 \cdot |a_\mathbf{l}| + |a_\mathbf{s}|
$$
- 是一個 $2^{32}$ 自然數
- $|a_{\mathbf{l}}|$: service account metadata (historical information) dictionary 的大小
- $|a_{\mathbf{s}}|$: service account storage dictionary 的大小
- ==為什麼乘 2? -> 因為 dictionary 包含 key 以及 value==
> [name=yu2C] 因為 $a_{\mathbf{l}}$ 的 key size 比別人大兩倍?
:::
::: info
#### $a_l$
> octets 儲存的總大小 (storage diciontary $s$ + preimage lookup dictionary $l$)
$$
a_l \in \mathbb{N}_{2^{64}} \equiv \sum\limits_{(h,z) \in \mathcal{K}(a_\mathbf{l})} (81 + \mathcal{z}) + \sum\limits_{x \in \mathcal{V}(a_s)} (32 + |\mathcal{x}|)
$$
- 是一個 $2^{64}$ 自然數
- $(h, z) \in \mathcal{K}(a_\mathbf{l})$
- $\mathcal{K}(a_\mathbf{l})$: service account metadata dictionary 的 keys
- $(h, z)$: metadata dictionary key 是一個 tuple
- $h$: preimage hash
- $z$: preimage 的長度 ($|\mathbf{p}|$)
- ==81 是? hash 固定大小?==
> [name=yu2C] How many bytes we are used to store items(keys)
- $x \in \mathcal{V}(a_s)$
- $\mathcal{V}(a_s)$: service account storage dictionary 的 values
- $x$: service account storage 某個儲存的數值
- ==32 是?== size of hash
:::
:::info
#### $a_t$
> service account 必須持有的最低餘額門檻, 因為他使用了這些儲存空間
> (基礎費用 + items 數量計費 + octet 儲存空間計費)
$$
a_t \in \mathbb{N}_B \equiv \mathsf{B}_S + \mathsf{B}_I \cdot a_i + \mathsf{B}_L \cdot a_l
$$
- $\mathbb{N}_B$: The set of balance values, 是 $2^{64}$ 的自然數
- (constant) $\mathsf{B}_S$ = 100, 所有 services 所需要的最低餘額
- (constant) $\mathsf{B}_I$ = 10, 儲存每個 item 所需要的最低餘額
- (constant) $\mathsf{B}_L$ = 1, 儲存每個 octet 所需要的最低餘額
:::
## 9.4 Service Privileges.
- 最多可以有三個 service 可以成為具有特權的 service
- 某些服務可以對特定的狀態進行變更,或是自動累積資源
- 這是 state 的一部分,被表示為 $\chi$
:::info
Service Privileges
$\chi$ 是由三個 service index 以及 gas 的限制所組成
$$
\chi \equiv ({
{\chi_m} \in {\mathbb{N}_S},
{\chi_a} \in {\mathbb{N}_S},
{\chi_v} \in {\mathbb{N}_S},
{\chi_\mathbf{g}} \in {\mathbb{D} \langle {\mathbb{N}_S} \rightarrow {\mathbb{N}_G} \rangle}
}
)
$$
- $\chi_m$: 代表一個 *manager* service 的 index, 這個 service 能夠影響區塊之間 $\chi$ 的組成 (可以影響 $\chi$ 中的 service index 或是 gas limit 數值)
- $\chi_a$: 可以修改區塊之間的 $\varphi$ (authorization queue)
- $\chi_v$: 可以修改區塊之間的 $\iota$ (pending validators set)
- $\chi_\mathbf{g}$: 是一個 Dictionary, 會持續累積每一個 service index, 在每一區塊所累積的基本 gas 數量 (每一個 service index 自動獲得基本的 gas 數量)
:::