Środowisko uruchomieniowe konta

Podsumowanie

Przed wykonaniem środowisko uruchomieniowe ładuje konta, weryfikuje płatnika opłat, sprawdza zwolnienie z czynszu i serializuje dane kont do układu pamięci, do którego mają dostęp programy.

Ta strona opisuje wewnętrzne mechanizmy środowiska uruchomieniowego. Większość deweloperów nie potrzebuje tych informacji do tworzenia programów. Zobacz Strukturę konta aby poznać perspektywę deweloperską.

Ładowanie konta

Przed wykonaniem transakcji środowisko uruchomieniowe ładuje wszystkie wskazane konta za pomocą load_transaction_accounts(). Ten proces wykonuje kilka weryfikacji:

  1. Weryfikacja płatnika opłat: Płatnik opłat (pierwsze konto) musi istnieć, być kontem systemowym lub kontem nonce oraz posiadać wystarczającą liczbę lamportów na pokrycie opłat (validate_fee_payer()). Po opłaceniu opłat konto musi pozostać zwolnione z czynszu lub mieć dokładnie 0 lamportów. Nie może mieć salda pomiędzy 0 a minimalną kwotą zwolnienia z czynszu. Konta nonce zawsze muszą mieć wystarczającą liczbę lamportów, aby pozostać zwolnione z czynszu. Jeśli płatnik nie jest kontem systemowym ani nonce, transakcja kończy się niepowodzeniem z TransactionError::InvalidAccountForFee.

  2. Limit rozmiaru załadowanych danych: Całkowity rozmiar wszystkich załadowanych kont (w tym TRANSACTION_ACCOUNT_BASE_SIZE 64 bajtów na konto) nie może przekroczyć MAX_LOADED_ACCOUNTS_DATA_SIZE_BYTES (64 MiB). Przekroczenie tego limitu skutkuje TransactionError::MaxLoadedAccountsDataSizeExceeded.

  3. Weryfikacja konta program account: Każdy program wywoływany przez instrukcję musi istnieć i być własnością prawidłowego loadera: jednego z PROGRAM_OWNERS (BPF Loader Upgradeable, BPF Loader, BPF Loader Deprecated, Loader V4) lub natywnego loadera. Jeśli konto program account nie istnieje, transakcja kończy się niepowodzeniem z TransactionError::ProgramAccountNotFound. Jeśli istnieje, ale ma nieprawidłowego właściciela, transakcja kończy się niepowodzeniem z TransactionError::InvalidProgramForExecution.

  4. Nieistniejące konta: Konta, które nie istnieją on-chain, są ładowane jako domyślne konta (0 lamportów, puste dane, właściciel: System Program) z rent_epoch ustawionym na u64::MAX.

Format serializacji BPF

Gdy program jest wywoływany, środowisko uruchomieniowe serializuje konta do ciągłego bufora w pamięci i przekazuje go do BPF VM. Format serializacji (standardowy format wyrównany używany przez wszystkie loadery poza przestarzałym loader-v1) jest zdefiniowany w serialize_parameters_aligned().

Bufor zaczyna się od u64 (8 bajtów, little-endian), zawierającego liczbę kont. Następnie, dla każdego konta w instrukcji, bufor zawiera:

OffsetRozmiarPoleTyp
01znacznik duplikatuu8 (0xFF = unikalny, index = duplikat tego konta)
11is_signeru8 (0 lub 1)
21is_writableu8 (0 lub 1)
31executableu8 (0 lub 1)
44original_data_len (zarezerwowane, zawsze 0)[0u8; 4]
832keyPubkey
4032ownerPubkey
728lamportsu64 (little-endian)
808data_lenu64 (little-endian)
88data_lendata[u8]
88 + data_len10240 + paddingmiejsce na realloc + wyrównanieWypełnione zerami do MAX_PERMITTED_DATA_INCREASE (10 KiB) + padding do wyrównania do BPF_ALIGN_OF_U128 (8 bajtów)
...8rent_epochu64 (little-endian)

Po wszystkich kontach bufor dołącza:

RozmiarPole
8instruction_data_len (u64, little-endian)
instruction_data_leninstruction_data
32program_id (Pubkey)

Dla zduplikowanych kont zapisywany jest tylko 1 bajt (znacznik duplikatu z indeksem oryginału) oraz 7 bajtów wypełnienia.

Deduplikacja kont

Gdy ten sam publiczny klucz konta pojawia się wielokrotnie w tablicy accounts instrukcji, środowisko wykonawcze deduplikuje je. Każdy wpis na liście kont instrukcji otrzymuje własną strukturę InstructionAccount, ale wpisy odnoszące się do tego samego konta na poziomie transakcji wskazują na te same dane bazowe.

Metoda is_instruction_account_duplicate określa, czy dany indeks konta instrukcji jest pierwszym wystąpieniem, czy duplikatem, poprzez wyszukanie indeksu konta na poziomie transakcji i znalezienie pierwszego indeksu na poziomie instrukcji, który do niego prowadzi:

  • Jeśli bieżący indeks konta instrukcji jest równy pierwszemu zmapowanemu indeksowi, to nie jest duplikatem (zwraca None).
  • W przeciwnym razie zwraca Some(first_index), gdzie first_index to indeks pierwszego wystąpienia.

Ponieważ wszystkie odwołania do tego samego konta współdzielą te same dane bazowe AccountSharedData, modyfikacje przez dowolne odwołanie są natychmiast widoczne przez wszystkie inne odwołania. Jednak w danym momencie można posiadać tylko jeden mutowalny zapożyczenie. Próba jednoczesnego mutowalnego zapożyczenia tego samego konta przez dwa różne indeksy konta instrukcji zwraca InstructionError::AccountBorrowFailed. Programy muszą zwolnić jedno zapożyczenie, zanim uzyskają kolejne na tym samym koncie bazowym.

Po wykonaniu programu środowisko wykonawcze deserializuje bufor z powrotem (deserialize_parameters_aligned()) i stosuje wszelkie zmiany do lamports, data (w tym zmiany długości do MAX_PERMITTED_DATA_INCREASE) oraz owner.

Is this page helpful?

Spis treści

Edytuj stronę

Zarządzane przez

© 2026 Solana Foundation.
Wszelkie prawa zastrzeżone.
Bądź na bieżąco