الدوال (Functions) في Solidity: من يمكنه قراءة وتعديل بيانات العقد؟

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

الدوال في Solidity: من يمكنه قراءة وتعديل بيانات العقد؟

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

فهم الفرق بين صلاحيات الدوال في Smart Contracts ليس أمراً شكلياً، بل هو أساس في الأمان، كفاءة استهلاك Gas Fees، وتجربة التكامل مع الواجهات الأمامية عبر Ethers.js أو أدوات التطوير مثل Hardhat وRemix IDE. وإذا كنت قد راجعت مسبقاً أساسيات لغة Solidity: أنواع البيانات والمتغيرات (State Variables)، فهذه المرحلة هي الامتداد الطبيعي لفهم كيف تتعامل الدوال مع تلك المتغيرات.

ما المقصود بالدالة في Solidity؟

الدالة هي كتلة منطقية قابلة للاستدعاء تنفذ مجموعة تعليمات داخل العقد الذكي. يمكن أن تستقبل مدخلات، وتعيد قيماً، وتتعامل مع متغيرات العقد أو معطيات الذاكرة المؤقتة. عند استدعاء الدالة من مستخدم أو عقد آخر، تُترجم تعليماتها إلى أوامر قابلة للتنفيذ داخل EVM.

التمييز الأهم هنا هو بين نوعين من المسؤوليات:

  • دوال تقرأ حالة العقد دون تعديلها.
  • دوال تغيّر حالة العقد عبر الكتابة إلى storage.

هذا الفرق يحدد هل سيتم إنشاء معاملة على الشبكة، وهل سيدفع المستخدم رسوماً، وهل يمكن استدعاء الدالة محلياً من دون تغيير حالة البلوكتشين.

محددات الوصول: من يمكنه استدعاء الدالة؟

في Solidity توجد محددات وصول تحدد من أين يمكن استدعاء الدالة. أشهرها:

  • public: يمكن استدعاؤها من داخل العقد وخارجه.
  • external: تُستدعى من خارج العقد أساساً، وغالباً تكون مناسبة للواجهات العامة.
  • internal: تُستخدم داخل العقد نفسه أو العقود المشتقة منه.
  • private: لا يمكن الوصول إليها إلا من داخل نفس العقد.

هذه المحددات لا تعني وحدها من يملك صلاحية التعديل الفعلي، بل تعني نطاق الاستدعاء البرمجي. أما التحكم الحقيقي في “من يحق له التعديل” فيتم غالباً بإضافة شروط مثل التحقق من msg.sender.

مثال عملي على دوال القراءة والتعديل

pragma solidity ^0.8.20;

contract UserProfile {
    address public owner;
    string private username;
    uint256 private age;

    constructor(string memory _username, uint256 _age) {
        owner = msg.sender;
        username = _username;
        age = _age;
    }

    function getProfile() public view returns (string memory, uint256) {
        return (username, age);
    }

    function updateUsername(string memory _newUsername) public {
        require(msg.sender == owner, "Not authorized");
        username = _newUsername;
    }

    function updateAge(uint256 _newAge) external {
        require(msg.sender == owner, "Not authorized");
        age = _newAge;
    }

    function _isAdult(uint256 _age) internal pure returns (bool) {
        return _age >= 18;
    }

    function checkAdultStatus() public view returns (bool) {
        return _isAdult(age);
    }
}

في هذا المثال، الدالة getProfile تقرأ فقط، بينما updateUsername وupdateAge تعدّلان البيانات. أما _isAdult فهي دالة داخلية منطقية لا تتعامل مباشرة مع التخزين.

حالات القابلية للتغيير: view وpure وبدون محدد

حتى تعرف من يمكنه قراءة أو تعديل بيانات العقد، يجب فهم ما يسمى state mutability. وهو توصيف يحدد هل الدالة ستتعامل مع حالة العقد أم لا.

دوال view

الدالة الموسومة بـ view تستطيع قراءة متغيرات الحالة، لكنها لا تستطيع تعديلها. هذا يعني أنها مناسبة لجلب الرصيد، الاسم، حالة التصويت، أو أي بيانات مخزنة داخل العقد.

استدعاء هذه الدوال من واجهات المستخدم غالباً لا يحتاج إلى إرسال معاملة فعلية إذا تم التنفيذ محلياً عبر call، ولهذا تكون أقل تكلفة على المستخدم.

