تنفيذ البرنامج

ملخص

تُجمَّع البرامج إلى sBPF عبر LLVM وتعمل في آلة افتراضية معزولة بميزانية 1.4 مليون وحدة حوسبة لكل معاملة. يخزن وقت التشغيل مؤقتًا ما يصل إلى 512 برنامجًا مجمعًا، ويوفر استدعاءات نظام للتسجيل، وCPI، والتشفير، والذاكرة، ويؤخر عمليات النشر الجديدة بمقدار فتحة واحدة.

التجميع

تستخدم سولانا LLVM لتجميع البرامج إلى ملفات ثنائية بصيغة ELF تحتوي على تنسيق سولانا للشفرة الثنائية (sBPF). يُخزَّن الملف الثنائي ELF على السلسلة في حساب قابل للتنفيذ.

sBPF هو نسخة سولانا المخصصة من شفرة eBPF الثنائية، مصممة خصيصًا لوقت تشغيل سولانا. إنها ليست eBPF قياسية ولديها تعديلات خاصة بسولانا.

كتابة البرامج

تُكتب برامج سولانا بشكل أساسي بلغة Rust باستخدام أحد نهجين:

نموذج تنفيذ البرنامج

عند معالجة معاملة، ينفذ وقت التشغيل كل تعليمة بشكل تسلسلي من خلال process_message(). لكل تعليمة، يقوم وقت التشغيل بـ:

  1. إعداد سياق التعليمة. يستدعي prepare_next_top_level_instruction() لتعيين فهارس حسابات التعليمة، وتعيين علامات الموقِّع والقابلية للكتابة، وتكوين TransactionContext.

  2. فحص البرامج المجمعة مسبقًا. إذا كان البرنامج مجمعًا مسبقًا، يستدعي وقت التشغيل process_precompile()، والذي لا يزال يدفع ويسحب إطار مكدس (عبر push() و pop()) لكنه يتجاوز آلة sBPF الافتراضية والبحث في ذاكرة التخزين المؤقت للبرنامج، وينفذ الشفرة الأصلية مباشرة.

  3. يدفع إطار مكدس. (تحدث الخطوات 3-6 داخل InvokeContext::process_instruction() و process_executable_chain()، المستدعاة من process_message().) يستدعي push() على InvokeContext، والذي يزيد ارتفاع مكدس التعليمات ويفرض قاعدة إعادة الدخول: يمكن للبرنامج إعادة الدخول إلى نفسه فقط إذا كان المستدعي المباشر (البرنامج الموجود في قمة مكدس التعليمات الحالية) هو نفس البرنامج. يُسمح بالتكرار الذاتي العميق (A -> A -> A)، مع مراعاة حدود عمق المكدس. أنماط إعادة الدخول الأخرى (مثل A يستدعي B يستدعي A) تُرجع InstructionError::ReentrancyNotAllowed.

  4. يحل البرنامج. يستدعي وقت التشغيل process_executable_chain() والذي يحدد المحمّل. إذا كان مالك حساب البرنامج هو المحمّل الأصلي، فإن البرنامج مدمج ويتم البحث عن دالة نقطة الدخول الخاصة به مباشرة من ProgramCacheForTxBatch. إذا كان المالك أحد محمّلات BPF (bpf_loader_deprecated، bpf_loader، bpf_loader_upgradeable، أو loader_v4)، يتم استدعاء نقطة الدخول المدمجة للمحمّل نفسه بدلاً من ذلك.

  5. ينفذ برنامج BPF. بالنسبة لبرامج BPF، نقطة دخول المحمّل تبحث عن الملف التنفيذي المترجم من ذاكرة التخزين المؤقت للبرنامج. دالة execute() تقوم بعد ذلك بـ:

    • تسلسل بيانات الحساب في مخزن مؤقت مسطح للمعاملات
    • إنشاء جهاز sBPF الافتراضي مع المكدس والكومة ومناطق الذاكرة
    • تشغيل الكود المترجم، مع استهلاك وحدات الحوسبة أثناء التنفيذ. يُرجع ComputationalBudgetExceeded إذا تم تجاوز الميزانية.
    • إلغاء تسلسل بيانات الحساب من المخزن المؤقت إلى حالة الحساب
  6. يسحب إطار المكدس. يستدعي pop() والذي يتحقق من أن التعليمات لم تنتهك قواعد المحاسبة الخاصة بوقت التشغيل (أرصدة lamport متوازنة، لم يتم تعديل الحسابات للقراءة فقط، أحجام بيانات الحساب ضمن الحدود).

  7. يجمع وحدات الحوسبة. تُضاف وحدات الحوسبة المستهلكة بواسطة التعليمات إلى إجمالي المعاملة عبر saturating_add.

