CPI-kostenmodel en gegevenssynchronisatie

Samenvatting

Elke CPI kost ~1.000 CU's basis plus serialisatiekosten. Accountgegevens worden gesynchroniseerd voor en na uitvoering van de aangeroepene. PDA-ondertekening gebruikt de program-ID van de aanroeper. Retourgegevens zijn beperkt tot 1.024 bytes.

CPI-kostenmodel

CPI-kosten worden afgetrokken van hetzelfde transactie-rekenbudget (gedeelde meter). De volledige kostenformule voor elke invoke / invoke_signed-aanroep:

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

Kostenverdeling

KostencomponentFormuleBron
Aanroep (vast)invoke_units = 1.000 CU's (946 met SIMD-0339)In rekening gebracht bij CPI-invoer
Instruction data-serialisatieinstruction_data_len / cpi_bytes_per_unitcpi_bytes_per_unit = 250. In rekening gebracht in translate_instruction.
Account meta-serialisatie (SIMD-0339)(num_account_metas * 34) / cpi_bytes_per_unitElke AccountMeta is 34 bytes (32 pubkey + 1 is_signer + 1 is_writable). In rekening gebracht in translate_instruction.
Account info-vertaling (SIMD-0339)(num_account_infos * 80) / cpi_bytes_per_unitACCOUNT_INFO_BYTE_SIZE = 80 bytes (32 key + 32 owner + 8 lamports + 8 data_len). In rekening gebracht in translate_account_infos.
Per-account gegevensaccount_data_len / cpi_bytes_per_unitIn rekening gebracht per account in CallerAccount::from_account_info en voor uitvoerbare accounts.
Uitvoering aangeroepeneHoeveel CU's het aangeroepen programma ook verbruiktAfgetrokken van de gedeelde meter tijdens uitvoering van de aangeroepene.

Voorbeeld kostenberekening

Een CPI met 100 bytes aan instruction data, 5 account meta's, 5 account infos (elk met 1.000 bytes aan gegevens), SIMD-0339 actief:

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

Synchronisatie van accountgegevens

De accountstatus wordt op twee momenten tijdens een CPI gesynchroniseerd tussen aanroeper en aangeroepene. Dit zorgt ervoor dat beide partijen een consistent beeld van de accountgegevens zien.

Pre-CPI synchronisatie (aanroeper naar aangeroepene)

Voordat de aangeroepene wordt uitgevoerd, kopieert update_callee_account de lopende wijzigingen van de aanroeper naar de accountweergave van de aangeroepene:

VeldRichtingWanneer
LamportsAanroeper -> AangeroepeneAls de waarde verschilt van de huidige weergave van de aangeroepene
DatalengteAanroeper -> AangeroepeneAls de aanroeper de grootte van het account heeft gewijzigd. Mag niet groter zijn dan original_data_len + MAX_PERMITTED_DATA_INCREASE (10 KiB).
Data-inhoudAanroeper -> AangeroepeneAls de data van het account aanpasbaar is (can_data_be_changed slaagt)
EigenaarAanroeper -> AangeroepeneAls laatste ingesteld, zodat data/lamport-wijzigingen zijn toegestaan onder de oude eigenaar

Post-CPI synchronisatie (aangeroepene naar aanroeper)

Nadat de aangeroepene terugkeert, kopieert update_caller_account de wijzigingen van de aangeroepene terug naar de weergave van de aanroeper. Dit gebeurt alleen voor accounts die als schrijfbaar zijn gemarkeerd:

VeldRichtingWanneer
LamportsAangeroepene -> AanroeperWordt altijd teruggekopieerd
EigenaarAangeroepene -> AanroeperWordt altijd teruggekopieerd
DatalengteAangeroepene -> AanroeperAls gewijzigd. De VM data slice pointer en geserialiseerde lengteveld worden bijgewerkt. Als het account is verkleind, wordt vrijgemaakte geheugen op nul gezet. Als de nieuwe lengte groter is dan original_data_len + MAX_PERMITTED_DATA_INCREASE, wordt InvalidRealloc geretourneerd.
Data-inhoudAangeroepene -> AanroeperGekopieerd van de databuffer van de aangeroepene naar de geserialiseerde dataregio van de aanroeper

