نموذج تكلفة CPI ومزامنة البيانات

ملخص

تكلف كل CPI حوالي 1,000 وحدة حسابية كتكلفة أساسية بالإضافة إلى تكاليف التسلسل. تتم مزامنة بيانات الحساب قبل وبعد تنفيذ المستدعى. يستخدم توقيع PDA معرف برنامج المستدعي. البيانات المُرجعة محدودة بـ 1,024 بايت.

نموذج تكلفة CPI

يتم سحب تكاليف CPI من نفس ميزانية الحساب للمعاملة (عداد مشترك). صيغة التكلفة الكاملة لكل استدعاء invoke / invoke_signed:

total_cpi_cost = invocation_cost
+ instruction_data_cost
+ account_meta_cost (SIMD-0339 only)
+ account_info_cost (SIMD-0339 only)
+ per_account_data_cost (for each non-executable account)
+ callee_execution_cost

تفصيل التكلفة

مكون التكلفةالصيغةالمصدر
الاستدعاء (ثابت)invoke_units = 1,000 وحدة حسابية (946 مع SIMD-0339)يتم احتسابها عند دخول CPI
تسلسل بيانات التعليماتinstruction_data_len / cpi_bytes_per_unitcpi_bytes_per_unit = 250. يتم احتسابها في translate_instruction.
تسلسل بيانات الحساب الوصفية (SIMD-0339)(num_account_metas * 34) / cpi_bytes_per_unitكل AccountMeta يبلغ 34 بايت (32 مفتاح عام + 1 is_signer + 1 is_writable). يتم احتسابها في translate_instruction.
ترجمة معلومات الحساب (SIMD-0339)(num_account_infos * 80) / cpi_bytes_per_unitACCOUNT_INFO_BYTE_SIZE = 80 بايت (32 مفتاح + 32 مالك + 8 لامبورت + 8 data_len). يتم احتسابها في translate_account_infos.
بيانات كل حسابaccount_data_len / cpi_bytes_per_unitيتم احتسابها لكل حساب في CallerAccount::from_account_info وللـ حسابات القابلة للتنفيذ.
تنفيذ المستدعىأي وحدات حسابية يستهلكها البرنامج المستدعىيتم خصمها من العداد المشترك أثناء تنفيذ المستدعى.

مثال على حساب التكلفة

CPI مع 100 بايت من بيانات التعليمات، و5 بيانات وصفية للحساب، و5 معلومات حساب (كل منها يحتوي على 1,000 بايت من البيانات)، مع تفعيل SIMD-0339:

invocation_cost = 946
instruction_data_cost = 100 / 250 = 0 (integer division)
account_meta_cost = (5 * 34) / 250 = 0
account_info_cost = (5 * 80) / 250 = 1
per_account_data_cost = 5 * (1000 / 250) = 20
total (before callee) = 967 CUs

مزامنة بيانات الحساب

تتم مزامنة حالة الحساب بين المستدعي والمستدعى في نقطتين أثناء CPI. وهذا يضمن أن كلا الطرفين يريان عرضاً متسقاً لبيانات الحساب.

المزامنة قبل CPI (من المستدعي إلى المستدعى)

قبل تنفيذ المستدعى، update_callee_account ينسخ التعديلات الجارية للمستدعي إلى عرض حساب المستدعى:

الحقلالاتجاهمتى
Lamportsالمستدعي -> المستدعىإذا كانت القيمة تختلف عن العرض الحالي للمستدعى
طول البياناتالمستدعي -> المستدعىإذا قام المستدعي بتغيير حجم الحساب. يجب ألا يتجاوز original_data_len + MAX_PERMITTED_DATA_INCREASE (10 كيلوبايت).
محتوى البياناتالمستدعي -> المستدعىإذا كانت بيانات الحساب قابلة للتعديل (can_data_be_changed ينجح)
المالكالمستدعي -> المستدعىيتم تعيينه أخيراً، بحيث يُسمح بتغييرات البيانات/lamport تحت المالك القديم

المزامنة بعد CPI (من المستدعى إلى المستدعي)

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

