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

Deep EVM #3: فهم الغاز — لماذا يكلف عقدك ما يكلفه

OS
Open Soft Team

Engineering Team

اقتصاديات الغاز في EVM

الغاز هو وحدة القياس للجهد الحسابي في إيثيريوم. كل كود تشغيل في EVM له تكلفة غاز محددة تعكس الموارد المطلوبة لتنفيذه: وقت المعالج، استخدام الذاكرة، عمليات القرص (التخزين)، وعرض النطاق الترددي للشبكة.

الغرض المزدوج للغاز:

  1. منع الإساءة — بدون الغاز، يمكن لأي شخص إرسال حلقة لانهائية تعطل جميع العقد.
  2. تسعير الموارد — العمليات الأكثر كثافة (مثل كتابة التخزين) تكلف أكثر من العمليات الخفيفة (مثل الجمع).

تسعير EIP-1559

قبل EIP-1559 (ترقية لندن، أغسطس 2021)، كان تسعير الغاز مزاداً بسيطاً من السعر الأول. بعد EIP-1559:

  • الرسم الأساسي (baseFee) — يُحدد بالبروتوكول، يُحرق (لا يذهب للمعدنين). يزداد عندما تكون الكتل أكثر من 50% ممتلئة، وينخفض عندما تكون أقل.
  • رسم الأولوية (tip) — يذهب للمعدن/المدقق. يحفز إدراج معاملتك.
  • الحد الأقصى للرسم (maxFeePerGas) — الحد الأعلى الذي ترغب في دفعه.
التكلفة الفعلية = gasUsed × (baseFee + priorityFee)
الاسترداد = (maxFeePerGas - baseFee - priorityFee) × gasUsed

لماذا بعض أكواد التشغيل أغلى

أكواد التشغيل مُسعرة وفقاً لتأثيرها على موارد العقدة:

عمليات التخزين (SLOAD/SSTORE)

التخزين يعيش على القرص في شجرة Merkle Patricia. كل قراءة تتطلب اجتياز الشجرة (O(log n))، وكل كتابة تتطلب تحديث الشجرة وإنشاء إثبات جديد. لهذا تكلف SSTORE ما يصل إلى 22100 غاز.

عمليات الذاكرة

الذاكرة خطية ومحلية لسياق الاستدعاء. MLOAD وMSTORE رخيصتان (3 غاز) لأنهما مجرد قراءة/كتابة في مصفوفة RAM. لكن تكلفة التوسيع التربيعية تمنع تخصيص كميات ضخمة.

عمليات التشفير

  • SHA3/KECCAK256 — 30 غاز + 6 لكل 32 بايت من المدخلات
  • عقود مترجمة مسبقاً — ecRecover (3000)، SHA256 (60)، التضاعف على المنحنى الإهليلجي (6000)

أنماط توفير الغاز

1. تعبئة التخزين

يخصص EVM 32 بايت لكل فتحة تخزين. إذا كان لديك متغيرات أصغر، يمكنك تعبئتها في فتحة واحدة:

// سيء: فتحتان (44200 غاز للتهيئة)
contract Bad {
    uint128 public a; // فتحة 0
    uint256 public b; // فتحة 1
    uint128 public c; // فتحة 2
}

// جيد: فتحتان (a وc في فتحة واحدة)
contract Good {
    uint128 public a; // فتحة 0 (نصف)
    uint128 public c; // فتحة 0 (نصف)
    uint256 public b; // فتحة 1
}

2. استخدام الأحداث بدلاً من التخزين

إذا كنت تحتاج فقط لتسجيل البيانات (وليس قراءتها على السلسلة)، استخدم الأحداث:

// SSTORE: 22100 غاز
storage_var = value;

// LOG: ~375 + 8 × len غاز
emit ValueUpdated(value);

3. عمليات قصيرة

استخدم الأنماط القصيرة للتحقق من المتطلبات:

// جيد: يفشل مبكراً
require(condition, "Error");
// يتم تنفيذ المنطق المكلف فقط إذا تحقق الشرط
expensiveOperation();

4. الحسابات خارج السلسلة

انقل ما يمكنك خارج السلسلة. احسب القيمة خارج السلسلة ومرر الإثبات فقط:

// بدلاً من حساب جذر Merkle على السلسلة
// تحقق فقط من الإثبات
function verify(bytes32[] calldata proof, bytes32 leaf) external view {
    require(MerkleProof.verify(proof, root, leaf), "Invalid");
}

استردادات الغاز

بعد EIP-3529، الحد الأقصى للاسترداد هو 20% من إجمالي الغاز المستخدم. المصدر الرئيسي المتبقي:

  • تصفير فتحة التخزين (SSTORE من غير صفري إلى 0): استرداد 4800 غاز

هذا يعني أن “تنظيف” التخزين لا يزال له قيمة اقتصادية، لكن لا يمكنك الحصول على استرداد أكبر من 20% من الغاز المستهلك.

أدوات تحليل الغاز

  • forge test –gas-report — تقرير غاز لكل دالة في اختبارات Foundry
  • hardhat-gas-reporter — مكوّن Hardhat لتقارير الغاز
  • solc –asm — إخراج التجميع لرؤية أكواد التشغيل المُولدة
  • tenderly.co — تتبع المعاملات مع تفصيل الغاز لكل كود تشغيل

الخلاصة

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