Solidity
高效訪問映射
我正在通過儲存在映射中的結構來跟踪數據。
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
因此第二種方法更便宜