(Remix IDE) Получение ошибки виртуальной машины: неверный код операции в Javascript VM, [закрыто]

Я создаю токен ERC20, который будет иметь 9 отдельных раундов финансирования. Когда я вызываю функцию startNextRound в виртуальной машине JavaScript, я получаю следующую ошибку:

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... 

Когда я развернул тот же контракт на Rinkeby через Remix и вызвал ту же функцию, у транзакции закончился газ:

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);. Что именно здесь происходит не так?

Вот код. Я наследую StandardToken от openZeplin.

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);
  }

}
Я голосую за то, чтобы закрыть этот вопрос, потому что автор уже решил это много лет назад (не уточняя и не зная, как именно), и он / она никогда не входил в систему более года назад. Автор пытался прорекламировать это, но его ответ был удален (похоже, его попытка была ошибочно принята за неправильный ответ).

Ответы (2)

Если функция не работает из-за вызовов require/assert/throw, вы получите сообщение об ошибке, связанное с нехваткой газа или неверным кодом операции vm.

Итак, если отладка показывает, что выполнение останавливается на require(msg.sender == owner); тогда единственное возможное объяснение состоит в том, что вы вызываете эту функцию с учетной записью, которая не является владельцем.

Это то, о чем я думал. Однако я сравнил переменную владельца с адресом учетной записи, из которого я вызываю функцию, и они абсолютно одинаковы.

Насколько я знаю, причиной сообщения «Неверный код операции» часто является пустая переменная. Я думаю, что в вашем случае следующая строка неверна:

address public owner = msg.sender;

Говоря это

contract TestCoin is StandardToken

переменная «владелец» уже установлена ​​конструктором StandardToken-Contract.

Поэтому, возможно, вам следует изменить строку выше на:

address public owner;

Надеюсь, поможет.