Podsumowanie
Każde CPI kosztuje ~1 000 CU bazowo plus koszty serializacji. Dane konta są synchronizowane przed i po wykonaniu przez wywoływanego. Podpisywanie PDA wykorzystuje program ID wywołującego. Dane zwrotne są ograniczone do 1 024 bajtów.
Model kosztów CPI
Koszty CPI są pobierane z tego samego budżetu obliczeniowego transakcji (wspólny
licznik). Pełny wzór kosztu dla każdego invoke / invoke_signed
wywołania:
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
Rozbicie kosztów
| Składnik kosztu | Wzór | Źródło |
|---|---|---|
| Wywołanie (stałe) | invoke_units = 1 000 CU (946 z SIMD-0339) | Naliczane przy wejściu CPI |
| Serializacja instruction data | instruction_data_len / cpi_bytes_per_unit | cpi_bytes_per_unit = 250. Naliczane w translate_instruction. |
| Serializacja meta konta (SIMD-0339) | (num_account_metas * 34) / cpi_bytes_per_unit | Każde AccountMeta to 34 bajty (32 pubkey + 1 is_signer + 1 is_writable). Naliczane w translate_instruction. |
| Translacja info o koncie (SIMD-0339) | (num_account_infos * 80) / cpi_bytes_per_unit | ACCOUNT_INFO_BYTE_SIZE = 80 bajtów (32 key + 32 owner + 8 lamports + 8 data_len). Naliczane w translate_account_infos. |
| Na konto | account_data_len / cpi_bytes_per_unit | Naliczane za każde konto w CallerAccount::from_account_info oraz dla kont wykonywalnych. |
| Wykonanie przez wywoływanego | Tyle CU, ile zużyje program wywoływanego | Odejmowane ze wspólnego licznika podczas wykonania przez wywoływanego. |
Przykład obliczenia kosztu
CPI ze 100 bajtami instruction data, 5 meta kont, 5 info o kontach (każde z 1 000 bajtami danych), aktywne 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
Synchronizacja danych konta
Stan konta jest synchronizowany między wywołującym a wywoływanym w dwóch momentach podczas CPI. Zapewnia to, że obie strony widzą spójny obraz danych konta.
Synchronizacja przed CPI (od wywołującego do wywoływanego)
Przed wykonaniem przez wywoływanego,
update_callee_account
kopiuje bieżące modyfikacje wywołującego do widoku konta wywoływanego:
| Pole | Kierunek | Kiedy |
|---|---|---|
| Lamports | Wywołujący -> Wywoływany | Jeśli wartość różni się od obecnego widoku wywoływanego |
| Długość danych | Wywołujący -> Wywoływany | Jeśli wywołujący zmienił rozmiar konta. Nie może przekroczyć original_data_len + MAX_PERMITTED_DATA_INCREASE (10 KiB). |
| Zawartość danych | Wywołujący -> Wywoływany | Jeśli dane konta są modyfikowalne (can_data_be_changed zwraca true) |
| Właściciel | Wywołujący -> Wywoływany | Ustawiane na końcu, aby zmiany danych/lamportów były dozwolone pod starym właścicielem |
Synchronizacja po CPI (od wywoływanego do wywołującego)
Po zakończeniu działania wywoływanego,
update_caller_account
kopiuje modyfikacje wywoływanego z powrotem do widoku wywołującego. Dzieje się
to tylko dla kont oznaczonych jako zapisywalne:
| Pole | Kierunek | Kiedy |
|---|---|---|
| Lamports | Wywoływany -> Wywołujący | Zawsze kopiowane z powrotem |
| Właściciel | Wywoływany -> Wywołujący | Zawsze kopiowane z powrotem |
| Długość danych | Wywoływany -> Wywołujący | Jeśli zmieniono. Wskaźnik VM na fragment danych i pole długości są aktualizowane. Jeśli konto zostało zmniejszone, zwolniona pamięć jest zerowana. Jeśli nowa długość przekracza original_data_len + MAX_PERMITTED_DATA_INCREASE, zwracany jest InvalidRealloc. |
| Zawartość danych | Wywoływany -> Wywołujący | Kopiowane z bufora danych wywoływanego do zserializowanego regionu danych wywołującego |
Limity reallocacji
Dane konta mogą być zmieniane (rozszerzane) podczas CPI do
MAX_PERMITTED_DATA_INCREASE
= 10 240 bajtów (10 KiB) powyżej długości danych konta na początku bieżącej
instrukcji najwyższego poziomu. Ten limit jest egzekwowany zarówno w
update_callee_account
(przed CPI), jak i
update_caller_account
(po CPI). Przekroczenie tego limitu skutkuje zwróceniem InvalidRealloc.
Podpisywanie przez PDA
Gdy wywoływana jest funkcja invoke_signed, środowisko uruchomieniowe
wyprowadza adresy PDA na podstawie podanych seedów oraz ID programu
wywołującego. Odbywa się to w
translate_signers_rust:
- Tablica seedów podpisującego jest weryfikowana: maksymalnie
MAX_SIGNERS(16) zestawów seedów podpisujących. - Każdy zestaw seedów jest weryfikowany: maksymalnie
MAX_SEEDS(16) seedów w zestawie, każdy seed maksymalnieMAX_SEED_LEN(32) bajty. Pubkey::create_program_addressjest wywoływana z seedami oraz ID programu wywołującego (nie wywoływanego).- Jeśli seedy nie generują poprawnego PDA (czyli wynikowy punkt leży na krzywej
ed25519), CPI kończy się błędem
BadSeeds. - Wyprowadzone pubkeye PDA są zbierane i przekazywane do
prepare_next_instructionjako poprawni sygnatariusze. Podczas sprawdzania uprawnień, jeśli konto wywoływanego programu jest oznaczone jako podpisujące i jego pubkey pasuje do jednego z tych wyprowadzonych PDA, weryfikacja podpisu przechodzi.
PDA jest wyprowadzany przy użyciu ID programu wywołującego, a nie wywoływanego. Oznacza to, że tylko program będący właścicielem PDA (ten, którego ID użyto do wyprowadzenia) może podpisywać w jego imieniu. Program nie może podpisywać za PDA wyprowadzone z innych programów.
Dane zwrotne
Programy mogą przekazywać dane z powrotem do wywołujących za pomocą mechanizmu danych zwrotnych. Wykorzystywane są do tego dwa syscalle:
sol_set_return_data: Ustawia doMAX_RETURN_DATA(1 024) bajtów danych zwrotnych dla bieżącej instrukcji. Koszt todata_len / cpi_bytes_per_unit + syscall_base_costCU.sol_get_return_data: Odczytuje dane zwrotne ustawione przez ostatnio wykonaną instrukcję. Zwraca dane wraz z ID programu, który je ustawił. Koszt to(data_len + 32) / cpi_bytes_per_unit + syscall_base_costCU (32 bajty dla ID programu).
Dane zwracane są przechowywane dla każdej transakcji osobno i nadpisywane przez
każdą instrukcję, która wywołuje sol_set_return_data. Na początku każdego
wywołania programu środowisko uruchomieniowe
resetuje dane zwrotne
do pustych. Po zakończeniu CPI, wywołujący może odczytać te dane zwrotne, które
ostatnio ustawił wywoływany program (lub dowolny program, który on sam wywołał).
Dane zwrotne są ograniczone do 1 024 bajtów. Tylko ostatni program, który
wywoła sol_set_return_data w łańcuchu wywołań, decyduje o tym, co widzi
wywołujący. Jeśli wywoływany program wykona kolejne CPI, które ustawią dane
zwrotne, jego własne dane zwrotne zostaną nadpisane.
Is this page helpful?