Ringkasan
CPI melewati 11 langkah runtime termasuk pemeriksaan hak akses, translasi akun, dan sinkronisasi data. Kedalaman panggilan maksimal: 5 (9 dengan SIMD-0268). Aturan hak akses mencegah callee meningkatkan hak akses melebihi yang diberikan caller.
Aturan hak akses
CPI memperluas hak akses akun caller ke callee dengan penegakan yang ketat.
Runtime memeriksa aturan-aturan ini di
prepare_next_instruction:
| Skenario | Diizinkan? | Titik penegakan | Error |
|---|---|---|---|
| Caller meneruskan akun sebagai writable, callee menandai writable | Ya | -- | -- |
| Caller meneruskan akun sebagai read-only, callee menandai writable | Tidak | prepare_next_instruction | PrivilegeEscalation |
| Caller meneruskan akun sebagai writable, callee menandai read-only | Ya | -- | -- |
| Caller meneruskan akun sebagai signer, callee menandai signer | Ya | -- | -- |
| Caller meneruskan akun sebagai non-signer, callee menandai signer, akun adalah PDA yang diturunkan dari seed caller | Ya | prepare_next_instruction | -- |
| Caller meneruskan akun sebagai non-signer, callee menandai signer, akun BUKAN PDA dari caller | Tidak | prepare_next_instruction | PrivilegeEscalation |
| Caller meneruskan akun sebagai signer, callee menandai non-signer | Ya | -- | -- |
| Program A memanggil dirinya sendiri secara langsung (A -> A) | Ya | push() | -- |
| Program A memanggil B yang memanggil A (reentrancy tidak langsung) | Tidak | push() | ReentrancyNotAllowed |
| CPI ke native loader, bpf_loader, bpf_loader_deprecated, atau precompile | Tidak | check_authorized_program | ProgramNotSupported |
| Akun tidak ditemukan dalam transaksi | Tidak | prepare_next_instruction | MissingAccount |
Aturan privilege dapat dirangkum sebagai:
- Privilege writable tidak dapat ditingkatkan. Jika pemanggil menandai akun sebagai read-only, yang dipanggil tidak dapat menandainya sebagai writable.
- Privilege signer memerlukan otorisasi. Sebuah akun dapat menjadi signer
dalam yang dipanggil hanya jika (a) akun tersebut sudah menjadi signer dalam
pemanggil, ATAU (b) akun tersebut adalah PDA yang diturunkan dari seed
program pemanggil melalui
invoke_signed. - Pengurangan privilege selalu diizinkan. Yang dipanggil dapat menggunakan privilege lebih sedikit daripada yang diberikan oleh pemanggil.
Alur eksekusi CPI
CPI melewati beberapa lapisan runtime. Bagian ini mendokumentasikan pipeline lengkap dari panggilan SDK program melalui batas syscall ke dalam runtime dan kembali. Setiap langkah merujuk pada file sumber yang mengimplementasikannya.
Tinggi maksimum dari pemanggilan instruksi program disebut
max_instruction_stack_depth
dan diatur ke konstanta
MAX_INSTRUCTION_STACK_DEPTH
sebesar 5. Dengan MAX_INSTRUCTION_STACK_DEPTH_SIMD_0268 aktif, ini meningkat menjadi 9.
Stack height 1 adalah instruksi transaksi awal. Setiap CPI menambah height sebesar 1. Maksimum 5 berarti program dapat melakukan CPI hingga kedalaman 4 level (8 level dengan SIMD-0268).
Langkah 1: Program memanggil invoke atau invoke_signed
Program memanggil
invoke
atau
invoke_signed.
invoke adalah wrapper tipis yang memanggil invoke_signed dengan
array signer seeds kosong. Fungsi SDK menserialisasi Instruction, slice
AccountInfo, dan signer seeds ke dalam memori VM, kemudian memicu syscall.
Langkah 2: Entry syscall
SBF VM melakukan dispatch ke handler syscall
sol_invoke_signed_rust,
yang memanggil entry point bersama:
cpi_common.
Langkah 3: Konsumsi biaya invokasi
Tindakan pertama di dalam cpi_common adalah
menagih biaya invokasi tetap
dari compute meter bersama:
invoke_units
= 1.000 CU (atau 946 CU dengan SIMD-0339).
Langkah 4: Terjemahkan instruksi dari memori VM
Syscall handler menerjemahkan instruksi dari ruang alamat VM program ke tipe
Rust sisi host melalui
translate_instruction_rust,
yang membaca struct StableInstruction, memvalidasi panjang data terhadap
MAX_INSTRUCTION_DATA_LEN
(10.240 byte), kemudian menagih
biaya serialisasi data.
Langkah 5: Terjemahkan signer seed dan turunkan PDA
Handler memanggil
translate_signers_rust.
Untuk setiap set signer seed, runtime:
- Memeriksa jumlah set signer seed terhadap
MAX_SIGNERS(16). - Memeriksa panjang setiap set seed terhadap
MAX_SEEDS(16 seed per set). - Memanggil
Pubkey::create_program_addressdengan seed dan program ID pemanggil. Jika seed tidak menghasilkan PDA yang valid, CPI gagal denganBadSeeds. - Mengumpulkan pubkey PDA yang dihasilkan ke dalam vec
signers.
PDA yang diturunkan ini diperlakukan sebagai signer yang valid untuk instruksi callee.
Langkah 6: Periksa program yang diotorisasi
Sebelum melanjutkan, runtime memanggil
check_authorized_program
untuk memverifikasi program target diizinkan untuk CPI. Program berikut
diblokir:
- Native loader
bpf_loaderdanbpf_loader_deprecatedbpf_loader_upgradeable(kecuali instruksi manajemen tertentu:upgrade,set_authority,set_authority_checked(feature-gated),extend_program_checked(feature-gated),close)- Program precompile (ed25519, secp256k1, dll.)
Pelanggaran mengembalikan
ProgramNotSupported.
Langkah 7: Verifikasi privilege (prepare_next_instruction)
Runtime memanggil
prepare_next_instruction
yang membangun daftar InstructionAccount callee dan menerapkan aturan
privilege. Lihat Aturan privilege di bawah untuk tabel
keputusan lengkap.
Langkah 8: Terjemahkan info akun
Handler memanggil translate_accounts yang:
- Memvalidasi jumlah info akun
terhadap
MAX_CPI_ACCOUNT_INFOS(128, atau 255 dengan SIMD-0339). - Mengenakan biaya terjemahan info akun
(hanya SIMD-0339):
(num_account_infos * 80) / 250CU. - Untuk setiap akun yang tidak dapat dieksekusi dan tidak duplikat, membangun
CallerAccountdengan menerjemahkan pointer dari memori VM ke memori host. Ini termasuk mengenakan biaya serialisasi data per akun:account_data_len / cpi_bytes_per_unitCU.
Langkah 9: Sinkronisasi akun pra-CPI (pemanggil ke yang dipanggil)
Sebelum mengeksekusi yang dipanggil, runtime menyinkronkan modifikasi akun
pemanggil sehingga yang dipanggil dapat melihatnya. Fungsi
update_callee_account
dipanggil untuk setiap akun yang diterjemahkan, menyalin lamport, data, dan
pemilik. Lihat
Sinkronisasi data akun
untuk pemetaan field yang detail.
Langkah 10: Push konteks instruksi, eksekusi yang dipanggil, dan pop
Runtime memanggil
process_instruction,
yang:
- Memanggil
push()untuk menambahkan frame baru ke stack instruksi.push()memberlakukan aturan reentrancy: sebuah program hanya dapat memanggil dirinya sendiri jika ia adalah pemanggil langsung (yaitu, program A dapat memanggil A, tetapi A tidak dapat memanggil B yang memanggil A). Pelanggaran mengembalikanReentrancyNotAllowed. - Memanggil
process_executable_chainyang menyelesaikan entry point program yang dipanggil dan memanggilnya. Yang dipanggil berjalan dengan compute meter bersama yang sama. Semua konsumsi CU oleh yang dipanggil mengurangi anggaran yang tersisa dari pemanggil. - Memanggil
pop()untuk menghapus frame yang dipanggil dan memverifikasi bahwa saldo lamport tidak berubah (UnbalancedInstructionjika tidak).
Langkah 11: Sinkronisasi akun pasca-CPI (yang dipanggil ke pemanggil)
Setelah process_instruction kembali (yang mencakup pop), runtime menyinkronkan
perubahan kembali ke pemanggil melalui
update_caller_account
untuk setiap akun yang dapat ditulis. Selain itu,
update_caller_account_region
memperbarui pemetaan region memori VM untuk akun yang region datanya berubah.
Lihat
Sinkronisasi data akun
untuk pemetaan field yang detail.
Syscall CPI mengembalikan 0 (sukses) ke program pemanggil.
Is this page helpful?