Solidity

同一合約的 Gas 使用量不斷增長

  • June 20, 2019

這是智能合約。該契約的天然氣使用量不斷增長。所有狀態變數都在部署時初始化並且永遠不會改變。Signers 數組的大小不再是 2-3 左右。而這份合約從使用 150,000 個gas 到現在的 600,000 個。

程式碼有任何明顯的問題嗎?

這是一些交易ID:

https://etherscan.io/tx/0x26f13d3b3d0809ffc24f22b5f33966aa0c144e433cbe239649df5f00f3d29740 (使用氣體:117,013)

https://etherscan.io/tx/0xfcf395bd21ce4e69857184ee3d7b2164f3d0d8536b666dad46d5be8455aed73c(使用氣體:681,795)

程式碼:

pragma solidity ^0.4.24;

contract MultiSigContract {
   mapping (address => bool) public IsSigner;
   address public Executer;
   address[] public Signers;

   function MultiSigContract(address[] _signers, address _executer) public {
       require(_executer != 0x0);
       Signers = _signers;
       Executer = _executer;
       for (uint i = 0; i < Signers.length; i++) {
           IsSigner[Signers[i]] = true;
       }        
   }

   function execute(address destination, uint amount, uint8[] sigV, bytes32[] sigR, bytes32[] sigS) public {
       require(sigR.length == sigS.length && sigR.length == sigV.length);
       require(sigR.length == Signers.length);
       require(msg.sender == Executer);
       require(address(this).balance >= amount);

       address[] recoveredAddresses;
       bytes32 txHash = keccak256("\x19Ethereum Signed Message:\n72", this, destination, amount);

       for(uint8 i = 0; i < Signers.length; i++) {
           address recovered = ecrecover(txHash, sigV[i], sigR[i], sigS[i]);
           require(IsSigner[recovered] == true);
           recoveredAddresses.push(recovered);
       }

       for(uint8 j = 0; j < Signers.length; j++) {
           require(contains(Signers[j], recoveredAddresses));
       }

       destination.transfer(amount);
   }

   function contains(address _address, address[] _addressArray) private pure returns (bool) {
       for(uint8 i = 0; i < _addressArray.length; i++) {
           if (_addressArray[i] == _address) {
               return true;
           }
       }

       return false;
   }

   function () public payable {}
}

這是因為recoveredAddresses沒有標記為記憶體,所以預設情況下,它在儲存中。每次推送時,長度都會增加,即使跨事務呼叫也是如此。這也意味著該函式必須在每次執行時contains迭代一個越來越大的數組,隨著時間的推移增加氣體成本。addressArray解決方案是通過將其寫入來製作recoveredAddresses一個記憶體數組address[] recoveredAddresses;。這也意味著您必須圍繞調整大小進行一些返工,因為您不能擁有動態調整大小的記憶體數組。大小必須在編譯時知道。如果數組大小的上限很小,這非常簡單,否則可能會變得複雜。

您可以通過查看“狀態更改”選項卡並展開合約地址來查看此範例。您不斷地將新恢復的地址附加到該數組中。

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