我认为在以太坊上读取数据应该是免费的,但在合同文档(链接如下(中指出,对于公共数组,自动生成的getter函数一次只返回一个元素,以避免高昂的天然气成本。
getter函数不是只读的吗?如果是这样的话,为什么会产生巨大的天然气成本?
请参阅中的Getter函数部分https://docs.soliditylang.org/en/v0.5.3/contracts.html
与智能合约交互主要有两种方式。
- 只读
call
不含气体 - 事务(可以生成状态更改-存储更改、事件日志等(需要煤气费
从链下客户端应用程序的角度来看,您可以使用Truffle call((函数、Web3 call((功能、JSON-RPC eth_call方法和其他几种方法调用调用。
从Solidity合同的角度来看,不进行状态更改的只读函数应标记为视图(读取区块链数据,例如getters(或纯函数(不要读取区块链的数据,例如数学助手(。
如果您有一个数组类型的
public
状态变量,那么您只能通过生成的getter函数检索数组的单个元素。这种机制的存在是为了避免在返回整个阵列时的高气体成本。可以使用参数指定要返回的单个元素,例如data(0)
。如果你想在一次调用中返回整个数组,那么你需要编写一个函数
来源:从您的问题链接的文档
getter函数不是只读的吗?如果是这样的话,为什么会产生巨大的天然气成本
它是只读的。但这并不意味着只能使用只读调用来访问它。
当您向Contract A
发送一个需要从Contract B
读取数据的事务时,它会生成一个内部事务。示例:
合同A部署在0x123
上
pragma solidity ^0.8;
interface B {
// this is the generated getter function that the docs mention
function data(uint256 index) external returns (address);
}
contract A {
// executing this function requires a transaction
function getContractBFirstItem() external returns (address) {
B memory b = B(address(0x456));
// this creates an internal transaction (not a read-only call)
address firstItem = b.data(0);
return firstItem;
}
}
合同B部署在0x456
上
pragma solidity ^0.8;
contract B {
// the getter function is generated from this public property
address[] public data;
constructor() {
// so that fhe first item exists and we can test it
data.push(address(0x789));
}
}
只读函数在事务处理过程中执行时,即封装在可能改变状态的函数中时,可能会产生天然气成本。
这是因为,由于此事务需要验证,它将由网络节点执行。这代表了冗余工作,最终导致相同的结果(给定相同的初始状态和相同的事务顺序(。
为了避免这种情况,标准的gas费用适用于在状态更改事务期间调用的只读函数。
来源-https://blog.b9lab.com/calls-vs-transactions-in-ethereum-smart-contracts-62d6b17d0bc2