Remix

(Remix IDE) 獲取 VM 錯誤:Javascript VM 中的操作碼無效,

  • January 11, 2022

我正在創建一個 ERC20 代幣,它將有 9 輪單獨的融資。當我在 JavaScript VM 中呼叫 startNextRound 函式時,我收到以下錯誤:

transact to browser/SatanCoin.sol:SatanCoin.startNextRound errored: VM error: invalid opcode.
   The constructor should be payable if you send value.
   The execution might have thrown.
   Debug the transaction to get more information. 
creation of browser/SatanCoin.sol:SatanCoin pending... 

當我通過 Remix 在 Rinkeby 上部署相同的合約並呼叫相同的函式時,交易耗盡了 gas:

transact to browser/SatanCoin.sol:SatanCoin.startNextRound errored: Gas required exceeds limit: 3000000.  An important gas estimation might also be the sign of a problem in the contract code. Please check loops and be sure you did not sent value to a non payable function (that's also the reason of strong gas estimation)

當我使用 Remix 調試器時,它告訴我函式在require(msg.sender == owner);. 這裡到底出了什麼問題?

這是程式碼。我從 openZepplin 繼承 StandardToken。

contract TestCoin is StandardToken {


 uint256 public rate = 0.0666 ether; //Each Testcoin will be worth .0666 ETH, Must be bought in exact increments
 address public owner = msg.sender;

 bool public roundActive = false; //only allows buying during a round
 uint public roundNum = 0;//current round number out of 9
 uint public roundMax = 74;//max number of tokens to be issued every round
 uint public roundIssued;//number of tokens issued during current or previous round
 address[] roundBuyers; //buyer address is recorded for every token issued

 modifier onlyOwner {
     require(msg.sender == owner);
     _;
 }

 event Raffled(uint roundNumber, address winner, uint amount);
 event RoundStart(uint roundNumber);


 function name() constant returns (string) { return "TestCoin"; }
 function symbol() constant returns (string) { return "TEST"; }
 function decimals() constant returns (uint8) { return 0; }


 function startNextRound()
   public
 {
     require(msg.sender == owner);
     assert(endPreviousRound()); //end the previous round before starting the next
     require(roundNum<9); //only 9 rounds may occur

     roundActive = true;
     roundBuyers = new address[](74);
     roundIssued = 0;
     roundNum++;

     RoundStart(roundNum);
 }

 function endPreviousRound()
   private
   returns (bool)
 {
     //raffles off remaining tokens if any are left
     if(roundIssued < roundMax) assert(raffle(amountRemaining()));
     roundActive = false;
     return true;
 }

 //raffles off remainig tokens to a random buyer from the previous round
 //the more tokens a buyer has, the greater their chance to win
 function raffle(uint raffleAmount)
   private
   returns (bool)
 {
   uint randomIndex = uint(block.blockhash(block.number))%(roundMax-raffleAmount)+1;
   mint(roundBuyers[randomIndex], raffleAmount);

   Raffled(roundNum, roundBuyers[randomIndex], raffleAmount);
 }

 function mint(address receiver, uint amount) 
   private
 {

   totalSupply = safeAdd(totalSupply, amount);
   balances[receiver] = safeAdd(balances[receiver], amount);

   for(uint i = 0; i < amount; i++) {
     roundBuyers[roundIssued+i] = receiver;
   }

   roundIssued = safeAdd(roundIssued, amount);

   // This will make the mint transaction apper in EtherScan.io
   Minted(receiver, amount);
  }

 //This function is called when Ether is sent to the contract address
 //Even if 0 ether is sent.
 function () payable {
   //If value is zero or not multiple of the rate, refund user. 
   if (msg.value <= 0 || (msg.value % rate) != 0) revert(); 

   uint tokenAmount = safeDiv(msg.value, rate);

   //Make sure there is an active round
   if(roundActive == false) revert();
   //Make sure a buyer can't buy more than round amount availible.
   if (tokenAmount > amountRemaining()) revert();
   //Make sure that no more than 666 TestCoins can be issued.
   if ((tokenAmount+totalSupply) > 666) revert();
   //Extra precaution to contract attack
   if (tokenAmount < 1) revert();  

   mint(msg.sender, tokenAmount);
   owner.transfer(msg.value);          //Send the ETH
 }  

 //returns number of tokens left to be issued in current round
 function amountRemaining()
   public
   constant
   returns (uint)
 {
   return (roundMax-roundIssued);
 }

}

如果函式由於 requires/assert/throw 呼叫而失敗,您將收到有關用盡 gas 或 vm 無效操作碼的錯誤。

因此,如果調試顯示執行停止在 require(msg.sender == owner); 那麼唯一可能的解釋是您使用不是所有者的帳戶呼叫此函式。

據我所知,“無效操作碼”消息的原因通常是變數為空。我認為在您的情況下,以下行不正確:

address public owner = msg.sender;

這麼說的時候

contract TestCoin is StandardToken

“所有者”變數已由 StandardToken-Contract 的建構子設置。

因此,也許您應該將上面的行更改為:

address public owner;

希望能幫助到你。

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