Solidity

高效訪問映射

  • August 31, 2021

我正在通過儲存在映射中的結構來跟踪數據。

mapping(uint256 => Session);

這是Session struct

 struct Session {
     // UID
     uint256 id;
     // Timestamp the sale starts
     uint256 start;
     // Timestamp the sale stops
     uint256 stop;
     // Last rate sync timestamp
     uint256 sync;
     // Current Rate
     uint256 rate;
     // Rate normalization: rate / 10**{decimal}
     uint8 decimal;
     // Current TOKEN|BNB Rate
     uint256 issue;
     // WEI raised
     uint256 raised;
     // Maximum sale quantity
     uint256 max;
     // Total tokens sold
     uint256 sold;
     // Total minutes before bnb rate update
     uint256 threshold;
     // Contract address of chainlink aggregator
     address chainlink;
     // Token Sale Owner
     address owner;
     // Token Contract
     IBEP20 token;
 }

修改會話的最有效方法是什麼?

方法一:

/**
  * @dev low level token purchase ***DO NOT OVERRIDE***
  * @param _beneficiary Address performing the token purchase
  */
 function buyTokens(uint256 _id, address _beneficiary) public payable open(_id) {

   uint256 weiAmount = msg.value;
   _preValidatePurchase(_beneficiary, weiAmount);

   // calculate token amount to be created
   uint256 tokens = _getTokenAmount(weiAmount);

   // update state
   sessions[_id].raised = sessions[_id].raised.add(weiAmount);

   _processPurchase(_beneficiary, tokens);
   emit TokenPurchase(
     msg.sender,
     _beneficiary,
     weiAmount,
     tokens
   );

   _forwardFunds();
   _postValidatePurchase(_beneficiary, weiAmount);
 }

方法二:

 /**
  * @dev low level token purchase ***DO NOT OVERRIDE***
  * @param _beneficiary Address performing the token purchase
  */
 function buyTokens(uint256 _id, address _beneficiary) public payable open(_id) {

   uint256 weiAmount = msg.value;
   _preValidatePurchase(_beneficiary, weiAmount);

   // calculate token amount to be created
   uint256 tokens = _getTokenAmount(weiAmount);

   // update state
   Session storage sesh = sessions[_id];
   sesh.raised = sesh.raised.add(weiAmount);

   _processPurchase(_beneficiary, tokens);
   emit TokenPurchase(
     msg.sender,
     _beneficiary,
     weiAmount,
     tokens
   );

   _forwardFunds();
   _postValidatePurchase(_beneficiary, weiAmount);
 }

出於某種原因,方法 2 更好,當我訪問映射時,每次都必須搜尋嗎?

和 storage 關鍵字,這實際上是否修改了映射中儲存中的對象,還是我只是瘋了?

提前知道哪種方法是最佳的有點困難。在您的場景中,gasEstimate 指出第二種方法更便宜。


為了測試您的實現,我從契約中剝離了所有內容,除了值的分配(我也有一個假結構):

契約

// contracts/Box.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;



contract Optim {
   struct Session {
       uint256 raised;
   }

   mapping(uint256 => Session) sessions; 
   
   
   constructor() {        
       sessions[1] = Session(1);
   }

   function direct(uint256 _id) public payable {            
       // update state
       sessions[_id].raised = sessions[_id].raised + 999;        
   }   

   function tmpvar(uint256 _id) public payable {            
       // update state
       Session storage sesh = sessions[_id];
       sesh.raised = sesh.raised + 999;        
   }   
}

用松露創建一個簡單的測試可以讓我們獲得一些資訊:

gasEstimate.js

const Optim = artifacts.require("Optim");

contract("Optim", () => {
   it("should have different gas", async() => {
       const O1 = await Optim.new();

       const method1 = await O1.direct.estimateGas(11);
       const method2 = await O1.tmpvar.estimateGas(11);

       console.log("method1 cost: " + method1, "method2 cost: " + method2);
       assert(method1 < method2, "method 1 < method2");
   });
});

控制台輸出是

method1 cost: 42762 method2 cost: 42675

因此第二種方法更便宜

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