1

I'm writing a test for a Lottery contract:

var Lottery = artifacts.require("./Lottery.sol");

contract('Lottery', function (accounts) {
    var ACC_FABIAN = accounts[0];
    var ACC_RENE = accounts[1];
    var ACC_OTHER = accounts[2];
    var TICKET_PRICE = 1;

    var balance_before = web3.eth.getBalance(ACC_FABIAN).toString(10);

    var lotteryFn = Lottery.deployed();

    it('should buy a ticket for one user', function () {
        var meta;
        return lotteryFn.then(function (instance) {
            meta = instance;
            return instance.buyTicket(200, {from: ACC_FABIAN, value: TICKET_PRICE});
        }).then(function () {
            var buyingTimeFactor;
            meta.calculateBuyingTimeScore.call().then(function (btf) {
                buyingTimeFactor = btf.toNumber();
            });
            // ESTIMATION
            meta.getEstimation.call(ACC_FABIAN).then(function (estimation) {
                assert.equal(estimation.toNumber(), 200, "Estimations are different");
            });
            // BUYING TIME
            meta.getBuyingTime.call(ACC_FABIAN).then(function (buyingTime) {
                assert.equal(buyingTime.toNumber(), buyingTimeFactor, "Buying time not correct");
            });

            // PAYOUT
            meta.payout(200).then(function (response) {
                var balance_now = web3.eth.getBalance(ACC_FABIAN);
                console.log(web3.fromWei(balance_before, 'ether').toString(), web3.fromWei(balance_now, 'ether').toString());
            });
        });
    });
});

As you can see, I'm checking the account balance before and after the contract. The console.log gives me something like this:

97.0711255 97.0326134

This is a difference of 0.0385121 ETH

Where is this coming from?

Even with a TICKET_PRICE of 0 I get this difference. Is the gas so expensive?


The contract:

contract Lottery {

    // CONSTANTS
    int constant LOTTERY_INTERVAL = 1 days;

    uint256 constant private TICKET_PRICE = 1;

    uint constant FEE_FACTOR = 200; // 0.5 %

    // VARIABLES
    uint256 totalBalance = 0;

    uint totalParticipants = 0;

    uint winnerCounter = 0;

    // Structs
    struct TicketHolder {
    address ticketHolder;
    uint estimation;
    uint buyingTimeScore;
    uint timestamp;
    uint score;
    }

    // Mappings
    mapping (address => TicketHolder) ticketHolders;

    mapping (uint => TicketHolder) ticketHoldersIndex;

    // Arrays
    address[] ticketHoldersAddress;

    address [] winners;

    // Constructor
    function Lottery(){

    }

    //Getters setters
    function getBuyingTime(address ticketHolder) /*internal*/ returns (uint){
        return ticketHolders[ticketHolder].buyingTimeScore;
    }


    function getEstimation(address ticketHolder) /*internal*/ returns (uint){
        return ticketHolders[ticketHolder].estimation;
    }

    function getScore(address ticketHolder) /*internal*/ returns (uint){
        return ticketHolders[ticketHolder].score;
    }


    function getMinute(uint timestamp) /*internal*/ constant returns (uint8) {
        return uint8((timestamp / 60) % 60);
    }

    function setScore(address ticketHolder, uint score) /*internal*/{
        ticketHolders[ticketHolder].score = score;
    }

    function calculateBuyingTimeScore() /*internal*/ returns (uint){
        uint timeBeforeNewRound = 60 - getMinute(now);
        return timeBeforeNewRound * 100 * 100 / 60;
    }

    function calculateDeviationScore(uint courseValue, uint estimatedValue) /*internal*/ returns (uint){
        uint difference = 0;
        if (courseValue >= estimatedValue) {
            difference = courseValue - estimatedValue;
        }
        else if (courseValue < estimatedValue) {
            difference = estimatedValue - courseValue;
        }

        // Calculated standard deviation
        uint deviation = (difference * 10000 / courseValue);
        uint score = 10000 - deviation;
        return score;
    }

    //TODO: add more conditions
    function buyTicket(uint estimation) payable {
        if (msg.value < TICKET_PRICE) throw;
        address ticketHolder = msg.sender;
        uint buyingTimeScore = calculateBuyingTimeScore();
        totalBalance += msg.value;
        ticketHolders[ticketHolder] = TicketHolder(msg.sender, estimation, buyingTimeScore, now, 0);
        ticketHoldersIndex[totalParticipants++] = TicketHolder(msg.sender, estimation, buyingTimeScore, now, 0);
        ticketHoldersAddress.push(ticketHolder);
    }

    function calculateScore(uint courseValue) /*internal*/ {
        if (totalParticipants == 0) throw;
        for (uint participant = 0; participant < totalParticipants; participant++) {
            TicketHolder ticketHolder = ticketHoldersIndex[participant];
            uint deviationScore = calculateDeviationScore(courseValue, ticketHolder.estimation) / 2;
            uint buyingTimeScore = ticketHolder.buyingTimeScore / 2;
            uint totalScore = deviationScore + buyingTimeScore;
            setScore(ticketHolder.ticketHolder, totalScore);
        }
    }

    function determineWinners() /*internal*/ returns (uint){
        uint highestScore = 0;
        for (uint participant = 0; participant < totalParticipants; participant++) {
            TicketHolder ticketHolder = ticketHoldersIndex[participant];
            uint score = ticketHolder.score;
            if (score >= highestScore) {
                winners.push(ticketHolder.ticketHolder);
                winnerCounter++;
                highestScore = score;
            }
        }
        return ticketHoldersAddress.length;
    }

    function payout(uint courseValue) /*internal*/ {
        if (totalParticipants == 0) throw;
        calculateScore(courseValue);
        determineWinners();
        uint256 winAmount = totalBalance / winnerCounter;
        for (uint i = 0; i < winnerCounter; i++) {
            address winnerTicket = winners[i];
            winnerTicket.transfer(winAmount);
        }
    }

}
1

every state changing transaction incure's cost inform of gas, you can specify a lower gas amount when calling the contract function but bear in mind that if you set a fee too low, your transaction will be rejected.

  • Thanks for your answer. In this case it would be around 10$. Isn't that WAYYY too much for this super tiny contract? – Fabian Lurz Jul 2 '17 at 7:10
  • 1
    Yes, it is, but it's really a temporary result of the rapid price increase of ETH. If you don't want to pay so much, you can set your gas price lower. The defaults just haven't adjusted very quickly – Tjaden Hess Jul 2 '17 at 12:01
2

Yes, this is expected. Since you are calling the functions which are causing state change(blockchain transactions) and that's the reason default user, which is accounts[0] is losing gas in order to execute the transaction and eventually gas expenditure results into balance loss.

Check this answer to understand more about Gas and how transaction fee is calculated.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.