Skip to content

Commit

Permalink
minor fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
antododo committed Feb 20, 2018
1 parent ed7fa66 commit 955212f
Show file tree
Hide file tree
Showing 12 changed files with 57 additions and 57 deletions.
8 changes: 4 additions & 4 deletions fr/4/00-overview.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
---
title: Système de combat zombie
header: "Leçon 4: Système de combat zombie"
title: Système de combat de zombies
header: "Leçon 4: Système de combat de zombies"
roadmap: roadmap4.jpg
---

Le temps est venu, humain...

Il est temps de faire COMBATTRE vos zombies!

Mais les batailles de zombies ne sont pas pour les âmes sensibles...
Mais les combats de zombies ne sont pas pour les âmes sensibles...

Dans cette leçon, nous allons mettre ensemble beaucoup de concepts que vous avez appris dans les chapitres précédents pour mettre en place notre fonction bataille de zombie. Nous allons aussi apprendre ce que sont les fonctions **payable**, et comment faire des DApps qui acceptent de l'argent des joueurs.
Dans cette leçon, nous allons regrouper beaucoup de concepts que vous avez appris dans les chapitres précédents pour mettre en place notre fonction combat de zombies. Nous allons aussi apprendre ce que sont les fonctions **payable**, et comment faire des DApps qui acceptent l'argent des joueurs.
6 changes: 3 additions & 3 deletions fr/4/battle-01.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
title: Batailles de zombies
title: Combats de zombies
actions: ['vérifierLaRéponse', 'indice']
requireLogin: true
material:
Expand Down Expand Up @@ -209,13 +209,13 @@ material:

Maintenant que nous en savons plus sur les fonctions payables et les balances de contrat, il est temps d'ajouter des fonctionnalités pour nos combats de zombies !

Pour reprendre le format des chapitres précédents, nous allons organiser notre code en créant un nouveau fichier / contrat pour la fonctionnalité d'attaque qui importera de notre contrat précédent.
Pour reprendre le format des chapitres précédents, nous allons organiser notre code en créant un nouveau fichier / contrat pour la fonctionnalité d'attaque qui importera notre contrat précédent.

## A votre tour

Passons en revue la création d'un nouveau contrat. La répétition conduit à la maîtrise !

Si vous ne vous rappelez plus de la syntaxe pour le faire, regardez `zombiehelper.sol` - mais essayer de le faire sans regarder en premier pour tester vos connaissances.
Si vous ne vous rappelez plus de la syntaxe pour le faire, regardez `zombiehelper.sol` - mais essayez de le faire sans regarder en premier pour tester vos connaissances.

1. En haut du fichier, indiquez que nous utilisons la version `^0.4.19` de Solidity.

Expand Down
20 changes: 10 additions & 10 deletions fr/4/battle-02.md
Original file line number Diff line number Diff line change
Expand Up @@ -220,9 +220,9 @@ 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 que vous ne pouvez pas. Du moins, nous ne pouvez pas le faire de manière sûre.
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
Voyons voir pourquoi.

## La génération de nombre aléatoire avec `keccak256`

Expand All @@ -237,21 +237,21 @@ uint random = uint(keccak256(now, msg.sender, randNonce)) % 100;
randNonce++;
uint random2 = uint(keccak256(now, msg.sender, randNonce)) % 100;
```
Cela prendra l'horodatage de `now`, le `msg.sender`, et incrémentera `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).
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, puis le convertir en un `uint` et utiliser `% 100` pour prendre seulement les 2 derniers chiffres, pour avoir un nombre aléatoire entre 0 et 99.
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.

### Cette méthode est vulnérable aux attaques d'un nœud malhonnête.

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 comme un **_bloc_** au reste du réseau.
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 à 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 sont valides, acceptent le bloc et passent à la résolution du bloc suivant.
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. Disons 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).
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'avais un noeud, je pourrais publier une transaction **seulement à mon propre noeud** 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ésoud. Je pourrais continuer indéfiniment jusqu'à ce que je gagne et résolve le bloc, et gagner de l'argent.
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.

## Comment faire pour générer des nombres aléatoires de manière sûre sur Ethereum ?

Expand All @@ -263,7 +263,7 @@ Même si cette fonction aléatoire N'EST PAS sécurisée sur Ethereum, en pratiq

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 verrons 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.
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.

## A votre tour

Expand All @@ -273,6 +273,6 @@ Nous allons implémenter une fonction de nombre aléatoire que nous pourrons uti

