Why do automatically generated getter functions incur gas cost?

Viewed 1171

I thought that reading data on Ethereum was supposed to be gas free, however in the contract documentation (linked below) it states that for public arrays the automatically generated getter functions only return one element at a time to avoid large gas costs.

Isn't a getter function read-only? If so, why would it incur large gas costs?

See Getter Functions section in https://docs.soliditylang.org/en/v0.5.3/contracts.html

2 Answers

There are two main ways to interact with a smart contract.

  • Read-only call is gas free.
  • Transaction (can generate state changes - storage change, event logs, ...) requires gas fees.

From the perspective of an off-chain client app, you can invoke a call using Truffle call() function, Web3 call() function, JSON-RPC eth_call method, and few other ways.

From the perspective of a Solidity contract, read-only functions that don't make state changes, should be marked as view (read blockchain data, e.g. getters) or pure (dont't read blockchain data, e.g. math helpers).


If you have a public state variable of array type, then you can only retrieve single elements of the array via the generated getter function. This mechanism exists to avoid high gas costs when returning an entire array. You can use arguments to specify which individual element to return, for example data(0). If you want to return an entire array in one call, then you need to write a function

Source: Docs linked from your question

Isn't a getter function read-only? If so, why would it incur large gas costs?

It is read-only. But it doesn't mean that it can be only accessed using the read-only call.

When you send a transaction to Contract A which needs to read data from Contract B, it makes an internal transaction. Example:

Contract A deployed on 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;
    }
}

Contract B deployed on 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));
    }
}

Read-only functions can incur gas costs when they are carried out during transactions, i.e. when wrapped inside a potentially state-changing function.

This is because, since this transaction requires verification, it will be executed by the networks nodes. This represents redundant work, eventually resulting in identical results (given the same initial state and the same transaction order).

To avoid this, standard gas-fees are applied to read-only functions invoked during state-changing transactions.

Source - https://blog.b9lab.com/calls-vs-transactions-in-ethereum-smart-contracts-62d6b17d0bc2

Related