Sealevel — это модель исполнения Solana, позволяющая запускать несколько транзакций одновременно, если они не конфликтуют по данным. Ключевая идея проста: каждая транзакция заранее объявляет все аккаунты (участки состояния), с которыми она собирается работать, и права доступа к ним (read/write, требуется ли подпись). Благодаря этому рантайм способен построить «сетку независимости» и распараллелить вызовы. В связке с моделью аккаунтов и источником времени Solana это даёт предсказуемую пропускную способность и низкие задержки.
Эта страница — техническая опора для разработчиков и продвинутых пользователей. Здесь собраны принципы Sealevel, поведение под нагрузкой, анти-паттерны и практические приёмы проектирования dApp. За обзор протокола см. Архитектура Solana: Объяснение Высокой Производительности, PoH, Sealevel, терминологию виртуальной машины — SVM (Solana Virtual Machine): что это и как работает — BPF, CPI и отличие от EVM, устройство хранения — Solana: модель аккаунтов — PDAs, read/write-локи, rent-exempt, ALTs.
Коротко про Sealevel: параллельное исполнение в Solana (рантайм и планировщик)
- Параллелизм идёт по данным, а не «по блокам»: независимые наборы аккаунтов исполняются одновременно.
- Транзакция обязана заранее указать все аккаунты, которыми будет пользоваться (включая те, что понадобятся во внутренних вызовах — CPI).
- Конфликт — это пересечение по аккаунту с правами записи (или по «горячим» системным ресурсам); чтение-чтение совместимо.
- Планировщик Sealevel строит партии транзакций, минимизируя конфликты; внутри партии операции идут параллельно.
- Комиссии и приоритеты работают локально вокруг «очагов данных», см. Local Fee Market (Solana): локальные рынки комиссий и priority fees и Priority Fee (Solana): приоритетная комиссия за compute units (CU) и «чаевые» валидатору.
Базовые сущности Sealevel
Программа (program) Развёрнутый исполняемый код (аналог «контракта»), который вызывает пользовательская транзакция или другая программа (через CPI).
Аккаунт (account) Хранилище данных и/или объект-ресурс (включая токены, записи DEX, ордера и т. п.). В контексте вызова каждому аккаунту назначаются флаги: *is_signer*, *is_writable*, а также порядок.
Инструкция (instruction) Мини-вызов функции программы с явным списком «account metas» — именно он определяет доступ к конкретным аккаунтам. Транзакция содержит одну или несколько инструкций.
Compute Units (CU) Квота вычислений на транзакцию. Предел CU регулирует сложность работы; экономия важна для пропускной способности и UX.
Cross-Program Invocation (CPI) Вызов одной программы из другой внутри той же транзакции. Важное правило Sealevel: CPI не может «тайно» открыть новый аккаунт — все потенциальные аккаунты должны быть перечислены заранее.
Как именно достигается параллелизм
Sealevel реализует предварительное планирование по данным. Упрощённый жизненный цикл обработки партии:
- Узел-лидер принимает поток транзакций и «нарезает» их на партии.
- Для каждой транзакции строится множество аккаунтов с типами доступа (R/W).
- Рантайм пытается набрать в одну партию транзакции, для которых нет пересечений по write (RW-конфликты).
- Чтение-чтение* совместимо; *чтение-запись* или *запись-запись* на одном аккаунте — конфликт.
- Партия отдаётся на параллельное исполнение (в пределах ядер/воркеров). Завершившиеся транзакции освобождают «замки» на аккаунтах, следующая волна стартует.
Если в процессе CPI возникает попытка доступа к аккаунту, не указанному в транзакции, или меняется режим доступа (нужна запись вместо чтения), рантайм прерывает выполнение — конфликты не утаить.
Типы конфликтов и их признаки
| Тип конфликта | Что это означает | Как выявлять/лечить в dApp |
|---|---|---|
| write–write на одном аккаунте | Две транзакции хотят одновременно изменить один и тот же аккаунт | Шардируйте состояние: разбивайте глобальные «счётчики/пулы» на пользовательские или «по рынкам» |
| read–write на «горячем» аккаунте | Одна транзакция пишет, другая читает тот же аккаунт (пока он «под замком») | Используйте «снимки»/кэши, ETag-подобные стратегии и финальные проверки инвариантов |
| Скрытая зависимость через CPI | Внутренний вызов пытается использовать неуказанный в транзакции аккаунт | Явно перечисляйте «пороговые» аккаунты; проектируйте API программ так, чтобы их невозможно было вызвать без полного списка |
| Системные/арифметические лимиты CU | Транзакция «съедает» квоту и блокирует воркер | Профилируйте и оптимизируйте горячие пути, дробите инструкции |
Модель аккаунтов и «шахматка независимости»
Solana хранит данные в аккаунтах, а не в «глобальном сторидже». Это задаёт геометрию параллелизма:
- Если два действия затрагивают разные аккаунты, Sealevel может их запустить одновременно.
- Если они делят один и тот же аккаунт на запись, возникнет блокировка — в партию попадёт что-то одно.
- При разумном проектировании схемы хранения (PDA, «ключ-разделитель», per-user/per-market состояния) достигается почти линейный рост Throughput с числом независимых «островков данных».
Подробнее об устройстве см. Solana: модель аккаунтов — PDAs, read/write-локи, rent-exempt, ALTs.
CPI: мощный инструмент с жёсткими рамками
CPI позволяет строить композицию программ: AMM вызывает токен-программу, ордербук — клиринг, кошелёк — системные операции и т. д. Но у этого есть следствия:
- Внешняя транзакция обязана принести с собой все аккаунты, которые могут понадобиться глубже по стеку CPI.
- Набор прав (read/write, signer) не может «усугубляться» вглубь без явного разрешения на поверхности.
- Поэтому API ваших программ должен быть детерминирован в части перечня ресурсов: указывайте в документации ровно, какие аккаунты нужны.
Этот контракт защищает Sealevel от «динамического» конфликта, который нельзя было бы спланировать заранее.
Локальные рынки комиссий и приоритеты
Параллелизм Sealevel тесно связан с локальными рынками комиссий: там, где много транзакций бьются за один и тот же «горячий» аккаунт (пул ликвидности, минт коллекции и т. п.), образуется локальный аукцион приоритета. Транзакции, не затрагивающие этот очаг, не переплачивают. Смотрите базовые страницы Local Fee Market (Solana): локальные рынки комиссий и priority fees и Priority Fee (Solana): приоритетная комиссия за compute units (CU) и «чаевые» валидатору для пользовательского UX и ценообразования.
Для инфраструктуры и потоков заказов в моменты пиков используйте модели приватного/пакетного отправления; архитектурно это раскрывается в связке с Jito Block Engine: частные бандлы, аукционы и MEV на Solana — как это работает, где бандлеры и блок-энджины минимизируют вредные перестановки и фронт-раннинг (MEV (Maximal Extractable Value) в блокчейнах и на Solana — определение и примеры).
Проектные паттерны для высокой параллельности
- Шардируйте по пользователю/рынку. Храните состояние так, чтобы каждая операция касалась минимального набора аккаунтов. Пример: не общий «супер-счётчик» для всей dApp, а счётчики на пользователя/рынок/ординарный ключ.
- Разделяйте «горячее» и «холодное». Метаданные, конфигурации и редко меняющиеся записи держите в отдельных аккаунтах без записи в каждом вызове.
- Фиксируйте инварианты «на входе». Пусть каждая инструкция валидирует пред-условия и завершает работу раньше, если конфликт неминуем.
- Делайте «узкие» инструкции. Разбейте тяжёлый путь на несколько независимых инструкций, чтобы планировщик мог впитать их в разные партии.
- Идентификаторы-разделители (PDA). Проектируйте адреса аккаунтов так, чтобы они естественно «раскладывались» по ключам, исключая ненужные пересечения.
- Контролируйте CU. Используйте лимиты и профилирование, не допускайте «взрыва» вычислений одной транзакцией.
Анти-паттерны (и как их исправить)
- Глобальные счётчики и «общие корзины». Любая запись в такой объект серийно блокирует всех — заменяйте на иерархию счётчиков/балансов.
- Длинные цепочки CPI с «сюрпризами». Не вносите вглубь новые зависимости; публикуйте явные требования к аккаунтам в API.
- Смешивание прав доступа. Если вам почти всегда нужна запись, объявляйте write сразу; излишне «оптимистичное» объявление read → повышает риск отказа.
- Одна транзакция «за всё». Склеивание множества логических шагов в один вызов делает параллелизм невозможным и повышает риск лимитов CU.
Поведение под нагрузкой и диагностика
| Симптом | Возможная причина | Что делать разработчику |
|---|---|---|
| Рост отказов без явных ошибок кода | Транзакции сталкиваются по «горячим» аккаунтам, планировщик вынужден серийно ставить их в очередь | Проведите профилирование конфликтов: какие аккаунты чаще всего в write; переразбейте хранение |
| «Флапающая» латентность (p95/p99) | Перемежающаяся перегрузка конкретного рынка/пула | Добавьте подсказки по Priority Fee (Solana): приоритетная комиссия за compute units (CU) и «чаевые» валидатору в UI, предложите режимы «обычно/быстро/срочно» |
| Высокий расход CU, деградация TPS | Излишняя логика на стороне одной транзакции, мало переиспользуемых кэшей | Декомпозируйте инструкции, оптимизируйте сериализацию/десериализацию |
| Отказы CPI «account not found/borrowed as immutable» | Неполный перечень аккаунтов или неверный режим доступа | Явно перечислите все аккаунты на поверхности, согласуйте флаги R/W и signer |
Пример: почему два свопа могут идти параллельно
Представьте две транзакции A и B:
- A меняет токен X↔Y в пуле «PX», трогая аккаунты: кошелёк пользователя A, два аккаунта токенов, записи пула «PX».
- B меняет токен U↔V в пуле «PY», трогая кошелёк пользователя B, два аккаунта токенов, записи пула «PY».
Если PX ≠ PY и нет пересечений по кошелькам/посредникам на запись, то A и B независимы — Sealevel отправит их в одну партию, и обе завершатся без ожидания друг друга. Если же две операции касаются одного и того же пула «PX» и пишут в его состояние, они будут сериализованы.
Сравнение Sealevel и классической модели EVM
| Аспект | Sealevel (Solana) | Классическая EVM (L1) |
|---|---|---|
| Единица состояния | Аккаунты с явными правами в инструкциях | Глобальный storage, адресуемый контрактами |
| Планирование | Параллельно по несовпадающим наборам аккаунтов | Последовательно (одна глобальная очередь) |
| Зависимости | Видны до исполнения (по списку account metas) | Выявляются во время исполнения |
| CPI / композиция | Разрешена, но только поверх объявленных аккаунтов | Вызовы свободны, зависимости — динамические |
| Ценообразование | Локальные рынки вокруг «горячих» данных (Local Fee Market (Solana): локальные рынки комиссий и priority fees) | Глобальный аукцион газа для всего блока |
| UX при пиках | Стабильно вне «очагов»; внутри — локальный аукцион приоритета | Растёт цена для всех, даже «непричастных» транзакций |
Безопасность и инварианты
- Подписи и владение. Любой аккаунт, требующий изменения, должен быть открыт с флагом *is_signer* у соответствующего владельца/программы.
- Borrow-правила. Аккаунт не может одновременно быть изменяемым и заимствованным как «immutable» в том же контексте — это защищает от классов ошибок на уровне ссылок.
- Детерминизм доступа. Поскольку все аккаунты указаны заранее, классы атак «скрытой подмены» через CPI существенно ограничены.
- Ограничение CU. Предел вычислений защищает узел от «пылесоса CPU», а сеть — от «залипания» одной транзакции.
Практические рекомендации по API программ
- Проектируйте плоские и предсказуемые интерфейсы: по названию инструкции и её параметрам должно быть ясно, какие аккаунты требуются.
- Документируйте минимальные и достаточные наборы аккаунтов для каждого пути.
- Валидируйте режимы доступа на старте: если нужен *write* — отклоняйте «read-транзакции» ранним кодом возврата.
- Синхронизируйте версии программ с клиентскими SDK: несовместимости часто проявляются в неправильно собранных списках account metas.
Метрики и наблюдаемость
- Доля конфликтов по аккаунтам. Сколько транзакций в партии пришлось сериализовать.
- Распределение CU. Где «горит» вычисление — в сериализации, криптографии, логике приложения.
- Латентность p95/p99 по типам операций, отдельно внутри и вне «горячих» рынков.
- Ошибки CPI. Частота «account not found», «borrowed as immutable», «insufficient privileges» — прямые подсказки, куда смотреть в API.
Частые вопросы (FAQ)
Это «параллельный консенсус»? Нет. Параллелится исполнение транзакций. Консенсус и финализация описаны отдельно (см. Solana Proof of History (PoH): как работает «доказательство истории» и Solana Tower BFT: механизм финализации блоков и «лок-ауты» голосов).
Можно ли скрыть конфликт, подтянув аккаунт через CPI? Нельзя: все аккаунты должны быть перечислены в транзакции, иначе выполнение прервётся.
Почему две «простые» операции иногда ждут друг друга? Потому что они пишут в один и тот же «горячий» аккаунт. Перепроектируйте хранение, чтобы сократить пересечения.
Помогают ли высокие приоритетные комиссии «обогнать» конкурентов? Да, но только внутри локального рынка вокруг затронутых аккаунтов. См. Priority Fee (Solana): приоритетная комиссия за compute units (CU) и «чаевые» валидатору.
Влияет ли Jito/бандлинг на параллелизм? Да: грамотное упорядочивание и пакетирование потоков снижает вредные перестановки и улучшает использование «пустот» параллелизма (см. Jito Block Engine: частные бандлы, аукционы и MEV на Solana — как это работает).
Мини-глоссарий
- Account metas — список аккаунтов с правами доступа, передаваемый в инструкцию.
- CPI (Cross-Program Invocation) — вызов одной программы из другой в рамках одной транзакции.
- Conflict set — пересечение транзакций по аккаунтам на запись; определяет сериализацию.
- Compute Units (CU) — лимит вычислений на транзакцию.
- PDA (Program-Derived Address) — адрес аккаунта, детерминированно получаемый программой по сид-параметрам.
См. также
Solana: модель аккаунтов — PDAs, read/write-локи, rent-exempt, ALTs Local Fee Market (Solana): локальные рынки комиссий и priority fees
