# EIP-7480: EOF - 資料區段存取指令
# 注意事項
本文並沒有經過作者外的其他審查者審核,因此若內容有誤,請到 issue 區提出問題,我會儘速修改,謝謝。
# 摘要
這個提案為 EOFv1 提供四個新指令,讓程式能夠讀取 EOF 容器中的資料區段:
DATALOAD
將 32 位元組的資料載入堆疊DATALOADN
給定一個靜態立即參數,代表從指定位址載入 32 位元組資料到堆疊DATASIZE
將資料區段大小載入堆疊DATACOPY
將一部分的資料區段複製到記憶體
# 動機
EOFv1 的重要特色之一是徹底分離程式碼區段與資料區段。這樣的設計使得資料區段可以包含任何內容,例如編譯器的詮釋資料,並且不需要在程式碼中進行任何額外的處理。
然而因為分離,導致新的智慧合約無法使用原本的指令來存取這段資料,以太坊虛擬機(EVM)需要一套新的指令來讀取分離後的資料區段。
因此為了避免混淆,在 EOFv1 中,原先使用於檢查位元組碼的相關指令(如 CODECOPY
、CODESIZE
等)已被棄用。
並提供以下新指令來替換:
DATALOAD
、DATASIZE
、DATACOPY
指令的設計模式如同現有的存取資料指令(比如對回傳資料 return data 與呼叫資料 call data)相似。DATALOADN
則是DATALOAD
的特化版本,能在編譯時期就設定好資料的讀取位置,因此不需要在執行時驗證,使得此指令更節省成本。
# 規格
本 EIP 預計與 EIP-3540 一起生效,在相同的區塊高度上加入以下四個新指令:
DATALOAD
(0xd0)DATALOADN
(0xd1)DATASIZE
(0xd2)DATACOPY
(0xd3)
如果是傳統的 EVM 位元組碼,以上這些指令都會觸發「異常停止」。
如果是有效的 EOFv1 程式碼,則將以下述規則來執行:
# DATALOAD
- 從堆疊彈出一個值
offset
。 - 從資料區段讀取
[offset:offset+32]
段落,並將其作為 32 位元組值推入堆疊。 - 如果
offset + 32
大於資料區段大小,超出資料區段結尾的位元組會被設為 0。 - 消耗 4 單位 Gas。
堆疊變化示意圖:
前 後
+---------+ +-----------+
| offset | | data[offs]|
+---------+ +-----------+
| ... | | ... |
+---------+ +-----------+
# DATALOADN
- 有一個立即參數
offset
,以 16 位元無符號 bit-endian 方式來編碼。 - 不從堆疊彈出任何內容。
- 從資料區段讀取
[offset:offset+32]
段落,並將其作為 32 位元組值推入堆疊。 - 消耗 3 單位 Gas。
注意,因為此指令是在編譯時期就給定參數,因此在程式碼驗證的關卡會確保 [offset:offset+32]
在資料區段範圍內。
立即參數:offset (16位元)
堆疊變化示意圖:
前 後
+---------+ +-----------+
| ... | | data[offs]|
+---------+ +-----------+
| ... | | ... |
+---------+ +-----------+
# DATASIZE
- 不從堆疊彈出任何內容。
- 將當前容器的資料區段大小推入堆疊。
- 消耗 2 單位 Gas。
堆疊變化示意圖:
前 後
+---------+ +-----------+
| ... | | data_size |
+---------+ +-----------+
| ... | | ... |
+---------+ +-----------+
# DATACOPY
- 從堆疊彈出三個值:
mem_offset
、offset
、size
。 - 執行記憶體擴展到
mem_offset + size
並扣除記憶體擴展成本。 - 消耗
3 + 3 * ((size + 31) // 32)
單位 Gas 用於複製操作。 - 從資料區段讀取
[offset:offset+size]
段落,並將其寫入從mem_offset
開始的記憶體位置。 - 如果
offset + size
大於資料區段大小,則超出資料區段結尾的部分將以 0 填充。
堆疊變化示意圖:
前 後
+---------+
| size |
+---------+
| offset | 空堆疊
+---------+
|mem_offset|
+---------+ +-----------+
| ... | | ... |
+---------+ +-----------+
記憶體變化:
mem_offset mem_offset+size
↓ ↓
+-----+---------------------------+-----+
| | 從資料區段複製的資料 | |
+-----+---------------------------+-----+
# 程式碼驗證
本 EIP 擴展了 EIP-3670 的程式碼區段驗證規則。
- 如果任何
DATALOADN
的立即參數offset
使得offset + 32
大於部署前容器標頭檔中寫明的資料區段大小,則程式碼區段無效。 RJUMP
、RJUMPI
和RJUMPV
立即參數值(跳轉目標的相對偏移量)驗證:如果偏移量指向DATALOADN
指令後面的兩個位元組中的任一個,則程式碼區段無效。
# 目前設計上的選擇
# 缺少 EXTDATACOPY
EXTCODECOPY
指令在 EOFv1 合約中被棄用並拒絕,當在傳統 EVM 程式碼呼叫 EOF 合約時,它將不會複製合約程式碼。主要只是想減少對於 EOF 合約的改動,雖然這個限制將導致依賴 EXTCODECOPY
的純資料合約無法在 EOFv1 中使用,但如果確實有強烈需求(請廣大合約開發者擊鼓申冤,去提新的 EIP 來讓這件事發生的話),就可以在未來的升級中引入 EXTDATACOPY
來恢復這些功能。