الوراثة (Inheritance): بناء عقود ذكية متقدمة بالاعتماد على أكواد عقود سابقة

دقائق القراءة: 2

الوراثة (Inheritance): بناء عقود ذكية متقدمة بالاعتماد على أكواد عقود سابقة

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

هذا الأسلوب يشبه إلى حد كبير مبادئ البرمجة كائنية التوجه، لكنه في بيئة EVM يحمل آثاراً مباشرة على الأمان، وقابلية التدقيق، وتكلفة التنفيذ. لذلك فإن فهم الوراثة لا يقتصر على كتابة كود أنظف، بل يرتبط أيضاً ببناء بنية عقود أكثر احترافية داخل تطبيقات DApps.

إذا كنت قد اطلعت سابقاً على أساسيات لغة Solidity: أنواع البيانات والمتغيرات (State Variables) والدوال (Functions) في Solidity: من يمكنه قراءة وتعديل بيانات العقد؟ والمعدلات (Modifiers): حماية الدوال برمجياً، فستجد أن الوراثة هي الخطوة الطبيعية التالية لتحويل هذه المفاهيم إلى بنية هندسية متماسكة وقابلة لإعادة التوظيف.

ما المقصود بالوراثة في العقود الذكية؟

الوراثة تعني أن عقداً جديداً يمكنه الاستفادة من خصائص ودوال عقد آخر. العقد الأصلي يسمى عادة Base Contract أو العقد الأب، بينما يسمى العقد الجديد Derived Contract أو العقد الابن.

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

أهم فوائد الوراثة

  • تقليل تكرار الشيفرة البرمجية داخل أكثر من عقد.
  • تحسين تنظيم المشروع وتقسيم المسؤوليات.
  • تسهيل الاختبار والمراجعة الأمنية.
  • إتاحة التوسع المستقبلي دون إعادة كتابة المنطق الأساسي.
  • بناء طبقات وصول وصلاحيات بطريقة أوضح.

بنية الوراثة الأساسية في Solidity

تُستخدم الكلمة المفتاحية is للإعلان عن أن عقداً ما يرث من عقد آخر. في المثال التالي سنبني عقداً أساسياً لإدارة الملكية، ثم عقداً آخر يرثه ويستخدمه لتقييد بعض العمليات.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract Ownable {
    address public owner;

    constructor() {
        owner = msg.sender;
    }

    modifier onlyOwner() {
        require(msg.sender == owner, "Not the owner");
        _;
    }

    function transferOwnership(address newOwner) public onlyOwner {
        require(newOwner != address(0), "Invalid address");
        owner = newOwner;
    }
}

contract Treasury is Ownable {
    uint256 public totalFunds;

    function deposit() public payable {
        totalFunds += msg.value;
    }

    function withdraw(uint256 amount) public onlyOwner {
        require(amount <= address(this).balance, "Insufficient balance");
        payable(owner).transfer(amount);
        totalFunds -= amount;
    }
}

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

التحكم في الرؤية وإمكانية الوصول

عند استخدام الوراثة، من المهم فهم مستويات الرؤية مثل public وinternal وprivate. المتغير أو الدالة المعلنة كـ private لا يمكن للعقد المشتق الوصول إليها مباشرة، بينما يسمح internal بذلك.

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

إعادة تعريف الدوال باستخدام virtual و override

في الأنظمة المتقدمة، قد تحتاج إلى تعريف دالة في العقد الأساسي ثم السماح للعقود المشتقة بتعديل سلوكها. هنا نستخدم virtual في العقد الأب، وoverride في العقد الابن.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract AccessControl {
    function canExecute(address user) public view virtual returns (bool) {
        return user == msg.sender;
    }
}

contract AdminAccess is AccessControl {
    address public admin;

    constructor(address _admin) {
        admin = _admin;
    }

    function canExecute(address user) public view override returns (bool) {
        return user == admin;
    }
}

الدالة canExecute في العقد الأساسي قابلة لإعادة التعريف لأنها معلنة كـ virtual. في العقد المشتق تم تعديل المنطق بحيث تصبح الصلاحية مرتبطة بعنوان المدير بدلاً من المستدعي الحالي.

متى نستخدم هذا النمط؟

  • عند بناء عقود تمتلك قواعد مشتركة مع اختلافات بسيطة.
  • عند تصميم أطر عمل داخلية خاصة بالمشروع.
  • عند الرغبة في فصل المنطق العام عن منطق الأعمال المتخصص.

