# EIP-7698: EOF - 部署交易

# 注意事項

本文並沒有經過作者外的其他審查者審核,因此若內容有誤,請到 issue 區提出問題,我會儘速修改,謝謝。

# 摘要

部署交易(也就是「to」欄位為空的交易)可以用來部署 EOF 智慧合約,方式是在交易的 data 欄位中提供 EOF 初始容器,以及用於執行初始容器的 calldata(並將兩者串接起來)。這種初始容器的執行流程與 EOFCREATE 指令的執行邏輯類似,最終會以 RETURNCODE 指令結束。新帳戶地址的計算則是根據發送者地址與其 Nonce 值。

# 動機

部署交易是除了傳統 EVM 的部署指令之外,用來部署新程式碼的三種方式之一。由於傳統的 CREATECREATE2 指令不支援部署 EOF 格式,因此部署交易是目前部署 EOF 程式碼上鏈,除了 EOFCREATE (參考 EIP-7620) 以外的唯一方式。

為了不破壞現有工具鏈的部署流程,如何傳遞建構函式參數的機制刻意與傳統部署方式相同,即把參數與初始容器串接起來即可,使得現有的部署工具無需任何修改也能無痛支援 EOF。

# 規格說明

除非另有說明,EOF 合約的部署規則應與傳統部署交易相同或類似,包括但不限於:

  • 關於 accessed_addresses 與地址衝突的處理(請參考 EIP-684 與 EIP-2929)
  • 為初始程式碼部署的 EVM 執行環境(例如記憶體、帳戶環境)
  • 新合約帳戶的 Nonce 增加(請參考 EIP-161)
  • 部署時轉帳的餘額驗證與轉移邏輯

# 常數定義

常數名稱
EOF_MAGIC 0xEF00(定義於 EIP-3540)
MAX_CODE_SIZE 24576(定義於 EIP-170)

當部署交易的 dataEOF_MAGIC (0xEF00) 開頭時,表示該 data 為 EOF 初始容器與 calldata 的串接。其處理步驟如下:

  1. 根據 EIP-3860,對整個 data 計算部署交易的固有 Gas 成本。
  2. data 分割為初始容器與 calldata
    • 解析 EOF 標頭檔
    • 累加所有區段大小與標頭檔大小,即為完整初始容器的長度
  3. 驗證初始容器及其遞迴子容器,並確認:
    • data_size 欄位值與實際資料區段大小一致
    • 不包含 RETURNSTOP 指令
  4. 若標頭檔解析或驗證失敗,交易仍有效但會執行失敗。只扣除固有部署交易成本,不執行初始容器。
  5. 剩餘的 calldata 作為執行初始容器時的輸入。
  6. 執行流程如下:
    • 使用 keccak256(sender || sender_nonce)[12:] 計算新帳戶地址
    • 執行成功會以 RETURNCODE{deploy_container_index}(aux_data_offset, aux_data_size) 結尾
      • 從指定容器索引載入部署容器
      • 串接其資料區段與記憶體中 (aux_data_offset, aux_data_offset + aux_data_size) 片段,並更新標頭檔資料大小
      • 若更新後大小 > MAX_CODE_SIZE,則異常終止
      • 成功部署後,state[new_address].code 即為更新後的部署容器
      • 此時不適用 EIP-3541 對 0xEF 開頭程式碼的禁止規定,畢竟我們確實在部署一個 EOFv1 合約
  7. 最後會額外扣除 200 * deployed_code_size 的 Gas

# 簡單範例

以下為一個簡單計數器合約的部署範例,初始值會透過建構函式設定:

// 計數器合約 (counter.eof)
// 功能:儲存數字,可增加或取得
// 建構函式參數:初始值

部署交易如下:

{
  "from": "0x123...789",
  "to": "",
  "value": 0,
  "data": "0xEF00...000000000000000000000000000000000000000000000000000000000000000A"
}

流程與 ASCII 示意圖

+-------------------------------+
|        部署交易開始           |
+-------------------------------+
             |
             v
+-------------------------------+
| 檢查交易.data 是否以 0xEF00 開頭 |
+-------------------------------+
             |
             v
+-------------------------------+
|     分割 data 為兩部分:      |
| 1. EOF 初始容器               |
| 2. 建構函式參數(calldata)   |
+-------------------------------+
             |
             v
+-------------------------------+
| 驗證初始容器(標頭、結構等)  |
+-------------------------------+
             |
             v
+-------------------------------+
| keccak256(sender || Nonce)[12:]|
| → 計算新帳戶地址              |
+-------------------------------+
             |
             v
+-------------------------------+
| 執行容器並處理 calldata       |
+-------------------------------+
             |
             v
+-------------------------------+
| 執行 RETURNCODE 指令          |
| → 回傳部署容器與附加資料     |
+-------------------------------+
             |
             v
+-------------------------------+
| 儲存至區塊鏈的最終部署程式碼 |
+-------------------------------+

# 資料結構圖解

交易.data 結構:
+-------------------------+------------------+
| EOF 初始容器            | 建構參數 (10)    |
| 0xEF00...               | 0x...0000000A    |
+-------------------------+------------------+

EOF 初始容器結構:
+------------+----------+-------------+------------+-------------+
| EOF_MAGIC  | 版本     | 區段標頭    | 程式碼區段 | 資料區段    |
| 0xEF00     | 0x01     | ...         | ...        | ...         |
+------------+----------+-------------+------------+-------------+

記憶體內容(執行時):
+------------+------------+------------+----------------+
| Offset 0   | ...        | aux_offset | ...            |
| 運算資料   | ...        | calldata   | ...            |
+------------+------------+------------+----------------+
                            ↓
                        初始化使用
                            ↓
最終部署程式碼:
+------------+----------+-------------+------------+------------------+
| EOF_MAGIC  | 版本     | 區段標頭    | 程式碼區段 | 資料區段 (含初始值) |
+------------+----------+-------------+------------+------------------+
Last Updated: 2025/5/21 下午3:18:25