Pick Winner Lottery test throws; Error: Transaction has been reverted by the EVM:
Pick Winner Lottery test throws; Error: Transaction has been reverted by the EVM:
我正在编写一个彩票合约,该合约应该接受玩家、选择赢家并将收集到的资金发送到赢家的地址,然后重新开始。
在 运行ning npm 运行 测试之后,前 5 个测试都通过了,但是“发送钱给获胜者并重置玩家数组”测试失败,错误消息如下。
1) lottery Contract
sends money to the winner & resets the players array:
Error: Transaction has been reverted by the EVM:
就我个人而言,我认为问题出在文件 Lottery.test.js 上的这段代码中,因为到目前为止,一切都很好 运行ning;
await lottery.methods.pickWinner().send({
from: accounts[0]
});
下面粘贴了其他项目文件以帮助调试。
我的 Lottery.sol 文件;
pragma solidity ^0.8.13;
contract Lottery {
address public manager;
address payable[] public players;
function myLottery() public {
manager = msg.sender;
}
function enter() public payable {
require(msg.value > .001 ether);
players.push(payable(msg.sender));
}
function random() private view returns(uint){
return uint(keccak256(abi.encodePacked(block.difficulty, block.timestamp, players)));
}
function pickWinner() public restricted{
uint index = random() % players.length;
players[index].transfer(address(this).balance);
players = new address payable[](0);
}
modifier restricted() {
require(msg.sender == manager);
_;
}
function getPlayers() public view returns (address payable[] memory) {
return players;
}
}
compile.js
const path = require("path");
const fs = require("fs");
const solc = require("solc");
const lotteryPath = path.resolve(__dirname, "contracts", "Lottery.sol");
const source = fs.readFileSync(lotteryPath, "utf8");
let input = {
language: "Solidity",
sources: {
[lotteryPath]: {
content: source,
},
},
settings: {
outputSelection: {
"*": {
"*": ["*"],
},
},
},
};
var output = JSON.parse(solc.compile(JSON.stringify(input)));
module.exports = {
abi: output.contracts[[lotteryPath]]["Lottery"].abi,
bytecode: output.contracts[[lotteryPath]]["Lottery"].evm.bytecode.object,
};
deploy.js
const HDWalletProvider = require('truffle-hdwallet-provider');
const Web3 = require('web3');
const { abi, bytecode } = require("./compile");
const provider = new HDWalletProvider(
'****myMneumonic*****',
'****myInfuraNode****'
);
const web3 = new Web3 (provider);
const deploy = async () => {
const accounts = await web3.eth.getAccounts();
console.log('Attempting to deploy from account;', accounts[0]);
const result = await new web3.eth.Contract(abi)
.deploy({ data: bytecode })
.send({ from: accounts[0], gas: '10000000', gasPrice: '2000000000'});
console.log('Contract deployed to;', result.options.address);
};
deploy();
Lottery.test.js
const assert = require("assert");
const ganache = require("ganache");
const Web3 = require("web3");
const web3 = new Web3(ganache.provider());
const { abi, bytecode } = require("../compile");
let accounts;
let lottery;
beforeEach(async () => {
//get a list of all accounts
accounts = await web3.eth.getAccounts();
lottery = await new web3.eth.Contract(abi)
.deploy({ data: bytecode })
.send({ from: accounts[0], gas: "1000000" });
});
describe('lottery Contract', () => {
it ('deploys a contract', () => {
assert.ok(lottery.options.address);
});
it('allows one account to enter', async () => {
await lottery.methods.enter().send({
from: accounts[0],
value: web3.utils.toWei('0.002', 'ether')
});
const players = await lottery.methods.getPlayers().call({
from: accounts [0]
});
assert.equal(accounts[0], players);
assert.equal(1, players.length);
});
it('allows multiple accounts to enter', async () => {
await lottery.methods.enter().send({
from: accounts[0],
value: web3.utils.toWei('0.002', 'ether')
});
await lottery.methods.enter().send({
from: accounts[1],
value: web3.utils.toWei('0.002', 'ether')
});
await lottery.methods.enter().send({
from: accounts[2],
value: web3.utils.toWei('0.002', 'ether')
});
const players = await lottery.methods.getPlayers().call({
from: accounts[0]
});
assert.equal(accounts[0], players[0]);
assert.equal(accounts[1], players[1]);
assert.equal(accounts[2], players[2]);
assert.equal(3, players.length);
});
it('requires a minimum amount of ether to enter', async () => {
try {
await lottery.methods.enter().send({
from: accounts[0],
value: 200
});
assert(false);
} catch (err) {
assert(err);
}
});
it ('only manager can call pickWinner', async () => {
try {
await lottery.methods.pickWinner().send({
from: accounts[1],
value: 200
});
assert(false);
} catch (err) {
assert(err);
}
});
it('sends money to the winner & resets the players array', async () =>{
await lottery.methods.enter().send({
from: accounts[0],
value: web3.utils.toWei('1', 'ether')
});
const initialBalance = await web3.eth.getBalance(accounts[0]);
await lottery.methods.pickWinner().send({
from: accounts[0]
});
const finalBalance = await web3.eth.getBalance(accounts[0]);
const difference = finalBalance - initialBalance;
console.log(difference);
assert(difference > web3.utils.toWei('0.8', 'ether'));
});
});
您面临的问题是,在尝试挑选获胜者之前,您实际上从未设置过经理角色。它失败是因为在调用 pickWinner()
方法时,您的经理地址为空,并且这会因 restricted
修饰符中的 require 语句而失败。我还要指出,允许任何人设置经理角色可能不是您想要做的事情。相反,您应该在部署合同时在合同构造函数中设置经理角色,如下所示:
constructor(){
manager = msg.sender;
}
然后你就可以一起摆脱myLottery()
了。希望这有所帮助。如果您有任何其他问题,请随时通过 Twitter @_syndk8 与我联系。
我正在编写一个彩票合约,该合约应该接受玩家、选择赢家并将收集到的资金发送到赢家的地址,然后重新开始。 在 运行ning npm 运行 测试之后,前 5 个测试都通过了,但是“发送钱给获胜者并重置玩家数组”测试失败,错误消息如下。
1) lottery Contract
sends money to the winner & resets the players array:
Error: Transaction has been reverted by the EVM:
就我个人而言,我认为问题出在文件 Lottery.test.js 上的这段代码中,因为到目前为止,一切都很好 运行ning;
await lottery.methods.pickWinner().send({
from: accounts[0]
});
下面粘贴了其他项目文件以帮助调试。
我的 Lottery.sol 文件;
pragma solidity ^0.8.13;
contract Lottery {
address public manager;
address payable[] public players;
function myLottery() public {
manager = msg.sender;
}
function enter() public payable {
require(msg.value > .001 ether);
players.push(payable(msg.sender));
}
function random() private view returns(uint){
return uint(keccak256(abi.encodePacked(block.difficulty, block.timestamp, players)));
}
function pickWinner() public restricted{
uint index = random() % players.length;
players[index].transfer(address(this).balance);
players = new address payable[](0);
}
modifier restricted() {
require(msg.sender == manager);
_;
}
function getPlayers() public view returns (address payable[] memory) {
return players;
}
}
compile.js
const path = require("path");
const fs = require("fs");
const solc = require("solc");
const lotteryPath = path.resolve(__dirname, "contracts", "Lottery.sol");
const source = fs.readFileSync(lotteryPath, "utf8");
let input = {
language: "Solidity",
sources: {
[lotteryPath]: {
content: source,
},
},
settings: {
outputSelection: {
"*": {
"*": ["*"],
},
},
},
};
var output = JSON.parse(solc.compile(JSON.stringify(input)));
module.exports = {
abi: output.contracts[[lotteryPath]]["Lottery"].abi,
bytecode: output.contracts[[lotteryPath]]["Lottery"].evm.bytecode.object,
};
deploy.js
const HDWalletProvider = require('truffle-hdwallet-provider');
const Web3 = require('web3');
const { abi, bytecode } = require("./compile");
const provider = new HDWalletProvider(
'****myMneumonic*****',
'****myInfuraNode****'
);
const web3 = new Web3 (provider);
const deploy = async () => {
const accounts = await web3.eth.getAccounts();
console.log('Attempting to deploy from account;', accounts[0]);
const result = await new web3.eth.Contract(abi)
.deploy({ data: bytecode })
.send({ from: accounts[0], gas: '10000000', gasPrice: '2000000000'});
console.log('Contract deployed to;', result.options.address);
};
deploy();
Lottery.test.js
const assert = require("assert");
const ganache = require("ganache");
const Web3 = require("web3");
const web3 = new Web3(ganache.provider());
const { abi, bytecode } = require("../compile");
let accounts;
let lottery;
beforeEach(async () => {
//get a list of all accounts
accounts = await web3.eth.getAccounts();
lottery = await new web3.eth.Contract(abi)
.deploy({ data: bytecode })
.send({ from: accounts[0], gas: "1000000" });
});
describe('lottery Contract', () => {
it ('deploys a contract', () => {
assert.ok(lottery.options.address);
});
it('allows one account to enter', async () => {
await lottery.methods.enter().send({
from: accounts[0],
value: web3.utils.toWei('0.002', 'ether')
});
const players = await lottery.methods.getPlayers().call({
from: accounts [0]
});
assert.equal(accounts[0], players);
assert.equal(1, players.length);
});
it('allows multiple accounts to enter', async () => {
await lottery.methods.enter().send({
from: accounts[0],
value: web3.utils.toWei('0.002', 'ether')
});
await lottery.methods.enter().send({
from: accounts[1],
value: web3.utils.toWei('0.002', 'ether')
});
await lottery.methods.enter().send({
from: accounts[2],
value: web3.utils.toWei('0.002', 'ether')
});
const players = await lottery.methods.getPlayers().call({
from: accounts[0]
});
assert.equal(accounts[0], players[0]);
assert.equal(accounts[1], players[1]);
assert.equal(accounts[2], players[2]);
assert.equal(3, players.length);
});
it('requires a minimum amount of ether to enter', async () => {
try {
await lottery.methods.enter().send({
from: accounts[0],
value: 200
});
assert(false);
} catch (err) {
assert(err);
}
});
it ('only manager can call pickWinner', async () => {
try {
await lottery.methods.pickWinner().send({
from: accounts[1],
value: 200
});
assert(false);
} catch (err) {
assert(err);
}
});
it('sends money to the winner & resets the players array', async () =>{
await lottery.methods.enter().send({
from: accounts[0],
value: web3.utils.toWei('1', 'ether')
});
const initialBalance = await web3.eth.getBalance(accounts[0]);
await lottery.methods.pickWinner().send({
from: accounts[0]
});
const finalBalance = await web3.eth.getBalance(accounts[0]);
const difference = finalBalance - initialBalance;
console.log(difference);
assert(difference > web3.utils.toWei('0.8', 'ether'));
});
});
您面临的问题是,在尝试挑选获胜者之前,您实际上从未设置过经理角色。它失败是因为在调用 pickWinner()
方法时,您的经理地址为空,并且这会因 restricted
修饰符中的 require 语句而失败。我还要指出,允许任何人设置经理角色可能不是您想要做的事情。相反,您应该在部署合同时在合同构造函数中设置经理角色,如下所示:
constructor(){
manager = msg.sender;
}
然后你就可以一起摆脱myLottery()
了。希望这有所帮助。如果您有任何其他问题,请随时通过 Twitter @_syndk8 与我联系。