通過L / R操作碼實現結構化跳過區域
抽象的
這引入了兩個新的 EVM 操作碼, L (左分隔符)和R (右分隔符) ,它們定義了字節碼中的結構化跳過區域。
執行時, L會導致 EVM 跳過其包含的字節,直接跳到匹配的R這些區域允許合約將不可執行的結構化數據直接嵌入字節碼中,同時保持確定性執行。
動機
EVM 字節碼目前沒有原生方法來區分:
- 可執行指令
- 嵌入式元數據
- 編譯表
- 結構常數
- 僅適用於鏈下工具的替代代碼路徑
所有字節都被視為潛在可執行指令,跳過代碼的唯一方法是通過動態跳轉。
這會導致以下問題:
- 編譯器無法安全地將結構化數據嵌入字節碼中。
- 靜態工具必須保守地將所有字節都視為可執行文件。
- 字節碼無法承載複雜的內部結構而不冒著意外執行的風險。
- 控制流必須使用非結構化跳轉來表達。
我們提出了一種結構化的跳過區域,其行為類似於字節碼內部的未執行島嶼。
這些區域允許字節碼安全地包含:
- 查找表
- 跳板
- 類型元數據
- 類似ABI的內部描述符
- 編譯器提示
- 未來擴展有效載荷
不影響執行。
規格
新操作碼
| 操作碼 | 姓名 | 堆 | 描述 |
|---|---|---|---|
0x?? | L | — | 開始跳過區域 |
0x?? | R | — | 跳過區域 |
語義學
1. L — 跳到匹配的R
當 EVM 執行操作碼L時:
- 它進入跳過模式
- 它向前掃描字節碼以查找匹配的
R - 中間的所有字節都會被忽略,永遠不會執行。
- 嵌套的
L/R對必須平衡
匹配算法
depth = 1pc = pc + 1while depth > 0:opcode = code[pc]if opcode == L:depth += 1 else if opcode == R:depth -= 1pc += 1 2. R — 結構分隔符
執行從匹配的R之後的第一個操作碼處恢復。
如果找不到匹配的R → 異常終止。
結構規則
1. 區域是不可執行的
L … R區域內的字節:
- 絕不能執行
- 被視為不透明有效載荷
- 可能包含任意字節值,包括無效的操作碼
2. 跳轉到或跳出不同區域並不被禁止
這樣做是合理的:
-
JUMP到JUMPI區域內的位置 - 從區域內部跳到區域外部
3. 允許嵌套
跳過區域可以嵌套:
L<data or metadata>L<more data> R R匹配算法確保配對正確。
汽油成本
| 操作碼 | 氣體 |
|---|---|
L | 3 |
R | 2 |
客戶端可以預處理字節碼以映射匹配對,從而使L能夠在恆定時間內執行。
理由
字節碼作為一種結構化容器
該提案允許合約將字節碼視為容器格式,而不僅僅是指令。
使用L/R ,字節碼可以安全地包含:
| 用例 | 例子 |
|---|---|
| 常量數據塊 | 預先計算的表格,大型常數 |
| 跳板 | 密集交換機調度表 |
| 類似ABI的內部佈局 | 內部領域特定語言的類型描述符 |
| 調試信息 | 源圖,符號名稱 |
| 編譯器元數據 | 優化提示、佈局信息 |
| 版本化擴展 | 向前兼容的有效載荷區域 |
所有這一切都無需冒意外處決的風險。
為什麼不直接使用JUMP呢?
使用JUMP跳過數據:
- 需要動態控制流
- 使跳過的字節在語法上可執行。
- 使靜態分析變得模糊不清
- 不能安全地包含任意字節模式
L/R則創建顯式的非可執行區域,類似於傳統二進制文件中的數據段。
為什麼不重複使用JUMPDEST ?
JUMPDEST標記有效的跳轉目標,但不標記不可執行區域。
我們需要相反的方法:一種聲明“這不是代碼”的方法。
向後兼容性
完全向下兼容:
- 現有合同不包含
L或R - 舊字節碼行為未改變
- 新的語義僅在存在操作碼時適用。
示例:嵌入數據表
PUSH1 0 x00SSTOREL 0 x12 0 x34 0 x56 0 x78 0 x9a 0 xbc 0 xde 0 xf0 R PUSH1 0 x01SSTORE L … R內部的字節永遠不會被執行,可以通過鏈下工具讀取,也可以通過EXTCODECOPY複製代碼來讀取。
結論
L和R向 EVM 引入了結構化非可執行區域,使字節碼能夠作為代碼和結構化數據的混合體發揮作用。
這:
- 提高可分析性
- 實現更安全的編譯器生成的元數據
- 允許使用密集的字節碼內數據結構
- 保持完全向後兼容性
- 執行模型只需做極少改動
只需添加一個小小的操作碼,EVM 字節碼就能變成一個自描述的、結構化的產物,而不僅僅是一個扁平的指令流。

