****************************** Solidity v0.5.0 Changements de rupture******************************
Cette section met en évidence les principaux changements introduits dans la version 0.5.0 de Solidity, ainsi que les raisons de ces changements et la façon de mettre à jour le code concerné. Pour la liste complète, consultez le journal des modifications de la version.
Note
Les contrats compilés avec Solidity v0.5.0 peuvent toujours s'interfacer avec des contrats et même des bibliothèques compilés avec des versions plus anciennes sans avoir à les recompiler ou à les redéployer. Il suffit de modifier les interfaces pour inclure les emplacements des données et les spécificateurs de visibilité et de mutabilité. Voir la section Interopérabilité avec les contrats plus anciens <interoperability>
en dessous.
Changements uniquement sémantiques =====================
Cette section énumère les changements qui sont uniquement sémantiques, donc potentiellement cacher un comportement nouveau et différent dans le code existant.
* Le décalage signé vers la droite utilise maintenant le décalage arithmétique approprié, c'est-à-dire qu'il arrondit vers l'infini négatif au lieu d'arrondir vers zéro. l'infini négatif, au lieu d'arrondir vers zéro. Les décalages signés et non signés auront des opcodes dédiés dans Constantinople, et sont émulés par Solidity pour le moment. Solidity pour le moment.
- La déclaration
continue
dans une boucledo...while
saute maintenant au comportement commun dans de tels cas. Auparavant, il sautait vers le corps de la boucle. Ainsi, si la condition est fausse, la boucle se termine. - Les fonctions
.call()
,.delegatecall()
et.staticcall()
ne tamponnent plus lorsqu'on leur donne un seul paramètrebytes
. - Les fonctions Pure et View sont désormais appelées en utilisant l'opcode
STATICCALL
au lieu deCALL
si la version de l'EVM est Byzantium ou ultérieure. Cela interdit les changements d'état au niveau de l'EVM. - L'encodeur ABI pallie désormais correctement les tableaux d'octets et les chaînes de caractères des données d'appel (
msg.data
et paramètres de fonctions externes) lorsqu'ils sont utilisés dans des appels externes et dansabi.encode
. Pour un encodage non codé, utilisezabi.encodePacked
. - Le décodeur ABI revient en arrière au début des fonctions et dans
abi.decode()
si les données d'appel passées sont trop courtes ou pointent hors des limites. Notez que les bits d'ordre supérieur sales sont toujours simplement ignorés. - Transférer tout le gaz disponible avec des appels de fonctions externes à partir de Tangerine Whistle.
Changements sémantiques et syntaxiques ==============================
Cette section met en évidence les changements qui affectent la syntaxe et la sémantique.
- Les fonctions
.call()
,.delegatecall()
,staticcall()
,keccak256()
,sha256()
etripemd160()
n'acceptent plus qu'un seul argumentbytes
. unique,bytes
. De plus, l'argument n'est pas paddé. Ceci a été changé pour rendre plus explicite et clair la façon dont les arguments sont concaténés. Changez chaque.call()
(et famille) en un.call("")
et chaque.call(signature, a, b, c)
en utilisant.call(abi.encodeWithSignature(signature, a, b, c))
(le dernier ne fonctionne que pour les types dernière ne fonctionne que pour les types de valeurs). Changez chaquekeccak256(a, b, c)
enkeccak256(abi.encodePacked(a, b, c))
. Même s'il ne s'agit pas d'une il est suggéré que les développeurs changentx.call(bytes4(keccak256("f(uint256)")), a, b)
enx.call(abi.encodeWithSignature("f(uint256)", a, b))
. - Les fonctions
.call()
,.delegatecall()
et.staticcall()
retournent maintenant(bool, bytes memory)
pour donner accès aux données de retour. Modifierbool success = otherContract.call("f")
en(bool success, bytes memory données) = otherContract.call("f")
. - Solidity met désormais en œuvre les règles de délimitation du style C99 pour les locales de fonctions, c'est-à-dire que les variables ne peuvent être utilisées que déclarées et seulement dans le même périmètre ou dans des périmètres imbriqués. Les variables déclarées dans le bloc d'initialisation d'une boucle `for'' sont valides en tout point de la boucle. boucle.
Cette section liste les modifications pour lesquelles le code doit être plus explicite. Pour la plupart des sujets, le compilateur fournira des suggestions.
- La visibilité explicite des fonctions est maintenant obligatoire. Ajouter
public
à chaque fonction et constructeur fonction et constructeur, etexternal
à chaque fonction de fallback ou d'interface d'interface qui ne spécifie pas déjà sa visibilité. - La localisation explicite des données pour toutes les variables de type struct, array ou mapping est maintenant obligatoire. Ceci s'applique également aux paramètres des fonctions et aux de retour. Par exemple, changez
uint[] x = m_x
enuint[] storage x = m_x
, etfonction f(uint[][] x)
enfonction f(uint[][] mémoire x)
où "memory" est l'emplacement des données et peut être remplacé par "storage" ou "calldata".calldata
en conséquence. Notez que les fonctionsexternes
requièrent des paramètres dont l'emplacement des données estcalldata
. - Les types de contrats n'incluent plus les membres
addresses
afin de afin de séparer les espaces de noms. Par conséquent, il est maintenant nécessaire de convertir explicitement les valeurs du type de contrat en adresses avant d'utiliser une membreaddress
. Exemple : sic
est un contrat, changezc.transfert(...)
enadresse(c).transfert(...)
, etc.balance
enaddress(c).balance
. - Les conversions explicites entre des types de contrats non liés sont désormais interdites. Vous pouvez seulement convertir un type de contrat en l'un de ses types de base ou ancêtres. Si vous êtes sûr que un contrat est compatible avec le type de contrat vers lequel vous voulez le convertir, bien qu'il n'en hérite pas. bien qu'il n'en hérite pas, vous pouvez contourner ce problème en convertissant d'abord en
adresse
. Exemple : siA
etB
sont des types de contrat,B
n'hérite pas deA
etb
est un contrat de typeB
, vous pouvez toujours convertirb
en typeA
en utilisantA(adresse(b))
. Notez que vous devez toujours faire attention aux fonctions de repli payantes correspondantes, comme expliqué ci-dessous. - Le type "adresse" a été divisé en "adresse" et "adresse payable", où seule "l'adresse payable" fournit la fonction "transfert". Un site Une "adresse payable" peut être directement convertie en une "adresse", mais l'inverse n'est pas autorisé. l'inverse n'est pas autorisé. La conversion de
adresse
enadresse payable" est possible par conversion via
uint160. Si
cest un contrat,
address(c)résulte en
address payableseulement si
cpossède une fonction de repli payable. Si vous utilisez le modèle :ref:`withdraw pattern<withdrawal_pattern>`, vous n'avez probablement pas à modifier votre code car
transferest uniquement utilisé sur
msg.senderau lieu des adresses stockées et
msg.senderest une
adresse. est une
adresse payable``. - Les conversions entre
bytesX
etuintY
de taille différente sont maintenant sont désormais interdites en raison du remplissage debytesX
à droite et du remplissage deuintY
à gauche. gauche, ce qui peut entraîner des résultats de conversion inattendus. La taille doit maintenant être ajustée dans le type avant la conversion. Par exemple, vous pouvez convertir unbytes4
(4 octets) en unuint64
(8 octets) en convertissant d'abord lebytes4
en unuint64`'. en convertissant d'abord la variable
bytes4en
bytes8, puis en
uint64`'. Vous obtenez le inverse en convertissant enuint32
. Avant la version 0.5.0, toute conversion entrebytesX
etuintY
passait paruint8X
. Pour Par exemple,uint8(bytes3(0x291807))
sera converti enuint8(uint24(bytes3(0x291807))
(le résultat est (le résultat est0x07
). - L'utilisation de
msg.value
dans des fonctions non payantes (ou son introduction par le biais d'un modificateur) est interdit par mesure de sécurité. Transformez la fonction en payante " ou créez une nouvelle fonction interne pour la logique du programme qui utilisemsg.value
. - Pour des raisons de clarté, l'interface de la ligne de commande exige maintenant
-
si l' l'entrée standard est utilisée comme source.
Cette section liste les changements qui déprécient des fonctionnalités ou des syntaxes antérieures. Notez que plusieurs de ces changements étaient déjà activés dans le mode expérimental v0.5.0
.
Interfaces en ligne de commande et JSON --------------------------------
- L'option de ligne de commande
--formal
(utilisée pour générer la sortie de Why3 pour une pour une vérification formelle plus poussée) était dépréciée et est maintenant supprimée. Un nouveau module de vérification formelle, le SMTChecker, est activé viapragma experimental SMTChecker;
. - L'option de ligne de commande
--julia
a été renommée en--yul
en raison du changement de nom du langage intermédiaire ``. en raison du changement de nom du langage intermédiaire "Julia" en "Yul". - Les options de ligne de commande
--clone-bin
et--combined-json clone-bin
ont été supprimées. ont été supprimées. - Les remappages avec un préfixe vide ne sont pas autorisés.
- Les champs AST JSON
constant
etpayable`' ont été supprimés. L'adresse informations sont maintenant présentes dans le champ
stateMutability`'. - Le champ JSON AST
isConstructor
du noeudFunctionDefinition
a été remplacé par un champ appeléFonctions''. a été remplacé par un champ appelé
kindqui peut avoir la valeur valeur
"constructor",
"fallback"ou
"function"``. - Dans les fichiers hexadécimaux binaires non liés, les adresses des bibliothèques sont maintenant les 36 premiers caractères hexadécimaux de la clé. sont désormais les 36 premiers caractères hexadécimaux du hachage keccak256 du nom de bibliothèque nom de bibliothèque entièrement qualifié, entouré de "$...$". Auparavant, seul le nom complet de la bibliothèque était utilisé. Cela réduit les risques de collisions, en particulier lorsque de longs chemins sont utilisés. Les fichiers binaires contiennent maintenant aussi une liste de correspondances entre ces caractères de remplacement vers les noms pleinement qualifiés.
Constructeurs ------------
- Les constructeurs doivent désormais être définis à l'aide du mot clé "constructeur".
- L'appel de constructeurs de base sans parenthèses est désormais interdit.
- La spécification des arguments des constructeurs de base plusieurs fois dans la même même hiérarchie d'héritage est maintenant interdit.
- L'appel d'un constructeur avec des arguments mais avec un nombre d'arguments incorrect est maintenant désapprouvé. Si vous souhaitez seulement spécifier une relation d'héritage sans sans donner d'arguments, ne fournissez pas de parenthèses du tout.
- La fonction
callcode
est maintenant désapprouvée (en faveur dedelegatecall
). Il est Il est toujours possible de l'utiliser via l'assemblage en ligne. - La fonction
suicide
n'est plus autorisée (au profit deselfdestruct
). sha3
n'est plus autorisé (au profit dekeccak256
).throw
est maintenant désapprouvé (en faveur derevert
,require
et deassert
).
- Les conversions explicites et implicites des littéraux décimaux en types `bytesXX'' sont maintenant désactivées. est désormais interdit.
- Les conversions explicites et implicites de littéraux hexadécimaux en types `bytesXX'' de taille différente sont désormais interdites. de taille différente sont désormais interdites.
- L'unité de dénomination "années" n'est plus autorisée en raison de complications et de confusions concernant les années bissextiles. complications et de confusions concernant les années bissextiles.
- Les points de fin de ligne qui ne sont pas suivis d'un nombre ne sont plus autorisés.
- La combinaison de nombres hexadécimaux avec des unités (par exemple, "0x1e wei") n'est plus autorisée. interdites.
- Le préfixe
0X
pour les nombres hexadécimaux n'est plus autorisé, seul0x
est possible.
- La déclaration de structures vides n'est plus autorisée pour des raisons de clarté.
- Le mot clé "var" n'est plus autorisé pour favoriser l'explicitation.
- Les affectations entre les tuples avec un nombre différent de composants sont maintenant interdites. désapprouvé.
- Les valeurs des constantes qui ne sont pas des constantes de compilation ne sont pas autorisées.
- Les déclarations multi-variables avec un nombre de valeurs non concordant sont maintenant désapprouvées.
- Les variables de stockage non initialisées ne sont plus autorisées.
- Les composants de tuple vides ne sont plus admis.
- La détection des dépendances cycliques dans les variables et les structures est limitée en récursion à 256. récursion à 256.
- Les tableaux de taille fixe avec une longueur de zéro ne sont plus autorisés.
Syntaxe ------
- L'utilisation de
constant
comme modificateur de mutabilité de l'état de la fonction est désormais interdite. - Les expressions booléennes ne peuvent pas utiliser d'opérations arithmétiques.
- L'opérateur unaire "+" n'est plus autorisé.
- Les littéraux ne peuvent plus être utilisés avec
abi.encodePacked
sans conversion conversion préalable vers un type explicite. - Les déclarations de retour vides pour les fonctions avec une ou plusieurs valeurs de retour ne sont plus sont désormais interdites.
- La syntaxe "loose assembly", c'est-à-dire les étiquettes de saut, est maintenant totalement interdite, les sauts et les instructions non fonctionnelles ne peuvent plus être utilisés. Utilisez les nouvelles fonctions
while
,switch
etif
à la place. - Les fonctions sans implémentation ne peuvent plus utiliser de modificateurs.
- Les types de fonctions avec des valeurs de retour nommées ne sont plus autorisés.
- Les déclarations de variables d'une seule déclaration à l'intérieur de corps if/while/for qui ne sont pas qui ne sont pas des blocs ne sont plus autorisées.
- Nouveaux mots-clés :
calldata
etconstructor
. - Nouveaux mots-clés réservés :
alias
,apply
,auto
,copyof
,définir'',
immutable'',implements'',
macro'',mutable'',
override,
partiel,
promise,
reference,
sealed,
sizeof'',supports'',
typedef'' et ``unchecked''.
Interopérabilité avec les anciens contrats =====================================
Il est toujours possible de s'interfacer avec des contrats écrits pour des versions de Solidity antérieures à la v0.5.0 (ou l'inverse) en définissant des interfaces pour eux. Considérons que vous avez le contrat suivant, antérieur à la version 0.5.0, déjà déployé :
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.4.25;
// This will report a warning until version 0.4.25 of the compiler
// This will not compile after 0.5.0
contract OldContract {
function someOldFunction(uint8 a) {
//...
}
function anotherOldFunction() constant returns (bool) {
//...
}
// ...
}
Il ne compilera plus avec Solidity v0.5.0. Cependant, vous pouvez lui définir une interface compatible :
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.5.0 <0.9.0;
interface OldContract {
function someOldFunction(uint8 a) external;
function anotherOldFunction() external returns (bool);
}
Notez que nous n'avons pas déclaré "anotherOldFunction" comme étant "view", bien qu'elle soit déclarée "constante" dans le contrat original. contrat original. Cela est dû au fait qu'à partir de la version 0.5.0 de Solidity, l'option staticcall
est utilisée pour appeler les fonctions view
. Avant la v0.5.0, le mot-clé constant
n'était pas appliqué, donc appeler une fonction déclarée constante
avec staticcall
peut encore se retourner, puisque la fonction constant
peut encore tenter de modifier le stockage. Par conséquent, lorsque vous définissez une pour des contrats plus anciens, vous ne devriez utiliser view
à la place de constant
que si vous êtes absolument sûr que la fonction fonctionnera avec staticcall
.
Avec l'interface définie ci-dessus, vous pouvez maintenant facilement utiliser le contrat pré-0.5.0 déjà déployé :
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.5.0 <0.9.0;
interface OldContract {
function someOldFunction(uint8 a) external;
function anotherOldFunction() external returns (bool);
}
contract NewContract {
function doSomething(OldContract a) public returns (bool) {
a.someOldFunction(0x42);
return a.anotherOldFunction();
}
}
De même, les bibliothèques pré-0.5.0 peuvent être utilisées en définissant les fonctions de la bibliothèque sans implémentation et en en fournissant l'adresse de la bibliothèque pré-0.5.0 lors de l'édition de liens (voir `commandline-compiler
pour savoir comment utiliser le pour savoir comment utiliser le compilateur en ligne de commande pour l'édition de liens) :
// This will not compile after 0.6.0
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.5.0;
library OldLibrary {
function someFunction(uint8 a) public returns(bool);
}
contract NewContract {
function f(uint8 a) public returns (bool) {
return OldLibrary.someFunction(a);
}
}
L'exemple suivant montre un contrat et sa version mise à jour pour Solidity v0.5.0 avec certaines des modifications énumérées dans cette section.
Ancienne version :
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.4.25;
// This will not compile after 0.5.0
contract OtherContract {
uint x;
function f(uint y) external {
x = y;
}
function() payable external {}
}
contract Old {
OtherContract other;
uint myNumber;
// Function mutability not provided, not an error.
function someInteger() internal returns (uint) { return 2; }
// Function visibility not provided, not an error.
// Function mutability not provided, not an error.
function f(uint x) returns (bytes) {
// Var is fine in this version.
var z = someInteger();
x += z;
// Throw is fine in this version.
if (x > 100)
throw;
bytes memory b = new bytes(x);
y = -3 >> 1;
// y == -1 (wrong, should be -2)
do {
x += 1;
if (x > 10) continue;
// 'Continue' causes an infinite loop.
} while (x < 11);
// Call returns only a Bool.
bool success = address(other).call("f");
if (!success)
revert();
else {
// Local variables could be declared after their use.
int y;
}
return b;
}
// No need for an explicit data location for 'arr'
function g(uint[] arr, bytes8 x, OtherContract otherContract) public {
otherContract.transfer(1 ether);
// Since uint32 (4 bytes) is smaller than bytes8 (8 bytes),
// the first 4 bytes of x will be lost. This might lead to
// unexpected behavior since bytesX are right padded.
uint32 y = uint32(x);
myNumber += y + msg.value;
}
}
Nouvelle version :
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.5.0;
// This will not compile after 0.6.0
contract OtherContract {
uint x;
function f(uint y) external {
x = y;
}
function() payable external {}
}
contract New {
OtherContract other;
uint myNumber;
// Function mutability must be specified.
function someInteger() internal pure returns (uint) { return 2; }
// Function visibility must be specified.
// Function mutability must be specified.
function f(uint x) public returns (bytes memory) {
// The type must now be explicitly given.
uint z = someInteger();
x += z;
// Throw is now disallowed.
require(x <= 100);
int y = -3 >> 1;
require(y == -2);
do {
x += 1;
if (x > 10) continue;
// 'Continue' jumps to the condition below.
} while (x < 11);
// Call returns (bool, bytes).
// Data location must be specified.
(bool success, bytes memory data) = address(other).call("f");
if (!success)
revert();
return data;
}
using address_make_payable for address;
// Data location for 'arr' must be specified
function g(uint[] memory /* arr */, bytes8 x, OtherContract otherContract, address unknownContract) public payable {
// 'otherContract.transfer' is not provided.
// Since the code of 'OtherContract' is known and has the fallback
// function, address(otherContract) has type 'address payable'.
address(otherContract).transfer(1 ether);
// 'unknownContract.transfer' is not provided.
// 'address(unknownContract).transfer' is not provided
// since 'address(unknownContract)' is not 'address payable'.
// If the function takes an 'address' which you want to send
// funds to, you can convert it to 'address payable' via 'uint160'.
// Note: This is not recommended and the explicit type
// 'address payable' should be used whenever possible.
// To increase clarity, we suggest the use of a library for
// the conversion (provided after the contract in this example).
address payable addr = unknownContract.make_payable();
require(addr.send(1 ether));
// Since uint32 (4 bytes) is smaller than bytes8 (8 bytes),
// the conversion is not allowed.
// We need to convert to a common size first:
bytes4 x4 = bytes4(x); // Padding happens on the right
uint32 y = uint32(x4); // Conversion is consistent
// 'msg.value' cannot be used in a 'non-payable' function.
// We need to make the function payable
myNumber += y + msg.value;
}
}
// We can define a library for explicitly converting ``address``
// to ``address payable`` as a workaround.
library address_make_payable {
function make_payable(address x) internal pure returns (address payable) {
return address(uint160(x));
}
}