Ethereum et smart contracts · 6 min · démo interactive
Ton premier smart contract, sans wallet
Un compteur, cinq fonctions, 136 octets de bytecode. Tu l'appelles, il s'exécute instruction par instruction sous tes yeux.
L’idée en une phrase
Un smart contract est un programme enregistré sur une blockchain, que personne ne peut modifier une fois publié et que tous les nœuds exécutent de la même façon.
Le mot « contrat » trompe : ce n'est pas un document juridique. C'est du code avec une mémoire persistante et, sur Ethereum, un solde propre. Il ne fait rien tout seul : il attend qu'une transaction l'appelle, exécute ses instructions, puis s'arrête.
La démo
| pc | opcode | gas | pile après (5 du sommet) |
|---|---|---|---|
| La trace apparaît ici. | |||
Données d'appel envoyées
Bytecode du contrat
Sans JavaScript, voici le cas de base : appeler increment() sur un compteur à 0 écrit 1 dans l'emplacement 0. L'appel coûte un peu plus de 22 100 gas d'exécution : 2 100 pour le premier accès à l'emplacement, 20 000 pour le faire passer de zéro à non-zéro, et quelques dizaines pour le reste. Le deuxième appel coûte 17 100 gas de moins, car l'emplacement n'est plus à zéro.
Ce que tu vois tourner est une mini-EVM pédagogique : quelques kilo-octets de JavaScript qui exécutent du vrai bytecode pour un sous-ensemble d'instructions. Ce n'est pas un nœud Ethereum. Il n'y a ni réseau, ni bloc, ni signature, ni déploiement par code d'initialisation, et le gas est indicatif : sans remboursement ni cas particuliers des écritures répétées dans une même transaction.
Pourquoi ça compte
Alice veut prêter des jetons à un inconnu sans passer par une banque. Qui garde le dépôt ? Qui vérifie le remboursement ? Sur Ethereum, un contrat de prêt tient ce rôle : son code dit qui peut retirer quoi, et aucun employé ne peut faire d'exception. Tu retrouves ce mécanisme derrière les tokens ERC-20, les pools d'échange et les protocoles de prêt.
Le revers est brutal. Le code s'applique même quand il contient une erreur, et une erreur publiée reste publiée. L'attaque par réentrance de 2016 a exploité exactement cela. Lire un contrat au niveau de la machine, c'est comprendre ce qui est vraiment garanti, et ce qui ne l'est pas.
Le code
Voici le contrat complet, en assembleur EVM traduit en bytecode par ton navigateur. Remplace 1 ADD par 2 ADD dans la ligne inc:, ou fais appeler reset() par Alice plutôt que Bob, puis relance.
Clique sur Lancer pour exécuter ce code dans ton navigateur.
Ce qui se passe vraiment
Ouvre la trace d'increment() et suis-la avec « Pas suivant ». Une EVM est une machine à pile : les instructions prennent leurs opérandes au sommet et y déposent leur résultat. Pas de registres, juste des mots de 256 bits.
- CALLVALUE puis JUMPI. Le contrat vérifie qu'on ne lui a pas envoyé d'ETH. Il n'a aucune fonction prévue pour en recevoir.
- CALLDATALOAD, SHR. Il lit les 4 premiers octets des données d'appel. Ce sélecteur est le début du Keccak-256 de la signature de la fonction :
increment()donne0xd09de08a. Le nom n'existe pas dans le bytecode, seul ce numéro y figure. - EQ, JUMPI. C'est un aiguillage : il compare le sélecteur à ceux qu'il connaît, puis saute vers le bon
JUMPDEST. Le sélecteur reste au fond de la pile, sans gêner la suite. Aucun ne correspond ? Il termine parREVERT. - SLOAD, ADD, SSTORE. Lecture de l'emplacement 0, ajout de 1, écriture. Ces deux accès au stockage pèsent presque tout le gas de l'appel. La ligne d'
SSTOREdomine la colonne gas. - STOP. Fin normale. L'état écrit est conservé.
Essaie maintenant reset() en tant que Bob. CALLER pousse son adresse, EQ la compare au propriétaire stocké dans l'emplacement 1, et l'exécution finit sur REVERT. La valeur de count ne bouge pas. Choisis ensuite decrement() à zéro : même fin. Une instruction REVERT annule toutes les écritures de l'appel, c'est la garantie du tout ou rien.
Personne n'écrit ce code à la main, sauf pour apprendre. Voici l'équivalent simplifié en Solidity :
contract Compteur {
uint256 public count; // emplacement 0
address public owner; // emplacement 1
constructor() { owner = msg.sender; }
function increment() external { count += 1; }
function incrementBy(uint256 n) external { count += n; }
function decrement() external { require(count > 0); count -= 1; }
function reset() external { require(msg.sender == owner); count = 0; }
}
Ce Solidity n'est pas la source exacte du bytecode de la démo, assemblé à la main. Compilé avec solc, il donne un programme différent et un peu plus coûteux, qui renvoie par exemple un code d'erreur là où notre version s'arrête sans message. Nous avons rejoué la même suite d'appels sur les deux, dans une EVM de référence : mêmes résultats, mêmes valeurs stockées. La logique est la même, pas les octets.
Dans la vraie vie
Sur le réseau, un appel qui écrit passe par une transaction signée depuis un compte, diffusée, puis incluse dans un bloc. Ces étapes ajoutent 21 000 gas de base et un délai, que la démo ignore. Les nœuds rejouent alors le bytecode et doivent tous obtenir le même état. C'est ce qui remplace la confiance dans un serveur. Ce modèle à comptes diffère beaucoup de celui de Bitcoin, comme le montre la page Ethereum vs Bitcoin.
Une lecture comme count() ne crée pas de transaction : un nœud exécute le code localement et répond gratuitement. Le coût n'existe que pour ce que le réseau entier doit rejouer et conserver. Chaque unité de gas se paie au prix du moment, comme l'explique notre page sur le gas.
« Immuable » s'applique au bytecode, pas forcément au service. Beaucoup de contrats passent par un proxy qui redirige vers une logique remplaçable par un administrateur. La question utile devant un contrat est donc : qui peut changer quoi, et avec quel délai ?
Ce qui peut mal tourner
- Croire qu'un contrat est sûr parce qu'il est sur la blockchain. L'exécution est fiable, le code peut être faux. La chaîne applique fidèlement un programme bogué.
- Oublier le contrôle d'accès. Retire la ligne
CALLER EQ ISZERO @fail JUMPIdereset: n'importe qui remet le compteur à zéro. Des fonds ont été perdus par des fonctions d'administration laissées ouvertes. - Stocker un secret dans le contrat. Tout l'état est public, même les variables marquées
privateen Solidity. Le mot-clé ne limite que l'accès depuis d'autres contrats. - Appeler un contrat dont on ignore l'administrateur. Un proxy peut changer le comportement après ton approbation. Vérifie les droits, pas seulement le code affiché.
- Supposer un code vérifié. Le bytecode est public, la source ne l'est pas toujours. Sans vérification, une interface peut prétendre faire autre chose que ce qui s'exécute. Regarde ce que tu signes : voir repérer le phishing.
Teste-toi
Contenu éducatif. Pas un conseil en investissement. Les crypto-actifs comportent un risque de perte en capital. Pour la démarche éditoriale, voir à propos. Mise à jour : 31 octobre 2026.