[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"article-deep-evm-10-gestion-pile-huff-dup-swap":3},{"article":4,"author":55},{"id":5,"category_id":6,"title":7,"slug":8,"excerpt":9,"content_md":10,"content_html":11,"locale":12,"author_id":13,"published":14,"published_at":15,"meta_title":16,"meta_description":17,"focus_keyword":18,"og_image":19,"canonical_url":19,"robots_meta":20,"created_at":15,"updated_at":15,"tags":21,"category_name":35,"related_articles":36},"d6000000-0000-0000-0000-000000000110","a0000000-0000-0000-0000-000000000062","Deep EVM #10 : Gestion de pile Huff — takes(), returns() et l'art du dup\u002Fswap","deep-evm-10-gestion-pile-huff-dup-swap","Maîtrisez la machine à pile de l'EVM : visualisez l'état de la pile, utilisez efficacement dup1-16 et swap1-16, et construisez des patterns pour conserver, faire tourner et nettoyer les valeurs.","## Le modèle mental de la machine à pile\n\nL'EVM est une machine à pile. Il n'y a pas de registres, pas de variables nommées — juste une pile dernier-entré-premier-sorti de mots de 32 octets, profonde de 1024 emplacements. Chaque opcode empile, dépile ou réarrange des éléments sur cette pile. Si vous ne pouvez pas tenir l'état actuel de la pile dans votre tête, vous produirez du bytecode bogué. Cet article porte sur la construction de ce modèle mental.\n\n### Convention de notation\n\nTout au long de cet article (et dans les commentaires Huff), nous représentons l'état de la pile avec des crochets où l'élément le plus à gauche est le sommet :\n\n```\n\u002F\u002F [sommet, deuxième, troisième, ..., fond]\n0x01  \u002F\u002F [1]\n0x02  \u002F\u002F [2, 1]\nadd   \u002F\u002F [3]\n```\n\nChaque macro Huff devrait avoir un commentaire de pile après chaque opcode. Ce n'est pas optionnel — c'est la seule façon d'auditer la correction.\n\n## DUP : dupliquer les éléments de la pile\n\nL'EVM fournit `DUP1` à `DUP16`. `DUPn` copie le n-ième élément depuis le sommet et l'empile. La pile grandit de 1.\n\n```huff\n\u002F\u002F Pile : [a, b, c, d]\ndup1   \u002F\u002F [a, a, b, c, d]       — copier le sommet\ndup3   \u002F\u002F [c, a, a, b, c, d]    — copier le 3e depuis le sommet\n```\n\nCoût en gas : 3 gas pour tout DUPn. C'est l'une des opérations les moins chères de l'EVM.\n\n### Quand utiliser DUP\n\nDUP est votre outil pour les **lectures non destructives**. Beaucoup d'opcodes consomment leurs arguments (ADD dépile deux, empile un), donc si vous avez besoin d'une valeur plus tard, dupliquez-la avant de la fournir à un opcode consommateur.\n\n```huff\n#define macro SAFE_SUB() = takes(2) returns(1) {\n    \u002F\u002F takes: [a, b] — calculer a - b, revert si b > a\n    dup2 dup2       \u002F\u002F [a, b, a, b]\n    lt              \u002F\u002F [a \u003C b?, a, b]\n    revert_underflow jumpi  \u002F\u002F [a, b]\n    sub             \u002F\u002F [a - b]\n    done jump\n    revert_underflow:\n        0x00 0x00 revert\n    done:\n}\n```\n\nNotez le `dup2 dup2` — nous dupliquons `a` et `b` parce que `lt` les consommera, mais nous avons encore besoin des originaux pour le `sub`.\n\n## SWAP : réarranger la pile\n\nL'EVM fournit `SWAP1` à `SWAP16`. `SWAPn` échange l'élément du sommet avec le (n+1)-ième élément. La taille de la pile reste la même.\n\n```huff\n\u002F\u002F Pile : [a, b, c, d]\nswap1  \u002F\u002F [b, a, c, d]          — échanger le sommet avec le 2e\nswap3  \u002F\u002F [d, a, c, b]          — échanger le sommet avec le 4e\n```\n\nCoût en gas : 3 gas pour tout SWAPn.\n\n## La limitation de profondeur 16\n\nDUP et SWAP n'atteignent que 16 niveaux de profondeur. Si une valeur est à la position 17 ou plus, vous ne pouvez pas y accéder avec un seul opcode. C'est une contrainte dure de l'EVM.\n\n**Stratégies pour les piles profondes :**\n\n1. **Restructurez votre logique** pour garder les valeurs nécessaires près du sommet.\n2. **Utilisez la mémoire comme espace temporaire.** Stockez une valeur avec `MSTORE`, récupérez-la plus tard avec `MLOAD`. Coûte 3+3=6 gas vs 3 pour DUP, mais brise la barrière de profondeur.\n3. **Divisez la macro en macros plus petites** qui opèrent chacune sur moins d'éléments de pile.\n\n```huff\n#define macro STASH_TO_MEMORY() = takes(1) returns(0) {\n    \u002F\u002F takes: [value]\n    0x80 mstore     \u002F\u002F []  — ranger à 0x80 (espace scratch)\n}\n\n#define macro RECALL_FROM_MEMORY() = takes(0) returns(1) {\n    0x80 mload      \u002F\u002F [value]\n}\n```\n\nDans les contrats MEV, nous réservons souvent `0x80..0xc0` comme zone scratch pour les valeurs qui autrement pousseraient la pile au-delà de 16.\n\n## Patterns courants\n\n### Pattern 1 : conserver une valeur à travers une opération consommatrice\n\n```huff\n\u002F\u002F Voulons : calculer le hash de x, mais garder x\n\u002F\u002F Pile : [x]\ndup1        \u002F\u002F [x, x]\n0x00 mstore \u002F\u002F [x]  — memory[0] = x\n0x20 0x00   \u002F\u002F [0, 32, x]\nkeccak256   \u002F\u002F [hash, x]\n```\n\n### Pattern 2 : faire tourner trois éléments\n\nVous avez `[a, b, c]` et voulez `[c, a, b]` :\n\n```huff\nswap2       \u002F\u002F [c, b, a]\nswap1       \u002F\u002F [c, a, b]\n```\n\n2 opcodes, 6 gas. Il n'y a pas de rotation en un seul opcode dans l'EVM.\n\n### Pattern 3 : nettoyer les éléments indésirables\n\n```huff\n\u002F\u002F Pile : [result, garbage1, garbage2]\nswap1 pop   \u002F\u002F [result, garbage2]\nswap1 pop   \u002F\u002F [result]\n```\n\n### Pattern 4 : dupliquer une paire\n\n```huff\n\u002F\u002F Pile : [a, b]\ndup2        \u002F\u002F [b, a, b]\ndup2        \u002F\u002F [a, b, a, b]\n```\n\n## Discipline de visualisation de la pile\n\nQuand vous écrivez du Huff, adoptez cette discipline :\n\n1. **Commentez chaque ligne** avec l'état de la pile après exécution.\n2. **Vérifiez takes\u002Freturns** — comptez les éléments à l'entrée et à la sortie.\n3. **Tracez chaque branche** — à chaque JUMPI, les deux chemins (pris et non pris) doivent laisser la pile dans un état valide.\n4. **Surveillez la dérive de pile** — si le corps d'une boucle n'équilibre pas parfaitement les empilements et dépilements, la pile croîtra ou rétrécira à chaque itération.\n\n## Débogage des erreurs de pile\n\nLes bugs les plus courants en Huff :\n\n1. **Sous-débordement de pile** — Dépiler depuis une pile vide. L'EVM reverte à l'exécution.\n2. **Déséquilibre de pile au JUMP** — Un JUMPDEST atteint depuis deux chemins différents attend des états de pile différents.\n3. **Erreur de un dans DUP\u002FSWAP** — `dup3` vs `dup4` quand vous avez ajouté un push supplémentaire plus tôt.\n\n`huffc` a un flag `--stack-check` qui effectue une analyse de pile basique :\n\n```bash\nhuffc src\u002FContract.huff -r --stack-check\n```\n\n## Résumé\n\nLa gestion de pile est la compétence fondamentale du développement Huff. DUP pour les lectures non destructives, SWAP pour le réordonnancement, et la mémoire pour les valeurs au-delà de la profondeur 16. Commentez chaque ligne avec l'état de la pile. Vérifiez chaque branche. Dans le prochain article, nous utiliserons ces compétences pour construire un dispatcher de fonctions O(1) avec des tables de saut compactes.","\u003Ch2 id=\"le-mod-le-mental-de-la-machine-pile\">Le modèle mental de la machine à pile\u003C\u002Fh2>\n\u003Cp>L’EVM est une machine à pile. Il n’y a pas de registres, pas de variables nommées — juste une pile dernier-entré-premier-sorti de mots de 32 octets, profonde de 1024 emplacements. Chaque opcode empile, dépile ou réarrange des éléments sur cette pile. Si vous ne pouvez pas tenir l’état actuel de la pile dans votre tête, vous produirez du bytecode bogué. Cet article porte sur la construction de ce modèle mental.\u003C\u002Fp>\n\u003Ch3>Convention de notation\u003C\u002Fh3>\n\u003Cp>Tout au long de cet article (et dans les commentaires Huff), nous représentons l’état de la pile avec des crochets où l’élément le plus à gauche est le sommet :\u003C\u002Fp>\n\u003Cpre>\u003Ccode>\u002F\u002F [sommet, deuxième, troisième, ..., fond]\n0x01  \u002F\u002F [1]\n0x02  \u002F\u002F [2, 1]\nadd   \u002F\u002F [3]\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Chaque macro Huff devrait avoir un commentaire de pile après chaque opcode. Ce n’est pas optionnel — c’est la seule façon d’auditer la correction.\u003C\u002Fp>\n\u003Ch2 id=\"dup-dupliquer-les-l-ments-de-la-pile\">DUP : dupliquer les éléments de la pile\u003C\u002Fh2>\n\u003Cp>L’EVM fournit \u003Ccode>DUP1\u003C\u002Fcode> à \u003Ccode>DUP16\u003C\u002Fcode>. \u003Ccode>DUPn\u003C\u002Fcode> copie le n-ième élément depuis le sommet et l’empile. La pile grandit de 1.\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-huff\">\u002F\u002F Pile : [a, b, c, d]\ndup1   \u002F\u002F [a, a, b, c, d]       — copier le sommet\ndup3   \u002F\u002F [c, a, a, b, c, d]    — copier le 3e depuis le sommet\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Coût en gas : 3 gas pour tout DUPn. C’est l’une des opérations les moins chères de l’EVM.\u003C\u002Fp>\n\u003Ch3>Quand utiliser DUP\u003C\u002Fh3>\n\u003Cp>DUP est votre outil pour les \u003Cstrong>lectures non destructives\u003C\u002Fstrong>. Beaucoup d’opcodes consomment leurs arguments (ADD dépile deux, empile un), donc si vous avez besoin d’une valeur plus tard, dupliquez-la avant de la fournir à un opcode consommateur.\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-huff\">#define macro SAFE_SUB() = takes(2) returns(1) {\n    \u002F\u002F takes: [a, b] — calculer a - b, revert si b &gt; a\n    dup2 dup2       \u002F\u002F [a, b, a, b]\n    lt              \u002F\u002F [a &lt; b?, a, b]\n    revert_underflow jumpi  \u002F\u002F [a, b]\n    sub             \u002F\u002F [a - b]\n    done jump\n    revert_underflow:\n        0x00 0x00 revert\n    done:\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Notez le \u003Ccode>dup2 dup2\u003C\u002Fcode> — nous dupliquons \u003Ccode>a\u003C\u002Fcode> et \u003Ccode>b\u003C\u002Fcode> parce que \u003Ccode>lt\u003C\u002Fcode> les consommera, mais nous avons encore besoin des originaux pour le \u003Ccode>sub\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Ch2 id=\"swap-r-arranger-la-pile\">SWAP : réarranger la pile\u003C\u002Fh2>\n\u003Cp>L’EVM fournit \u003Ccode>SWAP1\u003C\u002Fcode> à \u003Ccode>SWAP16\u003C\u002Fcode>. \u003Ccode>SWAPn\u003C\u002Fcode> échange l’élément du sommet avec le (n+1)-ième élément. La taille de la pile reste la même.\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-huff\">\u002F\u002F Pile : [a, b, c, d]\nswap1  \u002F\u002F [b, a, c, d]          — échanger le sommet avec le 2e\nswap3  \u002F\u002F [d, a, c, b]          — échanger le sommet avec le 4e\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Coût en gas : 3 gas pour tout SWAPn.\u003C\u002Fp>\n\u003Ch2 id=\"la-limitation-de-profondeur-16\">La limitation de profondeur 16\u003C\u002Fh2>\n\u003Cp>DUP et SWAP n’atteignent que 16 niveaux de profondeur. Si une valeur est à la position 17 ou plus, vous ne pouvez pas y accéder avec un seul opcode. C’est une contrainte dure de l’EVM.\u003C\u002Fp>\n\u003Cp>\u003Cstrong>Stratégies pour les piles profondes :\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Col>\n\u003Cli>\u003Cstrong>Restructurez votre logique\u003C\u002Fstrong> pour garder les valeurs nécessaires près du sommet.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Utilisez la mémoire comme espace temporaire.\u003C\u002Fstrong> Stockez une valeur avec \u003Ccode>MSTORE\u003C\u002Fcode>, récupérez-la plus tard avec \u003Ccode>MLOAD\u003C\u002Fcode>. Coûte 3+3=6 gas vs 3 pour DUP, mais brise la barrière de profondeur.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Divisez la macro en macros plus petites\u003C\u002Fstrong> qui opèrent chacune sur moins d’éléments de pile.\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cpre>\u003Ccode class=\"language-huff\">#define macro STASH_TO_MEMORY() = takes(1) returns(0) {\n    \u002F\u002F takes: [value]\n    0x80 mstore     \u002F\u002F []  — ranger à 0x80 (espace scratch)\n}\n\n#define macro RECALL_FROM_MEMORY() = takes(0) returns(1) {\n    0x80 mload      \u002F\u002F [value]\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Dans les contrats MEV, nous réservons souvent \u003Ccode>0x80..0xc0\u003C\u002Fcode> comme zone scratch pour les valeurs qui autrement pousseraient la pile au-delà de 16.\u003C\u002Fp>\n\u003Ch2 id=\"patterns-courants\">Patterns courants\u003C\u002Fh2>\n\u003Ch3>Pattern 1 : conserver une valeur à travers une opération consommatrice\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-huff\">\u002F\u002F Voulons : calculer le hash de x, mais garder x\n\u002F\u002F Pile : [x]\ndup1        \u002F\u002F [x, x]\n0x00 mstore \u002F\u002F [x]  — memory[0] = x\n0x20 0x00   \u002F\u002F [0, 32, x]\nkeccak256   \u002F\u002F [hash, x]\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>Pattern 2 : faire tourner trois éléments\u003C\u002Fh3>\n\u003Cp>Vous avez \u003Ccode>[a, b, c]\u003C\u002Fcode> et voulez \u003Ccode>[c, a, b]\u003C\u002Fcode> :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-huff\">swap2       \u002F\u002F [c, b, a]\nswap1       \u002F\u002F [c, a, b]\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>2 opcodes, 6 gas. Il n’y a pas de rotation en un seul opcode dans l’EVM.\u003C\u002Fp>\n\u003Ch3>Pattern 3 : nettoyer les éléments indésirables\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-huff\">\u002F\u002F Pile : [result, garbage1, garbage2]\nswap1 pop   \u002F\u002F [result, garbage2]\nswap1 pop   \u002F\u002F [result]\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>Pattern 4 : dupliquer une paire\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-huff\">\u002F\u002F Pile : [a, b]\ndup2        \u002F\u002F [b, a, b]\ndup2        \u002F\u002F [a, b, a, b]\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"discipline-de-visualisation-de-la-pile\">Discipline de visualisation de la pile\u003C\u002Fh2>\n\u003Cp>Quand vous écrivez du Huff, adoptez cette discipline :\u003C\u002Fp>\n\u003Col>\n\u003Cli>\u003Cstrong>Commentez chaque ligne\u003C\u002Fstrong> avec l’état de la pile après exécution.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Vérifiez takes\u002Freturns\u003C\u002Fstrong> — comptez les éléments à l’entrée et à la sortie.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Tracez chaque branche\u003C\u002Fstrong> — à chaque JUMPI, les deux chemins (pris et non pris) doivent laisser la pile dans un état valide.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Surveillez la dérive de pile\u003C\u002Fstrong> — si le corps d’une boucle n’équilibre pas parfaitement les empilements et dépilements, la pile croîtra ou rétrécira à chaque itération.\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Ch2 id=\"d-bogage-des-erreurs-de-pile\">Débogage des erreurs de pile\u003C\u002Fh2>\n\u003Cp>Les bugs les plus courants en Huff :\u003C\u002Fp>\n\u003Col>\n\u003Cli>\u003Cstrong>Sous-débordement de pile\u003C\u002Fstrong> — Dépiler depuis une pile vide. L’EVM reverte à l’exécution.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Déséquilibre de pile au JUMP\u003C\u002Fstrong> — Un JUMPDEST atteint depuis deux chemins différents attend des états de pile différents.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Erreur de un dans DUP\u002FSWAP\u003C\u002Fstrong> — \u003Ccode>dup3\u003C\u002Fcode> vs \u003Ccode>dup4\u003C\u002Fcode> quand vous avez ajouté un push supplémentaire plus tôt.\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp>\u003Ccode>huffc\u003C\u002Fcode> a un flag \u003Ccode>--stack-check\u003C\u002Fcode> qui effectue une analyse de pile basique :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\">huffc src\u002FContract.huff -r --stack-check\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"r-sum\">Résumé\u003C\u002Fh2>\n\u003Cp>La gestion de pile est la compétence fondamentale du développement Huff. DUP pour les lectures non destructives, SWAP pour le réordonnancement, et la mémoire pour les valeurs au-delà de la profondeur 16. Commentez chaque ligne avec l’état de la pile. Vérifiez chaque branche. Dans le prochain article, nous utiliserons ces compétences pour construire un dispatcher de fonctions O(1) avec des tables de saut compactes.\u003C\u002Fp>\n","fr","b0000000-0000-0000-0000-000000000001",true,"2026-03-28T10:44:29.096080Z","Deep EVM #10 : Gestion de pile Huff — dup, swap et discipline de pile","Maîtrisez la gestion de pile EVM en Huff : dup1-16, swap1-16, limitation de profondeur 16, patterns courants et débogage d'erreurs de pile.","huff gestion pile evm",null,"index, follow",[22,27,31],{"id":23,"name":24,"slug":25,"created_at":26},"c0000000-0000-0000-0000-000000000016","EVM","evm","2026-03-28T10:44:21.513630Z",{"id":28,"name":29,"slug":30,"created_at":26},"c0000000-0000-0000-0000-000000000020","Gas Optimization","gas-optimization",{"id":32,"name":33,"slug":34,"created_at":26},"c0000000-0000-0000-0000-000000000017","Huff","huff","Blockchain",[37,43,49],{"id":38,"title":39,"slug":40,"excerpt":41,"locale":12,"category_name":35,"published_at":42},"d0000000-0000-0000-0000-000000000608","La couche d'interoperabilite Ethereum : comment 55+ L2 deviennent une seule chaine","couche-interoperabilite-ethereum-55-l2-deviennent-une-seule-chaine","Ethereum compte 55+ rollups Layer 2, fragmentant la liquidite et l'experience utilisateur. La couche d'interoperabilite Ethereum — combinant messagerie cross-rollup, sequenceurs partages et based rollups — vise a les unifier en un reseau composable unique.","2026-03-28T10:44:45.078068Z",{"id":44,"title":45,"slug":46,"excerpt":47,"locale":12,"category_name":35,"published_at":48},"d0000000-0000-0000-0000-000000000607","Les preuves ZK au-dela des rollups : l'inference IA verifiable sur Ethereum","preuves-zk-au-dela-des-rollups-inference-ia-verifiable-ethereum","Les preuves a connaissance nulle ne sont plus un simple outil de scalabilite. En 2026, zkML permet l'inference IA verifiable on-chain, les ZK coprocesseurs deplacent le calcul lourd hors chaine avec verification on-chain, et de nouveaux systemes de preuve comme SP1 et Jolt rendent tout cela pratique.","2026-03-28T10:44:45.071974Z",{"id":50,"title":51,"slug":52,"excerpt":53,"locale":12,"category_name":35,"published_at":54},"d0000000-0000-0000-0000-000000000584","EIP-7702 en pratique : construire des flux de comptes intelligents apres Pectra","eip-7702-en-pratique-construire-flux-comptes-intelligents-apres-pectra","EIP-7702 permet a tout EOA Ethereum d'agir temporairement comme un contrat intelligent dans une seule transaction. Voici comment implementer les transactions par lots, le parrainage de gas et la recuperation sociale avec la nouvelle primitive d'account abstraction.","2026-03-28T10:44:43.586053Z",{"id":13,"name":56,"slug":57,"bio":58,"photo_url":19,"linkedin":19,"role":59,"created_at":60,"updated_at":60},"Open Soft Team","open-soft-team","The engineering team at Open Soft, building premium software solutions from Bali, Indonesia.","Engineering Team","2026-03-28T08:31:22.226811Z"]