2. Créez une fonction appelée `randMod` (Modulo aléatoire). Elle sera `internal`, aura un paramètre `uint` appelé `_modulus`, et renverra avec `returns` un `uint`.

3. La fonction devra d'abord incrémenter `randNonce` (en utlisant la syntaxe `randNonce++`).
3. La fonction devra d'abord incrémenter `randNonce` (en utilisant la syntaxe `randNonce++`).

4. Enfin, elle devra (en une ligne de code) calculer un `uint` à partir du hachage `keccak256` de `now`, `msg,sender` et `randNonce` - et renvoyer avec `return` 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).
12 changes: 6 additions & 6 deletions fr/4/battle-03.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
title: Combat de zombie
title: Les zombies se battent
actions: ['vérifierLaRéponse', 'indice']
requireLogin: true
material:
Expand Down Expand Up @@ -227,16 +227,16 @@ material:
}
---

Maintenant que nous avons une source d'aléatoire dans notre contrat, nous pouvons l'utiliser pour nos combats de zombie pour calculer le résultat.
Maintenant que nous avons une source d'aléatoire dans notre contrat, nous pouvons l'utiliser dans nos combats de zombie pour calculer le résultat.

Les combats de zombie marchent ainsi :
Les combats de zombie fonctionnent ainsi :

- Vous choisissez un de vos zombies, et un zombie adversaire à attaquer.
- Si vous êtes le zombie attaquant, vous avez 70% de chance de gagner. Le zombie qui se défend à 30% de chance de gagner.
- Tous les zombies (attaquant et défendant) auront un `winCount` (compte de victoire) et `lossCount` (compte de défaite) qui va changer en fonction du résultat du combat.
- Tous les zombies (attaquant et défendant) auront un `winCount` (compteur de victoire) et `lossCount` (compteur de défaite) qui vont évoluer en fonction du résultat du combat.
- Si le zombie attaquant gagne, il gagne un niveau et fait naître un nouveau zombie.
- Si il perd, rien ne se passe (à part son `lossCount` qui augmente).
- Qu'il gagne ou perdre, le compte à rebours de repos du zombie attaquant est remis déclenché.
- S'il perd, rien ne se passe (à part son `lossCount` qui augmente).
- Qu'il gagne ou perdre, le compte à rebours de repos du zombie attaquant est déclenché.

Cela fait beaucoup de logique à implémenter, nous allons donc le faire en plusieurs fois au cours des prochains chapitres.

Expand Down
14 changes: 7 additions & 7 deletions fr/4/battle-04.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ material:
return (_zombie.readyTime <= now);
}
// 2. Ajouter le modificateur à la définition de fonction :
// 2. Ajouter le modificateur à la définition de la fonction :
function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) internal {
// 3. Enlevez cette ligne
require(msg.sender == zombieToOwner[_zombieId]);
Expand Down Expand Up @@ -276,31 +276,31 @@ material:
}
---

Quand quelqu'un appelle notre fonction `attack`, nous voulons nous assurer que cet utilisateur possède bien le zombie avec lequel il attaque. Ca serait un problème de sécurité si on pouvait attaquer avec le zombie d'un autre !
Quand quelqu'un appelle notre fonction `attack`, nous voulons nous assurer que cet utilisateur possède bien le zombie avec lequel il attaque. Cela serait une faille de sécurité si on pouvait attaquer avec le zombie d'un autre !

Avez vous une idée de la façon que nous pourrions vérifier si la personne qui appelle la fonction est bien le propriétaire du `_zombieId` qu'il utilise ?
À votre avis, comment pourrions nous vérifier que la personne appelant la fonction est bien le propriétaire du `_zombieId` qu'il utilise ?

Réfléchissez-y, et voyez si vous pouvez trouver une réponse tout seul.
Réfléchissez-y, et voyez si vous arrivez à trouver une réponse tout seul.

Prenez votre temps, vous pouvez regarder le code des versions précédentes pour avoir des idées...

La réponse se trouve ci-dessous, réfléchissez par vous même avant de continuer.

## La réponse

Nous avons déjà effectué cette vérification plusieurs fois dans les leçons précédentes. Dans `changeName()`, `changeDna()`, et `feedAndMultiply()`, nous avons utilisez la vérification suivante :
Nous avons déjà effectué cette vérification plusieurs fois dans les leçons précédentes. Dans `changeName()`, `changeDna()`, et `feedAndMultiply()`, nous avons utilisé la vérification suivante :

```
require(msg.sender == zombieToOwner[_zombieId]);
```

