Solidity

如何在單個合約中將多達 50k 個地址列入白名單?

  • April 10, 2022

將合約中的大量地址列入白名單的最佳做法是什麼。例如,如果我想將 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;
   }
}

我以這種方式執行該功能:

  1. 選擇“Javascript VM”環境
  2. 點擊$$ Create $$在右側欄的白名單下
  3. "0x5B2063246F2191f18F2675ceDB8b28102e957458"在旁邊輸入$$ whitelistAddress $$按鈕
  4. 點擊$$ 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 倍。

引用自:https://ethereum.stackexchange.com/questions/23945