如何在單個合約中將多達 50k 個地址列入白名單?
將合約中的大量地址列入白名單的最佳做法是什麼。例如,如果我想將 50k 地址包含到
true
僅反映 50k 地址的映射中,這會是最佳方式嗎?每個地址需要多少費用?mapping (address => bool) userAddr; function whitelistAddress (address user) onlyOwner { userAddr[user] = true; }
毫無疑問,將 50k 個地址硬編碼到合約中會達到區塊 gas 限制。我如何準確計算這將花費多少
快速下限
您可以設置成本的下限,因為每個地址至少包含一個 SSTORE。因此,硬編碼 50k 個地址(每個 20 kgas)的成本將超過 1 Gigagas。最新的區塊限制為 6.7 Megagas。從長遠來看,它不適合。
Gsset - 20000 gas - 當儲存值從零設置為非零時為 SSTORE 操作付費
來源:黃皮書,附錄 G
實際成本
那麼讓我們看看增量添加白名單地址的實際成本。Remix是快速估算函式的 gas 成本的絕佳方式。
使用此合約:
pragma solidity ^0.4.15; contract Owned { address owner; function Owned() { owner = msg.sender; } modifier onlyOwner() { require(msg.sender == owner); _; } } contract Whitelist is Owned { mapping (address => bool) userAddr; function whitelistAddress (address user) onlyOwner { userAddr[user] = true; } }
我以這種方式執行該功能:
- 選擇“Javascript VM”環境
- 點擊$$ Create $$在右側欄的白名單下
"0x5B2063246F2191f18F2675ceDB8b28102e957458"
在旁邊輸入$$ whitelistAddress $$按鈕- 點擊$$ whitelistAddress $$按鈕
執行
whitelistAddress(...)
結果:Transaction cost: 43464 gas
總花費:
50k transactions * 43k gas ~= 2 Gigagas
按照目前 0.5 gwei 的“安全低”成本,這相當於總 gas 成本的約 1 乙太幣。
邊際改善的批處理
添加白名單地址的一些呼叫是成本:原始函式呼叫、檢查所有者等。讓我們看看有多少。
pragma solidity ^0.4.15; contract Whitelist is Owned { mapping (address => bool) userAddr; function whitelistAddress (address[] users) onlyOwner { for (uint i = 0; i < users.length; i++) { userAddr[users[i]] = true; } } }
使用包含四個地址的列表呼叫此方法會消耗 109833 gas,因此每個地址的成本僅為 27458.25 gas。我們不會比明確的白名單做得更好,因為下限是每個地址 20k gas。
使用這種方法,安全低價的總乙太幣成本下降到大約:
50k addresses * 27k gas * 0.5 gigawei ~= 0.7 Ether
更奇怪的選擇
也許你真的沒有白名單,也許是黑名單或客人名單,偶爾的誤報也不算太糟糕。那麼布隆過濾器可能是一個合理的解決方案。調整布隆過濾器需要對您的特定案例了解太多,但它可以輕鬆地將總成本降低 1,000 倍或 10,000 倍。