I have a function that I need to pass an arbitrary length array of addresses to. In remix, just calling a function that has an address[]
costs around 30k gas for an array of 5 addresses:
function fun(address[] calldata addresses) external returns (address[] memory) {
return addresses;
}
The addresses that I want to call are of a finite set of about 2000 addresses, but it could be any of those addresses when I call my function, so I thought that I could store them in a mapping of uint=>address
and call my function with an array of uint16's that I can then look up the addresses with (that I previously stored). Theoretically this should be much cheaper because the calldata is way smaller:
pragma solidity 0.5.17;
contract StoreIDToAddress {
mapping(uint => address) public numToAddress;
function getAddresses(uint16[] calldata _IDs) external view returns (address[] memory) {
address[] memory arr = new address[](_IDs.length);
for (uint i; i < _IDs.length; i++) {
arr[i] = numToAddress[_IDs[i]];
}
return arr;
}
// Other functions to initialize numToAddress etc
}
getAddresses
costs 29378 gas with an input of [0, 1, 2, 3, 4]
.
This alone makes it no cheaper than just including the addresses themselves in the calldata, and when I tested with a 2nd contract that takes in an uint16[]
and passes it to getAddresses
it costs 34196 gas:
function testUint16Arr3(uint16[] calldata _arr) external returns (address[] memory) {
return storeIDToAddress.getAddresses(_arr);
}
Using bytes
and decoding that in to a uint16
to call getAddresses
is 35095 gas.
So my question is, why does getAddresses
cost so much gas when (AFAIK) the biggest operation is 5 x SLOAD = 1000 gas? How can I reduce the gas cost of getting addresses in to my functions?
Best Answer
The Istanbul hardfork included EIP-1884, which (among other repricings) repriced SLOAD from 200 to 800 gas. That means loading 5 addresses from storage will cost 4000 gas, not including any overhead. The Istanbul hardfork also included EIP-2028, which lowered the cost of non-zero calldata bytes from 68 to 16. These two EIPS are what cause the huge difference in gas costs from what you are expecting.
Also as @goodvibration mentioned in a comment, there is an inbuilt cost of 21000 gas with all transactions. This is the base cost, and any contract interaction you do is on-top of this amount.