Solidity

從測試文件中獲取呼叫可靠函式的“無效操作碼”

  • January 13, 2020

我正在學習乙太坊和 Solidity,我在從測試文件中呼叫支付函式時遇到問題。

這是我的契約

pragma solidity >=0.4.22 <0.6.0;
//pragma solidity 0.4.17

contract Lottery {

   address public manager;
   address payable [] public players;

   constructor() public {
       manager = msg.sender;
   }

   function enter() public payable {
       require(msg.value > .01 ether);
       players.push(msg.sender);
   }

   function pickWinner() public payable restricted {
       uint index = random() % players.length;
       address payable winner = players[index];
       winner.transfer(address(this).balance);
       players = new address payable [](0);
   }

   function random() private view returns (uint) {
       return uint( keccak256(abi.encode(block.difficulty, now, players)));
   }

   modifier restricted() {
       require(msg.sender == manager, 'Your are not the manager!');
       _;
   }

   function getPlayers() public view returns (address payable[] memory) {
       return players;
   }
}

這是我的測試文件

let lottery;
let accounts;

beforeEach(async () => {
 accounts = await web3.eth.getAccounts();
 lottery = await new web3.eth.Contract(abi)
   .deploy({data: bytecode.object})
   .send({from: accounts[0], gas: '1000000'}});
});

describe('Lottery Contract', () => {
 it('deploys contract', () => {
   assert.ok(lottery.options.address);
 });

 it('Allows 1 account to enter', async () => {
   await lottery.methods.enter().send({
     from: accounts[0],
     value: web3.utils.toWei('0.02', 'ether')
   });

   const players = await lottery.methods.getPlayers().call({
     from: accounts[0]
   });

   assert.ok(accounts[0], players[0]);
   assert.ok(1, players.length);
 });


 it('Allows multiple accounts to enter', async () => {
   let conta = 0;
   for(let account of accounts) {
     await lottery.methods.enter().send({
       from: account,
       value: web3.utils.toWei('0.02', 'ether')
     });

     const players = await lottery.methods.getPlayers().call({
       from: account
     });

     assert.equal(account, players[conta]);
     assert.equal(conta + 1, players.length);
     conta++;
   }
 });

 it('Requires a minimun ammount to enter', async () => {
   try{
     await lottery.methods.enter().send({
       from: accounts[0],
       value: 200
     });
     assert(false);
   } catch(error){
     assert(error);
   }
 });

 it('only manager can call pick winner', async () => {
   try{
     await lottery.methods.pickWinner().send({
       from: accounts[1],
     });
     assert(false);
   } catch (error) {
     console.log(error);
     assert(error);
   }
 });

 it('manager can call pick winner', async () => {
     await lottery.methods.pickWinner().send({
       from: accounts[0],
     });
     assert(true);
 });

});

無論我嘗試什麼,在呼叫 lottery.methods.pickWinner() 時我仍然收到“無效的操作碼”錯誤

這是我正在使用的 lib 版本

"ganache-cli": "^6.7.0",
"mocha": "^6.2.2",
"solc": "^0.5.14",
"truffle-hdwallet-provider": "^1.0.17",
"web3": "^1.2.4"

我得到的完整跟踪是:

o: VM Exception while processing transaction: invalid opcode
     at Function.o.fromResults (node_modules\ganache-cli\build\ganache-core.node.cli.js:10:89727)
     at D:\DEVELOPMENT\repo\study\etherumSolidityCOurse\lottery\node_modules\ganache-cli\build\ganache-core.node.cli.js:25:121953
     at D:\DEVELOPMENT\repo\study\etherumSolidityCOurse\lottery\node_modules\ganache-cli\build\ganache-core.node.cli.js:25:98498
     at p (node_modules\ganache-cli\build\ganache-core.node.cli.js:25:98156)
     at D:\DEVELOPMENT\repo\study\etherumSolidityCOurse\lottery\node_modules\ganache-cli\build\ganache-core.node.cli.js:25:98209
     at t.default (node_modules\ganache-cli\build\ganache-core.node.cli.js:37:544097)
     at D:\DEVELOPMENT\repo\study\etherumSolidityCOurse\lottery\node_modules\ganache-cli\build\ganache-core.node.cli.js:25:99122
     at t.n.emit (node_modules\ganache-cli\build\ganache-core.node.cli.js:61:16355)
     at D:\DEVELOPMENT\repo\study\etherumSolidityCOurse\lottery\node_modules\ganache-cli\build\ganache-core.node.cli.js:61:654328
     at D:\DEVELOPMENT\repo\study\etherumSolidityCOurse\lottery\node_modules\ganache-cli\build\ganache-core.node.cli.js:61:654351
     at D:\DEVELOPMENT\repo\study\etherumSolidityCOurse\lottery\node_modules\ganache-cli\build\ganache-core.node.cli.js:37:1093446
     at D:\DEVELOPMENT\repo\study\etherumSolidityCOurse\lottery\node_modules\ganache-cli\build\ganache-core.node.cli.js:2:19209

已經檢查Invalid Opcode opcode error 合約中出現 Invalid opcode 是否正常?VM 錯誤:由修飾符引起的無效操作碼錯誤,但我很確定這不是我的情況

您的測試使用 abeforeEach()來設置新的空白契約。這是一件令人愉快的事情,因此沒有任何測試依賴於任何其他測試。

該函式使用模數來選擇一行,然後繼續工作,但如果有玩家,因為enter()沒有先呼叫,那麼模數將為零,它會嘗試訪問第 0 行players,但不存在.

您可以提出更有意義的回應,但契約已經在做正確的事情。

   function pickWinner() public payable restricted {
       require(players.length > 0, "Need at least one player."); // <== this
       uint index = random() % players.length;
       address payable winner = players[index];
       winner.transfer(address(this).balance);
       players = new address payable [](0);
   }

在您嘗試挑選獲勝者之前,請先執行其中的一些操作:

     await lottery.methods.enter().send({
       from: account,
       value: web3.utils.toWei('0.02', 'ether')

希望能幫助到你。

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