Как управлять большими циклами в солидности? - PullRequest
0 голосов
/ 27 марта 2019

Итак, у меня есть этот контракт, и спонсор может получить общую сумму определенной кампании с помощью функции getFundsByAddress. Проблема в том, что если в кампании более 30 тысяч учредителей, контракт не может выполнить код, потому что потребуется пройти 30 тысяч раз, чтобы найти все правильные адреса

В ньюорке Rinkeby максимальный цикл, который он может достичь, составляет 30 КБ, после чего возвращается 0

Как мне разрешить такие случаи?

contract CrowdFunding {
    struct Funder {
        address addr;
        uint amount;
    }

    struct Campaign {
        address beneficiary;
        uint numFunders;
        uint amount;
        mapping (uint => Funder) funders;
    }

    uint numCampaigns;
    Campaign[] public campaigns;

    function newCampaign() public returns (uint campaignID) {
        campaignID = campaigns.length++;
        Campaign storage c = campaigns[campaignID];
        c.beneficiary = msg.sender;
    }

    function contribute(uint _campaignID, uint _amount) public {
        Campaign storage c = campaigns[_campaignID];
        c.funders[c.numFunders++] = Funder({addr: msg.sender, amount: _amount});
        c.amount += 100;
    }

    // not tested
    function getFundsByAddress() public view returns (uint[] memory) {
        Campaign storage c = campaigns[0];
        uint cont = c.numFunders;

        uint[] memory allAmount = new uint[](TotalAmountOfUser);

        uint counter = 0;

        for (uint i=0; i < cont; i++) {
           if (c.funders[counter].addr == msg.sender) {
               allAmount[amountCont] = c.funders[counter].amount;
           }
           counter++;
        }

        return allAmount;
    }   
}

Ответы [ 2 ]

0 голосов
/ 28 марта 2019

Трудно догадаться, что должен делать getFundsByAddress, потому что код не компилируется и цикл, похоже, ничего не делает. (Переменная цикла i никогда не используется.)

Но если бы мне пришлось угадывать, он должен вернуть сумму вкладов, сделанных звонящим. Если это так, просто следите за этой суммой по мере внесения взносов и вообще избегайте петли:

mapping(address => uint256) public totalContributions;

function contribute(uint _campaignID, uint _amount) public {
    ...

    // Add this line to keep track of the total.
    totalContributions[msg.sender] += _amount;
}

// No need for getFundsByAddress at all because a call to `totalContributions(address)`
// (the auto-generated getter) does the trick.

// But if you want a function that returns specifically `msg.sender`'s total:
function getMyContributions() external view returns (uint256) {
    return totalContributions[msg.sender];
}
0 голосов
/ 27 марта 2019

Я не вижу ничего особенного с номером 30K, который бы это объяснил.

Ваша проблема может заключаться в том, что в транзакции не хватает газа или достигнут лимит блокировки газа. Если вам необходимо выполнить цикл по массиву, и вы не можете сделать это каким-либо иным способом, вам следует рассмотреть возможность циклического перемещения по массиву в нескольких транзакциях (т. Е. 0-9999,10.000-19.999, ...).

Тем не менее, просмотр большого количества записей будет довольно дорогим с точки зрения газа, который в реальной сети стоит денег. Но если это не может быть сделано по-другому, то вышеупомянутое должно помочь вам.

...