Réinitialiser la valeur d'une structure
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
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.
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