[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"article-deep-evm-15-simulacion-mev-busqueda-binaria-state-forks":3},{"article":4,"author":61},{"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-000000000115","a0000000-0000-0000-0000-000000000082","Deep EVM #15: Simulación MEV — Búsqueda Binaria, State Forks y el Deadline de 12 Segundos","deep-evm-15-simulacion-mev-busqueda-binaria-state-forks","Construye un motor de simulación MEV de alta velocidad: forks de estado con revm, búsqueda binaria para montos óptimos, pipelines de ejecución paralela y optimización bajo el deadline de 12 segundos por bloque.","## La necesidad de velocidad\n\nEn MEV, tienes exactamente 12 segundos entre bloques para detectar oportunidades, simular transacciones, optimizar montos y enviar bundles. Un motor de simulación lento significa oportunidades perdidas.\n\nLa cadena de ejecución típica:\n1. Nuevo bloque llega (t=0)\n2. Actualizar estado local (t=0.1s)\n3. Detectar oportunidades (t=0.5s)\n4. Simular y optimizar (t=1-8s)\n5. Construir y enviar bundles (t=8-10s)\n6. Buffer para propagación (t=10-12s)\n\nLa simulación consume la mayor parte del tiempo. Optimizarla es la diferencia entre capturar $10K o $0.\n\n## State forks con revm\n\nrevm es una implementación de la EVM en Rust, optimizada para simulación. Permite crear forks del estado de Ethereum y ejecutar transacciones hipotéticas sin afectar el estado real.\n\n```rust\nuse revm::{EVM, db::CacheDB, primitives::*};\n\nfn simulate_swap(\n    db: &CacheDB\u003CEmptyDB>,\n    router: Address,\n    calldata: Bytes,\n    value: U256,\n) -> Result\u003CExecutionResult, EvmError> {\n    let mut evm = EVM::new();\n    evm.database(db.clone());\n    \n    evm.env.tx.caller = searcher_address();\n    evm.env.tx.transact_to = TransactTo::Call(router);\n    evm.env.tx.data = calldata;\n    evm.env.tx.value = value;\n    evm.env.tx.gas_limit = 500_000;\n    \n    evm.transact()\n}\n```\n\n## Búsqueda binaria para monto óptimo\n\nDado un ciclo de arbitraje, necesitamos encontrar el monto de entrada que maximiza el beneficio. La función beneficio es típicamente cóncava (sube, alcanza un pico, y baja), lo que permite búsqueda ternaria:\n\n```rust\nfn find_optimal_amount(\n    db: &CacheDB\u003CEmptyDB>,\n    cycle: &ArbCycle,\n    gas_cost: U256,\n) -> (U256, U256) {\n    let mut lo = eth(0.01);  \u002F\u002F Mínimo: 0.01 ETH\n    let mut hi = eth(100.0); \u002F\u002F Máximo: 100 ETH\n    \n    for _ in 0..40 {\n        let mid1 = lo + (hi - lo) \u002F 3;\n        let mid2 = hi - (hi - lo) \u002F 3;\n        \n        let profit1 = simulate_cycle(db, cycle, mid1)\n            .saturating_sub(gas_cost);\n        let profit2 = simulate_cycle(db, cycle, mid2)\n            .saturating_sub(gas_cost);\n        \n        if profit1 \u003C profit2 {\n            lo = mid1;\n        } else {\n            hi = mid2;\n        }\n    }\n    \n    let optimal = (lo + hi) \u002F 2;\n    let profit = simulate_cycle(db, cycle, optimal)\n        .saturating_sub(gas_cost);\n    (optimal, profit)\n}\n```\n\n## Pipeline de ejecución paralela\n\nCon miles de oportunidades potenciales por bloque, la simulación secuencial no es suficiente. Usamos rayon para paralelizar:\n\n```rust\nuse rayon::prelude::*;\n\nfn evaluate_all_cycles(\n    db: &CacheDB\u003CEmptyDB>,\n    cycles: &[ArbCycle],\n    gas_price: U256,\n) -> Vec\u003C(ArbCycle, U256, U256)> {\n    cycles.par_iter()\n        .filter_map(|cycle| {\n            let gas_cost = estimate_gas(cycle) * gas_price;\n            let (amount, profit) = find_optimal_amount(\n                db, cycle, gas_cost\n            );\n            \n            if profit > min_profit_threshold() {\n                Some((cycle.clone(), amount, profit))\n            } else {\n                None\n            }\n        })\n        .collect()\n}\n```\n\n## CacheDB: evitar lecturas redundantes\n\nCada SLOAD que va al disco es lento. CacheDB cachea los valores leídos:\n\n```rust\nstruct CacheDB\u003CDB> {\n    accounts: HashMap\u003CAddress, AccountInfo>,\n    storage: HashMap\u003C(Address, U256), U256>,\n    underlying: DB,\n}\n```\n\nCuando simulamos múltiples ciclos que comparten pools, la caché se llena con la primera simulación y las siguientes son significativamente más rápidas.\n\n## Manejo del deadline\n\nCon 12 segundos por bloque, necesitamos un sistema de deadlines:\n\n```rust\nasync fn mev_loop(deadline: Instant) {\n    let cycles = find_cycles().await;\n    \n    let mut best = None;\n    \n    for cycle in cycles {\n        \u002F\u002F Verificar si queda tiempo\n        if Instant::now() > deadline - Duration::from_secs(2) {\n            break; \u002F\u002F Reservar 2s para envío\n        }\n        \n        let result = simulate(cycle).await;\n        if result.profit > best.map_or(U256::zero(), |b| b.profit) {\n            best = Some(result);\n        }\n    }\n    \n    if let Some(best) = best {\n        submit_bundle(best).await;\n    }\n}\n```\n\n## Métricas de rendimiento\n\n| Operación | Tiempo típico |\n|-----------|---------------|\n| Fork de estado | 1-5ms |\n| Simulación de swap | 0.5-2ms |\n| Búsqueda binaria (40 iter) | 20-80ms |\n| Evaluación de 1000 ciclos (paralela) | 200-500ms |\n| Construcción de bundle | 1-5ms |\n| Envío a builder | 10-50ms |\n\nTotal: ~300-600ms para evaluar y enviar, dejando suficiente margen dentro del deadline de 12 segundos.\n\n## Conclusión\n\nLa simulación MEV es un problema de ingeniería de rendimiento. revm proporciona una EVM rápida para forks de estado, la búsqueda ternaria encuentra montos óptimos eficientemente, y la paralelización con rayon escala la evaluación de miles de ciclos. El manejo correcto del deadline de 12 segundos es la diferencia entre un bot rentable y uno que pierde oportunidades sistemáticamente.","\u003Ch2 id=\"la-necesidad-de-velocidad\">La necesidad de velocidad\u003C\u002Fh2>\n\u003Cp>En MEV, tienes exactamente 12 segundos entre bloques para detectar oportunidades, simular transacciones, optimizar montos y enviar bundles. Un motor de simulación lento significa oportunidades perdidas.\u003C\u002Fp>\n\u003Cp>La cadena de ejecución típica:\u003C\u002Fp>\n\u003Col>\n\u003Cli>Nuevo bloque llega (t=0)\u003C\u002Fli>\n\u003Cli>Actualizar estado local (t=0.1s)\u003C\u002Fli>\n\u003Cli>Detectar oportunidades (t=0.5s)\u003C\u002Fli>\n\u003Cli>Simular y optimizar (t=1-8s)\u003C\u002Fli>\n\u003Cli>Construir y enviar bundles (t=8-10s)\u003C\u002Fli>\n\u003Cli>Buffer para propagación (t=10-12s)\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp>La simulación consume la mayor parte del tiempo. Optimizarla es la diferencia entre capturar $10K o $0.\u003C\u002Fp>\n\u003Ch2 id=\"state-forks-con-revm\">State forks con revm\u003C\u002Fh2>\n\u003Cp>revm es una implementación de la EVM en Rust, optimizada para simulación. Permite crear forks del estado de Ethereum y ejecutar transacciones hipotéticas sin afectar el estado real.\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-rust\">use revm::{EVM, db::CacheDB, primitives::*};\n\nfn simulate_swap(\n    db: &amp;CacheDB&lt;EmptyDB&gt;,\n    router: Address,\n    calldata: Bytes,\n    value: U256,\n) -&gt; Result&lt;ExecutionResult, EvmError&gt; {\n    let mut evm = EVM::new();\n    evm.database(db.clone());\n    \n    evm.env.tx.caller = searcher_address();\n    evm.env.tx.transact_to = TransactTo::Call(router);\n    evm.env.tx.data = calldata;\n    evm.env.tx.value = value;\n    evm.env.tx.gas_limit = 500_000;\n    \n    evm.transact()\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"b-squeda-binaria-para-monto-ptimo\">Búsqueda binaria para monto óptimo\u003C\u002Fh2>\n\u003Cp>Dado un ciclo de arbitraje, necesitamos encontrar el monto de entrada que maximiza el beneficio. La función beneficio es típicamente cóncava (sube, alcanza un pico, y baja), lo que permite búsqueda ternaria:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-rust\">fn find_optimal_amount(\n    db: &amp;CacheDB&lt;EmptyDB&gt;,\n    cycle: &amp;ArbCycle,\n    gas_cost: U256,\n) -&gt; (U256, U256) {\n    let mut lo = eth(0.01);  \u002F\u002F Mínimo: 0.01 ETH\n    let mut hi = eth(100.0); \u002F\u002F Máximo: 100 ETH\n    \n    for _ in 0..40 {\n        let mid1 = lo + (hi - lo) \u002F 3;\n        let mid2 = hi - (hi - lo) \u002F 3;\n        \n        let profit1 = simulate_cycle(db, cycle, mid1)\n            .saturating_sub(gas_cost);\n        let profit2 = simulate_cycle(db, cycle, mid2)\n            .saturating_sub(gas_cost);\n        \n        if profit1 &lt; profit2 {\n            lo = mid1;\n        } else {\n            hi = mid2;\n        }\n    }\n    \n    let optimal = (lo + hi) \u002F 2;\n    let profit = simulate_cycle(db, cycle, optimal)\n        .saturating_sub(gas_cost);\n    (optimal, profit)\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"pipeline-de-ejecuci-n-paralela\">Pipeline de ejecución paralela\u003C\u002Fh2>\n\u003Cp>Con miles de oportunidades potenciales por bloque, la simulación secuencial no es suficiente. Usamos rayon para paralelizar:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-rust\">use rayon::prelude::*;\n\nfn evaluate_all_cycles(\n    db: &amp;CacheDB&lt;EmptyDB&gt;,\n    cycles: &amp;[ArbCycle],\n    gas_price: U256,\n) -&gt; Vec&lt;(ArbCycle, U256, U256)&gt; {\n    cycles.par_iter()\n        .filter_map(|cycle| {\n            let gas_cost = estimate_gas(cycle) * gas_price;\n            let (amount, profit) = find_optimal_amount(\n                db, cycle, gas_cost\n            );\n            \n            if profit &gt; min_profit_threshold() {\n                Some((cycle.clone(), amount, profit))\n            } else {\n                None\n            }\n        })\n        .collect()\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"cachedb-evitar-lecturas-redundantes\">CacheDB: evitar lecturas redundantes\u003C\u002Fh2>\n\u003Cp>Cada SLOAD que va al disco es lento. CacheDB cachea los valores leídos:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-rust\">struct CacheDB&lt;DB&gt; {\n    accounts: HashMap&lt;Address, AccountInfo&gt;,\n    storage: HashMap&lt;(Address, U256), U256&gt;,\n    underlying: DB,\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Cuando simulamos múltiples ciclos que comparten pools, la caché se llena con la primera simulación y las siguientes son significativamente más rápidas.\u003C\u002Fp>\n\u003Ch2 id=\"manejo-del-deadline\">Manejo del deadline\u003C\u002Fh2>\n\u003Cp>Con 12 segundos por bloque, necesitamos un sistema de deadlines:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-rust\">async fn mev_loop(deadline: Instant) {\n    let cycles = find_cycles().await;\n    \n    let mut best = None;\n    \n    for cycle in cycles {\n        \u002F\u002F Verificar si queda tiempo\n        if Instant::now() &gt; deadline - Duration::from_secs(2) {\n            break; \u002F\u002F Reservar 2s para envío\n        }\n        \n        let result = simulate(cycle).await;\n        if result.profit &gt; best.map_or(U256::zero(), |b| b.profit) {\n            best = Some(result);\n        }\n    }\n    \n    if let Some(best) = best {\n        submit_bundle(best).await;\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"m-tricas-de-rendimiento\">Métricas de rendimiento\u003C\u002Fh2>\n\u003Ctable>\u003Cthead>\u003Ctr>\u003Cth>Operación\u003C\u002Fth>\u003Cth>Tiempo típico\u003C\u002Fth>\u003C\u002Ftr>\u003C\u002Fthead>\u003Ctbody>\n\u003Ctr>\u003Ctd>Fork de estado\u003C\u002Ftd>\u003Ctd>1-5ms\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Simulación de swap\u003C\u002Ftd>\u003Ctd>0.5-2ms\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Búsqueda binaria (40 iter)\u003C\u002Ftd>\u003Ctd>20-80ms\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Evaluación de 1000 ciclos (paralela)\u003C\u002Ftd>\u003Ctd>200-500ms\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Construcción de bundle\u003C\u002Ftd>\u003Ctd>1-5ms\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Envío a builder\u003C\u002Ftd>\u003Ctd>10-50ms\u003C\u002Ftd>\u003C\u002Ftr>\n\u003C\u002Ftbody>\u003C\u002Ftable>\n\u003Cp>Total: ~300-600ms para evaluar y enviar, dejando suficiente margen dentro del deadline de 12 segundos.\u003C\u002Fp>\n\u003Ch2 id=\"conclusi-n\">Conclusión\u003C\u002Fh2>\n\u003Cp>La simulación MEV es un problema de ingeniería de rendimiento. revm proporciona una EVM rápida para forks de estado, la búsqueda ternaria encuentra montos óptimos eficientemente, y la paralelización con rayon escala la evaluación de miles de ciclos. El manejo correcto del deadline de 12 segundos es la diferencia entre un bot rentable y uno que pierde oportunidades sistemáticamente.\u003C\u002Fp>\n","es","b0000000-0000-0000-0000-000000000001",true,"2026-03-28T10:44:31.402911Z","Deep EVM #15: Simulación MEV — Búsqueda Binaria, State Forks y Deadlines","Motor de simulación MEV con revm: state forks, búsqueda binaria para montos óptimos, ejecución paralela y manejo del deadline de 12 segundos.","MEV simulación revm",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-000000000019","MEV","mev",{"id":36,"name":37,"slug":38,"created_at":26},"c0000000-0000-0000-0000-000000000001","Rust","rust","Blockchain",[41,48,55],{"id":42,"title":43,"slug":44,"excerpt":45,"locale":12,"category_name":46,"published_at":47},"d0000000-0000-0000-0000-000000000660","WASI 0.3 y la muerte de los arranques en frío: Wasm del lado del servidor en producción","wasi-0-3-muerte-arranques-frio-wasm-servidor-produccion","WASI 0.3 se lanzó en febrero de 2026 con async I\u002FO nativo, tipos stream y soporte completo de sockets. WebAssembly del lado del servidor ahora ofrece arranques en frío en microsegundos, y cada proveedor cloud importante ofrece Wasm serverless.","DevOps","2026-03-28T10:44:48.518132Z",{"id":49,"title":50,"slug":51,"excerpt":52,"locale":12,"category_name":53,"published_at":54},"d0000000-0000-0000-0000-000000000638","El stack backend moderno 2026: Rust + PostgreSQL 18 + Wasm + eBPF","stack-backend-moderno-2026-rust-postgresql-wasm-ebpf","Cuatro tecnologias convergen para redefinir la infraestructura backend en 2026: Rust elimina la sobrecarga del garbage collection y reduce los contenedores en 3x, PostgreSQL 18 reemplaza bases de datos especializadas, WASI 0.3 ofrece arranques en frio de microsegundos para funciones serverless, y eBPF permite la observabilidad sin instrumentacion a una fraccion del costo del monitoreo tradicional.","Engineering","2026-03-28T10:44:47.080722Z",{"id":56,"title":57,"slug":58,"excerpt":59,"locale":12,"category_name":39,"published_at":60},"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":13,"name":62,"slug":63,"bio":64,"photo_url":19,"linkedin":19,"role":65,"created_at":66,"updated_at":66},"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"]