[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"article-deep-evm-18-debogage-bytecode-evm-traces":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-000000000118","a0000000-0000-0000-0000-000000000062","Deep EVM #18 : Débogage du bytecode EVM — Traces, dumps de pile et cast run","deep-evm-18-debogage-bytecode-evm-traces","Maîtrisez le débogage du bytecode EVM avec cast run pour le rejeu de transactions, forge debug pour l'analyse pas à pas et les techniques de lecture de traces d'opcodes bruts.","## Le défi du débogage de bas niveau\n\nQuand une transaction Solidity reverte, vous obtenez typiquement un message d'erreur descriptif. Quand une transaction Huff ou Yul reverte, vous obtenez un payload de revert vide avec zéro contexte. Le débogage au niveau du bytecode nécessite des outils et des modèles mentaux différents.\n\n## cast run : rejeu de transactions\n\n`cast run` de Foundry rejoue une transaction historique et affiche la trace complète :\n\n```bash\ncast run 0xTRANSACTION_HASH --rpc-url https:\u002F\u002Feth-mainnet.g.alchemy.com\u002Fv2\u002FKEY\n```\n\nLa sortie montre chaque appel, sous-appel, et le résultat :\n\n```\nTraces:\n  [85432] 0xTarget::swap()\n    ├─ [2541] 0xPool::getReserves() [staticcall]\n    │   └─ ← (1000000000, 2000000000, 1699000000)\n    ├─ [24521] 0xToken::transfer(0xRecipient, 1000)\n    │   └─ ← true\n    └─ ← ()\n```\n\n## forge debug : analyse pas à pas\n\n`forge debug` lance un débogueur interactif TUI qui affiche le bytecode, la pile, la mémoire et le stockage à chaque opcode :\n\n```bash\nforge debug --debug test\u002FContract.t.sol --sig \"test_swap()\"\n```\n\nCommandes clés :\n- `n` — Opcode suivant\n- `p` — Opcode précédent\n- `s` — Entrer dans le sous-appel\n- `o` — Sortir du sous-appel\n- `b` — Définir un breakpoint\n- `m` — Afficher la mémoire\n- `t` — Afficher le stockage\n\n## Lecture de traces d'opcodes bruts\n\nPour les contrats Huff, la trace au niveau des opcodes est souvent nécessaire :\n\n```bash\ncast run 0xHASH --rpc-url URL -t  # trace flag\n```\n\nChaque ligne montre : le compteur de programme, l'opcode, le coût en gas et l'état de la pile.\n\n```\n[0000] PUSH1 0x00     gas=29978993 stack=[]\n[0002] CALLDATALOAD   gas=29978990 stack=[0x00]\n[0003] PUSH1 0xe0     gas=29978987 stack=[0x70a08231...]\n[0005] SHR            gas=29978984 stack=[0xe0, 0x70a08231...]\n[0006] DUP1           gas=29978981 stack=[0x70a08231]\n```\n\n## Techniques de débogage courantes\n\n### 1. Injection de logs temporaires\n\nEn Huff, vous ne pouvez pas utiliser `console.log`. Injectez temporairement des événements LOG0 pour tracer les valeurs :\n\n```huff\n#define macro DEBUG_LOG() = takes(1) returns(1) {\n    \u002F\u002F takes: [value]\n    dup1            \u002F\u002F [value, value]\n    0x00 mstore     \u002F\u002F [value]\n    0x20 0x00 log0  \u002F\u002F [value] — émet un log avec la valeur\n}\n```\n\n### 2. Revert avec données\n\nPour identifier où un contrat reverte, faites reverter avec des données différentes à chaque point :\n\n```huff\n\u002F\u002F Checkpoint 1\n0x01 0x00 mstore\n0x20 0x00 revert\n\n\u002F\u002F Checkpoint 2\n0x02 0x00 mstore\n0x20 0x00 revert\n```\n\nLa valeur de retour du revert vous indique quel checkpoint a été atteint.\n\n### 3. Comparaison de traces\n\nComparez la trace de votre contrat Huff avec celle de l'équivalent Solidity pour identifier les divergences :\n\n```bash\n# Trace du contrat Huff\nforge test --match-test test_huffSwap -vvvvv > huff_trace.txt\n\n# Trace du contrat Solidity\nforge test --match-test test_solSwap -vvvvv > sol_trace.txt\n\n# Comparer\ndiff huff_trace.txt sol_trace.txt\n```\n\n### 4. Vérification de l'état de la pile\n\nAjoutez des assertions de pile dans vos tests :\n\n```solidity\nfunction test_stackState() public {\n    \u002F\u002F Appelez une fonction qui devrait retourner une valeur spécifique\n    (bool success, bytes memory data) = huffContract.call(\n        abi.encodeWithSignature(\"compute(uint256)\", 42)\n    );\n    assertTrue(success);\n    \u002F\u002F Si le retour est incorrect, la pile est déséquilibrée\n    assertEq(abi.decode(data, (uint256)), expectedValue);\n}\n```\n\n## Erreurs courantes et diagnostic\n\n| Symptôme | Cause probable | Diagnostic |\n|----------|---------------|------------|\n| Revert sans données | Sous-débordement de pile | Vérifier takes\u002Freturns |\n| Valeur de retour incorrecte | Mauvais offset mstore | Tracer la mémoire |\n| Gas out | Boucle infinie | Ajouter une limite de gas au test |\n| Succès mais données vides | return avec mauvais offset\u002Flongueur | Vérifier les arguments de return |\n\n## Conclusion\n\nLe débogage du bytecode EVM est un art qui s'apprend par la pratique. Les outils Foundry — cast run et forge debug — combinés avec l'injection de logs et la comparaison de traces, constituent un arsenal efficace pour identifier et corriger les bugs dans les contrats Huff et Yul.","\u003Ch2 id=\"le-d-fi-du-d-bogage-de-bas-niveau\">Le défi du débogage de bas niveau\u003C\u002Fh2>\n\u003Cp>Quand une transaction Solidity reverte, vous obtenez typiquement un message d’erreur descriptif. Quand une transaction Huff ou Yul reverte, vous obtenez un payload de revert vide avec zéro contexte. Le débogage au niveau du bytecode nécessite des outils et des modèles mentaux différents.\u003C\u002Fp>\n\u003Ch2 id=\"cast-run-rejeu-de-transactions\">cast run : rejeu de transactions\u003C\u002Fh2>\n\u003Cp>\u003Ccode>cast run\u003C\u002Fcode> de Foundry rejoue une transaction historique et affiche la trace complète :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\">cast run 0xTRANSACTION_HASH --rpc-url https:\u002F\u002Feth-mainnet.g.alchemy.com\u002Fv2\u002FKEY\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>La sortie montre chaque appel, sous-appel, et le résultat :\u003C\u002Fp>\n\u003Cpre>\u003Ccode>Traces:\n  [85432] 0xTarget::swap()\n    ├─ [2541] 0xPool::getReserves() [staticcall]\n    │   └─ ← (1000000000, 2000000000, 1699000000)\n    ├─ [24521] 0xToken::transfer(0xRecipient, 1000)\n    │   └─ ← true\n    └─ ← ()\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"forge-debug-analyse-pas-pas\">forge debug : analyse pas à pas\u003C\u002Fh2>\n\u003Cp>\u003Ccode>forge debug\u003C\u002Fcode> lance un débogueur interactif TUI qui affiche le bytecode, la pile, la mémoire et le stockage à chaque opcode :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\">forge debug --debug test\u002FContract.t.sol --sig \"test_swap()\"\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Commandes clés :\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Ccode>n\u003C\u002Fcode> — Opcode suivant\u003C\u002Fli>\n\u003Cli>\u003Ccode>p\u003C\u002Fcode> — Opcode précédent\u003C\u002Fli>\n\u003Cli>\u003Ccode>s\u003C\u002Fcode> — Entrer dans le sous-appel\u003C\u002Fli>\n\u003Cli>\u003Ccode>o\u003C\u002Fcode> — Sortir du sous-appel\u003C\u002Fli>\n\u003Cli>\u003Ccode>b\u003C\u002Fcode> — Définir un breakpoint\u003C\u002Fli>\n\u003Cli>\u003Ccode>m\u003C\u002Fcode> — Afficher la mémoire\u003C\u002Fli>\n\u003Cli>\u003Ccode>t\u003C\u002Fcode> — Afficher le stockage\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2 id=\"lecture-de-traces-d-opcodes-bruts\">Lecture de traces d’opcodes bruts\u003C\u002Fh2>\n\u003Cp>Pour les contrats Huff, la trace au niveau des opcodes est souvent nécessaire :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\">cast run 0xHASH --rpc-url URL -t  # trace flag\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Chaque ligne montre : le compteur de programme, l’opcode, le coût en gas et l’état de la pile.\u003C\u002Fp>\n\u003Cpre>\u003Ccode>[0000] PUSH1 0x00     gas=29978993 stack=[]\n[0002] CALLDATALOAD   gas=29978990 stack=[0x00]\n[0003] PUSH1 0xe0     gas=29978987 stack=[0x70a08231...]\n[0005] SHR            gas=29978984 stack=[0xe0, 0x70a08231...]\n[0006] DUP1           gas=29978981 stack=[0x70a08231]\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"techniques-de-d-bogage-courantes\">Techniques de débogage courantes\u003C\u002Fh2>\n\u003Ch3>1. Injection de logs temporaires\u003C\u002Fh3>\n\u003Cp>En Huff, vous ne pouvez pas utiliser \u003Ccode>console.log\u003C\u002Fcode>. Injectez temporairement des événements LOG0 pour tracer les valeurs :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-huff\">#define macro DEBUG_LOG() = takes(1) returns(1) {\n    \u002F\u002F takes: [value]\n    dup1            \u002F\u002F [value, value]\n    0x00 mstore     \u002F\u002F [value]\n    0x20 0x00 log0  \u002F\u002F [value] — émet un log avec la valeur\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>2. Revert avec données\u003C\u002Fh3>\n\u003Cp>Pour identifier où un contrat reverte, faites reverter avec des données différentes à chaque point :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-huff\">\u002F\u002F Checkpoint 1\n0x01 0x00 mstore\n0x20 0x00 revert\n\n\u002F\u002F Checkpoint 2\n0x02 0x00 mstore\n0x20 0x00 revert\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>La valeur de retour du revert vous indique quel checkpoint a été atteint.\u003C\u002Fp>\n\u003Ch3>3. Comparaison de traces\u003C\u002Fh3>\n\u003Cp>Comparez la trace de votre contrat Huff avec celle de l’équivalent Solidity pour identifier les divergences :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\"># Trace du contrat Huff\nforge test --match-test test_huffSwap -vvvvv &gt; huff_trace.txt\n\n# Trace du contrat Solidity\nforge test --match-test test_solSwap -vvvvv &gt; sol_trace.txt\n\n# Comparer\ndiff huff_trace.txt sol_trace.txt\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>4. Vérification de l’état de la pile\u003C\u002Fh3>\n\u003Cp>Ajoutez des assertions de pile dans vos tests :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-solidity\">function test_stackState() public {\n    \u002F\u002F Appelez une fonction qui devrait retourner une valeur spécifique\n    (bool success, bytes memory data) = huffContract.call(\n        abi.encodeWithSignature(\"compute(uint256)\", 42)\n    );\n    assertTrue(success);\n    \u002F\u002F Si le retour est incorrect, la pile est déséquilibrée\n    assertEq(abi.decode(data, (uint256)), expectedValue);\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"erreurs-courantes-et-diagnostic\">Erreurs courantes et diagnostic\u003C\u002Fh2>\n\u003Ctable>\u003Cthead>\u003Ctr>\u003Cth>Symptôme\u003C\u002Fth>\u003Cth>Cause probable\u003C\u002Fth>\u003Cth>Diagnostic\u003C\u002Fth>\u003C\u002Ftr>\u003C\u002Fthead>\u003Ctbody>\n\u003Ctr>\u003Ctd>Revert sans données\u003C\u002Ftd>\u003Ctd>Sous-débordement de pile\u003C\u002Ftd>\u003Ctd>Vérifier takes\u002Freturns\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Valeur de retour incorrecte\u003C\u002Ftd>\u003Ctd>Mauvais offset mstore\u003C\u002Ftd>\u003Ctd>Tracer la mémoire\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Gas out\u003C\u002Ftd>\u003Ctd>Boucle infinie\u003C\u002Ftd>\u003Ctd>Ajouter une limite de gas au test\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Succès mais données vides\u003C\u002Ftd>\u003Ctd>return avec mauvais offset\u002Flongueur\u003C\u002Ftd>\u003Ctd>Vérifier les arguments de return\u003C\u002Ftd>\u003C\u002Ftr>\n\u003C\u002Ftbody>\u003C\u002Ftable>\n\u003Ch2 id=\"conclusion\">Conclusion\u003C\u002Fh2>\n\u003Cp>Le débogage du bytecode EVM est un art qui s’apprend par la pratique. Les outils Foundry — cast run et forge debug — combinés avec l’injection de logs et la comparaison de traces, constituent un arsenal efficace pour identifier et corriger les bugs dans les contrats Huff et Yul.\u003C\u002Fp>\n","fr","b0000000-0000-0000-0000-000000000001",true,"2026-03-28T10:44:29.309637Z","Débogage du bytecode EVM — Traces, dumps de pile et cast run","Maîtrisez le débogage du bytecode EVM avec cast run, forge debug et l'analyse de traces d'opcodes pour les smart contracts Huff et Yul.","débogage bytecode 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-000000000021","Foundry","foundry",{"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"]