Wykonywanie programów

Podsumowanie

Programy są kompilowane do sBPF przez LLVM i uruchamiane w odizolowanej maszynie wirtualnej z budżetem 1,4M CU na transakcję. Runtime przechowuje w cache do 512 skompilowanych programów, udostępnia wywołania systemowe do logowania, CPI, kryptografii i pamięci oraz opóźnia nowe wdrożenia o 1 slot.

Kompilacja

Solana używa LLVM do kompilowania programów do binarek ELF zawierających Solana Bytecode Format (sBPF). Binarka ELF jest przechowywana on-chain w koncie wykonawczym.

sBPF to autorska wersja eBPF dostosowana do środowiska Solana. Nie jest to standardowy eBPF i zawiera modyfikacje specyficzne dla Solany.

Pisanie programów

Programy Solana są najczęściej pisane w języku Rust na dwa sposoby:

Model wykonywania programów

Podczas przetwarzania transakcji runtime wykonuje każdą instrukcję sekwencyjnie przez process_message(). Dla każdej instrukcji runtime:

  1. Przygotowuje kontekst instrukcji. Wywołuje prepare_next_top_level_instruction(), aby zmapować indeksy kont instrukcji, ustawić flagi podpisującego i zapisywalności oraz skonfigurować TransactionContext.

  2. Sprawdza prekompilacje. Jeśli program jest prekompilacją, runtime wywołuje process_precompile(), co nadal powoduje dodanie i usunięcie ramki stosu (przez push() i pop()), ale pomija maszynę wirtualną sBPF i wyszukiwanie w cache programu, wykonując natywny kod bezpośrednio.

  3. Dodaje ramkę stosu. (Kroki 3–6 odbywają się wewnątrz InvokeContext::process_instruction() oraz process_executable_chain(), wywoływanych z process_message().) Wywołuje push() na InvokeContext, co zwiększa wysokość stosu instrukcji i wymusza zasadę reentrancji: program może ponownie wejść w siebie tylko wtedy, gdy bezpośredni wywołujący (program na szczycie stosu instrukcji) jest tym samym programem. Głęboka rekurencja własna (A -> A -> A) jest dozwolona, pod warunkiem zachowania limitów głębokości stosu. Inne wzorce reentrancji (np. A wywołuje B, które wywołuje A) zwracają InstructionError::ReentrancyNotAllowed.

  4. Rozwiązuje program. Środowisko uruchomieniowe wywołuje process_executable_chain(), który określa loader. Jeśli właścicielem program account jest native loader, program jest wbudowany i jego punkt wejścia jest wyszukiwany bezpośrednio z ProgramCacheForTxBatch. Jeśli właścicielem jest jeden z loaderów BPF (bpf_loader_deprecated, bpf_loader, bpf_loader_upgradeable lub loader_v4), wywoływany jest wbudowany punkt wejścia loadera.

  5. Wykonuje program BPF. Dla programów BPF loader entrypoint wyszukuje skompilowany plik wykonywalny z cache programu. Następnie funkcja execute():

    • Serializuje dane kont do płaskiego bufora parametrów
    • Tworzy maszynę wirtualną sBPF ze stosem, stertą i regionami pamięci
    • Uruchamia skompilowany kod, zużywając jednostki obliczeniowe podczas wykonania. Zwraca ComputationalBudgetExceeded, jeśli przekroczono budżet.
    • Deserializuje dane kont z bufora z powrotem do stanu konta
  6. Zdejmuje ramkę stosu. Wywołuje pop(), który weryfikuje, czy instrukcja nie naruszyła zasad rozliczania środowiska uruchomieniowego (salda lamport są zbilansowane, konta tylko do odczytu nie zostały zmodyfikowane, rozmiary danych kont mieszczą się w limitach).

  7. Sumuje jednostki obliczeniowe. Jednostki obliczeniowe zużyte przez instrukcję są dodawane do sumy transakcji przez saturating_add.

Program cache

Środowisko uruchomieniowe utrzymuje globalny ProgramCache, który przechowuje zweryfikowane i skompilowane programy. Jest świadomy grafu forków i obsługuje zasady widoczności wdrożeń, usuwanie z pamięci oraz rekompilację na granicy epoch.

Typy wpisów w cache'u

Każdy program w cache'u posiada ProgramCacheEntryType, który określa jego zachowanie w środowisku uruchomieniowym:

TypOpis
LoadedZweryfikowany i skompilowany program, gotowy do wykonania.
BuiltinProgram natywny skompilowany do binarki validatora (System, Stake, Vote itd.). Nie jest przechowywany on-chain.
UnloadedWcześniej zweryfikowany program, którego skompilowany plik wykonywalny został usunięty z pamięci w celu zwolnienia miejsca. Nadal śledzi statystyki użycia. Może zostać ponownie załadowany bez ponownej weryfikacji.
FailedVerificationNagrobek dla programów, które nie przeszły weryfikacji sBPF w ramach aktualnego zestawu funkcji. Może stać się Loaded, jeśli aktywacje funkcji zmienią zasady weryfikacji.
ClosedNagrobek dla programów, które zostały jawnie zamknięte lub nigdy nie zostały wdrożone. Używany także dla kont (np. kont buforowych) należących do loadera, ale nie zawierających kodu wykonywalnego.
DelayVisibilitySyntetyczny nagrobek zwracany przez ProgramCacheForTxBatch::find(), gdy istnieje wpis Loaded, ale nie jest jeszcze aktywny (jego effective_slot jest w przyszłości). Nigdy nie jest przechowywany bezpośrednio w cache'u.

Opóźnienie widoczności

Nowo wdrożone lub zaktualizowane programy nie stają się aktywne natychmiast. Stała DELAY_VISIBILITY_SLOT_OFFSET ma wartość 1, co oznacza, że program wdrożony w slocie N staje się aktywny w slocie N+1. Podczas slotu wdrożenia każda próba wywołania nowej wersji zwraca DelayVisibility, powodując, że środowisko uruchomieniowe zgłasza "Program nie jest wdrożony."

Polityka usuwania (eviction policy)

Cache przechowuje maksymalnie MAX_LOADED_ENTRY_COUNT (512) skompilowanych wpisów programów. Po osiągnięciu limitu, najmniej używane programy są usuwane do stanu Unloaded. Użycie jest śledzone przez tx_usage_counter (zwiększane za każdym razem, gdy transakcja odwołuje się do programu) oraz latest_access_slot.

Rekompilacja na granicy epoch

Jeśli aktywacja funkcji zmienia ProgramRuntimeEnvironments na granicy epoch, wszystkie programy w cache są rekompilowane w nowym środowisku.

Dane zwrotne

Programy mogą ustawiać dane zwrotne za pomocą syscalla sol_set_return_data. Dane są przechowywane w strukturze na poziomie transakcji TransactionReturnData, która zawiera bajty danych oraz program_id programu, którego instrukcja wywołała syscall. Maksymalny rozmiar to 1 024 bajty (MAX_RETURN_DATA).

Is this page helpful?

Spis treści

Edytuj stronę

Zarządzane przez

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