Solidity

使用 abi.encodePacked() 儲存字元串或將其轉換為 bytes32 是否更便宜?

  • June 16, 2021

例如,在下面的程式碼中,將 儲存string在 a 中會更便宜mapping嗎?或者將其轉換為bytes32並儲存為然後在我使用 JavaScript 呼叫它時bytes32將其轉換回?string

mapping(string => bool) _tokenExists;

function test(string memory _str) public {
   _tokenExists[_str] = true;
}

或者

mapping(bytes32 => bool) _tokenExists;

function test(string memory _str) public {
   _tokenExists[abi.encodePacked(_str)] = true;
}

其中哪一種會更便宜、更好用,為什麼?

PS:有沒有一種方法可以讓我自己找出未來通過自己進行天然氣估算會更便宜的方法?

首先,abi.encodePacked(_str)將 轉換string _str為它的 UTF-8bytes表示,而不是轉換為bytes32. bytes是一個動態大小的字節數組,就像string. 由於Solidity 0.8.5可以bytes轉換為bytes32,但您需要注意,因為超過 32 字節的任何內容都將被截斷。

因此,如果您string的 UTF-8bytes表示為 32 字節或更短,則可以將其放在bytes32viabytes32(abi.encodePacked(_str))中,而如果您的字元串長於 32 字節,則可以將其壓縮為bytes32via keccak256(abi.encodePacked(_str))


來自Solidity 文件

對應於映射鍵的k值位於連接的位置,並且keccak256(h(k) . p)是根據其類型應用於鍵的函式:.``h

  • 對於值類型,h將值填充到 32 個字節,方法與將值儲存在記憶體中時的方式相同。
  • 對於字元串和字節數組,h計算keccak256未填充數據的雜湊值。

p上面是映射變數(你的_tokenExists)的“槽位置”,所以在合約中它是恆定的。對於此範例,假設p = 0. 所以我們有:

鑰匙類型k值槽位置
bytes32keccak256( k . 0 )
bytes或者stringkeccak256( keccak256(abi.encodePacked(k)) . 0 )

因此,對於mapping帶有bytesstring鍵類型的 s,訪問一個mapping值會呼叫一個額外的keccak256。但是呼叫keccak256足夠便宜,不會影響您的設計決策。相反,您應該使用stringbytes32取決於語義上更適合您的契約的內容。


一個簡單的方法來測試上面的理論“你自己,未來”是通過在Remix IDE中載入一個測試合約,將它部署到JavaScript VM Environment,並使用相同的輸入字元串呼叫不同的函式,嘗試短字元串和長字元串,並比較不同的功能’ execution cost,例如:

pragma solidity ^0.8.5;

contract Test {
   mapping(string => bool) _tokenExists1;
   function test1(string memory _str) external {
       _tokenExists1[_str] = true;
   }

   mapping(bytes => bool) _tokenExists2;
   function test2(string memory _str) external {
       _tokenExists2[abi.encodePacked(_str)] = true;
   }

   mapping(bytes32 => bool) _tokenExists3;
   function test3(string memory _str) external {
       _tokenExists3[keccak256(abi.encodePacked(_str))] = true;
   }

   mapping(bytes32 => bool) _tokenExists4;
   function test4(string memory _str) external {
       _tokenExists4[bytes32(abi.encodePacked(_str))] = true;
   }
}

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