Search code examples
mocha.jssoliditysmartcontractstruffleganache

Truffle tests not working, recieving: VM Exception while processing transaction: out of gas


I'm trying to test my contract but I'm receiving this error:

  Events
✔ deploys a factory and an event
✔ marks caller as the event manager
1) allows the user to buy a ticket and stores their details


2 passing (1s)
1 failing

1) Events
   allows the user to buy a ticket and stores their details:
 c: VM Exception while processing transaction: out of gas
  at Function.c.fromResults (node_modules/ganache-cli/build/ganache-core.node.cli.js:4:192416)
  at w.processBlock (node_modules/ganache-cli/build/ganache-core.node.cli.js:42:50915)
  at processTicksAndRejections (internal/process/task_queues.js:94:5)

However, when looking over my code I believe I have more than enough gas and perhaps this error has to do with something else.

Here is the code for my test:

const assert = require('assert');
const ganache = require('ganache-cli');
const Web3 = require('web3');
const web3 = new Web3(ganache.provider({ gasLimit: 10000000 }));

const compiledFactory = require("../ethereum/build/EventFactory.json");
const compiledCampaign = require("../ethereum/build/Event.json");

let accounts;
let factory;
let eventAddress;
let event;

beforeEach(async () => {
  accounts = await web3.eth.getAccounts();

  factory = await new web3.eth.Contract(JSON.parse(compiledFactory.interface))
    .deploy({ data: compiledFactory.bytecode })
    .send({ from: accounts[0], gas: "10000000" });

  await factory.methods.createEvent("test event", 2, 1, "Elton John's world tour", "Faketown auditorium", 100).send({
    from: accounts[0],
    gas: "10000000",
  });

  [eventAddress] = await factory.methods.getDeployedEvents().call();
  event = await new web3.eth.Contract(
    JSON.parse(compiledCampaign.interface),
    eventAddress
  );
});

describe("Events", () => {

  it("deploys a factory and an event", () => {
    assert.ok(factory.options.address);
    assert.ok(event.options.address);
  });

  it("marks caller as the event manager", async () => {
    const manager = await event.methods.manager().call();
    assert.equal(accounts[0], manager);
  });

  it("allows the user to buy a ticket and stores their details", async () => {
    await event.methods.buyTicket('Louie').send({
      value: '1',
      from: accounts[1]
    });
    const isContributor = await event.methods.attendees(account[1]).call();
    assert(isContributor);
  });

});

As you can see, my first two tests pass. However the third does not work. I believe I am providing enough gas. Here is my contract so you can look at the functions:

pragma solidity ^0.4.17;

contract EventFactory {
    address[] public deployedEvents;

    function createEvent(string title, uint max, uint cost, string description, string location, uint date) public {
        address newEvent = new Event(title, msg.sender, max, cost, description, location, date);
        deployedEvents.push(newEvent);
    }

    function getDeployedEvents() public view returns (address[]) {
        return deployedEvents;
    }
}

contract Event {
    struct Attendee {
        bool valid;
        string name;
        uint ticketNumber;
        bool confirmed;
        uint amountPaid;
        uint confirmationCode;
    }

    address public manager;
    string public title;
    uint public maxAttendees;
    uint public ticketsSold;
    mapping(address=>Attendee) public attendees;
    uint public ticketCost;
    string public eventDescription;
    string public eventLocation;
    uint public eventDate;
    mapping(address=>bool) public blacklist;


    modifier restricted() {
        require(msg.sender == manager);
        _;
    }

    function random(uint seed) private view returns (uint) {
        uint tmp = uint(block.blockhash(block.number - 1));
        return uint(keccak256(tmp,seed)) % 1000000000;
    }


    function Event(string eventTitle, address creator, uint max, uint cost, string description, string location, uint date) public {
        title = eventTitle;
        manager = creator;
        maxAttendees = max;
        ticketsSold = 0;
        ticketCost = cost;
        eventDescription = description;
        eventLocation = location;
        eventDate = date;
    }

    function buyTicket(string name) public payable {
        require(blacklist[msg.sender] != true);
        require(ticketsSold != maxAttendees);
        require(attendees[msg.sender].valid == false);
        require(msg.value == ticketCost);


        Attendee memory attendee = Attendee({
            valid: true,
            name: name,
            ticketNumber: (maxAttendees - ticketsSold),
            confirmed: false,
            amountPaid: ticketCost,
            confirmationCode: 0
        });

        ticketsSold++;
        attendees[msg.sender] = attendee;
    }


    function challengeAttendee(address attendee, uint seed) public restricted returns (uint) {
        require(attendees[attendee].valid == true);
        uint code = random(seed);
        attendees[attendee].confirmationCode = code;
        return code;
    }

    function confirmTicketOwnerShip(uint code) public {
        require(attendees[msg.sender].confirmationCode != 0);


        attendees[msg.sender].confirmed = attendees[msg.sender].confirmationCode == code;

    }

    function confirmResponse(address attendee) public restricted view returns (bool) {
        return attendees[attendee].confirmed;
    }

    function addToBlackList(address blockedAddress) public restricted {
        blacklist[blockedAddress] = true;
    }


    function getEventDetails() public view returns (string, uint, uint, uint, string, string, uint) {
        return (
            title,
            maxAttendees,
            ticketsSold,
            ticketCost,
            eventDescription,
            eventLocation,
            eventDate
        );
    }

}

Solution

  • I've found the error, unfortunately, it's simply a typo. On the sixth line down I use account[1] not accounts[1]. Also I had to specify the gas as the default amount was not enough.

    My code now looks like:

      it("allows the user to buy a ticket and stores their details", async () => {
      await event.methods.buyTicket("Louie").send({
        from: accounts[1],
        value: '1',
        gas: '20000000'
      });
       const isContributor = await event.methods.attendees(accounts[1]).call();
        assert(isContributor.valid);
      });