ذاكرة التخزين المؤقت للبرنامج

يحتفظ وقت التشغيل بـ ProgramCache عامة تخزن البرامج التي تم التحقق منها وتجميعها. وهي تدرك الرسم البياني للتفرع وتتعامل مع قواعد رؤية النشر والإزالة وإعادة التجميع عند حدود الـ epoch.

أنواع إدخالات ذاكرة التخزين المؤقت

كل برنامج مخزن مؤقتًا لديه ProgramCacheEntryType يحدد سلوكه في وقت التشغيل:

النوعالوصف
Loadedبرنامج تم التحقق منه وتجميعه، جاهز للتنفيذ.
Builtinبرنامج أصلي مجمّع في الملف الثنائي للمدقق (النظام، الرهان، التصويت، إلخ). غير مخزن على السلسلة.
Unloadedبرنامج تم التحقق منه سابقًا تمت إزالة ملفه التنفيذي المجمّع من الذاكرة لتحرير المساحة. لا يزال يتتبع إحصائيات الاستخدام. يمكن إعادة تحميله دون إعادة التحقق.
FailedVerificationعلامة قبر للبرامج التي لم تجتاز مدقق sBPF ضمن مجموعة الميزات الحالية. قد تصبح Loaded إذا غيرت تفعيلات الميزات قواعد التحقق.
Closedعلامة قبر للبرامج التي تم إغلاقها صراحةً أو لم يتم نشرها مطلقًا. تُستخدم أيضًا للحسابات (مثل حسابات المخزن المؤقت) التي تنتمي إلى محمّل ولكنها لا تحتوي على كود قابل للتنفيذ.
DelayVisibilityعلامة قبر اصطناعية يتم إرجاعها بواسطة ProgramCacheForTxBatch::find() عندما يوجد إدخال Loaded ولكنه غير فعال بعد (effective_slot الخاص به في المستقبل). لا يتم تخزينها مباشرة في ذاكرة التخزين المؤقت أبدًا.

تأخير الرؤية

البرامج المنشورة أو المحدثة حديثًا لا تصبح فعالة على الفور. ثابت DELAY_VISIBILITY_SLOT_OFFSET هو 1، مما يعني أن البرنامج المنشور في الـ slot N يصبح فعالاً في الـ slot N+1. خلال slot النشر، أي محاولة لاستدعاء الإصدار الجديد تُرجع DelayVisibility، مما يتسبب في إبلاغ وقت التشغيل بـ "البرنامج غير منشور."

سياسة الإزالة

يحتفظ الذاكرة المؤقتة بما يصل إلى MAX_LOADED_ENTRY_COUNT (512) إدخال برنامج مُجمَّع. عند الوصول إلى الحد الأقصى، تتم إزالة البرامج الأقل استخدامًا إلى حالة Unloaded. يتم تتبع الاستخدام بواسطة tx_usage_counter (يزداد في كل مرة تشير فيها معاملة إلى البرنامج) و latest_access_slot.

إعادة التجميع عند حدود الحقبة

إذا غيّر تفعيل ميزة ما ProgramRuntimeEnvironments عند حد حقبة، يتم إعادة تجميع جميع البرامج المخزنة مؤقتًا مقابل البيئة الجديدة.

بيانات الإرجاع

يمكن للبرامج تعيين بيانات الإرجاع عبر استدعاء النظام sol_set_return_data. يتم تخزين البيانات في بنية TransactionReturnData على مستوى المعاملة تحتفظ ببايتات البيانات و program_id للبرنامج الذي استدعى تعليمته استدعاء النظام. الحد الأقصى للحجم هو 1,024 بايت (MAX_RETURN_DATA).

Is this page helpful?

تدار بواسطة

© 2026 مؤسسة سولانا.
جميع الحقوق محفوظة.
تواصل معنا