Solidity

函式中什麼更好,每次需要時使用映射或將映射結果儲存在變數中並重新使用該變數?

  • September 5, 2022

我有一個將電子郵件(bytes32)連結到名為(uint256)的映射emailToId

   mapping(bytes32 => uint256) public emailToId;

我的智能合約中也有使用此映射的函式,但我不知道哪個更好:

1 - 每次需要時使用映射

   function changeUserNameAndEmail (
       bytes32 email,
       bytes32 newName,
       bytes32 newEmail
   ) public {
       users[emailToId[email]].name = newName;
       emailToId[newEmail] = emailToId[email];
       delete emailToId[email];
   }

2 - 將映射結果儲存在一個變數中userId,並在每次需要時重新使用該變數

  function changeUserNameAndEmail (
      bytes32 email,
      bytes32 newName,
      bytes32 newEmail
  ) public {
      uint256 userId = emailToId[email];
      users[userId].name = newName;
      emailToId[newEmail] = userId;
      delete emailToId[email];
  }

PS:這是一個簡單的例子,但有一些功能我需要使用 emailToId

$$ email $$幾次……我應該使用映射還是將其儲存在氣體成本和性能方面的變數中?

這有點棘手。

您所做的比較每種方法消耗的氣體的練習是要走的路。

通常,不需要mapping在記憶體中複製一個值。直接讀取和寫入它可能就足夠了。

但有時,如果我們知道我們將讀取/寫入mapping多次,則在記憶體中複製該值可能很有用,也許我們只需要複製該值,對其執行許多操作,然後將其寫入一次到映射。特別是如果我們使用循環。

請記住,在記憶體中複製一個值也需要消耗氣體,從 3 個氣體單位開始。複製的總成本將取決於您要複製的數據的大小。因此,有時我們可能不會從複製memory.

如果您在這裡查看操作碼和它們消耗的氣體,您會注意到MSTORE(將值儲存在記憶體中)使用3*氣體將數據儲存在記憶體中。這*意味著它將取決於要複製的數據的大小。 MLOAD(從記憶體中讀取值)消耗相同的3*.

請注意,SLOAD使用 800 gas 從儲存中讀取一個字(32 個字節)。另請注意,SSTORE用於20000*將值儲存在儲存器中,具體取決於要保存的值,從 20000 單位的氣體開始。

結論:

如果您不可避免地需要從 amapping或儲存 x 次讀取並且您必須不可避免地再寫入mappingx 次,那麼請考慮您是否真的需要在記憶體中製作副本,您可能不會這樣做。

不要複製數據,memory除非您需要並且認為這樣做是有益的。因為如果不需要進行複制memory,那麼您將浪費資源,因為您將在儲存中讀取/寫入,並且最重要的是在記憶體中製作數據的額外副本。有時它會很有用,有時它不會。

比較這兩種方法,您可以選擇使用較少氣體的方法。使用循環時,檢查您是否多次修改同一個狀態變數,並決定是否應該更好地在 中創建一個副本memory,修改該副本,然後只用結果更新一次儲存。

在此處檢查所有 EVM 操作碼和它們消耗的氣體:https ://github.com/crytic/evm-opcodes

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