[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"article-deep-evm-11-tables-saut-huff-dispatch-fonctions":3},{"article":4,"author":59},{"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":39,"related_articles":40},"d6000000-0000-0000-0000-000000000111","a0000000-0000-0000-0000-000000000062","Deep EVM #11 : Tables de saut Huff — Dispatch de fonctions O(1) sans overhead Solidity","deep-evm-11-tables-saut-huff-dispatch-fonctions","Construisez un dispatcher de fonctions O(1) en Huff utilisant des tables de saut compactes. Comparez la chaîne if-else de Solidity avec une table de saut artisanale qui économise des milliers de gas.","## Le problème du dispatcher de Solidity\n\nQuand vous appelez un contrat Solidity, la première chose que l'EVM exécute est le dispatcher de fonctions. Solidity génère une chaîne if-else linéaire qui compare les 4 premiers octets du calldata (le sélecteur de fonction) à chaque sélecteur connu.\n\nPour un contrat avec N fonctions, c'est du O(N) — le pire cas vérifie tous les N sélecteurs. Chaque comparaison coûte environ 22 gas. Un contrat avec 20 fonctions gaspille jusqu'à 440 gas rien que sur le dispatch.\n\nPour un contrat de bot MEV appelé des millions de fois, ces 400+ unités de gas par appel s'accumulent en vrai ETH.\n\n## L'approche table de saut : O(1)\n\nUne table de saut mappe un sélecteur de fonction directement à un offset de code en utilisant l'arithmétique, pas la comparaison. L'idée est empruntée à l'architecture CPU — les GOTO calculés sont utilisés depuis les années 1960.\n\nLe concept :\n\n1. Extraire le sélecteur de fonction du calldata (4 octets).\n2. Utiliser l'arithmétique pour calculer une destination de saut à partir du sélecteur.\n3. Sauter directement à cette destination.\n\nPas de comparaisons, pas de branchements, temps constant quel que soit le nombre de fonctions.\n\n### Approche 1 : encodage de sélecteur minimal\n\nSi votre contrat a un petit nombre de fonctions (1-8), vous pouvez assigner manuellement les sélecteurs en minant des sélecteurs vanity où le premier ou les deux premiers octets encodent un petit entier unique :\n\n```huff\n#define macro DISPATCHER() = takes(0) returns(0) {\n    0x00 calldataload       \u002F\u002F [calldata_word]\n    0xe0 shr                \u002F\u002F [selector]\n\n    \u002F\u002F Extraire l'octet de routage — premier octet du sélecteur\n    0x18 shr                \u002F\u002F [first_byte]\n\n    \u002F\u002F Chaque entrée dans notre table fait 2 octets (PUSH2 offset)\n    0x02 mul                \u002F\u002F [offset_in_table]\n    __tablestart(JumpTable) \u002F\u002F [table_start, offset_in_table]\n    add                     \u002F\u002F [entry_address]\n    \n    \u002F\u002F Charger la destination de saut de 2 octets depuis la table\n    0x00 codecopy           \u002F\u002F copier 2 octets du code vers la mémoire\n    0x00 mload              \u002F\u002F [jump_dest (rembourré à 32 octets)]\n    0xf0 shr                \u002F\u002F [jump_dest]\n    jump                    \u002F\u002F GOTO corps de la fonction\n}\n```\n\n### Approche 2 : table de code compacte\n\nPour une densité maximale, compactez la table de saut directement dans le bytecode en utilisant `__tablestart` et `__tablesize`. Huff supporte nativement les tables de saut :\n\n```huff\n#define jumptable__packed SELECTOR_TABLE {\n    fn_swap\n    fn_transfer\n    fn_approve\n    fn_balance\n}\n```\n\n## Comparaison de gas\n\n| Fonctions | Solidity (if-else) | Solidity (binaire) | Table de saut Huff |\n|-----------|-------------------|-------------------|--------------------|\n| 2         | 22-44 gas         | 22-44 gas         | 15 gas             |\n| 4         | 22-88 gas         | 22-66 gas         | 15 gas             |\n| 8         | 22-176 gas        | 22-88 gas         | 15 gas             |\n| 16        | 22-352 gas        | 22-110 gas        | 15 gas             |\n| 32        | 22-704 gas        | 22-132 gas        | 15 gas             |\n\nLe coût de la table de saut est constant : CALLDATALOAD (3) + SHR (3) + arithmétique (3-6) + JUMP (8) = environ 15-18 gas. Il ne change jamais, quel que soit le nombre de fonctions.\n\n## Minage de sélecteurs vanity\n\nPour que l'approche table de saut fonctionne, vous avez besoin de sélecteurs de fonction avec des octets de routage prévisibles. Vous pouvez les miner :\n\n```python\nimport hashlib\nimport itertools\n\ntarget_byte = 0x00  # premier octet désiré du sélecteur\nbase_name = \"swap\"\n\nfor suffix in itertools.count():\n    name = f\"{base_name}{suffix}(uint256,address)\"\n    selector = hashlib.sha3_256(name.encode()).digest()[:4]\n    if selector[0] == target_byte:\n        print(f\"Trouvé: {name} -> 0x{selector.hex()}\")\n        break\n```\n\nEn pratique, nous utilisons `cast sig` de Foundry ou un outil Rust qui brute-force les noms de fonctions pour trouver des sélecteurs avec les préfixes désirés.\n\n## Impact sur la taille du bytecode\n\nLa taille du bytecode affecte directement le coût de déploiement (200 gas par octet via CREATE). Comparaison :\n\n| Approche | Bytecode runtime | Gas de déploiement |\n|----------|-----------------|--------------------|\n| Solidity (8 foncs) | ~800 octets | 160 000 gas |\n| Table de saut Huff (8 foncs) | ~200 octets | 40 000 gas |\n| Huff minimal (2 foncs) | ~61 octets | 12 200 gas |\n\n## Limitations\n\n1. **ABI non standard** — Les outils externes (Etherscan, portefeuilles) ne peuvent pas décoder vos calldata sans définitions ABI personnalisées.\n2. **Minage de sélecteurs** — Nécessite un travail initial et contraint le nommage des fonctions.\n3. **Coût de maintenance** — Huff est plus difficile à auditer et modifier que Solidity.\n\n## Résumé\n\nLes tables de saut remplacent la chaîne de dispatch O(N) de Solidity par des sauts calculés O(1). Les économies de gas se cumulent sur des millions d'appels — un avantage significatif pour les contrats haute fréquence. Dans le prochain article, nous explorerons les patterns Huff avancés : exécution adaptative, authentification multi-opérateur et astuces de disposition mémoire.","\u003Ch2 id=\"le-probl-me-du-dispatcher-de-solidity\">Le problème du dispatcher de Solidity\u003C\u002Fh2>\n\u003Cp>Quand vous appelez un contrat Solidity, la première chose que l’EVM exécute est le dispatcher de fonctions. Solidity génère une chaîne if-else linéaire qui compare les 4 premiers octets du calldata (le sélecteur de fonction) à chaque sélecteur connu.\u003C\u002Fp>\n\u003Cp>Pour un contrat avec N fonctions, c’est du O(N) — le pire cas vérifie tous les N sélecteurs. Chaque comparaison coûte environ 22 gas. Un contrat avec 20 fonctions gaspille jusqu’à 440 gas rien que sur le dispatch.\u003C\u002Fp>\n\u003Cp>Pour un contrat de bot MEV appelé des millions de fois, ces 400+ unités de gas par appel s’accumulent en vrai ETH.\u003C\u002Fp>\n\u003Ch2 id=\"l-approche-table-de-saut-o-1\">L’approche table de saut : O(1)\u003C\u002Fh2>\n\u003Cp>Une table de saut mappe un sélecteur de fonction directement à un offset de code en utilisant l’arithmétique, pas la comparaison. L’idée est empruntée à l’architecture CPU — les GOTO calculés sont utilisés depuis les années 1960.\u003C\u002Fp>\n\u003Cp>Le concept :\u003C\u002Fp>\n\u003Col>\n\u003Cli>Extraire le sélecteur de fonction du calldata (4 octets).\u003C\u002Fli>\n\u003Cli>Utiliser l’arithmétique pour calculer une destination de saut à partir du sélecteur.\u003C\u002Fli>\n\u003Cli>Sauter directement à cette destination.\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp>Pas de comparaisons, pas de branchements, temps constant quel que soit le nombre de fonctions.\u003C\u002Fp>\n\u003Ch3>Approche 1 : encodage de sélecteur minimal\u003C\u002Fh3>\n\u003Cp>Si votre contrat a un petit nombre de fonctions (1-8), vous pouvez assigner manuellement les sélecteurs en minant des sélecteurs vanity où le premier ou les deux premiers octets encodent un petit entier unique :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-huff\">#define macro DISPATCHER() = takes(0) returns(0) {\n    0x00 calldataload       \u002F\u002F [calldata_word]\n    0xe0 shr                \u002F\u002F [selector]\n\n    \u002F\u002F Extraire l'octet de routage — premier octet du sélecteur\n    0x18 shr                \u002F\u002F [first_byte]\n\n    \u002F\u002F Chaque entrée dans notre table fait 2 octets (PUSH2 offset)\n    0x02 mul                \u002F\u002F [offset_in_table]\n    __tablestart(JumpTable) \u002F\u002F [table_start, offset_in_table]\n    add                     \u002F\u002F [entry_address]\n    \n    \u002F\u002F Charger la destination de saut de 2 octets depuis la table\n    0x00 codecopy           \u002F\u002F copier 2 octets du code vers la mémoire\n    0x00 mload              \u002F\u002F [jump_dest (rembourré à 32 octets)]\n    0xf0 shr                \u002F\u002F [jump_dest]\n    jump                    \u002F\u002F GOTO corps de la fonction\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>Approche 2 : table de code compacte\u003C\u002Fh3>\n\u003Cp>Pour une densité maximale, compactez la table de saut directement dans le bytecode en utilisant \u003Ccode>__tablestart\u003C\u002Fcode> et \u003Ccode>__tablesize\u003C\u002Fcode>. Huff supporte nativement les tables de saut :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-huff\">#define jumptable__packed SELECTOR_TABLE {\n    fn_swap\n    fn_transfer\n    fn_approve\n    fn_balance\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"comparaison-de-gas\">Comparaison de gas\u003C\u002Fh2>\n\u003Ctable>\u003Cthead>\u003Ctr>\u003Cth>Fonctions\u003C\u002Fth>\u003Cth>Solidity (if-else)\u003C\u002Fth>\u003Cth>Solidity (binaire)\u003C\u002Fth>\u003Cth>Table de saut Huff\u003C\u002Fth>\u003C\u002Ftr>\u003C\u002Fthead>\u003Ctbody>\n\u003Ctr>\u003Ctd>2\u003C\u002Ftd>\u003Ctd>22-44 gas\u003C\u002Ftd>\u003Ctd>22-44 gas\u003C\u002Ftd>\u003Ctd>15 gas\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>4\u003C\u002Ftd>\u003Ctd>22-88 gas\u003C\u002Ftd>\u003Ctd>22-66 gas\u003C\u002Ftd>\u003Ctd>15 gas\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>8\u003C\u002Ftd>\u003Ctd>22-176 gas\u003C\u002Ftd>\u003Ctd>22-88 gas\u003C\u002Ftd>\u003Ctd>15 gas\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>16\u003C\u002Ftd>\u003Ctd>22-352 gas\u003C\u002Ftd>\u003Ctd>22-110 gas\u003C\u002Ftd>\u003Ctd>15 gas\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>32\u003C\u002Ftd>\u003Ctd>22-704 gas\u003C\u002Ftd>\u003Ctd>22-132 gas\u003C\u002Ftd>\u003Ctd>15 gas\u003C\u002Ftd>\u003C\u002Ftr>\n\u003C\u002Ftbody>\u003C\u002Ftable>\n\u003Cp>Le coût de la table de saut est constant : CALLDATALOAD (3) + SHR (3) + arithmétique (3-6) + JUMP (8) = environ 15-18 gas. Il ne change jamais, quel que soit le nombre de fonctions.\u003C\u002Fp>\n\u003Ch2 id=\"minage-de-s-lecteurs-vanity\">Minage de sélecteurs vanity\u003C\u002Fh2>\n\u003Cp>Pour que l’approche table de saut fonctionne, vous avez besoin de sélecteurs de fonction avec des octets de routage prévisibles. Vous pouvez les miner :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-python\">import hashlib\nimport itertools\n\ntarget_byte = 0x00  # premier octet désiré du sélecteur\nbase_name = \"swap\"\n\nfor suffix in itertools.count():\n    name = f\"{base_name}{suffix}(uint256,address)\"\n    selector = hashlib.sha3_256(name.encode()).digest()[:4]\n    if selector[0] == target_byte:\n        print(f\"Trouvé: {name} -&gt; 0x{selector.hex()}\")\n        break\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>En pratique, nous utilisons \u003Ccode>cast sig\u003C\u002Fcode> de Foundry ou un outil Rust qui brute-force les noms de fonctions pour trouver des sélecteurs avec les préfixes désirés.\u003C\u002Fp>\n\u003Ch2 id=\"impact-sur-la-taille-du-bytecode\">Impact sur la taille du bytecode\u003C\u002Fh2>\n\u003Cp>La taille du bytecode affecte directement le coût de déploiement (200 gas par octet via CREATE). Comparaison :\u003C\u002Fp>\n\u003Ctable>\u003Cthead>\u003Ctr>\u003Cth>Approche\u003C\u002Fth>\u003Cth>Bytecode runtime\u003C\u002Fth>\u003Cth>Gas de déploiement\u003C\u002Fth>\u003C\u002Ftr>\u003C\u002Fthead>\u003Ctbody>\n\u003Ctr>\u003Ctd>Solidity (8 foncs)\u003C\u002Ftd>\u003Ctd>~800 octets\u003C\u002Ftd>\u003Ctd>160 000 gas\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Table de saut Huff (8 foncs)\u003C\u002Ftd>\u003Ctd>~200 octets\u003C\u002Ftd>\u003Ctd>40 000 gas\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Huff minimal (2 foncs)\u003C\u002Ftd>\u003Ctd>~61 octets\u003C\u002Ftd>\u003Ctd>12 200 gas\u003C\u002Ftd>\u003C\u002Ftr>\n\u003C\u002Ftbody>\u003C\u002Ftable>\n\u003Ch2 id=\"limitations\">Limitations\u003C\u002Fh2>\n\u003Col>\n\u003Cli>\u003Cstrong>ABI non standard\u003C\u002Fstrong> — Les outils externes (Etherscan, portefeuilles) ne peuvent pas décoder vos calldata sans définitions ABI personnalisées.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Minage de sélecteurs\u003C\u002Fstrong> — Nécessite un travail initial et contraint le nommage des fonctions.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Coût de maintenance\u003C\u002Fstrong> — Huff est plus difficile à auditer et modifier que Solidity.\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Ch2 id=\"r-sum\">Résumé\u003C\u002Fh2>\n\u003Cp>Les tables de saut remplacent la chaîne de dispatch O(N) de Solidity par des sauts calculés O(1). Les économies de gas se cumulent sur des millions d’appels — un avantage significatif pour les contrats haute fréquence. Dans le prochain article, nous explorerons les patterns Huff avancés : exécution adaptative, authentification multi-opérateur et astuces de disposition mémoire.\u003C\u002Fp>\n","fr","b0000000-0000-0000-0000-000000000001",true,"2026-03-28T10:44:29.102366Z","Deep EVM #11 : Tables de saut Huff — Dispatch de fonctions O(1)","Construisez un dispatcher O(1) en Huff avec des tables de saut compactes. Comparez avec le dispatch Solidity if-else et mesurez les économies de gas.","huff tables saut dispatch",null,"index, follow",[22,27,31,35],{"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",{"id":36,"name":37,"slug":38,"created_at":26},"c0000000-0000-0000-0000-000000000018","Yul","yul","Blockchain",[41,47,53],{"id":42,"title":43,"slug":44,"excerpt":45,"locale":12,"category_name":39,"published_at":46},"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":48,"title":49,"slug":50,"excerpt":51,"locale":12,"category_name":39,"published_at":52},"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":54,"title":55,"slug":56,"excerpt":57,"locale":12,"category_name":39,"published_at":58},"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":60,"slug":61,"bio":62,"photo_url":19,"linkedin":19,"role":63,"created_at":64,"updated_at":64},"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"]