الحقلالاتجاهمتى
Lamportsالمستدعى -> المستدعييتم النسخ دائماً
المالكالمستدعى -> المستدعييتم النسخ دائماً
طول البياناتالمستدعى -> المستدعيإذا تم التغيير. يتم تحديث مؤشر شريحة بيانات VM وحقل الطول المتسلسل. إذا تم تقليص الحساب، يتم تصفير الذاكرة المحررة. إذا تجاوز الطول الجديد original_data_len + MAX_PERMITTED_DATA_INCREASE، يُرجع InvalidRealloc.
محتوى البياناتالمستدعى -> المستدعييتم النسخ من مخزن بيانات المستدعى إلى منطقة البيانات المتسلسلة للمستدعي

حدود إعادة التخصيص

يمكن تغيير حجم بيانات الحساب أثناء CPI حتى MAX_PERMITTED_DATA_INCREASE = 10,240 بايت (10 كيلوبايت) بعد طول بيانات الحساب في بداية التعليمة الحالية من المستوى الأعلى. يتم فرض هذا الحد في كل من update_callee_account (قبل CPI) و update_caller_account (بعد CPI). تجاوزه يُرجع InvalidRealloc.

توقيع PDA

عند استدعاء invoke_signed، يشتق وقت التشغيل عناوين PDA من البذور المقدمة ومعرف البرنامج الخاص بالمستدعي. يحدث هذا في translate_signers_rust:

  1. يتم التحقق من صحة مصفوفة بذور الموقع: بحد أقصى MAX_SIGNERS (16) مجموعة بذور موقع.
  2. يتم التحقق من صحة كل مجموعة بذور: بحد أقصى MAX_SEEDS (16) بذرة لكل مجموعة، كل بذرة بحد أقصى MAX_SEED_LEN (32) بايت.
  3. يتم استدعاء Pubkey::create_program_address مع البذور ومعرف برنامج المستدعي (وليس المستدعى).
  4. إذا لم تنتج البذور PDA صالحًا (أي أن النقطة الناتجة موجودة على منحنى ed25519)، فإن CPI يفشل مع BadSeeds.
  5. يتم جمع مفاتيح PDA العامة المشتقة وتمريرها إلى prepare_next_instruction كموقعين صالحين. أثناء فحص الامتيازات، إذا تم وضع علامة على حساب المستدعى كموقع وكان مفتاحه العام يطابق أحد PDAs المشتقة هذه، فإن فحص الموقع ينجح.

يتم اشتقاق PDA باستخدام معرف برنامج المستدعي، وليس المستدعى. هذا يعني أن البرنامج الذي يملك PDA فقط (الذي تم استخدام معرفه لاشتقاقه) يمكنه التوقيع نيابة عنه. لا يمكن للبرنامج التوقيع على PDAs المشتقة من برامج أخرى.

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

يمكن للبرامج تمرير البيانات إلى المستدعين باستخدام آلية إرجاع البيانات. تستخدم هذه استدعاءين نظاميين:

  • sol_set_return_data: يعين حتى MAX_RETURN_DATA (1,024) بايت من بيانات الإرجاع للتعليمة الحالية. التكلفة هي data_len / cpi_bytes_per_unit + syscall_base_cost وحدة حسابية.
  • sol_get_return_data: يقرأ بيانات الإرجاع التي عينتها التعليمة المنفذة مؤخرًا. يُرجع البيانات مع معرف البرنامج الذي عينها. التكلفة هي (data_len + 32) / cpi_bytes_per_unit + syscall_base_cost وحدة حسابية (32 بايت لمعرف البرنامج).

يتم تخزين بيانات الإرجاع لكل معاملة ويتم استبدالها بواسطة كل تعليمة تستدعي sol_set_return_data. في بداية كل استدعاء للبرنامج، يقوم وقت التشغيل بإعادة تعيين بيانات الإرجاع إلى فارغة. بعد عودة CPI، يمكن للمستدعي قراءة أي بيانات إرجاع قام المستدعى (أو أي برنامج استدعاه المستدعى) بتعيينها أخيراً.

بيانات الإرجاع محدودة بـ 1,024 بايت. فقط آخر برنامج يستدعي sol_set_return_data في سلسلة الاستدعاء هو الذي يحدد ما يراه المستدعي. إذا قام المستدعى بإجراء استدعاءات CPI إضافية تعيّن بيانات الإرجاع، فإن بيانات الإرجاع الخاصة بالمستدعى نفسه يتم استبدالها.

Is this page helpful?

تدار بواسطة

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