[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"article-deep-evm-11-huff-jump-tables-despacho-funciones":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},"d8000000-0000-0000-0000-000000000111","a0000000-0000-0000-0000-000000000082","Deep EVM #11: Jump Tables en Huff — Despacho de Funciones O(1) Sin Overhead de Solidity","deep-evm-11-huff-jump-tables-despacho-funciones","Construye jump tables O(1) en Huff para despacho de funciones ultra-eficiente: cálculo de offsets, tablas de despacho perfectas, y benchmarks contra el despacho lineal de Solidity.","## El problema del despacho de funciones\n\nCuando llamas a un contrato, los primeros 4 bytes del calldata son el selector de función — un hash keccak256 truncado de la firma. El contrato necesita mapear este selector al código correspondiente.\n\nSolidity genera un despacho lineal: compara el selector contra cada función hasta encontrar coincidencia. Con N funciones, esto es O(N) en el peor caso.\n\n```\n\u002F\u002F Solidity genera (simplificado):\nif selector == 0xa9059cbb jump transfer    \u002F\u002F 3+3+10 = 16 gas\nif selector == 0x70a08231 jump balanceOf   \u002F\u002F 16 gas\nif selector == 0x18160ddd jump totalSupply  \u002F\u002F 16 gas\n\u002F\u002F ... más comparaciones ...\nrevert\n```\n\nPara un contrato con 50 funciones, la función más \"lejana\" paga 50 * 16 = 800 gas solo en despacho. En MEV, esto es inaceptable.\n\n## Jump tables: O(1) constante\n\nUna jump table usa el selector directamente como índice para saltar a la posición correcta. Sin comparaciones, sin branches — un solo salto.\n\n### Concepto\n1. Tomar los primeros N bits del selector\n2. Usarlos como offset en una tabla almacenada en el bytecode\n3. Saltar directamente a la dirección indicada\n\n### Implementación en Huff\n\n```huff\n#define jumptable DISPATCH_TABLE {\n    balanceOf   \u002F\u002F selector 0x70a08231 -> posición 0\n    transfer    \u002F\u002F selector 0xa9059cbb -> posición 1\n    totalSupply \u002F\u002F selector 0x18160ddd -> posición 2\n}\n\n#define macro MAIN() = takes(0) returns(0) {\n    \u002F\u002F Leer selector\n    0x00 calldataload 0xe0 shr\n    \n    \u002F\u002F Buscar en la jump table\n    __tablestart(DISPATCH_TABLE)    \u002F\u002F [table_offset, selector]\n    \u002F\u002F ... lógica de lookup ...\n}\n```\n\nHuff proporciona `__tablestart` y `__tablesize` para referenciar jump tables embebidas en el bytecode.\n\n## Hash perfecto para selectores\n\nPara un conjunto conocido de selectores, podemos encontrar una función hash que mapee cada selector a un índice único sin colisiones:\n\n```huff\n#define macro PERFECT_DISPATCH() = takes(0) returns(0) {\n    0x00 calldataload 0xe0 shr  \u002F\u002F [selector]\n    \n    \u002F\u002F Función hash perfecta (precalculada offline):\n    \u002F\u002F h(selector) = (selector * MAGIC_NUMBER) >> SHIFT\n    \u002F\u002F donde MAGIC_NUMBER y SHIFT se eligen para evitar colisiones\n    \n    dup1\n    0x0f and                    \u002F\u002F Usar los últimos 4 bits como índice\n    0x02 shl                    \u002F\u002F Multiplicar por 4 (cada entrada = 4 bytes)\n    __tablestart(DISPATCH_TABLE)\n    add                         \u002F\u002F [table_addr]\n    \n    \u002F\u002F Leer la dirección de salto desde la tabla\n    0x00 codecopy              \u002F\u002F Copiar 2 bytes del bytecode\n    0x00 mload                 \u002F\u002F Cargar la dirección\n    0xf0 shr                   \u002F\u002F Alinear\n    jump                       \u002F\u002F Saltar directamente\n}\n```\n\n## Benchmarks\n\n| Método | Gas (mejor caso) | Gas (peor caso) | Gas (promedio, 20 funciones) |\n|--------|-------------------|------------------|-----------------------------|\n| Solidity lineal | 16 | 320 | 168 |\n| Solidity binary search | 48 | 80 | 64 |\n| Huff jump table | 35 | 35 | 35 |\n\nLa jump table de Huff tiene coste constante sin importar cuántas funciones tenga el contrato. Para contratos con muchas funciones (como routers de DEX), el ahorro es masivo.\n\n## Jump tables packed vs padded\n\n### Packed table\nCada entrada ocupa solo 2 bytes (dirección de salto). Más compacto, pero requiere calcular offsets.\n\n### Padded table\nCada entrada ocupa 32 bytes. Más desperdicio, pero el lookup es trivial con multiplicación.\n\n```huff\n\u002F\u002F Packed: 2 bytes por entrada\n\u002F\u002F Offset = index * 2\n\u002F\u002F Más compacto, menos gas en codecopy\n\n\u002F\u002F Padded: 32 bytes por entrada\n\u002F\u002F Offset = index * 32\n\u002F\u002F Más simple, pero bytecode más grande\n```\n\n## Consideraciones prácticas\n\n1. **Colisiones de hash** — La función hash perfecta debe ser verificada exhaustivamente offline\n2. **Selectores desconocidos** — Siempre incluir un fallback para selectores que no coincidan\n3. **Tamaño del bytecode** — Jump tables grandes pueden aumentar el coste de despliegue\n4. **Mantenimiento** — Añadir funciones requiere recalcular la función hash perfecta\n\n## Aplicaciones en MEV\n\nLos bots de MEV son el caso de uso principal para jump tables:\n\n- Un router que ejecuta arbitraje a través de 50+ pools necesita despacho O(1)\n- La latencia de 12 segundos por bloque significa que cada gas ahorrado se convierte en ventaja competitiva\n- Los contratos de ejecución MEV típicamente tienen 3-5 funciones de punto de entrada, pero el patrón se escala a cualquier número\n\n## Conclusión\n\nLas jump tables transforman el despacho de funciones de O(N) a O(1), eliminando una fuente significativa de overhead en contratos con muchas funciones. Para desarrolladores de MEV y protocolos de alto rendimiento, este patrón es esencial.","\u003Ch2 id=\"el-problema-del-despacho-de-funciones\">El problema del despacho de funciones\u003C\u002Fh2>\n\u003Cp>Cuando llamas a un contrato, los primeros 4 bytes del calldata son el selector de función — un hash keccak256 truncado de la firma. El contrato necesita mapear este selector al código correspondiente.\u003C\u002Fp>\n\u003Cp>Solidity genera un despacho lineal: compara el selector contra cada función hasta encontrar coincidencia. Con N funciones, esto es O(N) en el peor caso.\u003C\u002Fp>\n\u003Cpre>\u003Ccode>\u002F\u002F Solidity genera (simplificado):\nif selector == 0xa9059cbb jump transfer    \u002F\u002F 3+3+10 = 16 gas\nif selector == 0x70a08231 jump balanceOf   \u002F\u002F 16 gas\nif selector == 0x18160ddd jump totalSupply  \u002F\u002F 16 gas\n\u002F\u002F ... más comparaciones ...\nrevert\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Para un contrato con 50 funciones, la función más “lejana” paga 50 * 16 = 800 gas solo en despacho. En MEV, esto es inaceptable.\u003C\u002Fp>\n\u003Ch2 id=\"jump-tables-o-1-constante\">Jump tables: O(1) constante\u003C\u002Fh2>\n\u003Cp>Una jump table usa el selector directamente como índice para saltar a la posición correcta. Sin comparaciones, sin branches — un solo salto.\u003C\u002Fp>\n\u003Ch3>Concepto\u003C\u002Fh3>\n\u003Col>\n\u003Cli>Tomar los primeros N bits del selector\u003C\u002Fli>\n\u003Cli>Usarlos como offset en una tabla almacenada en el bytecode\u003C\u002Fli>\n\u003Cli>Saltar directamente a la dirección indicada\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Ch3>Implementación en Huff\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-huff\">#define jumptable DISPATCH_TABLE {\n    balanceOf   \u002F\u002F selector 0x70a08231 -&gt; posición 0\n    transfer    \u002F\u002F selector 0xa9059cbb -&gt; posición 1\n    totalSupply \u002F\u002F selector 0x18160ddd -&gt; posición 2\n}\n\n#define macro MAIN() = takes(0) returns(0) {\n    \u002F\u002F Leer selector\n    0x00 calldataload 0xe0 shr\n    \n    \u002F\u002F Buscar en la jump table\n    __tablestart(DISPATCH_TABLE)    \u002F\u002F [table_offset, selector]\n    \u002F\u002F ... lógica de lookup ...\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Huff proporciona \u003Ccode>__tablestart\u003C\u002Fcode> y \u003Ccode>__tablesize\u003C\u002Fcode> para referenciar jump tables embebidas en el bytecode.\u003C\u002Fp>\n\u003Ch2 id=\"hash-perfecto-para-selectores\">Hash perfecto para selectores\u003C\u002Fh2>\n\u003Cp>Para un conjunto conocido de selectores, podemos encontrar una función hash que mapee cada selector a un índice único sin colisiones:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-huff\">#define macro PERFECT_DISPATCH() = takes(0) returns(0) {\n    0x00 calldataload 0xe0 shr  \u002F\u002F [selector]\n    \n    \u002F\u002F Función hash perfecta (precalculada offline):\n    \u002F\u002F h(selector) = (selector * MAGIC_NUMBER) &gt;&gt; SHIFT\n    \u002F\u002F donde MAGIC_NUMBER y SHIFT se eligen para evitar colisiones\n    \n    dup1\n    0x0f and                    \u002F\u002F Usar los últimos 4 bits como índice\n    0x02 shl                    \u002F\u002F Multiplicar por 4 (cada entrada = 4 bytes)\n    __tablestart(DISPATCH_TABLE)\n    add                         \u002F\u002F [table_addr]\n    \n    \u002F\u002F Leer la dirección de salto desde la tabla\n    0x00 codecopy              \u002F\u002F Copiar 2 bytes del bytecode\n    0x00 mload                 \u002F\u002F Cargar la dirección\n    0xf0 shr                   \u002F\u002F Alinear\n    jump                       \u002F\u002F Saltar directamente\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"benchmarks\">Benchmarks\u003C\u002Fh2>\n\u003Ctable>\u003Cthead>\u003Ctr>\u003Cth>Método\u003C\u002Fth>\u003Cth>Gas (mejor caso)\u003C\u002Fth>\u003Cth>Gas (peor caso)\u003C\u002Fth>\u003Cth>Gas (promedio, 20 funciones)\u003C\u002Fth>\u003C\u002Ftr>\u003C\u002Fthead>\u003Ctbody>\n\u003Ctr>\u003Ctd>Solidity lineal\u003C\u002Ftd>\u003Ctd>16\u003C\u002Ftd>\u003Ctd>320\u003C\u002Ftd>\u003Ctd>168\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Solidity binary search\u003C\u002Ftd>\u003Ctd>48\u003C\u002Ftd>\u003Ctd>80\u003C\u002Ftd>\u003Ctd>64\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Huff jump table\u003C\u002Ftd>\u003Ctd>35\u003C\u002Ftd>\u003Ctd>35\u003C\u002Ftd>\u003Ctd>35\u003C\u002Ftd>\u003C\u002Ftr>\n\u003C\u002Ftbody>\u003C\u002Ftable>\n\u003Cp>La jump table de Huff tiene coste constante sin importar cuántas funciones tenga el contrato. Para contratos con muchas funciones (como routers de DEX), el ahorro es masivo.\u003C\u002Fp>\n\u003Ch2 id=\"jump-tables-packed-vs-padded\">Jump tables packed vs padded\u003C\u002Fh2>\n\u003Ch3>Packed table\u003C\u002Fh3>\n\u003Cp>Cada entrada ocupa solo 2 bytes (dirección de salto). Más compacto, pero requiere calcular offsets.\u003C\u002Fp>\n\u003Ch3>Padded table\u003C\u002Fh3>\n\u003Cp>Cada entrada ocupa 32 bytes. Más desperdicio, pero el lookup es trivial con multiplicación.\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-huff\">\u002F\u002F Packed: 2 bytes por entrada\n\u002F\u002F Offset = index * 2\n\u002F\u002F Más compacto, menos gas en codecopy\n\n\u002F\u002F Padded: 32 bytes por entrada\n\u002F\u002F Offset = index * 32\n\u002F\u002F Más simple, pero bytecode más grande\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"consideraciones-pr-cticas\">Consideraciones prácticas\u003C\u002Fh2>\n\u003Col>\n\u003Cli>\u003Cstrong>Colisiones de hash\u003C\u002Fstrong> — La función hash perfecta debe ser verificada exhaustivamente offline\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Selectores desconocidos\u003C\u002Fstrong> — Siempre incluir un fallback para selectores que no coincidan\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Tamaño del bytecode\u003C\u002Fstrong> — Jump tables grandes pueden aumentar el coste de despliegue\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Mantenimiento\u003C\u002Fstrong> — Añadir funciones requiere recalcular la función hash perfecta\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Ch2 id=\"aplicaciones-en-mev\">Aplicaciones en MEV\u003C\u002Fh2>\n\u003Cp>Los bots de MEV son el caso de uso principal para jump tables:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>Un router que ejecuta arbitraje a través de 50+ pools necesita despacho O(1)\u003C\u002Fli>\n\u003Cli>La latencia de 12 segundos por bloque significa que cada gas ahorrado se convierte en ventaja competitiva\u003C\u002Fli>\n\u003Cli>Los contratos de ejecución MEV típicamente tienen 3-5 funciones de punto de entrada, pero el patrón se escala a cualquier número\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2 id=\"conclusi-n\">Conclusión\u003C\u002Fh2>\n\u003Cp>Las jump tables transforman el despacho de funciones de O(N) a O(1), eliminando una fuente significativa de overhead en contratos con muchas funciones. Para desarrolladores de MEV y protocolos de alto rendimiento, este patrón es esencial.\u003C\u002Fp>\n","es","b0000000-0000-0000-0000-000000000001",true,"2026-03-28T10:44:31.377630Z","Deep EVM #11: Jump Tables en Huff — Despacho de Funciones O(1)","Construye jump tables O(1) en Huff: despacho ultra-eficiente, hash perfecto para selectores y benchmarks contra Solidity.","huff jump table despacho funciones",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-000000000614","La capa de interoperabilidad de Ethereum: Como 55+ L2s se convierten en una sola cadena","capa-interoperabilidad-ethereum-55-l2s-una-sola-cadena","Ethereum tiene 55+ rollups Layer 2, fragmentando la liquidez y la experiencia del usuario. La capa de interoperabilidad de Ethereum — combinando mensajeria cross-rollup, secuenciadores compartidos y based rollups — busca unificarlos en una red componible unica.","2026-03-28T10:44:45.451917Z",{"id":48,"title":49,"slug":50,"excerpt":51,"locale":12,"category_name":39,"published_at":52},"d0000000-0000-0000-0000-000000000613","Pruebas ZK mas alla de los rollups: Inferencia de IA verificable en Ethereum","pruebas-zk-mas-alla-rollups-inferencia-ia-verificable-ethereum","Las pruebas de conocimiento cero ya no son solo una herramienta de escalabilidad. En 2026, zkML permite la inferencia de IA verificable on-chain, los coprocesadores ZK mueven el calculo pesado off-chain con verificacion on-chain, y nuevos sistemas de prueba como SP1 y Jolt lo hacen practico.","2026-03-28T10:44:45.446211Z",{"id":54,"title":55,"slug":56,"excerpt":57,"locale":12,"category_name":39,"published_at":58},"d0000000-0000-0000-0000-000000000590","EIP-7702 en la practica: construir flujos de cuenta inteligente despues de Pectra","eip-7702-en-la-practica-construir-flujos-cuenta-inteligente-despues-pectra","EIP-7702 permite a cualquier EOA de Ethereum actuar temporalmente como contrato inteligente en una sola transaccion. Asi se implementan transacciones por lotes, patrocinio de gas y recuperacion social con la nueva primitiva de account abstraction.","2026-03-28T10:44:43.986612Z",{"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"]