بلوكتشينMar 28, 2026
Deep EVM #17: اختبار عقود Huff — اختبارات Fork في Foundry وتأكيدات الغاز
OS
Open Soft Team
Engineering Team
تحدي اختبار Huff
عقود Huff ليس لها ABI قياسي ولا أنواع Solidity — إنها مجرد بايتكود. كيف تكتب اختبارات لها؟ الإجابة: Foundry مع foundry-huff.
إعداد بيئة الاختبار
forge init huff-project
forge install huff-language/foundry-huff
في foundry.toml:
[profile.default]
src = "src"
test = "test"
libs = ["lib"]
ffi = true # مطلوب لـ foundry-huff
نشر عقد Huff في الاختبار
// test/TokenSwap.t.sol
import {Test} from "forge-std/Test.sol";
import {HuffDeployer} from "foundry-huff/HuffDeployer.sol";
contract TokenSwapTest is Test {
address public swapContract;
function setUp() public {
swapContract = HuffDeployer.deploy("TokenSwap");
}
function testOwner() public {
(bool success, bytes memory data) = swapContract.staticcall(
abi.encodeWithSignature("owner()")
);
assertTrue(success);
address owner = abi.decode(data, (address));
assertEq(owner, address(this));
}
}
اختبارات Fork
اختبارات Fork تنفذ ضد حالة شبكة رئيسية حقيقية:
function testSwapOnMainnetFork() public {
vm.createSelectFork("mainnet", 18_000_000);
address weth = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
address usdc = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
// إعداد الرصيد
deal(weth, address(this), 10 ether);
IERC20(weth).approve(swapContract, type(uint256).max);
// تنفيذ المبادلة
(bool success,) = swapContract.call(
abi.encodeWithSignature(
"swap(address,address,uint256)",
weth, usdc, 1 ether
)
);
assertTrue(success);
// تحقق من النتيجة
uint256 usdcBalance = IERC20(usdc).balanceOf(address(this));
assertGt(usdcBalance, 0);
}
تأكيدات الغاز
تتبع استهلاك الغاز ومنع التراجع:
function testGasConsumption() public {
uint256 gasBefore = gasleft();
(bool success,) = swapContract.call(
abi.encodeWithSignature("owner()")
);
assertTrue(success);
uint256 gasUsed = gasBefore - gasleft();
// تأكد أن الغاز لا يتجاوز الحد
assertLt(gasUsed, 5000, "owner() يستهلك غاز أكثر من المتوقع");
}
مع --gas-report:
forge test --gas-report
اختبار التراجعات
function testRevertOnZeroAmount() public {
(bool success,) = swapContract.call(
abi.encodeWithSignature(
"swap(address,address,uint256)",
address(0x1), address(0x2), 0
)
);
assertFalse(success, "يجب أن يتراجع عند المبلغ صفر");
}
function testRevertOnUnknownSelector() public {
(bool success,) = swapContract.call(
abi.encodeWithSelector(bytes4(0xdeadbeef))
);
assertFalse(success, "يجب أن يتراجع عند محدد غير معروف");
}
اختبارات الطفرات (Mutation Testing)
تأكد من أن اختباراتك تكتشف الأخطاء فعلاً عن طريق إدخال طفرات مقصودة في البايتكود وتحقق من فشل الاختبارات.
استراتيجيات التغطية
بما أن Huff ليس لها أداة تغطية مدمجة:
- اختبر كل محدد — تأكد من وجود اختبار لكل دالة
- اختبر الحالات الحدية — أصفار، قيم قصوى، عناوين صفرية
- اختبر التراجعات — كل مسار revert يجب أن يُختبر
- اختبر التفاعلات — استدعاءات متتالية، حالات مختلفة
الخلاصة
Foundry يوفر بيئة اختبار ممتازة لعقود Huff عبر foundry-huff. اختبارات Fork تضمن التوافق مع الشبكة الرئيسية، وتأكيدات الغاز تمنع التراجع في الأداء. القاعدة: إذا لم تستطع اختباره، لا تنشره.