ملخص
تكلف كل 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_unit | cpi_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_unit | ACCOUNT_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 = 946instruction_data_cost = 100 / 250 = 0 (integer division)account_meta_cost = (5 * 34) / 250 = 0account_info_cost = (5 * 80) / 250 = 1per_account_data_cost = 5 * (1000 / 250) = 20total (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:
- يتم التحقق من صحة مصفوفة بذور الموقع: بحد أقصى
MAX_SIGNERS(16) مجموعة بذور موقع. - يتم التحقق من صحة كل مجموعة بذور: بحد أقصى
MAX_SEEDS(16) بذرة لكل مجموعة، كل بذرة بحد أقصىMAX_SEED_LEN(32) بايت. - يتم استدعاء
Pubkey::create_program_addressمع البذور ومعرف برنامج المستدعي (وليس المستدعى). - إذا لم تنتج البذور PDA صالحًا (أي أن النقطة الناتجة موجودة على منحنى
ed25519)، فإن CPI يفشل مع
BadSeeds. - يتم جمع مفاتيح 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?