CPIコストモデルとデータ同期

概要

各CPIは基本コストとして約1,000 CU、さらにシリアライゼーションコストがかかります。アカウントデータは呼び出し先の実行前後で同期されます。PDA署名は呼び出し元のプログラムIDを使用します。戻りデータは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 CU (SIMD-0339では946)CPIエントリで課金
instruction dataのシリアライゼーションinstruction_data_len / cpi_bytes_per_unitcpi_bytes_per_unit = 250。translate_instructionで課金。
アカウントメタのシリアライゼーション (SIMD-0339)(num_account_metas * 34) / cpi_bytes_per_unitAccountMeta は34バイト(32 pubkey + 1 is_signer + 1 is_writable)。translate_instructionで課金。
アカウント情報の変換 (SIMD-0339)(num_account_infos * 80) / cpi_bytes_per_unitACCOUNT_INFO_BYTE_SIZE = 80バイト(32 key + 32 owner + 8 lamports + 8 data_len)。translate_account_infosで課金。
アカウントごとのデータaccount_data_len / cpi_bytes_per_unitCallerAccount::from_account_infoおよび実行可能アカウントでアカウントごとに課金。
呼び出し先の実行呼び出し先プログラムが消費するCU呼び出し先の実行中に共有メーターから差し引かれます。

コスト計算の例

100バイトのinstruction data、5つのアカウントメタ、5つのアカウント情報(それぞれ1,000バイトのデータ)を持つCPI、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中の2つのポイントで呼び出し元と呼び出し先の間で同期されます。これにより、両者がアカウントデータの一貫したビューを確認できます。

CPI前の同期(呼び出し元から呼び出し先へ)

呼び出し先が実行される前に、 update_callee_account は呼び出し元の実行中の変更を呼び出し先のアカウントビューにコピーします:

フィールド方向タイミング
Lamports呼び出し元 -> 呼び出し先値が呼び出し先の現在のビューと異なる場合
データ長呼び出し元 -> 呼び出し先呼び出し元がアカウントをリサイズした場合。original_data_len + MAX_PERMITTED_DATA_INCREASE(10 KiB)を超えてはいけません。
データ内容呼び出し元 -> 呼び出し先アカウントのデータが変更可能な場合(can_data_be_changedが通過)
オーナー呼び出し元 -> 呼び出し先最後に設定されるため、古いオーナーの下でデータ/lamportの変更が許可されます

CPI後の同期(呼び出し先から呼び出し元へ)

呼び出し先が戻った後、 update_caller_account は呼び出し先の変更を呼び出し元のビューにコピーします。これは書き込み可能としてマークされたアカウントに対してのみ実行されます:

フィールド方向タイミング
Lamports呼び出し先 -> 呼び出し元常にコピーされます
オーナー呼び出し先 -> 呼び出し元常にコピーされます
データ長呼び出し先 -> 呼び出し元変更された場合。VMデータスライスポインタとシリアル化された長さフィールドが更新されます。アカウントが縮小された場合、解放されたメモリはゼロ化されます。新しい長さがoriginal_data_len + MAX_PERMITTED_DATA_INCREASEを超える場合、InvalidReallocを返します。
データ内容呼び出し先 -> 呼び出し元呼び出し先のデータバッファから呼び出し元のシリアル化されたデータ領域にコピーされます

Reallocの制限

アカウントデータは、CPI中に現在のトップレベル命令の開始時点でのアカウントのデータ長を超えて MAX_PERMITTED_DATA_INCREASE = 10,240バイト(10 KiB)までリサイズできます。この制限は update_callee_account (CPI前)と update_caller_account (CPI後)の両方で適用されます。これを超えると*rsInvalidRealloc*が返されます。

PDA署名

*rsinvoke_signed*が呼び出されると、ランタイムは提供されたseedと呼び出し元のプログラムIDからPDAアドレスを導出します。これは translate_signers_rustで行われます:

  1. 署名者seed配列が検証されます:最大 MAX_SIGNERS (16)個の署名者seedセット。
  2. 各seedセットが検証されます:セットあたり最大 MAX_SEEDS (16)個のseed、各seedは最大 MAX_SEED_LEN (32)バイト。
  3. Pubkey::create_program_address がseedと呼び出し元のプログラムID(呼び出し先ではない)で呼び出されます。
  4. seedが有効なPDAを生成しない場合(つまり、結果のポイントがed25519曲線上にある場合)、CPIは BadSeedsで失敗します。
  5. 導出されたPDA pubkeyが収集され、有効な署名者としてprepare_next_instructionに渡されます。権限チェック中に、呼び出し先アカウントが署名者としてマークされ、そのpubkeyがこれらの導出されたPDAのいずれかと一致する場合、署名者チェックは成功します。

PDAは呼び出しのプログラムIDではなく、呼び出し元のプログラムIDを使用して導出されます。これは、PDAを所有するプログラム(導出に使用されたIDを持つプログラム)のみがその代わりに署名できることを意味します。プログラムは他のプログラムから導出されたPDAに対して署名することはできません。

リターンデータ

プログラムはリターンデータメカニズムを使用して、呼び出し元にデータを返すことができます。これは2つのsyscallを使用します:

  • sol_set_return_data: 現在の命令に対して最大 MAX_RETURN_DATA (1,024)バイトのリターンデータを設定します。コストは data_len / cpi_bytes_per_unit + syscall_base_cost CUです。
  • sol_get_return_data: 最後に実行された命令によって設定されたリターンデータを読み取ります。データとそれを設定したプログラムIDを返します。コストは (data_len + 32) / cpi_bytes_per_unit + syscall_base_cost CU(プログラムIDの32バイト)です。

リターンデータはトランザクションごとに保存され、sol_set_return_dataを呼び出す各命令によって上書きされます。各プログラム呼び出しの開始時に、ランタイムはリターンデータをリセットして空にします。CPIが戻った後、呼び出し元は呼び出し先(または呼び出し先が呼び出した任意のプログラム)が最後に設定したリターンデータを読み取ることができます。

リターンデータは1,024バイトに制限されています。呼び出しチェーンでsol_set_return_dataを呼び出した最後のプログラムのみが、呼び出し元に表示される内容を決定します。呼び出し先がリターンデータを設定するさらなるCPIを行う場合、呼び出し先自身のリターンデータは上書きされます。

Is this page helpful?

目次

ページを編集

管理運営

© 2026 Solana Foundation.
無断転載を禁じます。
つながろう