Realloc-limieten

Accountgegevens kunnen tijdens CPI worden aangepast tot MAX_PERMITTED_DATA_INCREASE = 10.240 bytes (10 KiB) boven de gegevenslengte van het account aan het begin van de huidige top-level instructie. Deze limiet wordt afgedwongen in zowel update_callee_account (pre-CPI) als update_caller_account (post-CPI). Overschrijding hiervan retourneert InvalidRealloc.

PDA-ondertekening

Wanneer invoke_signed wordt aangeroepen, leidt de runtime PDA-adressen af van de verstrekte seeds en de program-ID van de aanroeper. Dit gebeurt in translate_signers_rust:

  1. De signer seeds-array wordt gevalideerd: maximaal MAX_SIGNERS (16) signer seed-sets.
  2. Elke seed-set wordt gevalideerd: maximaal MAX_SEEDS (16) seeds per set, elke seed maximaal MAX_SEED_LEN (32) bytes.
  3. Pubkey::create_program_address wordt aangeroepen met de seeds en de program-ID van de aanroeper (niet die van de aangeroepene).
  4. Als de seeds geen geldige PDA opleveren (d.w.z. het resulterende punt ligt op de ed25519-curve), mislukt de CPI met BadSeeds.
  5. De afgeleide PDA-pubkeys worden verzameld en doorgegeven aan prepare_next_instruction als geldige ondertekenaars. Tijdens de privilege-controle, als een callee-account is gemarkeerd als ondertekenaars en de pubkey overeenkomt met een van deze afgeleide PDA's, slaagt de ondertekenaarscontrole.

De PDA wordt afgeleid met behulp van de program-ID van de aanroeper, niet die van de aangeroepene. Dit betekent dat alleen het programma dat eigenaar is van de PDA (degene waarvan de ID is gebruikt om deze af te leiden) namens deze kan ondertekenen. Een programma kan niet ondertekenen voor PDA's die zijn afgeleid van andere programma's.

Retourgegevens

Programma's kunnen gegevens terugsturen naar aanroepers met behulp van het retourgegevensmechanisme. Dit gebruikt twee syscalls:

  • sol_set_return_data: Stelt tot MAX_RETURN_DATA (1.024) bytes aan retourgegevens in voor de huidige instructie. De kosten zijn data_len / cpi_bytes_per_unit + syscall_base_cost CU's.
  • sol_get_return_data: Leest de retourgegevens die zijn ingesteld door de meest recent uitgevoerde instructie. Retourneert de gegevens samen met de program-ID die deze heeft ingesteld. De kosten zijn (data_len + 32) / cpi_bytes_per_unit + syscall_base_cost CU's (32 bytes voor de program-ID).

Retourgegevens worden per transactie opgeslagen en worden overschreven door elke instructie die sol_set_return_data aanroept. Aan het begin van elke programma-aanroep reset de runtime de retourgegevens naar leeg. Nadat een CPI terugkeert, kan de aanroeper de retourgegevens lezen die de aangeroepene (of een programma dat de aangeroepene heeft aangeroepen) als laatste heeft ingesteld.

Retourgegevens zijn beperkt tot 1.024 bytes. Alleen het laatste programma dat sol_set_return_data aanroept in de aanroepketen bepaalt wat de aanroeper ziet. Als een aangeroepene verdere CPI's maakt die retourgegevens instellen, worden de eigen retourgegevens van de aangeroepene overschreven.

Is this page helpful?

Inhoudsopgave

Pagina Bewerken

Beheerd door

© 2026 Solana Foundation.
Alle rechten voorbehouden.
Blijf Verbonden