Zusammenfassung
Jeder CPI kostet ~1.000 CUs Basis plus Serialisierungskosten. Kontodaten werden vor und nach der Ausführung des Aufgerufenen synchronisiert. PDA-Signierung verwendet die Programm-ID des Aufrufers. Rückgabedaten sind auf 1.024 Bytes begrenzt.
CPI-Kostenmodell
CPI-Kosten werden aus demselben Transaktions-Rechenbudget gezogen (gemeinsamer
Zähler). Die vollständige Kostenformel für jeden invoke /
invoke_signed Aufruf:
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
Kostenaufschlüsselung
| Kostenkomponente | Formel | Quelle |
|---|---|---|
| Aufruf (fest) | invoke_units = 1.000 CUs (946 mit SIMD-0339) | Berechnet beim CPI-Eintritt |
| Instruction-Data-Serialisierung | instruction_data_len / cpi_bytes_per_unit | cpi_bytes_per_unit = 250. Berechnet in translate_instruction. |
| Account-Meta-Serialisierung (SIMD-0339) | (num_account_metas * 34) / cpi_bytes_per_unit | Jedes AccountMeta ist 34 Bytes (32 Pubkey + 1 is_signer + 1 is_writable). Berechnet in translate_instruction. |
| Account-Info-Übersetzung (SIMD-0339) | (num_account_infos * 80) / cpi_bytes_per_unit | ACCOUNT_INFO_BYTE_SIZE = 80 Bytes (32 Key + 32 Owner + 8 Lamports + 8 data_len). Berechnet in translate_account_infos. |
| Pro-Konto-Daten | account_data_len / cpi_bytes_per_unit | Berechnet pro Konto in CallerAccount::from_account_info und für ausführbare Konten. |
| Ausführung des Aufgerufenen | Beliebige CUs, die das aufgerufene Programm verbraucht | Vom gemeinsamen Zähler während der Ausführung des Aufgerufenen abgezogen. |
Beispiel für Kostenberechnung
Ein CPI mit 100 Bytes instruction data, 5 Account-Metas, 5 Account-Infos (jeweils mit 1.000 Bytes Daten), SIMD-0339 aktiv:
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
Synchronisierung von Kontodaten
Der Kontostatus wird zwischen Aufrufer und Aufgerufenem an zwei Punkten während eines CPI synchronisiert. Dies stellt sicher, dass beide Seiten eine konsistente Ansicht der Kontodaten sehen.
Pre-CPI-Synchronisierung (Aufrufer zu Aufgerufenem)
Bevor der Aufgerufene ausgeführt wird, kopiert
update_callee_account
die laufenden Änderungen des Aufrufers in die Kontoansicht des Aufgerufenen:
| Feld | Richtung | Wann |
|---|---|---|
| Lamports | Aufrufer -> Aufgerufener | Wenn sich der Wert von der aktuellen Ansicht des Aufgerufenen unterscheidet |
| Datenlänge | Aufrufer -> Aufgerufener | Wenn der Aufrufer die Größe des Kontos geändert hat. Darf original_data_len + MAX_PERMITTED_DATA_INCREASE (10 KiB) nicht überschreiten. |
| Dateninhalt | Aufrufer -> Aufgerufener | Wenn die Daten des Kontos änderbar sind (can_data_be_changed erfolgreich) |
| Eigentümer | Aufrufer -> Aufgerufener | Wird zuletzt gesetzt, damit Daten-/Lamport-Änderungen unter dem alten Eigentümer zulässig sind |
Post-CPI-Synchronisierung (Aufgerufener zu Aufrufer)
Nachdem der Aufgerufene zurückkehrt, kopiert
update_caller_account
die Änderungen des Aufgerufenen zurück in die Ansicht des Aufrufers. Dies
erfolgt nur für Konten, die als beschreibbar markiert sind:
| Feld | Richtung | Wann |
|---|---|---|
| Lamports | Aufgerufener -> Aufrufer | Wird immer zurückkopiert |
| Eigentümer | Aufgerufener -> Aufrufer | Wird immer zurückkopiert |
| Datenlänge | Aufgerufener -> Aufrufer | Bei Änderung. Der VM-Daten-Slice-Zeiger und das serialisierte Längenfeld werden aktualisiert. Wenn das Konto verkleinert wurde, wird freigegebener Speicher auf null gesetzt. Wenn die neue Länge original_data_len + MAX_PERMITTED_DATA_INCREASE überschreitet, wird InvalidRealloc zurückgegeben. |
| Dateninhalt | Aufgerufener -> Aufrufer | Wird vom Datenpuffer des Aufgerufenen in die serialisierte Datenregion des Aufrufers kopiert |
Realloc-Limits
Kontendaten können während CPI bis zu
MAX_PERMITTED_DATA_INCREASE
= 10.240 Bytes (10 KiB) über die Datenlänge des Kontos zu Beginn der aktuellen
Top-Level-Instruktion hinaus vergrößert werden. Dieses Limit wird sowohl in
update_callee_account
(vor CPI) als auch in
update_caller_account
(nach CPI) durchgesetzt. Bei Überschreitung wird InvalidRealloc
zurückgegeben.
PDA-Signierung
Wenn invoke_signed aufgerufen wird, leitet die Runtime PDA-Adressen aus
den bereitgestellten Seeds und der Programm-ID des Aufrufers ab. Dies geschieht
in
translate_signers_rust:
- Das Signer-Seed-Array wird validiert: maximal
MAX_SIGNERS(16) Signer-Seed-Sets. - Jedes Seed-Set wird validiert: maximal
MAX_SEEDS(16) Seeds pro Set, jeder Seed maximalMAX_SEED_LEN(32) Bytes. Pubkey::create_program_addresswird mit den Seeds und der Programm-ID des Aufrufers (nicht des Aufgerufenen) aufgerufen.- Wenn die Seeds keine gültige PDA erzeugen (d. h. der resultierende Punkt
liegt auf der ed25519-Kurve), schlägt der CPI mit
BadSeedsfehl. - Die abgeleiteten PDA-Pubkeys werden gesammelt und an
prepare_next_instructionals gültige Signer übergeben. Während der Berechtigungsprüfung wird, wenn ein Callee-Konto als Signer markiert ist und sein Pubkey mit einer dieser abgeleiteten PDAs übereinstimmt, die Signer-Prüfung bestanden.
Die PDA wird unter Verwendung der Programm-ID des Aufrufers abgeleitet, nicht des Aufgerufenen. Das bedeutet, dass nur das Programm, das die PDA besitzt (dasjenige, dessen ID zur Ableitung verwendet wurde), in ihrem Namen signieren kann. Ein Programm kann nicht für PDAs signieren, die von anderen Programmen abgeleitet wurden.
Rückgabedaten
Programme können Daten mithilfe des Rückgabedaten-Mechanismus an Aufrufer zurückgeben. Dieser verwendet zwei Syscalls:
sol_set_return_data: Legt bis zuMAX_RETURN_DATA(1.024) Bytes an Rückgabedaten für die aktuelle Instruktion fest. Die Kosten betragendata_len / cpi_bytes_per_unit + syscall_base_costCUs.sol_get_return_data: Liest die Rückgabedaten, die von der zuletzt ausgeführten Instruktion festgelegt wurden. Gibt die Daten zusammen mit der Programm-ID zurück, die sie festgelegt hat. Die Kosten betragen(data_len + 32) / cpi_bytes_per_unit + syscall_base_costCUs (32 Bytes für die Programm-ID).
Rückgabedaten werden pro Transaktion gespeichert und von jeder Anweisung
überschrieben, die sol_set_return_data aufruft. Zu Beginn jedes
Programmaufrufs
setzt die Runtime die Rückgabedaten
auf leer zurück. Nachdem ein CPI zurückkehrt, kann der Aufrufer alle
Rückgabedaten lesen, die der Aufgerufene (oder ein vom Aufgerufenen aufgerufenes
Programm) zuletzt gesetzt hat.
Rückgabedaten sind auf 1.024 Bytes begrenzt. Nur das letzte Programm, das
sol_set_return_data in der Aufrufkette aufruft, bestimmt, was der Aufrufer
sieht. Wenn ein Aufgerufener weitere CPIs durchführt, die Rückgabedaten
setzen, werden die eigenen Rückgabedaten des Aufgerufenen überschrieben.
Is this page helpful?