Solidity doesn't currently support returning a mapping or a variable-sized list, so you would need to implement a getter function as you described that takes an index.
The approach I think you're describing is keeping a second list next to the mapping, and using it to return the mapping in chunks like the source code below.
contract SomeContract {
mapping(address => uint256) public someMapping;
address[] public addresses;
function addValue(address _newAddress, uint256 _newValue) public {
someMapping[_newAddress] = _newValue;
addresses.push(_newAddress);
}
function getAddressCount() public view returns (uint256 _count) {
return addresses.length;
}
function getValueByIndex(uint256 _index) public view returns (uint256 _val) {
return someMapping[addresses[_index]];
}
// Get the values from mapping in chunks of size 10
// This isn't a feasible solution in my opinion
function getValuesChunk(uint256 _index) public view returns (uint256[10] memory _chunk) {
uint256[10] memory vals;
require(_index < 2^256 - 10, 'Index would wrap around unsafely');
for (uint256 i = _index; i < _index+10; i++) {
vals[i] = someMapping[addresses[i]];
}
return vals;
}
}
The view
methods are read-only and don't cost gas, so you can technically call them as many times as you like in order to display values to your front-end. However, there are a few reasons not to do this.
* It would still take CPU power on your Ethereum node. If it's a large enough list, your node might consider it a DoS attack and throttle or ban you. If you run your own node, that's a lot of work or AWS credits to burn on blockchain operations.
* The mapping won't change much in between calls to addValue
. You would be re-doing the work of retrieving mostly the same values each time, even if you do some caching in your front-end.
Instead, I would recommend using Solidity events (EVM logs), a facility which lets you emit an event, which is retrieved by a database that allows one-pass indexing to be read multiple times off-chain, like Subgraph https://thegraph.com/
This lets you keep your solidity code minimal and clean, not spending gas on a complicated contract just to support front-end functionality that you can easily offload onto systems that are designed for it (GraphQL + React + Typescript)
contract SomeContract {
event NewValue (
address _address,
uint256 _value
);
mapping(address => uint256) public someMapping;
function addValue(address _newAddress, uint256 _newValue) public {
someMapping[_newAddress] = _newValue;
emit NewValue(_newAddress, _newValue);
}
}
Hope this helps.