Contract-Design

為什麼刪除會增加總gas成本?

  • December 18, 2018

我的理解是有一個 gas 退款delete,這個想法是鼓勵開發人員從契約狀態中刪除垃圾。

考慮這個合約與映射結構的鍵的刪除啟用索引。中的delete操作deleteVoter() 不是功能按要求工作所必需的。

deletes包括在內時,a 的氣體約為 34056 deleteVoter()deletes註釋掉後,合約功能和以前一樣,但只deleteVoter()需要大約 23926 個 gas。因此,該功能在沒有垃圾收集deleteVoter()的情況下更加省油。delete

**Q1:**為什麼會deletes增加成本?

**Q2:**我是否遺漏了優化這兩個delete似乎會增加 gas 成本的操作?

**Q3:**我可能錯過了gas退款的要點嗎?我預計退款會deletes變成淨儲蓄,因此成本deleteVoter()會降低。也就是說,激勵垃圾收集。

pragma solidity 0.4.11;

contract IterableMappingWithDelete {

 struct Voter {
   uint votesCast;                                         // application data
   uint voterListPointer;                                  // structurally important
 }

 mapping(address => Voter) public voterStructs;            // random access by key
 address[] public voterList;                               // sequential access by row and count

 function getVoterCount() public constant returns(uint voterCount) {return voterList.length;}

 function isVoter(address voterId) public constant returns(bool isIndeed) {
   if(voterList.length==0) return false;
   return voterList[voterStructs[voterId].voterListPointer]==voterId; 
 }

 function insertVoter(address voterId) public returns(bool success) {
   if(isVoter(voterId)) throw;
   voterStructs[voterId].voterListPointer = voterList.push(voterId) - 1;
   return true;
 }

 function deleteVoter(address voterId) public returns(bool success) {
   if(!isVoter(voterId)) throw;
   uint rowToDelete = voterStructs[voterId].voterListPointer;
   uint voterListLastRow = voterList.length-1;
   address keyToMove = voterList[voterListLastRow];
   voterStructs[keyToMove].voterListPointer = rowToDelete;
   voterList[rowToDelete] = keyToMove;

   // The next line is optional garbage collection. 
   // It increases the cost of this operation. 

   delete voterStructs[voterId];

   voterList.length--;
   return true;
 }

}

此問題是從原始文章更新的,因此該片段按預期工作。氣體數據也更新了。

刪除儲存中的某些內容(將非零設置為零)確實降低了 gas 成本,但是您的程式碼中有幾件事使這很難看到:

  1. voterList.length--已經具有將“已刪除”值設置為零的副作用,因此delete voterList[voterListLastRow]是多餘的。添加它需要額外的 5,000 氣體(儲存零的成本)。
  2. voterStructs[voterId].voterListPointer = voterList.push(voterId) - 1;意味著添加的第一個投票者的voterListPointer值將為 0。這意味著delete voterStructs[voterId]在第一個投票者上將再次增加 5,000 天然氣。(因為價值已經為零,所以不予退款。)
  3. 此程式碼中的votesCast欄位始終為 0,因此清除它始終是額外的 5,000 氣體。

通過添加這兩行,您將添加 15,000 個 gas(5,000 * 3,因為您正在寫三個零)並獲得 10,000 或 15,000 個額外的 gas 退款(取決於它是否是數組中的第一個選民)。回想一下,gas 退款最多可以返還您消耗的 gas 的一半,所以即使在最好的情況下,您實際上也不會收支平衡。

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