انتقل إلى المحتوى الرئيسي
بلوكتشينMar 28, 2026

Deep EVM #16: التجميع وحل التعارضات — حزم المعاملات المربحة

OS
Open Soft Team

Engineering Team

ما هو التجميع؟

عندما يجد روبوت MEV عدة فرص في نفس الكتلة، يجب تجميعها في “حزمة” (bundle) واحدة. الحزمة هي مجموعة مرتبة من المعاملات تُنفذ بشكل ذري — إما تنجح جميعها أو تفشل جميعها.

التحدي: بعض الفرص تتعارض — تلمس نفس فتحات التخزين أو تعتمد على نفس الحالة.

اكتشاف تعارضات الحالة

معاملتان تتعارضان إذا:

  1. كلتاهما تكتبان إلى نفس فتحة التخزين
  2. إحداهما تقرأ فتحة تكتبها الأخرى
struct StateAccess {
    reads: HashSet<(Address, U256)>,   // (عقد، فتحة)
    writes: HashSet<(Address, U256)>,
}

fn has_conflict(a: &StateAccess, b: &StateAccess) -> bool {
    // تعارض كتابة-كتابة
    if !a.writes.is_disjoint(&b.writes) {
        return true;
    }
    // تعارض قراءة-كتابة
    if !a.reads.is_disjoint(&b.writes) || !b.reads.is_disjoint(&a.writes) {
        return true;
    }
    false
}

جمع الوصولات من المحاكاة

revm يمكنه تتبع كل عملية تخزين أثناء المحاكاة:

fn collect_state_access(
    db: &mut InMemoryDB,
    tx: &Transaction,
) -> Result<StateAccess> {
    let mut inspector = AccessInspector::new();
    let mut evm = Evm::builder()
        .with_db(db)
        .with_external_context(&mut inspector)
        .build();
    
    evm.transact()?;
    
    Ok(StateAccess {
        reads: inspector.reads,
        writes: inspector.writes,
    })
}

رسم بياني للتعارضات

نبني رسماً بيانياً حيث كل فرصة هي عقدة وكل تعارض هو حافة:

struct ConflictGraph {
    opportunities: Vec<Opportunity>,
    conflicts: Vec<(usize, usize)>,  // أزواج المتعارضين
}

impl ConflictGraph {
    fn find_max_independent_set(&self) -> Vec<usize> {
        // NP-hard بشكل عام، لكن عادة الرسم البياني صغير
        // نستخدم خوارزمية جشعة: اختر الأعلى ربحاً أولاً
        let mut selected = Vec::new();
        let mut excluded = HashSet::new();
        
        let mut sorted: Vec<usize> = (0..self.opportunities.len()).collect();
        sorted.sort_by(|a, b| {
            self.opportunities[*b].profit
                .cmp(&self.opportunities[*a].profit)
        });
        
        for idx in sorted {
            if excluded.contains(&idx) {
                continue;
            }
            selected.push(idx);
            // استبعاد جميع المتعارضين
            for &(a, b) in &self.conflicts {
                if a == idx { excluded.insert(b); }
                if b == idx { excluded.insert(a); }
            }
        }
        selected
    }
}

ترتيب المعاملات داخل الحزمة

حتى الفرص غير المتعارضة قد يكون لها ترتيب أمثل. القواعد:

  1. المعاملات التي تؤثر على السعر أولاً — إذا كانت معاملة تغير سعراً يعتمد عليه أخرى
  2. الأقل غازاً أولاً — لتقليل تأثير فشل معاملة لاحقة
  3. ترتيب طوبولوجي — حسب تبعيات البيانات
fn order_bundle(opportunities: &[Opportunity]) -> Vec<Opportunity> {
    // بناء رسم بياني موجه للتبعيات
    let mut deps = HashMap::new();
    for (i, opp_a) in opportunities.iter().enumerate() {
        for (j, opp_b) in opportunities.iter().enumerate() {
            if i != j && depends_on(opp_b, opp_a) {
                deps.entry(j).or_insert_with(Vec::new).push(i);
            }
        }
    }
    
    // ترتيب طوبولوجي
    topological_sort(&deps, opportunities.len())
}

تقديم الحزمة لبناة الكتل

async fn submit_bundle(
    bundle: &[Transaction],
    block_number: u64,
) -> Result<BundleHash> {
    let flashbots = FlashbotsClient::new(signer);
    
    let response = flashbots
        .send_bundle(BundleRequest {
            txs: bundle.to_vec(),
            block_number: block_number + 1,
            min_timestamp: None,
            max_timestamp: None,
            reverting_tx_hashes: vec![],  // لا نسمح بأي معاملة فاشلة
        })
        .await?;
    
    Ok(response.bundle_hash)
}

مقاييس الإنتاج

المقياسالقيمة النموذجية
الفرص المكتشفة لكل كتلة50-200
التعارضات المكتشفة20-40%
الفرص في الحزمة النهائية5-15
الربح الإجمالي0.01-0.5 ETH/كتلة
معدل الإدراج15-30%

الخلاصة

التجميع وحل التعارضات هما المرحلة الأخيرة في خط أنابيب MEV. اكتشاف التعارضات عبر تتبع الوصولات، اختيار المجموعة المثلى عبر المجموعة المستقلة القصوى، والترتيب الأمثل عبر الترتيب الطوبولوجي — هذه هي المكونات التي تحول فرصاً فردية إلى حزمة مربحة.