在此样板中,它将用户帐户余额存储在状态变量中。在我有限的理解中,在链上存储数据将是昂贵的。这是否意味着使用智能契约的用户越多,运行合同的成本就越高?保持一个可能在状态变量中无限期增长的映射可以吗?还是有更好的选择?也许把它存储在IPFS里?
以下是守则的副本:
//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];
}
}发布于 2022-09-06 15:14:34
这真的取决于你对数据做了什么。
如果您有一个存储数组,向它添加元素,然后在一个函数中遍历该数组,是的,您的合同可能会开始消耗越来越多的气体,直到它无法使用为止。除非您也从其中移除元素。循环遍历存储数组来查找一个元素是昂贵的,因为该操作的时间复杂度是线性的,O(n)。如果您有1000个元素,最坏的情况是您需要经过1000次迭代才能找到项目。
但是对于mappings来说,你不需要循环它的元素。您一个接一个地访问它们,这在恒定的时间内发生,O(1) (无论映射中有多少元素,您总是要执行完全相同的操作来找到其中的一个元素,这意味着它将花费相同的气体)。因此,mapping可以增长和增长,仍然是廉价的使用。此外,如果您有从映射中删除元素的逻辑,或者映射中的值被设置为默认值,那么它们将不包含任何空间,并且会更轻。
例如:
如果您有此映射:
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气体开始。
https://ethereum.stackexchange.com/questions/135107
复制相似问题