تخطي إلى المحتوى الرئيسي
Change page

تشريح العقود الذكية

العقد الذكي هو برنامج يعمل على عنوان في إيثيريوم. تتكون من بيانات ودوال يمكن تنفيذها عند تلقي معاملة. إليك نظرة عامة على ما يتكون منه العقد الذكي.

المتطلبات الأساسية

تأكد من قراءة حول العقود الذكية أولاً. تفترض هذه الوثيقة أنك على دراية بالفعل بلغات البرمجة مثل JavaScript أو Python.

البيانات

يجب تعيين أي بيانات عقد إلى موقع: إما إلى storage أو memory. من المكلف تعديل التخزين في عقد ذكي، لذا يجب عليك التفكير في المكان الذي يجب أن توجد فيه بياناتك.

التخزين

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

// مثال Solidity
contract SimpleStorage {
    uint storedData; // متغير حالة
    // ...
}
# مثال Vyper
storedData: int128

إذا كنت قد برمجت بالفعل بلغات كائنية التوجه، فمن المحتمل أن تكون على دراية بمعظم الأنواع. ومع ذلك، يجب أن يكون address جديدًا بالنسبة لك إذا كنت جديدًا في تطوير إيثيريوم.

يمكن أن يحمل النوع address عنوان إيثيريوم والذي يعادل 20 bytes أو 160 bits. يتم إرجاعه بالتدوين السداسي العشري مع بادئة 0x.

تشمل الأنواع الأخرى:

  • منطقي (boolean)
  • عدد صحيح (integer)
  • أرقام الفاصلة الثابتة (fixed point numbers)
  • مصفوفات بايتات ثابتة الحجم
  • مصفوفات بايتات متغيرة الحجم
  • القيم الحرفية المنطقية والصحيحة
  • القيم الحرفية النصية
  • القيم الحرفية السداسية العشرية
  • التعدادات (enums)

لمزيد من التوضيح، ألق نظرة على المستندات:

الذاكرة

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

تعرف على المزيد حول كيفية تخزين آلة إيثيريوم الافتراضية (EVM) للبيانات (التخزين، الذاكرة، والمكدس) في مستندات Solidity (opens in a new tab).

متغيرات البيئة

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

أمثلة:

الخاصيةمتغير الحالةالوصف
block.timestampuint256الطابع الزمني لحقبة الكتلة الحالية
msg.senderaddressمرسل الرسالة (الاستدعاء الحالي)

الدوال

بعبارات بسيطة للغاية، يمكن للدوال الحصول على معلومات أو تعيين معلومات استجابة للمعاملات الواردة.

هناك نوعان من استدعاءات الدوال:

  • internal – هذه لا تنشئ استدعاء لآلة إيثيريوم الافتراضية (EVM)
    • لا يمكن الوصول إلى الدوال الداخلية ومتغيرات الحالة إلا داخليًا (أي من داخل العقد الحالي أو العقود المشتقة منه)
  • external – هذه تنشئ استدعاء لآلة إيثيريوم الافتراضية (EVM)
    • الدوال الخارجية هي جزء من واجهة العقد، مما يعني أنه يمكن استدعاؤها من عقود أخرى وعبر المعاملات. لا يمكن استدعاء دالة خارجية f داخليًا (أي أن f() لا يعمل، ولكن this.f() يعمل).

يمكن أن تكون أيضًا public أو private

  • يمكن استدعاء دوال public داخليًا من داخل العقد أو خارجيًا عبر الرسائل
  • دوال private مرئية فقط للعقد الذي تم تعريفها فيه وليس في العقود المشتقة

يمكن جعل كل من الدوال ومتغيرات الحالة عامة أو خاصة

إليك دالة لتحديث متغير حالة في عقد:

// مثال Solidity
function update_name(string value) public {
    dapp_name = value;
}
  • يتم تمرير المعلمة value من النوع string إلى الدالة: update_name
  • تم التصريح عنها كـ public، مما يعني أنه يمكن لأي شخص الوصول إليها
  • لم يتم التصريح عنها كـ view، لذا يمكنها تعديل حالة العقد

دوال العرض (View functions)

تتعهد هذه الدوال بعدم تعديل حالة بيانات العقد. الأمثلة الشائعة هي دوال "الجلب" (getter) – يمكنك استخدام هذا لتلقي رصيد المستخدم على سبيل المثال.

// مثال Solidity
function balanceOf(address _owner) public view returns (uint256 _balance) {
    return ownerPizzaCount[_owner];
}
dappName: public(string)

@view
@public
def readName() -> string:
  return dappName

ما يُعتبر تعديلاً للحالة:

  1. الكتابة في متغيرات الحالة.
  2. إصدار الأحداث (opens in a new tab).
  3. إنشاء عقود أخرى (opens in a new tab).
  4. استخدام selfdestruct.
  5. إرسال الإيثر عبر الاستدعاءات.
  6. استدعاء أي دالة غير مميزة بـ view أو pure.
  7. استخدام الاستدعاءات منخفضة المستوى.
  8. استخدام لغة التجميع المضمنة (inline assembly) التي تحتوي على أكواد تشغيل (opcodes) معينة.

دوال المُنشئ

يتم تنفيذ دوال constructor مرة واحدة فقط عند نشر العقد لأول مرة. مثل constructor في العديد من لغات البرمجة القائمة على الفئات (class-based)، غالبًا ما تقوم هذه الدوال بتهيئة متغيرات الحالة إلى قيمها المحددة.

# مثال Vyper

@external
def __init__(_beneficiary: address, _bidding_time: uint256):
    self.beneficiary = _beneficiary
    self.auctionStart = block.timestamp
    self.auctionEnd = self.auctionStart + _bidding_time

الدوال المدمجة

بالإضافة إلى المتغيرات والدوال التي تحددها في عقدك، هناك بعض الدوال المدمجة الخاصة. المثال الأكثر وضوحًا هو:

  • address.send() – Solidity
  • send(address) – Vyper

تسمح هذه للعقود بإرسال ETH إلى حسابات أخرى.

كتابة الدوال

تحتاج دالتك إلى:

  • متغير المعلمة والنوع (إذا كانت تقبل معلمات)
  • التصريح بكونها داخلية/خارجية (internal/external)
  • التصريح بكونها pure/view/payable
  • نوع الإرجاع (إذا كانت تُرجع قيمة)

قد يبدو العقد الكامل شيئًا كهذا. هنا توفر دالة constructor قيمة أولية للمتغير dapp_name.

الأحداث والسجلات

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

أمثلة مشروحة

هذه بعض الأمثلة المكتوبة بلغة Solidity. إذا كنت ترغب في تجربة الكود، يمكنك التفاعل معها في Remix (opens in a new tab).

مرحبًا بالعالم

رمز مميز

أصل رقمي فريد

قراءة إضافية

تحقق من وثائق Solidity و Vyper للحصول على نظرة عامة أكثر اكتمالاً على العقود الذكية: