Réinitialiser la valeur d'une structure

Oct 04 2020

Je suis assez nouveau dans la solidité et j'essaie de créer un contrat de loterie où chaque adresse doit payer 1 éther pour être ajoutée au pool de loterie et à la fin, le propriétaire sélectionnerait au hasard un gagnant. Il y a 2 conditions qui sont importantes

(a) Si une adresse a déjà été ajoutée au pool, elle ne peut pas être ajoutée à nouveau pour ce tour (c'est-à-dire jusqu'à ce qu'un gagnant ait été sélectionné).

(b) Cependant, une fois ce cycle terminé, l'ensemble du contrat sera réinitialisé (c'est-à-dire que tous les détails antérieurs tels que les adresses qui étaient entrées dans le pool et les détails de la structure mappés à ces adresses seraient supprimés) et l'adresse antérieure peut être ajoutée à nouveau à le nouveau cycle.

Mon code ci-dessous remplit la condition 1 mais la condition 2 ne fonctionne pas et une fois que le contrat se réinitialise, je ne peux pas faire en sorte que les joueurs précédents soient à nouveau ajoutés au nouveau tour. Je suppose que les données de la structure ne sont pas réinitialisées. Toute aide serait grandement appréciée


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)));
        }
    
}```

Réponses

goodvibration Oct 04 2020 at 20:17

Ajoute ça:

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

Avant ça:

delete playersAddressList;

Notez qu'une fois playersAddressListdevenu trop grand, vous ne pourrez peut-être plus exécuter la fonction, car la quantité de gaz requise à ce stade dépassera le maximum possible (c.-à-d., Bloquer la limite de gaz).

Donc, vous devriez généralement fixer votre conception pour avoir une fonction restreinte (autorisée uniquement à une partie de confiance, comme vous-même, par exemple), qui prendra comme entrée le nombre maximum d'éléments à supprimer.

Par exemple:

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();
    }
}

Ensuite, vous pouvez appeler cette fonction plusieurs fois jusqu'à ce que le mappage et le tableau soient effacés.


Vous devrez peut-être ajouter un indicateur vous indiquant quand le contrat a été réinitialisé, afin d'empêcher toute autre transaction pendant ce processus (non atomique).

Par exemple:

bool public resetInProgress;

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

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

Ensuite, appliquez le onlyIfResetNotInProgressmodificateur sur chaque fonction qui ne devrait pas s'exécuter pendant la réinitialisation.

RwijuPal Oct 05 2020 at 09:55

J'ai vérifié le lien ici et j'ai mis à jour le code comme ci-dessous, ce qui, je pense, serait efficace pour la consommation de gaz
a) J'ai créé une variable globale appelée uint gamecounter = 1;
b) J'ai créé un mappage de l'adresse selon mapping (address => uint) playerStatus;
c) Lorsqu'un joueur est ajouté dans le La fonction a addPlayer()vérifié la condition suivante require(playerStatus[creator]!=gameCounter);et a également augmenté la valeur de playerStatus de 1 à la fin.
d) Enfin, lors de l'appel de la selectWinner()fonction, j'ai également augmenté la valeur du compteur de variable globale de 1 de sorte qu'il soit configuré pour le tour suivant