title | actions | requireLogin | material | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Nombres aléatoires |
|
true |
|
Super ! Maintenant essayons de comprendre la logique de combat.
Tous les bons jeux ont besoin d'une part d'aléatoire. Comment pouvons-nous générer des nombres aléatoires en Solidity ?
La vraie réponse est qu'on ne peut pas. Du moins, nous ne pouvons pas le faire de manière sûre.
Voyons voir pourquoi.
La meilleure source d'aléatoire que nous avons avec Solidity est la fonction de hachage keccak256
.
Pour générer un nombre aléatoire, nous pourrions faire quelque chose qui ressemble à :
// Générer un nombre aléatoire entre 1 et 100 :
uint randNonce = 0;
uint random = uint(keccak256(now, msg.sender, randNonce)) % 100;
randNonce++;
uint random2 = uint(keccak256(now, msg.sender, randNonce)) % 100;
Cela prendrait l'horodatage de now
, le msg.sender
, et incrémenterait nonce
(un nombre qui est utilisé seulement une fois, pour ne pas exécuter la même fonction avec les même paramètres plusieurs fois).
Ensuite, cela utilisera le keccak
pour convertir ces paramètres en un hachage aléatoire, le convertir en un uint
et utiliser % 100
pour prendre seulement les 2 derniers chiffres, afin d'avoir un nombre aléatoire entre 0 et 99.
En Ethereum, quand vous appelez la fonction d'un contrat, vous diffuser une transaction à un nœud ou à des nœuds du réseau. Les nœuds du réseau vont ensuite collecter plusieurs transactions, vont essayer d'être le premier à résoudre un problème mathématique qui demande un calcul intensif appelé "Proof of Work" (Preuve de Travail) ou PoW, et vont ensuite diffuser ce groupe de transactions avec leur PoW dans un bloc au reste du réseau.
Quand un nœud a résolu un PoW, les autres nœuds arrêtent d'essayer de résoudre le PoW, ils vérifient que la liste des transactions de l'autre nœud soit valide, acceptent le bloc et passent à la résolution du bloc suivant.
Cela rend notre fonction nombre aléatoire exploitable.
Imaginez que nous avons un contrat pile ou face - face vous doublez votre argent, pile vous perdez tout. Et qu'il utilise la fonction ci-dessus pour déterminer si c'est pile ou face. (random >= 50
c'est face, random < 50
c'est pile).
Si j'ai un nœud, je pourrais publier une transaction seulement à mon propre nœud et ne pas la partager. Je pourrais exécuter le code de la fonction pile ou face pour voir si j'ai gagné - et si je perds, choisir de ne pas ajouter cette transaction dans le prochain bloc que je résous. Je pourrais continuer indéfiniment jusqu'à ce que je gagne et résolve le bloc, et gagner de l'argent.
Parce que tout le contenu de la blockchain est visible de tous les participants, c'est un problème difficile, et la solution est au-delà du cadre de ce tutoriel. Vous pouvez lire Cette discussion StackOverflow (en anglais) pour vous faire une idée. Une des possibilités serait d'avoir un oracle pour avoir accès à une fonction aléatoire en dehors de la blockchain Ethereum.
Bien sur, puisque des dizaine de milliers de nœuds Ethereum sur le réseau rivalisent pour résoudre le prochain bloc, mes chances de résoudre le prochain bloc sont vraiment faibles. Il me faudrait énormément de puissance de calcul et de temps pour réussir à l'exploiter - mais si la récompense est assez élevée (si je pouvais parier 100 000 000$ sur la fonction pile ou face), cela vaudrait la peine de l'attaquer.
Même si cette fonction aléatoire N'EST PAS sécurisée sur Ethereum, en pratique, à part si notre fonction aléatoire a beaucoup d'argent en jeu, les utilisateurs de votre jeu n'auront sûrement pas assez de ressources pour l'attaquer.
Puisque nous construisons simplement un jeu à des fin de démonstration dans ce tutoriel, et qu'il n'y a pas vraiment d'argent en jeu, nous allons accepter les compromis d'utiliser un générateur de nombre aléatoire simple à implémenter, sachant qu'il n'est pas totalement sûr.
Dans une prochaine leçon, il se peut que nous voyons comment utiliser des oracles (un moyen sécurisé de récupérer des données en dehors d'Ethereum) pour générer une fonction aléatoire depuis l'extérieur de la blockchain.
Nous allons implémenter une fonction de nombre aléatoire que nous pourrons utiliser pour déterminer le résultat de nos combats, même si ce n'est pas totalement sécurisé contre les attaques.
-
Donnez à notre contrat un
uint
appelérandNonce
égal à0
. -
Créez une fonction appelée
randMod
(Modulo aléatoire). Elle serainternal
, aura un paramètreuint
appelé_modulus
, et renverra avecreturns
unuint
. -
La fonction devra d'abord incrémenter
randNonce
(en utilisant la syntaxerandNonce++
). -
Enfin, elle devra (en une ligne de code) calculer un
uint
à partir du hachagekeccak256
denow
,msg,sender
etrandNonce
- et renvoyer avecreturn
cette valeur modulo%_modulus
. (Ouf! C'était un gros morceau, si vous n'avez pas tout suivi, jetez un œil à l'exemple ci-dessus où nous avons généré un nombre aléatoire - la logique est très similaire).