Remix

錯誤:錯誤:所需的氣體超過限額或總是失敗的交易

  • July 17, 2018

嗨我有這個錯誤:

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()。確保使用初始餘額創建契約。

引用自:https://ethereum.stackexchange.com/questions/42173