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

Deep EVM #19: الاختبار القائم على الخصائص للعقود الذكية — الاختبار العشوائي مع Foundry

OS
Open Soft Team

Engineering Team

لماذا اختبارات الوحدة ليست كافية

اختبارات الوحدة تتحقق من سيناريوهات محددة. لكن العقود الذكية تواجه مدخلات عشوائية من مهاجمين محتملين. الاختبار القائم على الخصائص يولّد مئات الآلاف من المدخلات العشوائية ويتحقق من أن خصائص معينة تبقى صحيحة دائماً.

الاختبار العشوائي (Fuzzing) مع Foundry

Foundry يدعم الاختبار العشوائي بشكل أصلي. أي دالة اختبار تأخذ معاملات ستُستدعى تلقائياً بقيم عشوائية:

function testFuzz_transferNeverExceedsBalance(
    address from,
    address to,
    uint256 amount
) public {
    vm.assume(from != address(0) && to != address(0));
    vm.assume(amount > 0 && amount <= 1000 ether);
    
    deal(address(token), from, amount);
    
    vm.prank(from);
    token.transfer(to, amount);
    
    // الخاصية: الرصيد لا يتجاوز المبلغ الأصلي
    assertLe(token.balanceOf(to), amount);
    assertEq(token.balanceOf(from), 0);
}

اختبارات الثوابت (Invariant Testing)

أقوى شكل من الاختبار العشوائي: Foundry يستدعي عدة دوال بترتيب عشوائي ويتحقق من الثوابت بعد كل استدعاء:

contract VaultInvariantTest is Test {
    Vault vault;
    
    function setUp() public {
        vault = new Vault();
        targetContract(address(vault));
    }
    
    function invariant_totalAssetsMatchesSum() public {
        uint256 total = vault.totalAssets();
        uint256 sum = 0;
        for (uint i = 0; i < users.length; i++) {
            sum += vault.balanceOf(users[i]);
        }
        assertEq(total, sum, "إجمالي الأصول لا يتطابق مع المجموع");
    }
    
    function invariant_noNegativeBalance() public {
        for (uint i = 0; i < users.length; i++) {
            assertGe(vault.balanceOf(users[i]), 0);
        }
    }
}

تكوين الاختبار العشوائي

# foundry.toml
[fuzz]
runs = 10000           # عدد التكرارات
max_test_rejects = 500 # الحد الأقصى للرفض بواسطة vm.assume
seed = "0x1234"        # بذرة قابلة لإعادة الإنتاج

[invariant]
runs = 256
depth = 100            # عدد الاستدعاءات لكل تشغيل

أمثلة على خصائص

  1. الحفظ — إجمالي العرض لا يتغير بعد التحويل
  2. أحادية الاتجاه — السحب يقلل الرصيد دائماً
  3. الحدود — لا قيمة تتجاوز MAX_UINT256
  4. التناظر — الإيداع ثم السحب يُرجع المبلغ الأصلي
  5. عدم التراجع — التشغيل العادي لا يسبب revert

الخلاصة

الاختبار القائم على الخصائص هو أقوى أداة لاكتشاف الثغرات قبل النشر. إنه يكتشف الحالات الحدية التي لا يفكر فيها المطور. استخدم الاختبار العشوائي لكل عقد واختبارات الثوابت للبروتوكولات المعقدة.