# EIP-7698: EOF - 部署交易
# 注意事項
本文並沒有經過作者外的其他審查者審核,因此若內容有誤,請到 issue 區提出問題,我會儘速修改,謝謝。
# 摘要
部署交易(也就是「to」欄位為空的交易)可以用來部署 EOF 智慧合約,方式是在交易的 data
欄位中提供 EOF 初始容器,以及用於執行初始容器的 calldata
(並將兩者串接起來)。這種初始容器的執行流程與 EOFCREATE
指令的執行邏輯類似,最終會以 RETURNCODE
指令結束。新帳戶地址的計算則是根據發送者地址與其 Nonce 值。
# 動機
部署交易是除了傳統 EVM 的部署指令之外,用來部署新程式碼的三種方式之一。由於傳統的 CREATE
和 CREATE2
指令不支援部署 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) |
當部署交易的 data
以 EOF_MAGIC
(0xEF00
) 開頭時,表示該 data
為 EOF 初始容器與 calldata
的串接。其處理步驟如下:
- 根據 EIP-3860,對整個
data
計算部署交易的固有 Gas 成本。 - 將
data
分割為初始容器與calldata
:- 解析 EOF 標頭檔
- 累加所有區段大小與標頭檔大小,即為完整初始容器的長度
- 驗證初始容器及其遞迴子容器,並確認:
data_size
欄位值與實際資料區段大小一致- 不包含
RETURN
或STOP
指令
- 若標頭檔解析或驗證失敗,交易仍有效但會執行失敗。只扣除固有部署交易成本,不執行初始容器。
- 剩餘的
calldata
作為執行初始容器時的輸入。 - 執行流程如下:
- 使用
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 合約
- 使用
- 最後會額外扣除
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 | 版本 | 區段標頭 | 程式碼區段 | 資料區段 (含初始值) |
+------------+----------+-------------+------------+------------------+