Description
tokensOfOwnerByIndex linearly scans all kitties looking for the nth one owned by the specified account. Since each call iterates over all the previous results, if there are n kitties, m of them owned by the specified address, this will take O(m * n) time.
Although this function notes that it's not intended to be called onchain, even offchain the execution time of listing kitties will soon become impractical.
Scenario
- Create lots of kitties.
- Attempt to enumerate all kitties owned by someone with lots of kitties.
Impact
It may become effectively impossible to list someone's kitties - particularly newer ones.
Reproduction
See Scenario.
Fix
Maintain an array of kitties-by-owner. This array can be efficiently updated by moving the last element into deleted indexes, since it's not necessary for the array to be kept in order. EG:
mapping(address=>uint[]) kittiesByOwner;
function deleteKitty(address owner, uint idx) {
var kittyList = kittiesByOwner[owner];
require(idx < kittyList.length);
if(idx < kittyList.length - 1) {
kittyList[idx] = kittyList[kittyList.length - 1];
}
kittyList.length -= 1;
}
Description
tokensOfOwnerByIndex linearly scans all kitties looking for the nth one owned by the specified account. Since each call iterates over all the previous results, if there are n kitties, m of them owned by the specified address, this will take O(m * n) time.
Although this function notes that it's not intended to be called onchain, even offchain the execution time of listing kitties will soon become impractical.
Scenario
Impact
It may become effectively impossible to list someone's kitties - particularly newer ones.
Reproduction
See Scenario.
Fix
Maintain an array of kitties-by-owner. This array can be efficiently updated by moving the last element into deleted indexes, since it's not necessary for the array to be kept in order. EG: