Contrat intelligent: mauvais code ou condition de concurrence?

systempuntoout

Contrat intelligent: mauvais code ou condition de concurrence?


Nous avons développé un contrat intelligent simple qui propose cette méthode de transaction publique suivante:

 struct Bid { uint256 userCode; uint256 amount; } Bid public winningBid; Bid[] public bids; function bidAmount(uint256 _userCode, uint256 _amount) public { assert(_userCode> 0); assert(_amount> 0); assert(_amount > winningBid.amount + winningBid.amount * (5/100)); winningBid.userCode= _userCode; winningBid.amount= _amount; var bidData=Bid(_userCode, _amount); bids.push(bidData); } 

La méthode bidAmount vérifie si l’enchère est valide en vérifiant si le montant est supérieur au montant de l’enchère gagnante actuelle plus une étape de montant obligatoire (winningBid.amount * (5/100)) ; si la vérification est vérifiée, l’enchère gagnante devient l’enchère gagnante actuelle et une nouvelle enchère est poussée dans la liste des enchères.

Comment est-il possible que nous ayons pu stocker dans ethereum une liste d’enchères comme celle-ci?

 22/01/2018 11:51 13.500,00 MrX 22/01/2018 11:51 13.440,00 MrY 22/01/2018 11:49 12.800,00 MrZ 

L’offre MrX viole la vérification du contrat intelligent:

 assert(_amount > winningBid.amount + winningBid.amount * (5/100)); 

Cela ressemble à une « condition de MrX  » où les enchères MrX et MrY ont toutes deux été effectuées juste en vérifiant la validité de l’ MrZ bid . Ce que nous attendions, c’est que l’une des deux enchères échoue pour violation de la règle.

À ma connaissance, les exécutions de contrats sont sérialisées dans un bloc et ne sont pas effectuées en parallèle.
Est-ce simplement un mauvais codage ou une condition de concurrence?

Réponses


 Ismael

Ethereum utilise uniquement l’arithmétique entière et tronquera les opérations mathématiques.

L’expression va d’abord calculer 5/100, ce qui est 0.

 winningBid.amount * (5/100) = winningBid.amount * 0 = 0 

La solution est de forcer l’ordre des opérations à se multiplier d’abord

 require(_amount > winningBid.amount + (winningBid.amount * 5) / 100); 

Il est également suggéré d’utiliser require au lieu de assert pour valider l’entrée, assert est pour des circonstances totalement inattendues. Après byzantinum require provoquera un revert() renvoyant le gaz inutilisé à l’expéditeur, et assert consommera tout le gaz restant.

systempuntoout

Uhm, c’est ça le problème. Mais votre solution suggérée ne semble pas non plus correcte. Cela invaliderait un montant correct en raison de la troncature. Ayant par exemple 210 comme dernière offre, une offre licite de 220,9 serait rejetée.

systempuntoout

Lecture de la Division on integer literals used to truncate in earlier versions, but it will now convert into a rational number, ie 5 / 2 is not equal to 2, but to 2.5. de la documentation Division on integer literals used to truncate in earlier versions, but it will now convert into a rational number, ie 5 / 2 is not equal to 2, but to 2.5. Pensez-vous que j’utilise une ancienne version?

Ismael

@systempuntoout Si vous utilisez des entiers, vous ne pourrez pas envoyer 220,9. Jusqu’à présent, pour augmenter la précision, la solution courante consiste à utiliser une arithmétique à virgule fixe. Je pense que le soutien aux justifications est actuellement incomplet. Par exemple, 5/2 en interne est 2,5 mais vous ne pouvez pas l’affecter à une variable, il n’y a pas encore de type rational .

systempuntoout

Oui, nous multiplions déjà l’importation * 1000.

Ismael

@systempuntoout Si vous utilisez l’arithmétique à virgule fixe * 1000, la solution proposée devrait fonctionner. Si A = 210000 et B = 220900 , alors A + A * 5 / 100 == 211050 , et require(B > A + A * 5 / 100) A + A * 5 / 100 == 211050 require(B > A + A * 5 / 100) sera satisfait.

 

#de, #ou, code, concurrence?, condition, contrat, intelligent, mauvais?

 

yahoo

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *