لوحة معلومات ضمان الجودة لمراقبة حالة العقد الذكي  تناولت المشاركة السابقة تنفيذًا شاملاً: عقد رمزي بسيط، إعادة بناء الحالة خارج السلسلةلوحة معلومات ضمان الجودة لمراقبة حالة العقد الذكي  تناولت المشاركة السابقة تنفيذًا شاملاً: عقد رمزي بسيط، إعادة بناء الحالة خارج السلسلة

حالة حساب الإيثريوم: خط أنابيب ضمان الجودة لتوكن بسيط

2026/04/09 13:48
8 دقيقة قراءة
للحصول على ملاحظات أو استفسارات بشأن هذا المحتوى، يرجى التواصل معنا على crypto.news@mexc.com
لوحة معلومات ضمان الجودة لمراقبة حالة العقد الذكي

تناولت المشاركة السابقة التنفيذ الشامل من البداية إلى النهاية: عقد توكن بسيط، وإعادة بناء الحالة خارج السلسلة، وواجهة أمامية React — من `()mint` إلى MetaMask. تبدأ هذه المشاركة من حيث توقفت تلك: كيف تضمن جودة شيء مثل هذا؟

لست مهندس بلوكتشين (بعد)، ولكن أنماط ضمان الجودة تنتقل بشكل جيد عبر المجالات، واستعارة ما ينجح بالفعل في مكان آخر هو الطريقة التي أتعلم بها بشكل أسرع.

العقد يقوم بثلاثة أشياء فقط: `mint`، `transfer`، و `burn`، لكن حتى هذا يكفي لممارسة سلسلة أدوات ضمان الجودة الكاملة: التحليل الثابت، اختبار الطفرات، تحليل استهلاك الغاز، التحقق الرسمي.

الكود موجود في `egpivo/ethereum-account-state`.

هرم ضمان جودة البلوكتشين: من التحليل الثابت في القاعدة إلى التحقق الرسمي في القمة

ما بدأنا به

قبل إضافة أي شيء جديد، كان لدى المشروع بالفعل:

  • 21 اختبار وحدة Foundry تغطي كل انتقال حالة (النجاح، الارتداد عند الإدخال غير القانوني، إصدار الحدث)
  • 3 اختبارات ثابتة عبر `TokenHandler` الذي يشغل تسلسلات عشوائية من `mint`/`transfer`/`burn` على 10 فاعلين (128 ألف استدعاء لكل منهم)
  • اختبارات Fuzz تفحص `sum(balances) == totalSupply` للمبالغ العشوائية
  • اختبارات نطاق TypeScript (Vitest) تعكس آلة الحالة على السلسلة
  • CI: تجميع، اختبار، فحص (Prettier + solhint)

نجحت جميع الاختبارات. بدا التغطية جيدة. فلماذا نهتم بالمزيد؟

لأن "جميع الاختبارات تمر" لا يعني "تم اكتشاف جميع الأخطاء". تغطية 100٪ من السطور لا يزال بإمكانها تفويت خطأ حقيقي إذا لم يتحقق أي تأكيد من الشيء الصحيح.

المرحلة 1: التحليل الثابت للعقد الذكي والتغطية

Slither

Slither (Trail of Bits) يكتشف المشكلات غير المرئية للاختبارات: إعادة الدخول، القيم المرجعة غير المحققة، عدم تطابق الواجهة.

./scripts/run-qa.sh slither

النتيجة: اكتشاف متوسط واحد: `erc20-interface`: `()transfer` لا ترجع `bool`.

هذا متوقع. العقد ليس ERC20 كاملاً عمداً: إنه آلة حالة تعليمية. لكن الاكتشاف ليس أكاديمياً:

إذا قام شخص ما لاحقاً باستيراد هذا التوكن إلى بروتوكول يتوقع ERC20، فإن عدم تطابق الواجهة سيفشل بصمت. يشير Slither إليه الآن حتى يكون القرار واعياً.

التغطية

./scripts/run-qa.sh coverage نتيجة التغطية.

دالة واحدة غير مغطاة: `()BalanceLib.gt`. سنعود إلى هذا.

مخرجات تغطية forge: نجح 24 اختبار، جدول تغطية Token.sol

لقطات الغاز

./scripts/run-qa.sh gas

تكاليف الغاز الأساسية للعمليات الثلاث:

الغاز من حيث العمليات

في التشغيلات اللاحقة، `forge snapshot — diff` يقارن مع الخط الأساسي. تراجع بنسبة 20٪ في الغاز في `()transfer` هو تكلفة حقيقية على كل مستخدم — اكتشافه قبل الدمج رخيص.

المرحلة 2: اختبار الطفرات والتحقق الرسمي

اختبار الطفرات (Gambit)

هنا أصبحت الأمور مثيرة للاهتمام. Gambit (Certora) يولد المتحولين: نسخ من `Token.sol` بأخطاء صغيرة متعمدة (`+=` إلى `-=`، `>=` إلى `>`، شروط منفية). يشغل خط الأنابيب مجموعة الاختبارات الكاملة ضد كل متحول. إذا نجا متحول (لا تزال جميع الاختبارات تمر)، فهذه فجوة اختبار ملموسة.

./scripts/run-qa.sh mutation

النتيجة: درجة طفرة 97.0٪ — 32 قتيل، 1 نجا من 33 متحول.

سجل مخرجات Gambit يعرض كل متحول وما تغير. بعض الأمثلة:

تم توليد المتحول #7: BinaryOpMutation — Token.sol:168
totalSupply = totalSupply.add(amountBalance) → totalSupply = totalSupply.sub(amountBalance)
قُتل بواسطة test_Mint_Success
تم توليد المتحول #19: RelationalOpMutation — Token.sol:196
if (!fromBalance.gte(amountBalance)) → if (fromBalance.gte(amountBalance))
قُتل بواسطة test_Transfer_Success
تم توليد المتحول #28: SwapArgumentsMutation — Token.sol:81
return Balance.unwrap(a) > Balance.unwrap(b) → return Balance.unwrap(b) > Balance.unwrap(a)
نجا ← لم يكتشفه أي اختبار اختبار طفرة Gambit: 32 قتيل، 1 نجا، درجة طفرة 97.0٪

المتحول الناجي بدّل `a > b` إلى `b > a` في `()BalanceLib.gt`. لم يكتشفه أي اختبار لأن `()gt` هو كود ميت. لا يتم استدعاؤه أبداً في أي مكان في `Token.sol`.

أشارت التغطية إلى 91.67٪ من الدوال لكنها لم تستطع تفسير الفجوة. اختبار الطفرات فعل: `()gt` هو كود ميت، لا شيء يستدعيه، ولن يلاحظ أحد إذا كان خاطئاً.

الكود الميت أو غير المحمي في العقود الذكية له سابقة حقيقية.

لم تكن الدالة مقصودة لتكون قابلة للاستدعاء، لكن لم يختبر أحد هذا الافتراض. `()gt` الخاص بنا غير ضار بالمقارنة، لكن النمط هو نفسه: الكود الموجود لكن لم يتم تنفيذه أبداً هو كود لا أحد يراقبه.

التحقق الرسمي (Halmos)

Halmos (a16z) يستدل حول جميع المدخلات الممكنة بشكل رمزي. حيث تأخذ اختبارات fuzz عينات من قيم عشوائية وتأمل في الوصول إلى حالات حافة، يثبت Halmos الخصائص بشكل شامل.

./scripts/run-qa.sh halmos

النتيجة: نجح 9/9 اختبارات رمزية — تم إثبات جميع الخصائص لجميع المدخلات.

الخصائص التي تم التحقق منها:

الخصائص التي تم التحقق منها

ملاحظة عملية واحدة: Halmos 0.3.3 لا يدعم `()vm.expectRevert`، لذا لم أتمكن من كتابة اختبارات الارتداد بطريقة Foundry العادية. الحل البديل هو نمط try/catch — إذا نجح الاستدعاء عندما يجب أن يرتد، `assert(false)` يفشل الإثبات:

function check_mint_reverts_on_zero_address(uint256 amount) public {
vm.assume(amount > 0);
try token.mint(address(0), amount) {
assert(false); // لا ينبغي الوصول إلى هنا
} catch {
// ارتداد متوقع - Halmos يثبت أن هذا المسار يتم اتخاذه دائماً
}
}

ليس الأجمل، لكنه يعمل — Halmos لا يزال يثبت الخاصية لجميع المدخلات. هذا هو نوع الأشياء التي تكتشفها فقط بتشغيل الأداة فعلياً.

للسياق حول سبب أهمية التحقق الرسمي:

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

مخرجات Halmos: نجح 9 اختبارات، 0 فشل، نتائج الاختبار الرمزي

ملف الاختبار هو `contracts/test/Token.halmos.t.sol`.

المرحلة 3: اختبار الخاصية عبر الطبقات

تحتوي بنية المشاركة الأولى على طبقة نطاق TypeScript تعكس آلة الحالة على السلسلة. تختبر هذه المرحلة ما إذا كانت الاثنتان تتفقان فعلاً.

الاختبار القائم على الخاصية مع fast-check

أضفت اختبارات خاصية fast-check لطبقة نطاق TypeScript، تعكس ما يفعله fuzzer الخاص بـ Foundry لـ Solidity:

npm test - tests/unit/property.test.ts

النتيجة: نجح 9/9 اختبارات خاصية بعد إصلاح خطأ حقيقي.

الخصائص التي تم اختبارها:

  • `Balance`: التبديلية، الترابطية، الهوية، العكس، اتساق المقارنة
  • `Token`: ثابت `sum(balances) == totalSupply` تحت تسلسلات عمليات عشوائية (200 تشغيل، 50 عملية لكل منها)
  • `Token`: `totalSupply` غير سالب بعد تسلسلات عشوائية
  • `mint` ينجح دائماً للمدخلات الصالحة
  • `transfer` يحافظ على `totalSupply`

الخطأ الذي وجده fast-check

وجد fast-check خطأ اتساق حقيقي عبر الطبقات في `()Token.ts` `transfer`. كان المثال المضاد المنكمش واضحاً على الفور:

فشلت الخاصية بعد 3 اختبارات
انكمشت مرتين
مثال مضاد: transfer(from=0xaaa…, to=0xaaa…, amount=1n)
→ from == to (تحويل ذاتي)
→ ()verifyInvariant أرجع false

التحويل الذاتي (`from == to`) كسر ثابت `sum(balances) == totalSupply`. تمت قراءة `toBalance` قبل تحديث `fromBalance`، لذلك عندما `from == to`، القيمة القديمة استبدلت الخصم:

// قبل (به خطأ)
const fromBalance = this.getBalance(from);
const toBalance = this.getBalance(to); // ← قديمة عندما from == to
this.accounts.set(from.getValue(), fromBalance.subtract(amount));
this.accounts.set(to.getValue(), toBalance.add(amount)); // ← يستبدل الطرح

الإصلاح: اقرأ `toBalance` بعد كتابة `fromBalance`، مطابقاً دلالات تخزين Solidity:

// بعد (تم إصلاحه)
const fromBalance = this.getBalance(from);
this.accounts.set(from.getValue(), fromBalance.subtract(amount));
const toBalance = this.getBalance(to); // ← الآن يقرأ القيمة المحدثة
this.accounts.set(to.getValue(), toBalance.add(amount));

العقد Solidity لم يتأثر: يعيد قراءة التخزين بعد كل كتابة. لكن مرآة TypeScript كان لها اعتماد ترتيب دقيق لم يغطيه أي اختبار وحدة موجود.

عدم تطابق عبر الطبقات على نطاق أكبر كان كارثياً.

خطأ التحويل الذاتي لدينا لم يكن ليخسر أي شخص أموالاً، لكن وضع الفشل هو نفسه هيكلياً: طبقتان من المفترض أن تتفقا، لا تتفقان.

المخاطر التي واجهناها على طول الطريق

تشغيل أدوات ضمان الجودة على مشروع موجود ليس مجرد "تثبيت وتشغيل". انكسرت بعض الأشياء قبل أن تعمل:

  • تغطية 0٪ لأن `foundry.toml` لم يكن لديه مسار اختبار: أرجع أول تشغيل لـ `forge coverage` 0٪ عبر اللوحة. اتضح أن `foundry.toml` لم يحدد `test = "contracts/test"` أو `script = "contracts/script"`، لذلك لم يكن Forge يكتشف أي اختبارات. نجح أمر التغطية بصمت — لم يكن لديه شيء لتغطيته. كان هذا الفشل الأكثر تضليلاً: تشغيل أخضر بدون مخرجات مفيدة.
  • استيراد `InvariantTest` اختفى في forge-std v1.14.0: استورد `Invariant.t.sol` `InvariantTest` من `forge-std`، والذي تمت إزالته في إصدار حديث. فشل التجميع بخطأ غامض "لم يتم العثور على الرمز". كان الإصلاح هو إسقاط الاستيراد — `Test` وحده كافٍ لاختبار ثابت Foundry الآن.
  • `()uint256(token.totalSupply)` مقابل `()Balance.unwrap`: كانت الاختبارات تستخدم تحويلاً صريحاً لاستخراج `uint256` الأساسي من نوع `Balance` المعرف من قبل المستخدم. تم تجميعها، لكنها التعبير الخاطئ — `()Balance.unwrap(token.totalSupply)` هو ما صُمم له نظام UDVT. طُبق عبر `Token.t.sol`، `Invariant.t.sol`، و `DeploySepolia.s.sol`.

تصميم خط الأنابيب

كل شيء يعمل من خلال نصين برمجيين:

  • `scripts/setup-qa-tools.sh`: يثبت Slither وHalmos وGambit (متماثل القدرة)
  • `scripts/run-qa.sh`: يشغل الفحوصات، يحفظ النتائج المؤرخة في `qa-results/`

./scripts/run-qa.sh slither gas # فقط التحليل الثابت + الغاز
./scripts/run-qa.sh mutation # فقط اختبار الطفرات
./scripts/run-qa.sh all # كل شيء