الوراثة المتعددة وترتيب الاستدعاء

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

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract Pausable {
    bool public paused;

    modifier whenNotPaused() {
        require(!paused, "Contract is paused");
        _;
    }

    function setPaused(bool _paused) public virtual {
        paused = _paused;
    }
}

contract Ownable {
    address public owner;

    constructor() {
        owner = msg.sender;
    }

    modifier onlyOwner() {
        require(msg.sender == owner, "Not owner");
        _;
    }
}

contract SecureVault is Ownable, Pausable {
    function pauseContract() public onlyOwner {
        setPaused(true);
    }

    function unpauseContract() public onlyOwner {
        setPaused(false);
    }

    function sensitiveAction() public whenNotPaused {
        // protected logic
    }
}

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

عند استخدام الوراثة المتعددة، تأكد من فهم Method Resolution Order وطريقة حسم override. الخطأ هنا قد يؤدي إلى سلوك منطقي غير متوقع حتى لو نجح العقد في الترجمة دون مشاكل.

الربط بين الوراثة والمعدلات والأخطاء والأموال

القيمة الحقيقية للوراثة تظهر عندما تُدمج مع مفاهيم أخرى سبق تناولها مثل التعامل مع الأخطاء وإرجاع الأموال: استخدام require, assert, revert واستلام وإرسال الأموال (Ether) برمجياً. يمكنك مثلاً إنشاء عقد أساسي مسؤول عن التحقق من الصلاحيات، وآخر مسؤول عن إيقاف العمليات، ثم بناء عقد مالي يرث الاثنين معاً.

كما يمكن ربط الوراثة مع الأحداث (Events) لإخطار الواجهة الأمامية عند تغيير المالك أو إيقاف العقد أو تنفيذ سحب مالي. بهذه الطريقة يصبح لديك تصميم معياري واضح، حيث تقوم كل طبقة بوظيفة محددة دون خلط المسؤوليات.

أفضل الممارسات عند تصميم عقود قابلة للتوريث

  1. اجعل العقد الأساسي صغيراً وواضح المسؤولية.
  2. استخدم internal فقط عندما تحتاج فعلاً إلى تمكين العقد المشتق من الوصول.
  3. لا تُكثر من الطبقات الوراثية لأن ذلك يصعّب التدقيق والفهم.
  4. استخدم أسماء دقيقة للدوال التي قد تُعاد كتابتها.
  5. اختبر سلوك override في جميع السيناريوهات المحتملة.

من زاوية Gas Optimization، الوراثة لا تعني دائماً تكلفة أقل في التنفيذ، لكنها تقلل كثيراً من تكرار الشيفرة على مستوى التطوير والصيانة. الأفضل هو قياس استهلاك الغاز فعلياً باستخدام Hardhat أو أدوات التحليل، مع الرجوع إلى التكاليف (Gas Fees): كيف يحسب البلوكتشين تكلفة تنفيذ الأكواد؟ وأنواع الدوال : فهم view و pure لتوفير رسوم الـ Gas.

كيف تختبر عقود الوراثة عملياً؟

بعد كتابة العقد، يمكن تجربته بسهولة عبر محرر Remix IDE: كتابة ونشر أول عقد ذكي على المتصفح مباشرة، أو عبر بيئة Hardhat إذا كنت تعمل على مشروع أكثر احترافية. اختبر على الأقل النقاط التالية:

  • هل يرث العقد المشتق جميع الدوال المتوقعة؟
  • هل تعمل المعدلات الموروثة بالشكل الصحيح؟
  • هل تؤدي إعادة تعريف الدوال إلى سلوك مقصود فعلاً؟
  • هل يتأثر منطق إرسال الأموال أو استقبالها بأي طبقة حماية موروثة؟

وإذا كنت تعمل على شبكة اختبار، فمن المفيد تجهيز البيئة مسبقاً عبر إعداد بيئة التطوير: تثبيت محفظة MetaMask والاتصال بشبكات الاختبار ثم الحصول على رصيد تجريبي من الحصول على عملات تجريبية مجانية (Faucet).

خاتمة

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

لكن في المقابل، كل طبقة وراثية إضافية تعني مسؤولية أكبر في الفهم والاختبار والمراجعة الأمنية. لذلك، المهندس المحترف لا يستخدم الوراثة لمجرد الأناقة البرمجية، بل عندما تكون هناك فائدة معمارية واضحة. هذا هو الفرق بين عقد يعمل، وعقد يُبنى ليصمد داخل منظومة Blockchain حقيقية.

7 comments

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *