在大量数据上循环的稳定性

时间:2018-01-05 12:25:19

标签: ethereum solidity

我想使用一个函数来查找用户的所有标记,所以我使用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;
    }

1 个答案:

答案 0 :(得分:2)

  

坚固性是否存在巨大的for循环问题?

是的,但这不是错误。你正在点击gas limit

我想不出您为什么要按照您尝试的方式跟踪令牌所有权的任何原因。存储在mapping(address => uint)中的地址所拥有的总余额是不够的?这类似于跟踪美元账单上的序列号,因此您可以审核谁拥有它的历史记录。

如果你绝对需要这样的东西,不要在方法中循环你的供应。只需将每个id存储在mapping(address => uint256[])中,并在调用此函数时返回。即使采用这种方法,在频繁转移代币时跟踪所有权状态也会花费很多交易费用。

编辑 - 发表评论:

常量/纯函数仅指示函数是否可以写入/读取合同状态。它仍然需要资源来执行这些功能,因此消耗气体。你想到的不同之处在于呼叫者可能不会为气体充电。如果从具有本地完全同步的非光节点的客户端调用常量函数,则不会收取费用(毕竟,您使用自己的资源)。从事务中调用时,常量函数不是空闲的。

注意Remix中的注释,了解运行常量函数时的成本:

enter image description here