Contract-Design
為什麼刪除會增加總gas成本?
我的理解是有一個 gas 退款
delete
,這個想法是鼓勵開發人員從契約狀態中刪除垃圾。考慮這個合約與映射結構的鍵的刪除啟用索引。中的
delete
操作deleteVoter()
不是功能按要求工作所必需的。當
deletes
包括在內時,a 的氣體約為 34056deleteVoter()
。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 成本,但是您的程式碼中有幾件事使這很難看到:
voterList.length--
已經具有將“已刪除”值設置為零的副作用,因此delete voterList[voterListLastRow]
是多餘的。添加它需要額外的 5,000 氣體(儲存零的成本)。voterStructs[voterId].voterListPointer = voterList.push(voterId) - 1;
意味著添加的第一個投票者的voterListPointer
值將為 0。這意味著delete voterStructs[voterId]
在第一個投票者上將再次增加 5,000 天然氣。(因為價值已經為零,所以不予退款。)- 此程式碼中的
votesCast
欄位始終為 0,因此清除它始終是額外的 5,000 氣體。通過添加這兩行,您將添加 15,000 個 gas(5,000 * 3,因為您正在寫三個零)並獲得 10,000 或 15,000 個額外的 gas 退款(取決於它是否是數組中的第一個選民)。回想一下,gas 退款最多可以返還您消耗的 gas 的一半,所以即使在最好的情況下,您實際上也不會收支平衡。