Remix
錯誤:錯誤:所需的氣體超過限額或總是失敗的交易
嗨我有這個錯誤:
transact to Roulette.betSingle errored: Error: gas required exceeds allowance or always failing transaction
我的程序:
contract Roulette { uint public lastRoundTimestamp; uint public nextRoundTimestamp; address _creator; uint _interval; enum BetType { Single, Odd, Even } struct Bet { BetType betType; address player; uint number; uint value; } Bet[] public bets; function getBetsCountAndValue() public constant returns(uint, uint) { uint value = 0; for (uint i = 0; i < bets.length; i++) { value += bets[i].value; } return (bets.length, value); } event Finished(uint number, uint nextRoundTimestamp); modifier transactionMustContainEther() { if (msg.value == 0) throw; _; } modifier bankMustBeAbleToPayForBetType(BetType betType) { uint necessaryBalance = 0; for (uint i = 0; i < bets.length; i++) { necessaryBalance += getPayoutForType(bets[i].betType) * bets[i].value; } necessaryBalance += getPayoutForType(betType) * msg.value; if (necessaryBalance > this.balance) throw; _; } function getPayoutForType(BetType betType) constant returns(uint) { if (betType == BetType.Single) return 35; if (betType == BetType.Even || betType == BetType.Odd) return 2; return 0; } function Roulette(uint interval) { _interval = interval; _creator = msg.sender; nextRoundTimestamp = 1517784279 + _interval; } function betSingle(uint number) public payable transactionMustContainEther() bankMustBeAbleToPayForBetType(BetType.Single) { if (number > 36) throw; bets.push(Bet({ betType: BetType.Single, player: msg.sender, number: number, value: msg.value })); } function betEven() public payable transactionMustContainEther() bankMustBeAbleToPayForBetType(BetType.Even) { bets.push(Bet({ betType: BetType.Even, player: msg.sender, number: 0, value: msg.value })); } function betOdd() public payable transactionMustContainEther() bankMustBeAbleToPayForBetType(BetType.Odd) { bets.push(Bet({ betType: BetType.Odd, player: msg.sender, number: 0, value: msg.value })); } function launch() public { if (now < nextRoundTimestamp) throw; uint number = uint(block.blockhash(block.number - 1)) % 37; for (uint i = 0; i < bets.length; i++) { bool won = false; uint payout = 0; if (bets[i].betType == BetType.Single) { if (bets[i].number == number) { won = true; } } else if (bets[i].betType == BetType.Even) { if (number > 0 && number % 2 == 0) { won = true; } } else if (bets[i].betType == BetType.Odd) { if (number > 0 && number % 2 == 1) { won = true; } } if (won) { if (bets[i].player.send(bets[i].value * getPayoutForType(bets[i].betType))) throw; } } uint thisRoundTimestamp = nextRoundTimestamp; nextRoundTimestamp = thisRoundTimestamp + _interval; lastRoundTimestamp = thisRoundTimestamp; bets.length = 0; Finished(number, nextRoundTimestamp); } }
請幫幫我 !:)
你的問題是由這條線引起的
necessaryBalance += getPayoutForType(betType) * msg.value; if (necessaryBalance > this.balance) throw;
開始時 this.balance 為零。
當您第一次呼叫 betSingle 時
msg.value
將等於this.balance
. 現在getPayoutForType(betType)
將返回 35。然後
necessaryBalance = 35 * msg.value
,檢查if (necessaryBalance > this.balance) throw
將始終為真,導致拋出並撤銷對契約的所有更改。其他投注功能也會同樣失敗,從而阻塞合約。
一些建議:
- 避免使用 throw,這被認為是一種不好的做法,您應該使用 require 或 assert。
- 避免無界的 for/while 循環,如果迭代次數過多,它們可能會導致氣體不足錯誤。
交易需要太多gas才能執行的原因之一是合約拋出異常。我注意到一些可能在 betSingle() 中拋出異常的地方:
- 使用輸入 > 36 呼叫 betSingle()
- 如果交易沒有價值金額,則拋出修飾符 transactionMustContainEther()
- 如果合約沒有餘額來支付賭注,則輸入修飾符 bankMustBeAbleToPayForBetType()。確保使用初始餘額創建契約。