Виконання програм

Підсумок

Програми компілюються в sBPF через LLVM і виконуються в ізольованій VM з бюджетом 1,4 млн CU на транзакцію. Середовище виконання кешує до 512 скомпільованих програм, надає системні виклики для логування, CPI, криптографії та пам'яті, а також затримує нові розгортання на 1 slot.

Компіляція

Solana використовує LLVM для компіляції програм у бінарні файли ELF, що містять Solana Bytecode Format (sBPF). ELF-бінарний файл зберігається в мережі у виконуваному акаунті.

sBPF — це власний варіант байткоду eBPF від Solana, адаптований для середовища виконання Solana. Це не стандартний eBPF — він містить специфічні для Solana модифікації.

Написання програм

Програми Solana переважно пишуться на Rust з використанням одного з трьох підходів:

Дивіться Cross-Program Invocations для ознайомлення з концепціями та прикладами CPI, що застосовуються в усіх цих підходах.

Модель виконання програм

Коли транзакція обробляється, середовище виконання послідовно виконує кожну інструкцію через process_message(). Для кожної інструкції середовище виконання:

  1. Готує контекст інструкції. Викликає prepare_next_top_level_instruction(), щоб зіставити індекси акаунтів інструкції, встановити прапорці підписанта та запису, а також налаштувати TransactionContext.

  2. Перевіряє прекомпілятори. Якщо програма є прекомпілятором, середовище виконання викликає process_precompile(), що все одно додає та знімає кадр стека (через push() та pop()), але обходить sBPF VM і пошук у кеші програм, виконуючи нативний код безпосередньо.

  3. Додає кадр стека. (Кроки 3–6 відбуваються всередині InvokeContext::process_instruction() та process_executable_chain(), що викликаються з process_message().) Викликає push() на InvokeContext, що збільшує висоту стека інструкцій і забезпечує дотримання правила повторного входу: програма може повторно входити сама в себе лише якщо безпосередній викликач (програма на поточній вершині стека інструкцій) є тією самою програмою. Глибока само-рекурсія (A -> A -> A) дозволена з урахуванням обмежень глибини стека. Інші шаблони повторного входу (наприклад, A викликає B, B викликає A) повертають InstructionError::ReentrancyNotAllowed.

  4. Визначає програму. Середовище виконання викликає process_executable_chain(), яка визначає завантажувач. Якщо власником program account є native loader, програма є вбудованою, і її точка входу знаходиться безпосередньо в ProgramCacheForTxBatch. Якщо власником є один із BPF-завантажувачів (bpf_loader_deprecated, bpf_loader, bpf_loader_upgradeable або loader_v4), натомість викликається власна вбудована точка входу завантажувача.

  5. Виконує BPF-програму. Для BPF-програм точка входу завантажувача знаходить скомпільований виконуваний файл у кеші програм. Потім функція execute():

    • Серіалізує дані акаунтів у плаский буфер параметрів
    • Створює sBPF VM зі стеком, купою та областями пам'яті
    • Запускає скомпільований код, споживаючи обчислювальні одиниці під час виконання. Повертає ComputationalBudgetExceeded, якщо бюджет перевищено.
    • Десеріалізує дані акаунтів із буфера назад у стан акаунту
  6. Знімає кадр стека. Викликає pop(), яка перевіряє, що інструкція не порушила правила обліку середовища виконання (баланси lamport збалансовані, акаунти лише для читання не були змінені, розміри даних акаунтів знаходяться в межах допустимого).

  7. Накопичує обчислювальні одиниці. Обчислювальні одиниці, спожиті інструкцією, додаються до загальної суми транзакції через saturating_add.

Кеш програм

Середовище виконання підтримує глобальний ProgramCache, що зберігає перевірені та скомпільовані програми. Він підтримує граф форків і обробляє правила видимості розгортань, виселення та перекомпіляцію на межі epoch.

Типи записів кешу

Кожна кешована програма має ProgramCacheEntryType, що визначає її поведінку під час виконання:

ТипОпис
LoadedПеревірена та скомпільована програма, готова до виконання.
BuiltinНативна програма, скомпільована у бінарний файл validator (System, Stake, Vote тощо). Не зберігається в мережі.
UnloadedРаніше перевірена програма, скомпільований виконуваний файл якої було виселено з пам'яті для звільнення місця. Все ще відстежує статистику використання. Може бути перезавантажена без повторної перевірки.
FailedVerificationЗапис-«надгробок» для програм, які не пройшли верифікатор sBPF за поточного набору функцій. Може стати Loaded, якщо активація функцій змінить правила верифікації.
ClosedЗапис-«надгробок» для програм, які були явно закриті або так і не були розгорнуті. Також використовується для акаунтів (наприклад, буферних), що належать завантажувачу, але не містять виконуваного коду.
DelayVisibilityСинтетичний запис-«надгробок», який повертає ProgramCacheForTxBatch::find(), коли запис Loaded існує, але ще не набрав чинності (його effective_slot знаходиться в майбутньому). Ніколи не зберігається безпосередньо в кеші.

Затримка видимості

Щойно розгорнуті або оновлені програми не набирають чинності негайно. Константа DELAY_VISIBILITY_SLOT_OFFSET дорівнює 1, тобто програма, розгорнута в slot N, набирає чинності в slot N+1. Протягом slot розгортання будь-яка спроба викликати нову версію повертає DelayVisibility, і середовище виконання повідомляє «Program is not deployed.»

Політика виселення

Кеш містить до MAX_LOADED_ENTRY_COUNT (512) записів скомпільованих програм. Коли ліміт досягнуто, найменш використовувані програми виселяються до стану Unloaded. Використання відстежується за допомогою tx_usage_counter (збільшується щоразу, коли транзакція звертається до програми) та latest_access_slot.

Перекомпіляція на межі epoch

Якщо активація функції змінює ProgramRuntimeEnvironments на межі epoch, усі кешовані програми перекомпілюються під нове середовище.

Повернення даних

Програми можуть встановлювати повернені дані через системний виклик sol_set_return_data. Дані зберігаються у структурі рівня транзакції TransactionReturnData, яка містить байти даних і program_id програми, чия інструкція викликала системний виклик. Максимальний розмір — 1 024 байти (MAX_RETURN_DATA).

Is this page helpful?