访问大型阵列会导致用尽异常

时间:2019-07-05 08:47:42

标签: solidity

我需要有一个参考编号列表,每个编号都与一个特定的数量相关,但是当列表数量很大时,与该列表相关的任何交易都会触发“停电异常”。

我正在为ERC-20令牌编写

我试图将迭代次数限制在参考数字列表上,以尝试减少使用的气体,但这不会影响异常的触发。

我尝试通过注释函数的某些部分来缩小问题的范围,这些部分在理论上会触发异常。

我还尝试过创建键的struct数组而不是字符串数组来映射数量。

完整代码在这里https://github.com/Abmorano11/GGC-SmartContract

除了标准ERC-20,我还声明了以下内容作为状态变量

    string[] private keyRef;
    string[] private tempKeys;

    struct account {
        uint256 balance;
        mapping(string => uint256) tokens;
        string[] keys;
        bool isVerified;
    }

    mapping (address => account) public accInfo;

这是“薄荷”功能

function buy(uint256 value, address buyer, string calldata serial) external {
        _totalSupply = _totalSupply.add(value);
        if (accInfo[buyer].tokens[serial] == 0) { //checks if an account owns a serial with an amount
            accInfo[buyer].keys.push(serial);  // Adds it to the account key list
        }
        accInfo[buyer].tokens[serial] = accInfo[buyer].tokens[serial] + value; // Minto Token into Buyer Account Token Mapping
        accInfo[buyer].balance = accInfo[buyer].balance.add(value);     // Updates Buyer Account Balance
    }

这是传递函数

function  _transfer(address _from, address _to, uint _value) internal {
        uint256 val = _value;                                                                       // Temporary Value Holder
        uint256 length = accInfo[_from].keys.length;                                                // Temporary Length Holder
        keyRef = accInfo[_from].keys;
        for(uint256 index = 0; index < length && index < 10; index++) {
            string memory key = keyRef[index];                                         // Temporary Reference Holder
            if (accInfo[_from].tokens[key] > val && val > 0) {                                     // Check if Token Entry can handle amount
                accInfo[_from].tokens[key] = accInfo[_from].tokens[key] - val;                   // Deduct Temporary Value from Token Entry
                if (accInfo[_to].tokens[key] == 0) {                                                // Check if recipient doesn't have this reference
                    accInfo[_to].keys.push(key);                                                    // Add Serial to account
                }
                accInfo[_to].tokens[key] = accInfo[_to].tokens[key] + val;                          // Add Value to serial
                val = 0;                                                                            // Empty Temporary Value
            }
            if (accInfo[_from].tokens[key] <= val && val > 0) {                                     // Check if Token Entry will be Emptied
                if (accInfo[_to].tokens[key] == 0) {                                                // Check if recipient doesn't have this serial
                    accInfo[_to].keys.push(key);                                                    // Add Serial to account
                }
                accInfo[_to].tokens[key] = accInfo[_to].tokens[key] + accInfo[_from].tokens[key];   // Add Amount to serial
                val = val - accInfo[_from].tokens[key];                                                // Deduct Token Entry from Temporary Value
                delete accInfo[_from].tokens[key];                                                  // Empty Token Entry
                uint256 len = accInfo[_from].keys.length;
                len = len - 1;
                for (uint256 i = 0; i < len; i++) {
                    tempKeys.push(accInfo[_from].keys[i+1]);
                }
                delete accInfo[_from].keys[len];                                                    // Remove last Entry
                accInfo[_from].keys = tempKeys;                                                   // Reduce Array Length
                delete tempKeys;
            }
        }
        delete keyRef;
        uint256 deducted = _value - val;
        accInfo[_from].balance = accInfo[_from].balance - deducted;                                // Subtract amount from the sender
        accInfo[_to].balance = accInfo[_to].balance + deducted;                                    // Add the amount to the recipient
    }

当一个帐户拥有大约30个不同的参考号时,任何旨在读取或更改列表的交易都会产生异常的异常,但是铸造功能仍然会执行。

使用松露在Ganache网络上进行测试。

0 个答案:

没有答案