Solidity

為什麼這個合約要求增加gas limit?

  • October 3, 2020
string test;
   function assemblyStorage() public payable returns (string memory a){
    test = "good";
    assembly {
        a:=sload(0)
    }
   }

我正在嘗試返回應該儲存在第一個插槽中的字元串以及文件中所述的字元串長度。但是呼叫 assemblyStorage 函式結果:increase gas limit。無論我增加什麼,都無所謂。真正導致此錯誤的是彙編程式碼。不知道為什麼。

問題是a最終指向一個非常大的記憶體地址,這會導致 EVM 耗盡 gas,因為您需要為使用的記憶體付費。

此行修改了第一個儲存槽

test = "good";

由於它是一個“短”字元串(小於 31 個字節),它以緊湊的形式儲存在一個插槽中(右側的數據和左側的長度 x 2)。

0x676f6f6400000000000000000000000000000000000000000000000000000008

有關更多詳細資訊,請閱讀文章深入了解乙太坊 VM 第 3 部分 — 陣列的隱藏成本

然後a被第一個儲存槽的內容覆蓋。

a := sload(0)

Nowa指向一個非常大的地址,這會導致 out of gas 錯誤,因為solidity 會嘗試從中讀取,即使沒有分配任何內容,您也需要為整個記憶體支付 gas。


我們可以在彙編中安全地使用“短”字元串

function assemblyStorage() public payable returns (string memory a){
   test = "good";
   assembly {
       let r := sload(0)
       // string length
       let l := shr(1, and(r, 0xff))
       // allocate memory for a
       a := mload(0x40)
       // update free memory pointer
       // a + 0x20 + 0x20 * trunc((l + 0x1f) / 0x20)
       mstore(0x40, add(a, add(0x20, shl(5, shr(5, add(l, 0x1f))))))
       // store length
       mstore(a, l)
       // copy data
       mstore(add(a, 0x20), and(r, not(0xff)))
   }
}

在這種情況下,直接使用solidity 更容易且不易出錯。它適用於任何字元串。

function assemblyStorage() public payable returns (string memory a){
   test = "good";
   a = test;
}

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