首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在实体中使用状态变量的大小限制和成本是多少?

在实体中使用状态变量的大小限制和成本是多少?
EN

Ethereum用户
提问于 2022-09-06 14:24:58
回答 1查看 114关注 0票数 2

在此样板中,它将用户帐户余额存储在状态变量中。在我有限的理解中,在链上存储数据将是昂贵的。这是否意味着使用智能契约的用户越多,运行合同的成本就越高?保持一个可能在状态变量中无限期增长的映射可以吗?还是有更好的选择?也许把它存储在IPFS里?

以下是守则的副本:

代码语言:javascript
复制
//SPDX-License-Identifier: UNLICENSED

// Solidity files have to start with this pragma.
// It will be used by the Solidity compiler to validate its version.
pragma solidity ^0.8.9;

// We import this library to be able to use console.log
import "hardhat/console.sol";


// This is the main building block for smart contracts.
contract Token {
    // Some string type variables to identify the token.
    string public name = "My Hardhat Token";
    string public symbol = "MHT";

    // The fixed amount of tokens stored in an unsigned integer type variable.
    uint256 public totalSupply = 1000000;

    // An address type variable is used to store ethereum accounts.
    address public owner;

    // A mapping is a key/value map. Here we store each account balance.
    mapping(address => uint256) balances;

    // The Transfer event helps off-chain aplications understand
    // what happens within your contract.
    event Transfer(address indexed _from, address indexed _to, uint256 _value);

    /**
     * Contract initialization.
     */
    constructor() {
        // The totalSupply is assigned to the transaction sender, which is the
        // account that is deploying the contract.
        balances[msg.sender] = totalSupply;
        owner = msg.sender;
    }

    /**
     * A function to transfer tokens.
     *
     * The `external` modifier makes a function *only* callable from outside
     * the contract.
     */
    function transfer(address to, uint256 amount) external {
        // Check if the transaction sender has enough tokens.
        // If `require`'s first argument evaluates to `false` then the
        // transaction will revert.
        require(balances[msg.sender] >= amount, "Not enough tokens");

        // We can print messages and values using console.log, a feature of
        // Hardhat Network:
        console.log(
            "Transferring from %s to %s %s tokens",
            msg.sender,
            to,
            amount
        );

        // Transfer the amount.
        balances[msg.sender] -= amount;
        balances[to] += amount;

        // Notify off-chain applications of the transfer.
        emit Transfer(msg.sender, to, amount);
    }

    /**
     * Read only function to retrieve the token balance of a given account.
     *
     * The `view` modifier indicates that it doesn't modify the contract's
     * state, which allows us to call it without executing a transaction.
     */
    function balanceOf(address account) external view returns (uint256) {
        return balances[account];
    }
}
EN

回答 1

Ethereum用户

回答已采纳

发布于 2022-09-06 15:14:34

这真的取决于你对数据做了什么。

如果您有一个存储数组,向它添加元素,然后在一个函数中遍历该数组,是的,您的合同可能会开始消耗越来越多的气体,直到它无法使用为止。除非您也从其中移除元素。循环遍历存储数组来查找一个元素是昂贵的,因为该操作的时间复杂度是线性的,O(n)。如果您有1000个元素,最坏的情况是您需要经过1000次迭代才能找到项目。

但是对于mappings来说,你不需要循环它的元素。您一个接一个地访问它们,这在恒定的时间内发生,O(1) (无论映射中有多少元素,您总是要执行完全相同的操作来找到其中的一个元素,这意味着它将花费相同的气体)。因此,mapping可以增长和增长,仍然是廉价的使用。此外,如果您有从映射中删除元素的逻辑,或者映射中的值被设置为默认值,那么它们将不包含任何空间,并且会更轻。

例如:

如果您有此映射:

代码语言:javascript
复制
mapping(address => uint256) public balances;

你把一些余额加到一些地址上。然后将其中一些地址的余额减少到0(这是uint256的默认值),然后契约“重置”balances映射用于该地址的空间。

理论上,将大量数据存储在智能契约中是很昂贵的,因为每次向存储中添加新数据时,您都会花费大量的精力在存储中存储数据。将数据放在那里并不那么昂贵,除非您需要多次阅读它。更昂贵的是循环遍历数据,正如我前面在使用数组时解释的那样,我们应该花时间设计一个好的解决方案,这个解决方案不会大幅度增长,并且认为契约是不可用的。

经验丰富的开发人员可以使用mapping和数组的组合来创建高效的解决方案。还可以有逻辑来处理不再需要的数据并清除存储。EVM奖励你一些汽油退款,当你清除数据从存储,也从内存时,合同运行。https://github.com/ethereum/EIPs/issues/1048

您的示例合同看上去不错,而且看起来将来运行成本也不会更高。您使用的是映射,而不是循环遍历任何内容。

一篇可能有助于理解存储数据是如何根据类型存储和访问的文章:

https://coinsbench.com/solidity-layout-and-access-of-storage-variables-simply-explained-1ce964d7c738

EVM操作码和它们消耗了多少气体:

https://github.com/crytic/evm-opcodes

特别是从存储中读取一个字(32个字节)的SLOAD,要花费800个气体。

SSTORE把数据写入存储,从20000气体开始。

票数 2
EN
页面原文内容由Ethereum提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://ethereum.stackexchange.com/questions/135107

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档