[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"article-deep-evm-15-muhaakat-mev-bahth-thunai-tafriaat-hala-mawid-nihai":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},"d9000000-0000-0000-0000-000000000115","a0000000-0000-0000-0000-000000000092","Deep EVM #15: محاكاة MEV — البحث الثنائي وتفريعات الحالة والموعد النهائي 12 ثانية","deep-evm-15-muhaakat-mev-bahth-thunai-tafriaat-hala-mawid-nihai","بناء طبقة المحاكاة لروبوت MEV: تفريع حالة EVM محلياً، البحث الثنائي للمبلغ الأمثل، وإدارة الموعد النهائي 12 ثانية بين الكتل.","## لماذا المحاكاة ضرورية\n\nلا يمكنك إرسال معاملة MEV إلى بلوكتشين \"وتأمل الأفضل\". يجب أن تعرف مسبقاً:\n1. هل ستنجح المعاملة؟\n2. كم غاز ستستهلك؟\n3. ما الربح الدقيق؟\n\nالمحاكاة تنفذ المعاملة محلياً على نسخة من حالة البلوكتشين دون إرسالها فعلاً.\n\n## تفريع حالة EVM\n\nنستخدم مكتبة `revm` (Rust EVM) لإنشاء بيئة تنفيذ محلية:\n\n```rust\nuse revm::{Database, Evm, InMemoryDB};\n\nfn simulate_swap(\n    db: &mut InMemoryDB,\n    router: Address,\n    calldata: Bytes,\n) -> Result\u003CSimResult> {\n    let mut evm = Evm::builder()\n        .with_db(db)\n        .with_tx_env(|tx| {\n            tx.caller = bot_address;\n            tx.transact_to = router;\n            tx.data = calldata;\n            tx.gas_limit = 500_000;\n        })\n        .build();\n    \n    let result = evm.transact()?;\n    Ok(SimResult {\n        gas_used: result.gas_used,\n        output: result.output,\n        success: result.is_success(),\n    })\n}\n```\n\n## البحث الثنائي للمبلغ الأمثل\n\nدالة الربح ليست خطية — هناك نقطة مثلى حيث الربح أقصى. البحث الثنائي يجدها بكفاءة:\n\n```rust\nasync fn binary_search_optimal(\n    cycle: &Cycle,\n    db: &mut InMemoryDB,\n) -> Result\u003C(U256, U256)> {\n    let mut lo = parse_ether(\"0.01\")?;\n    let mut hi = parse_ether(\"100\")?;\n    let mut best_amount = lo;\n    let mut best_profit = U256::ZERO;\n    \n    for iteration in 0..48 {\n        let mid = (lo + hi) \u002F 2;\n        \n        \u002F\u002F محاكاة الدورة الكاملة\n        let db_fork = db.clone();  \u002F\u002F تفريع الحالة\n        let result = simulate_cycle(&mut db_fork, cycle, mid).await?;\n        \n        let profit = result.output.saturating_sub(mid);\n        \n        if profit > best_profit {\n            best_profit = profit;\n            best_amount = mid;\n        }\n        \n        \u002F\u002F تحديد اتجاه البحث\n        let db_fork2 = db.clone();\n        let result_plus = simulate_cycle(&mut db_fork2, cycle, mid + parse_ether(\"0.001\")?).await?;\n        let profit_plus = result_plus.output.saturating_sub(mid + parse_ether(\"0.001\")?);\n        \n        if profit_plus > profit {\n            lo = mid;\n        } else {\n            hi = mid;\n        }\n    }\n    \n    Ok((best_amount, best_profit))\n}\n```\n\n## الموعد النهائي 12 ثانية\n\nعلى إيثيريوم، كتلة جديدة كل 12 ثانية. هذا يعني:\n- اكتشاف الفرصة\n- محاكاة المعاملة\n- تحسين المبلغ\n- إرسال الحزمة\n\nكل هذا يجب أن يحدث في أقل من 12 ثانية. عملياً، الهدف أقل من 500 ميلي ثانية.\n\n```rust\nuse tokio::time::{timeout, Duration};\n\nasync fn process_opportunity(opp: Opportunity) -> Result\u003C()> {\n    let deadline = Duration::from_millis(400);\n    \n    let result = timeout(deadline, async {\n        let sim = simulate(&opp).await?;\n        if sim.profit > MIN_PROFIT {\n            let optimal = binary_search_optimal(&opp, &mut sim.db).await?;\n            submit_bundle(&opp, optimal).await?;\n        }\n        Ok::\u003C_, Error>(())\n    }).await;\n    \n    match result {\n        Ok(Ok(())) => {}\n        Ok(Err(e)) => tracing::warn!(\"فشلت المعالجة: {e}\"),\n        Err(_) => tracing::warn!(\"تجاوز الموعد النهائي\"),\n    }\n    Ok(())\n}\n```\n\n## تخبئة الحالة\n\nإعادة تحميل حالة كل مجمع من RPC مكلف. بدلاً من ذلك:\n\n1. **عند بداية الكتلة** — تحميل احتياطيات جميع المجمعات المراقبة\n2. **عند وصول معاملة معلقة** — تطبيق التغييرات محلياً\n3. **محاكاة** — استخدام الحالة المحلية المحدثة\n\n```rust\nasync fn update_reserves_on_new_block(\n    provider: &Provider,\n    pools: &mut HashMap\u003CAddress, Pool>,\n) {\n    let multicall = Multicall::new(provider);\n    for pool in pools.values() {\n        multicall.add_call(pool.address, \"getReserves()\");\n    }\n    let results = multicall.execute().await?;\n    \u002F\u002F تحديث الاحتياطيات محلياً\n}\n```\n\n## مقاييس الأداء\n\n| العملية | الوقت النموذجي |\n|---------|---------------|\n| تحميل الاحتياطيات (500 مجمع) | 50ms |\n| DFS (1000 رمز) | 10ms |\n| محاكاة دورة واحدة | 2ms |\n| بحث ثنائي (48 تكرار) | 96ms |\n| إرسال الحزمة | 20ms |\n| **الإجمالي** | **~180ms** |\n\nهذا يترك هامشاً واسعاً ضمن الموعد النهائي 12 ثانية.\n\n## الخلاصة\n\nطبقة المحاكاة هي الفرق بين روبوت MEV مربح وآخر خاسر. تفريع الحالة المحلي مع revm، البحث الثنائي للتحسين، والالتزام الصارم بالموعد النهائي هي المكونات الأساسية.","\u003Ch2 id=\"\">لماذا المحاكاة ضرورية\u003C\u002Fh2>\n\u003Cp>لا يمكنك إرسال معاملة MEV إلى بلوكتشين “وتأمل الأفضل”. يجب أن تعرف مسبقاً:\u003C\u002Fp>\n\u003Col>\n\u003Cli>هل ستنجح المعاملة؟\u003C\u002Fli>\n\u003Cli>كم غاز ستستهلك؟\u003C\u002Fli>\n\u003Cli>ما الربح الدقيق؟\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp>المحاكاة تنفذ المعاملة محلياً على نسخة من حالة البلوكتشين دون إرسالها فعلاً.\u003C\u002Fp>\n\u003Ch2 id=\"evm\">تفريع حالة EVM\u003C\u002Fh2>\n\u003Cp>نستخدم مكتبة \u003Ccode>revm\u003C\u002Fcode> (Rust EVM) لإنشاء بيئة تنفيذ محلية:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-rust\">use revm::{Database, Evm, InMemoryDB};\n\nfn simulate_swap(\n    db: &amp;mut InMemoryDB,\n    router: Address,\n    calldata: Bytes,\n) -&gt; Result&lt;SimResult&gt; {\n    let mut evm = Evm::builder()\n        .with_db(db)\n        .with_tx_env(|tx| {\n            tx.caller = bot_address;\n            tx.transact_to = router;\n            tx.data = calldata;\n            tx.gas_limit = 500_000;\n        })\n        .build();\n    \n    let result = evm.transact()?;\n    Ok(SimResult {\n        gas_used: result.gas_used,\n        output: result.output,\n        success: result.is_success(),\n    })\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"\">البحث الثنائي للمبلغ الأمثل\u003C\u002Fh2>\n\u003Cp>دالة الربح ليست خطية — هناك نقطة مثلى حيث الربح أقصى. البحث الثنائي يجدها بكفاءة:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-rust\">async fn binary_search_optimal(\n    cycle: &amp;Cycle,\n    db: &amp;mut InMemoryDB,\n) -&gt; Result&lt;(U256, U256)&gt; {\n    let mut lo = parse_ether(\"0.01\")?;\n    let mut hi = parse_ether(\"100\")?;\n    let mut best_amount = lo;\n    let mut best_profit = U256::ZERO;\n    \n    for iteration in 0..48 {\n        let mid = (lo + hi) \u002F 2;\n        \n        \u002F\u002F محاكاة الدورة الكاملة\n        let db_fork = db.clone();  \u002F\u002F تفريع الحالة\n        let result = simulate_cycle(&amp;mut db_fork, cycle, mid).await?;\n        \n        let profit = result.output.saturating_sub(mid);\n        \n        if profit &gt; best_profit {\n            best_profit = profit;\n            best_amount = mid;\n        }\n        \n        \u002F\u002F تحديد اتجاه البحث\n        let db_fork2 = db.clone();\n        let result_plus = simulate_cycle(&amp;mut db_fork2, cycle, mid + parse_ether(\"0.001\")?).await?;\n        let profit_plus = result_plus.output.saturating_sub(mid + parse_ether(\"0.001\")?);\n        \n        if profit_plus &gt; profit {\n            lo = mid;\n        } else {\n            hi = mid;\n        }\n    }\n    \n    Ok((best_amount, best_profit))\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"12\">الموعد النهائي 12 ثانية\u003C\u002Fh2>\n\u003Cp>على إيثيريوم، كتلة جديدة كل 12 ثانية. هذا يعني:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>اكتشاف الفرصة\u003C\u002Fli>\n\u003Cli>محاكاة المعاملة\u003C\u002Fli>\n\u003Cli>تحسين المبلغ\u003C\u002Fli>\n\u003Cli>إرسال الحزمة\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>كل هذا يجب أن يحدث في أقل من 12 ثانية. عملياً، الهدف أقل من 500 ميلي ثانية.\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-rust\">use tokio::time::{timeout, Duration};\n\nasync fn process_opportunity(opp: Opportunity) -&gt; Result&lt;()&gt; {\n    let deadline = Duration::from_millis(400);\n    \n    let result = timeout(deadline, async {\n        let sim = simulate(&amp;opp).await?;\n        if sim.profit &gt; MIN_PROFIT {\n            let optimal = binary_search_optimal(&amp;opp, &amp;mut sim.db).await?;\n            submit_bundle(&amp;opp, optimal).await?;\n        }\n        Ok::&lt;_, Error&gt;(())\n    }).await;\n    \n    match result {\n        Ok(Ok(())) =&gt; {}\n        Ok(Err(e)) =&gt; tracing::warn!(\"فشلت المعالجة: {e}\"),\n        Err(_) =&gt; tracing::warn!(\"تجاوز الموعد النهائي\"),\n    }\n    Ok(())\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"\">تخبئة الحالة\u003C\u002Fh2>\n\u003Cp>إعادة تحميل حالة كل مجمع من RPC مكلف. بدلاً من ذلك:\u003C\u002Fp>\n\u003Col>\n\u003Cli>\u003Cstrong>عند بداية الكتلة\u003C\u002Fstrong> — تحميل احتياطيات جميع المجمعات المراقبة\u003C\u002Fli>\n\u003Cli>\u003Cstrong>عند وصول معاملة معلقة\u003C\u002Fstrong> — تطبيق التغييرات محلياً\u003C\u002Fli>\n\u003Cli>\u003Cstrong>محاكاة\u003C\u002Fstrong> — استخدام الحالة المحلية المحدثة\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cpre>\u003Ccode class=\"language-rust\">async fn update_reserves_on_new_block(\n    provider: &amp;Provider,\n    pools: &amp;mut HashMap&lt;Address, Pool&gt;,\n) {\n    let multicall = Multicall::new(provider);\n    for pool in pools.values() {\n        multicall.add_call(pool.address, \"getReserves()\");\n    }\n    let results = multicall.execute().await?;\n    \u002F\u002F تحديث الاحتياطيات محلياً\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"\">مقاييس الأداء\u003C\u002Fh2>\n\u003Ctable>\u003Cthead>\u003Ctr>\u003Cth>العملية\u003C\u002Fth>\u003Cth>الوقت النموذجي\u003C\u002Fth>\u003C\u002Ftr>\u003C\u002Fthead>\u003Ctbody>\n\u003Ctr>\u003Ctd>تحميل الاحتياطيات (500 مجمع)\u003C\u002Ftd>\u003Ctd>50ms\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>DFS (1000 رمز)\u003C\u002Ftd>\u003Ctd>10ms\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>محاكاة دورة واحدة\u003C\u002Ftd>\u003Ctd>2ms\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>بحث ثنائي (48 تكرار)\u003C\u002Ftd>\u003Ctd>96ms\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>إرسال الحزمة\u003C\u002Ftd>\u003Ctd>20ms\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>\u003Cstrong>الإجمالي\u003C\u002Fstrong>\u003C\u002Ftd>\u003Ctd>\u003Cstrong>~180ms\u003C\u002Fstrong>\u003C\u002Ftd>\u003C\u002Ftr>\n\u003C\u002Ftbody>\u003C\u002Ftable>\n\u003Cp>هذا يترك هامشاً واسعاً ضمن الموعد النهائي 12 ثانية.\u003C\u002Fp>\n\u003Ch2 id=\"\">الخلاصة\u003C\u002Fh2>\n\u003Cp>طبقة المحاكاة هي الفرق بين روبوت MEV مربح وآخر خاسر. تفريع الحالة المحلي مع revm، البحث الثنائي للتحسين، والالتزام الصارم بالموعد النهائي هي المكونات الأساسية.\u003C\u002Fp>\n","ar","b0000000-0000-0000-0000-000000000001",true,"2026-03-28T10:44:32.499053Z","Deep EVM #15: محاكاة MEV — البحث الثنائي وتفريعات الحالة والمواعيد النهائية","محاكاة MEV: تفريع حالة EVM مع revm، البحث الثنائي للمبلغ الأمثل، إدارة الموعد النهائي 12 ثانية.","محاكاة MEV Rust EVM",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","بلوكتشين",[41,48,55],{"id":42,"title":43,"slug":44,"excerpt":45,"locale":12,"category_name":46,"published_at":47},"d0000000-0000-0000-0000-000000000663","WASI 0.3 ونهاية البدء البارد: Wasm من جانب الخادم في الإنتاج","wasi-0-3-nihayat-albad-albarid-wasm-janib-alkhadim-intaj","صدر WASI 0.3 في فبراير 2026 مع async I\u002FO أصلي وأنواع stream ودعم كامل للمقابس. يوفر WebAssembly من جانب الخادم الآن بدءاً بارداً بالميكروثانية، وكل مزود سحابي رئيسي يقدم Wasm بدون خادم.","DevOps","2026-03-28T10:44:48.694830Z",{"id":49,"title":50,"slug":51,"excerpt":52,"locale":12,"category_name":53,"published_at":54},"d0000000-0000-0000-0000-000000000641","حزمة الخلفية الحديثة 2026: Rust + PostgreSQL 18 + Wasm + eBPF","huzmat-alkhalfiyya-alhaditha-2026-rust-postgresql-wasm-ebpf","أربع تقنيات تتقارب لإعادة تعريف البنية التحتية للخلفية في 2026: Rust يزيل عبء جمع القمامة ويقلل الحاويات بمقدار 3 أضعاف، PostgreSQL 18 يحل محل قواعد البيانات المتخصصة، WASI 0.3 يوفر بدء تشغيل بالميكروثانية للدوال بدون خادم، وeBPF يمكّن المراقبة بدون أدوات بجزء بسيط من تكلفة المراقبة التقليدية.","Engineering","2026-03-28T10:44:47.292897Z",{"id":56,"title":57,"slug":58,"excerpt":59,"locale":12,"category_name":39,"published_at":60},"d0000000-0000-0000-0000-000000000617","طبقة التشغيل البيني لـ Ethereum: كيف تصبح 55+ سلسلة L2 سلسلة واحدة","tabaqat-altashghil-albaini-ethereum-55-l2-silsila-wahida","يملك Ethereum اكثر من 55 rollup من الطبقة الثانية، مما يجزئ السيولة وتجربة المستخدم. طبقة التشغيل البيني لـ Ethereum — الجمع بين الرسائل عبر الـ rollups والمتسلسلات المشتركة والـ based rollups — تهدف الى توحيدها في شبكة قابلة للتركيب واحدة.","2026-03-28T10:44:45.626845Z",{"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"]