C'est la même logique dont nous allons avoir besoin pour notre fonction `attack`. Puisque nous utilisons la même logique plusieurs fois, nous allons créer un modificateur pour nettoyer notre code et éviter de trop se répéter.
C'est la même logique dont nous allons avoir besoin pour notre fonction `attack`. Puisque nous utilisons la même logique plusieurs fois, nous allons créer un modificateur pour clarifier notre code et éviter de trop se répéter.

## A votre tour

Nous sommes de retour à `zombiefeeding.sol`, puisque c'est le premier endroit où nous utilisons cette logique. Nous allons mettre la logique dans son propre `modifier`.

1. Créez un `modifier` appelée `ownerOf` qui aura un paramètre, `_zombieId` (un `uint`).
1. Créez un `modifier` appelé `ownerOf` qui aura un paramètre, `_zombieId` (un `uint`).

Le corps devra vérifier avec `require` que `msg.sender` soit égal à `zombieToOwner[_zombieId]`, puis continuer avec la fonction. Vous pouvez regarder la fonction `zombiehelper.sol` si vous ne vous rappelez plus de la syntaxe d'un modificateur.

Expand Down
4 changes: 2 additions & 2 deletions fr/4/battle-06.md
Original file line number Diff line number Diff line change
Expand Up @@ -238,10 +238,10 @@ Nous allons continuer de définir notre fonction `attack`, maintenant que nous p

1. Ajoutez le modificateur `ownerOf` à `attack`, pour être sûr que l'appelant possède `_zombieId`.

2. La première chose que notre fonction doit faire, c'est d'obtenir un pointeur `storage` de nos deux zombies pour intéragir plus facilement avec eux :
2. La première chose que notre fonction doit faire, c'est d'obtenir un pointeur `storage` de nos deux zombies pour interagir plus facilement avec eux :

a. Déclarez un `Zombie storage` appelé `myZombie` égal à `zombies[_zombieId]`.

b. Déclarez un `Zombie storage` appelé `enemyZombie` égal à `zombies[_targetId]`.

3. Nous allons utliser un nombre aléatoire entre 0 et 99 pour déterminer le résultat du combat. Déclarez un `uint` appelé `rand` égal au résultat de la fonction `randMod` avec comme argument `100`.
3. Nous allons utiliser un nombre aléatoire entre 0 et 99 pour déterminer le résultat du combat. Déclarez un `uint` appelé `rand` égal au résultat de la fonction `randMod` avec comme argument `100`.
8 changes: 4 additions & 4 deletions fr/4/battle-07.md
Original file line number Diff line number Diff line change
Expand Up @@ -262,9 +262,9 @@ material:
}
---

Pour notre jue de zombie, nous allons vouloir comptabiliser le nombre de victoire et de défaite de nos zombies. Ainsi nous pourrons avoir un "classement zombie" dans notre jeu.
Pour notre jeu de zombie, nous allons vouloir comptabiliser le nombre de victoire et de défaite de nos zombies. Ainsi nous pourrons avoir un "classement zombie" dans notre jeu.

Nous pouvons stocker ces données de plusieurs façons dans notre DApp - un mappage indivuel, une structure classement, ou directement dans la structure `Zombie`.
Nous pouvons stocker ces données de plusieurs façons dans notre DApp - un mappage individuel, une structure classement, ou directement dans la structure `Zombie`.

Chaque méthode a ses avantages et ses inconvénients, dépendamment de comment nous voulons interagir avec ces données. Pour ce tutoriel, nous allons stocker les statistiques dans notre structure `Zombie` par simplicité, et les appeler `winCount` et `lossCount`.

Expand All @@ -278,8 +278,8 @@ Revenons à `zombiefactory.sol`, et ajoutons ces propriétés à notre structure

b. `lossCount`, aussi un `uint16`

> Remarque : Rappelez-vous, puisque nous pouvons combiner les `uint`s dans une structure, nous voulons utliser le plus petit `uint` possible. un `uint8` serait trop petit, car 2^8 = 256 - si nos zombies attaquent tous les jours, en un an ce serait dépassé. Mais 2^16 = 65536 - alors à moins qu'un utilisateur ne fasse que gagner ou que perdre chaque jour pendant 179 ans, nous sommes tranquille.
> Remarque : Rappelez-vous, puisque nous pouvons combiner les `uint`s dans une structure, nous voulons utiliser le plus petit `uint` possible. un `uint8` serait trop petit, car 2^8 = 256 - si nos zombies attaquent tous les jours, en un an cela pourrait être dépassé. Mais 2^16 = 65536 - alors à moins qu'un utilisateur ne fasse que gagner ou que perdre chaque jour pendant 179 ans, nous sommes tranquilles.
2. Maintenant que nous avons de nouvelles propriétés pour notre structure `Zombie`, nous devons changer la définition de notre fonction `_createZombie()`.

