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?
uint256 public gasUsed
in your contract, then adduint256 gasLeft = gasleft();
at the beginning of your function, and then addgasUsed = gasLeft - gasleft();
at the end of your function. Then, after calling your function from the offchain, callgasUsed()
in order to check how much gas the function really used.gasleft()
in solc 0.4.x togasLeft()
in solc 0.5.x, so you might need to use different names in my example above, depending on your solc version.gasleft()
for 0.5.x but I was still surprised at the ~9k+ of gas attributed to dealing withstorage
variables