Solidity
從測試文件中獲取呼叫可靠函式的“無效操作碼”
我正在學習乙太坊和 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 錯誤:由修飾符引起的無效操作碼錯誤,但我很確定這不是我的情況
您的測試使用 a
beforeEach()
來設置新的空白契約。這是一件令人愉快的事情,因此沒有任何測試依賴於任何其他測試。該函式使用模數來選擇一行,然後繼續工作,但如果有玩家,因為
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')
希望能幫助到你。