Changez la définition de création de zombie pour que chaque nouveau zombie créés est `0` victoire et `0` défaite.
Changez la définition de création de zombie pour que chaque nouveau zombie créé est `0` victoire et `0` défaite.
8 changes: 4 additions & 4 deletions fr/4/battle-08.md
Original file line number Diff line number Diff line change
Expand Up @@ -242,19 +242,19 @@ material:

Maintenant que nous avons un `winCount` et un `lossCount`, nous pouvons les mettre à jour en fonction du zombie qui gagne le combat.

Au chapitre 6 nous avons calculé un nombre aléatoire entre 0 et 100. Nous allons utliser ce nombre pour déterminer le vainceur du combat, et mettre à jour en conséquence.
Au chapitre 6 nous avons calculé un nombre aléatoire entre 0 et 100. Nous allons utiliser ce nombre pour déterminer le vainqueur du combat, et mettre à jour en conséquence.


## A votre tour

1. Créez une déclaration `if` qui va vérifier si `rand` est **_plus petit ou égal_** à `attackVictoryProbability`.

2. Si c'est le cas, nos zombie gagne ! Donc :
2. Si c'est le cas, notre zombie gagne ! Donc :

a. Incrémentez `winCount` de `myZombie`.

b. Incrémentez le `level` de `myZombie`. (Nouveau niveau !!!!!!!)

c. Incrémentez le `lossCount` de `enemyZombie`. (Perdant !!!!!! 😫 😫 😫)
c. Incrémentez le `lossCount` de `enemyZombie`. (Le nul !!!!!! 😫 😫 😫)

d. Exécuter la fonction `feedAndMultiply`. Regardez `zombiefeeding.sol` pour voir la syntaxe pour l'appeler. Pour le 3ème argument (`_species_`), mettez `"zombie"`. (Cela ne fait rien pour l'instant, mais plus tard nous pourrons ajouter des fonctionnalités supplémentaire pour les zombies générés à partir d'autres zombies).
d. Exécutez la fonction `feedAndMultiply`. Regardez `zombiefeeding.sol` pour voir la syntaxe pour l'appeler. Pour le 3ème argument (`_species_`), mettez `"zombie"`. (Cela ne fait rien pour l'instant, mais plus tard nous pourrons ajouter des fonctionnalités supplémentaires pour les zombies générés à partir d'autres zombies).
6 changes: 3 additions & 3 deletions fr/4/battle-09.md
Original file line number Diff line number Diff line change
Expand Up @@ -251,11 +251,11 @@ material:

Maintenant que nous avons codé ce qu'il se passe quand notre zombie gagne, voyons voir ce qu'il arrive quand il **perd**.

Dans notre jeu, quand les zombies perdent, ils ne perdent pas de niveau - ils rajoutent simplement une défaite à leur compte `lossCount`, et leur compte à rebours est déclenché afin qu'ils attendent un jour pour attaquer de nouveau.
Dans notre jeu, quand les zombies perdent, ils ne perdent pas de niveau - ils rajoutent simplement une défaite à leurs compteurs `lossCount`, et leurs comptes à rebours sont déclenchés afin qu'ils attendent un jour pour attaquer de nouveau.

Pour implémenter cette logique, nous allons avoir besoin de la déclaration `else` (sinon) :

Les déclarations `else` s'écrivent comme en JavaScript et beaucoup d'autres langages.
Les déclarations `else` s'écrivent comme en JavaScript et comme dans beaucoup d'autres langages.

```
if (zombieCoins[msg.sender] > 100000000) {
Expand All @@ -273,4 +273,4 @@ if (zombieCoins[msg.sender] > 100000000) {

b. Incrémentez `winCount` de `enemyZombie`.

2. En dehors de la déclaration `else`, exécuter la fonction `_triggerCooldown` sur `myZombie`. De cette manière le zombie ne peut attaquer qu'une fois par jour.
2. En dehors de la déclaration `else`, exécutez la fonction `_triggerCooldown` sur `myZombie`. De cette manière le zombie ne peut attaquer qu'une fois par jour.
Loading

0 comments on commit 955212f

Please sign in to comment.