我想使用一个函数来查找用户的所有标记,所以我使用for循环遍历所有标记并查看地址是否匹配。令牌的totalSupply()大约为10Mio,这对于for循环来说似乎太多了。以下函数仅适用于小于500000的totalSupply(),我不知道究竟是什么问题。超过500000它运行该函数,但是如果用户拥有令牌,我得到的结果是空的。坚固性是否存在巨大的for循环问题?
function tokensOfOwner(address _owner) external view returns(uint256[] ownerTokens) {
uint256 tokenCount = balanceOf(_owner);
if (tokenCount == 0) {
// Return an empty array
return new uint256[](0);
} else {
uint256[] memory result = new uint256[](tokenCount);
uint256 total = totalSupply();
uint256 resultIndex = 0;
uint256 id;
for (id = 1; id <= total; id++) {
if (IndexToOwner[id] == _owner) {
result[resultIndex] = id;
resultIndex++;
}
}
return result;
}
}
编辑:我做了一个测试函数来查看错误是什么,并且不知何故最大循环大小大约是3'840'000次迭代,然后不知何故我总是回来0.有谁知道是否有错误巨大的循环的坚固性?
function testLoop(uint256 num) external view returns(uint256 res) {
uint256 i=0;
uint256 cnt=0;
for(i;i<num;i++) {
cnt++;
}
return cnt;
}
答案 0 :(得分:2)
坚固性是否存在巨大的for循环问题?
是的,但这不是错误。你正在点击gas limit。
我想不出您为什么要按照您尝试的方式跟踪令牌所有权的任何原因。存储在mapping(address => uint)
中的地址所拥有的总余额是不够的?这类似于跟踪美元账单上的序列号,因此您可以审核谁拥有它的历史记录。
如果你绝对需要这样的东西,不要在方法中循环你的供应。只需将每个id存储在mapping(address => uint256[])
中,并在调用此函数时返回。即使采用这种方法,在频繁转移代币时跟踪所有权状态也会花费很多交易费用。
编辑 - 发表评论:
常量/纯函数仅指示函数是否可以写入/读取合同状态。它仍然需要资源来执行这些功能,因此消耗气体。你想到的不同之处在于呼叫者可能不会为气体充电。如果从具有本地完全同步的非光节点的客户端调用常量函数,则不会收取费用(毕竟,您使用自己的资源)。从事务中调用时,常量函数不是空闲的。
注意Remix中的注释,了解运行常量函数时的成本: