1

I am fairly new to solidity and I am trying to create a lottery contract where every address needs to pay 1 ether to get added to the lottery pool and at the end, the owner would randomly select one winner. There are 2 conditions which are important

(a) If an address has already been added to the pool then he can't be added again for that round(i.e till a winner has been selected).

(b) However, once that round is over the whole contract will reset (i.e all the earlier details like the addresses which had entered the pool and the structure details mapped to those addresses would be deleted) and the earlier address can be added again to the new round.

My code below satisfies the condition 1 but the condition 2 is not working and once the contract resets itself I can't get the earlier players to be added again to the new round. I am assuming the struct data is not resetting. Any help would be greatly appreciated


contract Lottery
{

        //Defining the Owner
            address Owner;
            constructor() public
            {   
                 Owner = msg.sender;    
                 
            }
    
        // Defining players
        
            struct person
            {
                string name;
                uint age;
                bool played;
            }
    
        // One to one mapping of player and its address    
            mapping (address => person) players;

        // creating a list/array of players    
        address payable[] playersAddressList;

        // Tracking balance;
            uint public balance=0;
            
        // modifier for Owner Only
        modifier ownerOnly(){
         require(msg.sender==Owner);
         _;
        }
        
        
        function addPlayer(string memory a, uint b) public payable
        {

                address payable creator = msg.sender;
               
            //  Checking if the player has played earlier or not for that particular round
                require (players[creator].played == false);
                
            //  If has not played then adding it to the player array    
                playersAddressList.push(creator);
            
            // Updating the balance the contract has    
                balance = balance + msg.value;
                require (msg.value >= 1 ether);
                
                
            //  Entering the input for the structure
                players[creator].name = a;
                players[creator].age = b;
                players[creator].played = true;
        }
        
    
        //Function to select a winner
        function selectWinner() public ownerOnly {
            uint a = random() % playersAddressList.length;
            address payable winner; 
            winner = playersAddressList[a];
            winner.transfer(balance);
            balance = 0;
            delete playersAddressList;
        }
    
        //displa the players list array length
        function displayDetails(uint a) public view returns(uint,  string memory, bool){
            
            return(players[playersAddressList[a]].age,players[playersAddressList[a]].name,players[playersAddressList[a]].played);

        }
    
        //Generating a pseudo random number
        function random() private view returns(uint){
           return uint(keccak256(abi.encodePacked(block.difficulty, now, playersAddressList)));
        }
    
}```
5
  • but the condition 2 is not working and once the contract resets itself I can get the earlier players to be added I again - first of all, that's exactly what your 2nd requirement states, so I don't quite see what the problem is. Second, you need to explain what the contract resets itself means to begin with! Oct 4 '20 at 12:13
  • Hey @goodvibration thanks a lot for highlighting this. It was a bit unclear, my bad. I have edited the question again and hopefully it's better now
    – Rwiju Pal
    Oct 4 '20 at 12:55
  • all the earlier details like the addresses which had entered the pool and the structure details mapped to those addresses would be deleted - where exactly is that in your code??? Oct 4 '20 at 13:04
  • I have been storing the address which enters the contract in the array playersAddressList. What I am doing currently is I am deleting that array using delete playersAddressList under the function selectWinner(). However, I am not sure if it deletes the data mapped to that address.
    – Rwiju Pal
    Oct 4 '20 at 13:10
  • Deleteing the array doesn't clear up the mapping. Oct 4 '20 at 13:14
0

Add this:

for (uint256 i = 0; i < playersAddressList.length; i++)
    delete players[playersAddressList[i]];

Before this:

delete playersAddressList;

Note that once playersAddressList becomes too large, you may no longer be able to execute the function, because the amount of gas required at that point will exceed the maximum possible (i.e., block gas-limit).

So you should generally fix your design to have a restricted function (allowed only to a trusted party, such as yourself, for example), which will take as input the maximum number of elements to delete.

For example:

function reset(uint256 maxNumOfElements) public ownerOnly {
    uint256 numOfElements = maxNumOfElements;

    if (numOfElements > playersAddressList.length)
        numOfElements = playersAddressList.length;

    for (uint256 i = 0; i < numOfElements; i++) {
        address element = playersAddressList[playersAddressList.length - 1];
        delete players[element];
        players.pop();
    }
}

Then you can call this function several times until both the mapping and the array are cleared.


You may need to add a flag telling you when the contract has been reset, in order to prevent any other transaction during this (non-atomic) process.

For example:

bool public resetInProgress;

modifier onlyIfResetNotInProgress(){
    require(!resetInProgress, "reset in progress");
     _;
}

function reset(uint256 maxNumOfElements) public ownerOnly {
    resetInProgress = true;
    ...
    resetInProgress = playersAddressList.length > 0;
}

Then apply the onlyIfResetNotInProgress modifier on every function which should not execute while reset is in progress.

1
  • Thanks a lot. The solution worked like a charm. However, to avoid the usage of gas I referred to the solution here. The solution has bee updated below
    – Rwiju Pal
    Oct 5 '20 at 2:41
0

I checked the link here and have updated the code as below which I think would be efficient in gas consumption
a) I created a global variable called uint gamecounter = 1;
b) I created a mapping of the address as per mapping (address => uint) playerStatus;
c) When a player is getting added in the function addPlayer() checked the following condition require(playerStatus[creator]!=gameCounter); and also increased the value of playerStatus by 1 at the end.
d) Finally when calling the selectWinner() function I also increased the value of the global variable counter by 1 such that it is setup for the next round

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.