Solidity 智慧合約字節碼優化
source : https://medium.com/@uzair.afzal/smart-contract-bytecode-downsizing-6bcfeb237a4c by M. Uzair Afzal
Solidity 智能合約字節碼大小的最大限制在 24 kb — 25 kb 之間。具有超出此範圍的字節碼的合約無法部署到以太坊主網路。來自官方文件:
“ 2016 年 11 月 22 日, Spurious Dragon 硬分叉引入了EIP-170,增加了 24.576 kb 的智能合約大小限制。”
讓我們仔細看看,更好地理解為什麼我們有這樣的限制,以及如何將合約字節碼大小保持在 24K 位元組以下。
為什麼有字節碼限制?
為了防止 DoS(拒絕服務)攻擊,最大數量有限制。可以部署到區塊鏈的合約的大小(部署字節碼的大小)。
原因
當合約大小增加時,呼叫者的Gas 使用量不會增加太多,因為他們只需支付函數執行所需的Gas 使用量,但礦工運作函數的資源使用量會增加,因為他們必須將更大的合約讀入RAM現在。因此,攻擊者可以建立一個非常大的合約,然後呼叫其中的一個小函數。這或許會讓攻擊者付出不到一美元的代價,但礦工的 RAM 可能會因為讀取如此巨大的合約而崩潰,從而掛起他們的系統。鑑於所有礦工都運行每筆交易,每個人的電腦都會被凍結,所有人的網路服務都會中斷。這就是為什麼合約規模限制至關重要。
如何節省字節碼大小?
若要減少合約的位元組大小,請遵循以下提示(根據它們對合約字節碼大小減少的影響標記為“中”或“大” ):
- [ MEDIUM ]:組合函數:不要建立多個函數,而是將程式碼組合成一個函數
- [ MEDIUM ]:內嵌函數呼叫:不是建立函數,而是在同一呼叫函數中處理函數。放棄其他功能。
- [ MEDIUM ] 建立較少的記憶體變數:不要在記憶體中的函數內創建大量變數。相反,直接使用來自 calldata 的傳入參數
- [ MEDIUM ]:自訂錯誤和小錯誤字串:應使用小錯誤字串和自訂錯誤(例如錯誤 Unauthorized();),而不是長字串。來自 Solidity 文件:
「Solidity 0.8.4 中引入了自訂錯誤。它們是減少合約大小的好方法,因為它們被 ABI 編碼為選擇器(就像函數一樣)”
- [ LARGE ]:使用編譯器最佳化:編譯器最佳化可以做很多事情,例如刪除未使用的程式碼、重新排序函數呼叫、內聯函數、組合函數等。在 Hardhat 設定檔中 — 如果讀者熟悉 Hardhat生態系統並使用它- 添加此程式碼以在編譯過程中啟用編譯器最佳化:
solidity: {
compilers: [
{
version: "0.8.21",
settings: {
optimizer: {
enabled: SHOULD_ENABLE_OPTIMIZATION, // true or false
runs: OPTIMIZER_RUNS,
/*
Runs:
Default: 200
Min: 1
Max: 4.2 billion = (2 ^ 32) - 1
Runs determine for how many function calls a
contract function should be optimized. According
to the docs:
> 01. Smaller value means cheap deployment but expensive function calls
> 02. Larger value means expensive deployment but cheaper function
*/
},
},
},
],
},
閱讀Solidity 官方文檔,以更好地了解運行參數及其對智能合約優化的影響。現在,當您使用以下命令編譯合約時:
npx hardhat compile
它們將在編譯過程中進行最佳化。
- [ LARGE ]:單獨合約:將您的合約拆分為多個合約。這對於減少單一合約的字節碼大小有巨大的影響
- [ LARGE ]:更多函式庫用法:來自以太坊文件:
“庫與合約類似,但其目的是僅在特定位址部署一次,並且透過 DELEGATECALL 重複使用其程式碼。”
使用函式庫,而不是自己編寫所有內容。庫使用“delegateCall”來保留上下文並運行外部程式碼來修改呼叫者的合約狀態。因此,當函式庫函數不是內部函數時(因為內部成員由子級繼承!),它們可以節省大量字節碼大小。然而,如果它們是內部的,它們將全部添加到基礎合約中,從而增加其大小。例如,OpenZeppelin的幾個函式庫中的幾乎所有函數都標記為「內部」。因此,它們被添加到基礎合約中,增加了合約的字節碼大小。
直到下一次,
Uzair