首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >选中赢家彩票测试抛出;错误:事务已被EVM恢复

选中赢家彩票测试抛出;错误:事务已被EVM恢复
EN

Ethereum用户
提问于 2022-04-25 14:13:53
回答 3查看 176关注 0票数 0

我正在写一份彩票合同,应该是接受玩家,挑选一位获奖者,并将收到的资金发送到获奖者的地址,然后重新开始。运行npm运行测试后,前5个测试正在通过,但是“向赢家发送钱并重置球员数组”测试失败,下面的错误消息如下。

代码语言:javascript
运行
复制
1) lottery Contract
   sends money to the winner & resets the players array:
 Error: Transaction has been reverted by the EVM:

就我个人而言,我认为问题在文件Lottery.test.js上,在这个代码片段上,因为到目前为止,一切都运行得很好;

代码语言:javascript
运行
复制
await lottery.methods.pickWinner().send({
        from: accounts[0]
    });

下面粘贴其他项目文件以帮助调试。

我的Lottery.sol文件;

代码语言:javascript
运行
复制
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

代码语言:javascript
运行
复制
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

代码语言:javascript
运行
复制
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

代码语言:javascript
运行
复制
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'));
    });
}); 
EN

回答 3

Ethereum用户

回答已采纳

发布于 2022-06-07 20:23:45

问题是,在我试着挑选获胜者之前,我从来没有设定过经理的角色。它失败了,因为在调用pickWinner()方法时,管理器地址为null,这将从受限修饰符中的require语句中失败。

我也要指出,允许任何人设置经理角色可能不是您想要做的事情。相反,在部署合同时,您应该在契约构造函数中设置经理角色,如下所示:

代码语言:javascript
运行
复制
constructor(){
  manager = msg.sender;
}

然后你就可以一起摆脱myLottery()了。希望这能帮上忙。

在推特上回答;@_syndk8。

票数 1
EN

Ethereum用户

发布于 2022-04-26 04:56:31

random()的S输出是一个数字太多的整数。

您可以通过将random()设置为public来检查它,并查看它返回的内容。

换句话说,如果n是玩家的数字,x是随机数,作为函数正常工作的一般条件,x必须等于或小于n。在您的代码中,这个条件不太可能被满足。

票数 0
EN

Ethereum用户

发布于 2022-06-06 19:45:14

以前的评论确实是一个很好的观察。但是,如果你不解决这个问题,我可能会给你一个解决办法。我按照以下步骤更改了pickWinner函数:

代码语言:javascript
运行
复制
function pickWinner() external restricted {
    //generating a uint number using the random function modulo array size
    uint index = random() % players.length;
    //send ethers to the winner at the position = index
    payable(players[index]).transfer(address(this).balance);
    //clean up the players' array initializing it again
    players = new address payable[](0);
}

因此,从公共到外部的可见性可能解决了这个问题。

票数 -2
EN
页面原文内容由Ethereum提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://ethereum.stackexchange.com/questions/126866

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档