Solidity
氣體估計錯誤並顯示以下消息
我收到“氣體估算錯誤,出現以下消息(見下文)。交易執行可能會失敗。您要強制發送嗎?內部 JSON-RPC 錯誤。” 在使用 drawWinner 函式時進行混音
pragma solidity ^0.4.18; contract RecurringLottery { struct Round { uint deployBlock; uint endBlock; uint drawBlock; Entry[] entries; uint totalQuantity; address winner; } struct Entry { address buyer; uint quantity; } uint constant public TICKET_PRICE = 1e15; mapping(uint => Round) public rounds; uint public round; uint public duration; mapping (address => uint) public balances; // duration is in blocks. 1 day = ~5500 blocks function RecurringLottery (uint _duration) public { round = 1; duration = _duration; rounds[round].deployBlock = block.number; rounds[round].endBlock = block.number + duration; rounds[round].drawBlock = block.number + duration + 5; } function buy () payable public { require(msg.value % TICKET_PRICE == 0); if (block.number > rounds[round].endBlock) { round += 1; rounds[round].deployBlock = block.number; rounds[round].endBlock = block.number + duration; rounds[round].drawBlock = block.number + duration + 5; } uint quantity = msg.value / TICKET_PRICE; Entry memory entry = Entry(msg.sender, quantity); rounds[round].entries.push(entry); rounds[round].totalQuantity += quantity; } function drawWinner (uint roundNumber) public { Round storage drawing = rounds[roundNumber]; require(drawing.winner == address(0)); require(block.number > drawing.drawBlock); require(drawing.entries.length > 0); // pick winner bytes32 rand = keccak256( block.blockhash(drawing.drawBlock) ); uint counter = uint(rand) % drawing.totalQuantity; for (uint i=0; i < drawing.entries.length; i++) { uint quantity = drawing.entries[i].quantity; if (quantity > counter) { drawing.winner = drawing.entries[i].buyer; break; } else counter -= quantity; } balances[drawing.winner] += TICKET_PRICE * drawing.totalQuantity; } function withdraw () public { uint amount = balances[msg.sender]; balances[msg.sender] = 0; msg.sender.transfer(amount); } function deleteRound (uint _round) public { require(block.number > rounds[_round].drawBlock + 100); require(rounds[_round].winner != address(0)); delete rounds[_round]; } function () payable public { buy(); }
}
當程式碼執行失敗時,您通常會收到該錯誤,這可能是因為正常執行或因為其中一個還原擷取錯誤,在您的情況下,問題是還原,您可以通過以下方式找到:
此功能尚未在節點上,僅在您可以在混音中使用的 javascriptVM 中,或在您的松露測試/ganache 中,但建議您現在開始使用它;您可以在還原中添加錯誤消息,這是獲得更好的綜合錯誤的最簡單方法,IE:
require(condition, "string returned if condition fails");
請注意,我在此範例中使用 javascript vm 而不是注入的 web3。當我執行您的程式碼時,我們可以找到的第一個錯誤在第二個要求中:
require(block.number > drawing.drawBlock, "Can't draw yet");
直到一些塊過去我們才能繪製,我通過呼叫其他函式在VM中強制生成一些塊,如果你在乙太坊上這樣做,你只需要等待。
解決這個問題後,它在下一行崩潰了:
require(drawing.entries.length > 0, "No entries for that round");
所以我呼叫了幾次 buy() 發送了 TICKET_PRICE 中指定的乙太幣數量,然後我檢查了通過呼叫 rounds(numberOfRound) 添加的條目,並在使用有效輪次呼叫 drawWinner(numberOfRound) 之後,該函式正常工作.
您應該創建一個呼叫,通過檢查這些條件來告訴您該功能是否有效或將失敗,這樣您就可以解決很多麻煩,記住將錯誤消息放在要求上,如果您想逐步查看所有內容步驟,remix 中提供的調試器非常有用。
TLDR:要使您的程式碼正常工作,您需要確保已經通過了足夠多的塊,並且該輪至少有一個條目。
順便說一句,你的 drawWinner() 函式中有幾個漏洞,不要在生產中使用它!