ليست كل فحص سريعاً. يعمل Slither والتغطية على كل التزام. اختبار الطفرات وHalmos أبطأ — أكثر ملاءمة للتشغيلات الأسبوعية أو قبل الإصدار.

الملخص

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

خمس طبقات لضمان الجودة، كل منها يكتشف فئة مختلفة من المشاكل.

شرح الطبقات

أعطى Gambit وfast-check أكثر النتائج قابلية للتنفيذ في هذه الجولة.

خط أنابيب CI

تم توصيل فحوصات ضمان الجودة الآن في GitHub Actions كخط أنابيب من ست مراحل:

خط أنابيب CI: Build & Lint يتفرع إلى مراحل Test وCoverage وGas وSlither وAudit

خط أنابيب GitHub Actions: Build & Lint يتحكم في جميع المراحل اللاحقة.

شرح المراحل

المراجع

  • مصدر Ethereum Account State: [github.com/egpivo/ethereum-account-state](https://github.com/egpivo/ethereum-account-state)
  • المشاركة السابقة: Ethereum Account State
  • Slither: github.com/crytic/slither
  • Gambit: github.com/Certora/gambit
  • Halmos: github.com/a16z/halmos
  • fast-check: github.com/dubzzz/fast-check
  • Foundry: getfoundry.sh

ملاحظات

  • تم تكييف هذه المشاركة من منشور مدونتي الأصلي.

تم نشر Ethereum Account State: QA Pipeline for a Minimal Token في الأصل في Coinmonks على Medium، حيث يواصل الناس المحادثة من خلال تسليط الضوء والرد على هذه القصة.

إخلاء مسؤولية: المقالات المُعاد نشرها على هذا الموقع مستقاة من منصات عامة، وهي مُقدمة لأغراض إعلامية فقط. لا تُظهِر بالضرورة آراء MEXC. جميع الحقوق محفوظة لمؤلفيها الأصليين. إذا كنت تعتقد أن أي محتوى ينتهك حقوق جهات خارجية، يُرجى التواصل عبر البريد الإلكتروني crypto.news@mexc.com لإزالته. لا تقدم MEXC أي ضمانات بشأن دقة المحتوى أو اكتماله أو حداثته، وليست مسؤولة عن أي إجراءات تُتخذ بناءً على المعلومات المُقدمة. لا يُمثل المحتوى نصيحة مالية أو قانونية أو مهنية أخرى، ولا يُعتبر توصية أو تأييدًا من MEXC.

قد يعجبك أيضاً

توقعات سعر USD/CAD: يحافظ على المتوسط المتحرك الأسي لمدة 20 يومًا في العد التنازلي لمحادثات الولايات المتحدة وإيران

توقعات سعر USD/CAD: يحافظ على المتوسط المتحرك الأسي لمدة 20 يومًا في العد التنازلي لمحادثات الولايات المتحدة وإيران

ظهر المنشور توقعات سعر USD/CAD: يحافظ على المتوسط المتحرك الأسي لمدة 20 يومًا في العد التنازلي لمحادثات الولايات المتحدة وإيران على BitcoinEthereumNews.com. يتداول زوج USD/CAD بارتفاع طفيف حول
مشاركة
BitcoinEthereumNews2026/04/09 15:32
الدولار الأمريكي: التركيز على التضخم ومخاطر التوترات في الاحتياطي الفيدرالي – Commerzbank

الدولار الأمريكي: التركيز على التضخم ومخاطر التوترات في الاحتياطي الفيدرالي – Commerzbank

ظهر منشور الدولار الأمريكي: التركيز على التضخم ومخاطر التوترات مع المجلس الاحتياطي الاتحادي – كومرتس بنك على BitcoinEthereumNews.com. تجادل أنتيه برايفكه من كومرتس بنك بأن وقف إطلاق النار الإيراني
مشاركة
BitcoinEthereumNews2026/04/09 15:20
سهم نتفليكس (NFLX)؛ مكاسب مع ترقية جولدمان وموجة الشراء ترفع المعنويات

سهم نتفليكس (NFLX)؛ مكاسب مع ترقية جولدمان وموجة الشراء ترفع المعنويات

الملخص؛ ارتفع سهم Netflix بشكل طفيف حيث زاد المستثمرون المؤسسيون من حيازاتهم قبل أرباح الربع الأول وعزز تصنيف Goldman الثقة. Goldman Sachs Buy
مشاركة
Coincentral2026/04/09 15:40

PRL بقيمة 30,000$ + 15,000 USDT

PRL بقيمة 30,000$ + 15,000 USDTPRL بقيمة 30,000$ + 15,000 USDT

أودع وتداول PRL لزيادة مكافآتك!