所以我有这个合同,资助者可以通过getFundsByAddress函数检索特定活动的总金额。问题是,如果一个活动有超过3万个创始人,合约就无法执行代码,因为它需要经历3万次,所以可以找到所有正确的地址。
在 Rinkeby nework 中,它可以达到的最大循环是 30k,之后返回 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;
}
}
我没有看到数字 30K 有什么特别之处可以解释这一点。
您的问题可能是交易要么耗尽了汽油,要么达到了区块气体限制。如果您必须遍历数组并且无法以任何其他方式执行此操作,则应考虑在多个事务中遍历数组(即 0-9999,10.000-19.999,...(。
然而,循环访问这么多条目在天然气方面将非常昂贵,这在真正的网络上需要花钱。但是,如果不能以其他方式完成,那么上述内容应该对您有所帮助。
很难猜测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];
}