دوال pure

الدالة pure لا تقرأ من حالة العقد ولا تعدّلها. هي تعتمد فقط على المعطيات التي تستقبلها أو العمليات الحسابية الداخلية. لذلك فهي مفيدة للعمليات المساعدة مثل التحقق، الحساب، أو التنسيق المنطقي.

الدوال القابلة للتعديل

إذا لم تُعلَّم الدالة بـ view أو pure، فهي مرشحة لتعديل الحالة. هنا يتم تنفيذها كمعاملة تستهلك gas وتكتب في storage إذا كانت تحتوي على أوامر تحديث.

الخطأ الشائع لدى المطورين الجدد هو اعتبار أي دالة public قابلة للتنفيذ بأمان. الواقع أن الدالة العامة التي تغيّر الحالة يجب أن تُحاط دائماً بفحوص صلاحيات مثل require(msg.sender == owner) أو أنظمة أدوار أكثر تقدماً.

من يقرأ البيانات؟ ومن يغيّرها فعلياً؟

من ناحية نظرية، أي طرف يستطيع الوصول إلى العقد على شبكة عامة يمكنه قراءة البيانات المكشوفة أو استدعاء الدوال العامة الخاصة بالقراءة. فالبلوكتشين بطبيعته شفاف، وما يُنشر عليه يمكن تتبعه وتحليله. لذلك لا ينبغي تخزين أسرار حقيقية داخل on-chain storage.

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

  1. محدد الوصول البرمجي مثل public أو external.
  2. شروط التحقق مثل require.
  3. هوية المستدعي في msg.sender.
  4. أحياناً التوقيع الرقمي أو نظام الصلاحيات متعدد الأدوار.

هذه الفكرة ترتبط مباشرة بما تعلمته في التشفير والمفاتيح: كيف تعمل المحافظ الرقمية (Public & Private Keys) برمجياً؟، لأن هوية المستدعي على السلسلة تنبع من توقيع المعاملة بواسطة المفتاح الخاص للمستخدم.

كيف تختبر الدوال عملياً أثناء التطوير؟

لفهم الفروقات عملياً، يمكنك تجربة العقد في محرر Remix IDE: كتابة ونشر أول عقد ذكي (Smart Contract) على المتصفح مباشرة. بعد النشر، ستلاحظ أن الدوال من نوع view تظهر غالباً بأزرار استدعاء لا تنشئ معاملة، بينما الدوال المعدِّلة تتطلب تأكيداً من المحفظة.

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

أفضل الممارسات الأمنية وتحسين استهلاك الغاز

اجعل الدوال التي لا تعدّل الحالة موسومة دائماً بـ view أو pure. هذا لا يحسن الوضوح البرمجي فقط، بل يساعد أدوات التحليل والتدقيق على اكتشاف السلوك غير المتوقع وتقليل أخطاء المنطق.

كل عملية كتابة في storage مكلفة مقارنة بالقراءة أو العمل على memory. لذلك صمم دوالك بحيث تقلل عدد مرات التحديث، وادمج العمليات المرتبطة عندما يكون ذلك منطقياً وآمناً.

  • استخدم دوال داخلية internal لتجزئة المنطق وتفادي تكرار الكود.
  • لا تجعل دوال التعديل مفتوحة بلا تحقق من الصلاحيات.
  • أعد استخدام النتائج الحسابية بدل تكرار الوصول إلى التخزين.
  • افصل بوضوح بين دوال القراءة للواجهة الأمامية ودوال الكتابة للمستخدمين المصرح لهم.

خاتمة

فهم الدوال في Solidity يعني فهم الحدود الدقيقة بين القراءة والكتابة، وبين الإتاحة العامة والتحكم الآمن. فالدالة لا تُقيَّم فقط بما تفعله، بل أيضاً بمن يستطيع استدعاؤها، وهل تغيّر حالة العقد، وما تكلفة ذلك على الشبكة.

كلما صممت دوالك بوضوح أكبر عبر محددات الوصول، توصيف state mutability، والتحقق الصارم من الصلاحيات، حصلت على عقد ذكي أسهل في المراجعة، أكثر أماناً، وأفضل من حيث كفاءة gas. وهذه هي القاعدة الأساسية لأي مطور يريد بناء DApps موثوقة وقابلة للتوسع.

43 comments

اترك تعليقاً

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