Solidity

氣體估計錯誤並顯示以下消息

  • October 20, 2021

我收到“氣體估算錯誤,出現以下消息(見下文)。交易執行可能會失敗。您要強制發送嗎?內部 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() 函式中有幾個漏洞,不要在生產中使用它!

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