# EIP-7480: EOF - 資料區段存取指令

# 注意事項

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

# 摘要

這個提案為 EOFv1 提供四個新指令,讓程式能夠讀取 EOF 容器中的資料區段:

  • DATALOAD 將 32 位元組的資料載入堆疊
  • DATALOADN 給定一個靜態立即參數,代表從指定位址載入 32 位元組資料到堆疊
  • DATASIZE 將資料區段大小載入堆疊
  • DATACOPY 將一部分的資料區段複製到記憶體

# 動機

EOFv1 的重要特色之一是徹底分離程式碼區段與資料區段。這樣的設計使得資料區段可以包含任何內容,例如編譯器的詮釋資料,並且不需要在程式碼中進行任何額外的處理。 然而因為分離,導致新的智慧合約無法使用原本的指令來存取這段資料,以太坊虛擬機(EVM)需要一套新的指令來讀取分離後的資料區段。 因此為了避免混淆,在 EOFv1 中,原先使用於檢查位元組碼的相關指令(如 CODECOPYCODESIZE 等)已被棄用。 並提供以下新指令來替換:

  • DATALOADDATASIZEDATACOPY 指令的設計模式如同現有的存取資料指令(比如對回傳資料 return data 與呼叫資料 call data)相似。
  • DATALOADN 則是 DATALOAD 的特化版本,能在編譯時期就設定好資料的讀取位置,因此不需要在執行時驗證,使得此指令更節省成本。

# 規格

本 EIP 預計與 EIP-3540 一起生效,在相同的區塊高度上加入以下四個新指令:

  1. DATALOAD (0xd0)
  2. DATALOADN (0xd1)
  3. DATASIZE (0xd2)
  4. DATACOPY (0xd3)

如果是傳統的 EVM 位元組碼,以上這些指令都會觸發「異常停止」。

如果是有效的 EOFv1 程式碼,則將以下述規則來執行:

# DATALOAD

  1. 從堆疊彈出一個值 offset
  2. 從資料區段讀取 [offset:offset+32] 段落,並將其作為 32 位元組值推入堆疊。
  3. 如果 offset + 32 大於資料區段大小,超出資料區段結尾的位元組會被設為 0。
  4. 消耗 4 單位 Gas。
堆疊變化示意圖:
    
    前                後
+---------+     +-----------+
| offset  |     | data[offs]|
+---------+     +-----------+
|   ...   |     |    ...    |
+---------+     +-----------+

# DATALOADN

  1. 有一個立即參數 offset,以 16 位元無符號 bit-endian 方式來編碼。
  2. 不從堆疊彈出任何內容。
  3. 從資料區段讀取 [offset:offset+32] 段落,並將其作為 32 位元組值推入堆疊。
  4. 消耗 3 單位 Gas。

注意,因為此指令是在編譯時期就給定參數,因此在程式碼驗證的關卡會確保 [offset:offset+32] 在資料區段範圍內。

立即參數:offset (16位元)

堆疊變化示意圖:
    
    前                後
+---------+     +-----------+
|   ...   |     | data[offs]|
+---------+     +-----------+
|   ...   |     |    ...    |
+---------+     +-----------+

# DATASIZE

  1. 不從堆疊彈出任何內容。
  2. 將當前容器的資料區段大小推入堆疊。
  3. 消耗 2 單位 Gas。
堆疊變化示意圖:
    
    前                後
+---------+     +-----------+
|   ...   |     | data_size |
+---------+     +-----------+
|   ...   |     |    ...    |
+---------+     +-----------+

# DATACOPY

  1. 從堆疊彈出三個值:mem_offsetoffsetsize
  2. 執行記憶體擴展到 mem_offset + size 並扣除記憶體擴展成本。
  3. 消耗 3 + 3 * ((size + 31) // 32) 單位 Gas 用於複製操作。
  4. 從資料區段讀取 [offset:offset+size] 段落,並將其寫入從 mem_offset 開始的記憶體位置。
  5. 如果 offset + size 大於資料區段大小,則超出資料區段結尾的部分將以 0 填充。
堆疊變化示意圖:
    
    前                後
+---------+     
|   size  |     
+---------+     
| offset  |     空堆疊
+---------+     
|mem_offset|    
+---------+     +-----------+
|   ...   |     |    ...    |
+---------+     +-----------+

記憶體變化:
  mem_offset                 mem_offset+size
      ↓                           ↓
+-----+---------------------------+-----+
|     |    從資料區段複製的資料     |     |
+-----+---------------------------+-----+

# 程式碼驗證

本 EIP 擴展了 EIP-3670 的程式碼區段驗證規則。

  1. 如果任何 DATALOADN 的立即參數 offset 使得 offset + 32 大於部署前容器標頭檔中寫明的資料區段大小,則程式碼區段無效。
  2. RJUMPRJUMPIRJUMPV 立即參數值(跳轉目標的相對偏移量)驗證:如果偏移量指向 DATALOADN 指令後面的兩個位元組中的任一個,則程式碼區段無效。

# 目前設計上的選擇

# 缺少 EXTDATACOPY

EXTCODECOPY 指令在 EOFv1 合約中被棄用並拒絕,當在傳統 EVM 程式碼呼叫 EOF 合約時,它將不會複製合約程式碼。主要只是想減少對於 EOF 合約的改動,雖然這個限制將導致依賴 EXTCODECOPY 的純資料合約無法在 EOFv1 中使用,但如果確實有強烈需求(請廣大合約開發者擊鼓申冤,去提新的 EIP 來讓這件事發生的話),就可以在未來的升級中引入 EXTDATACOPY 來恢復這些功能。

Last Updated: 2025/5/21 下午3:18:25