НОВОЕ: Helius приобретает Light Protocol
Версии транзакций Solana: Legacy, v0 и v1
Блог/Основы

Версии транзакций Solana: Legacy, v0 и v1

ИсследовательLostin в X
Чтение: 17 мин

Краткая история форматов транзакций Solana

В Solana есть три формата транзакций: Legacy, v0 и v1. На высоком уровне все они решают одну задачу: объединяют подписи, аккаунты и инструкции, которые валидаторы выполняют в ончейн-программах.

Со временем менялся формат передачи данных — то, как эти элементы сериализуются и передаются по сети.

Каждый новый формат устранял ограничения, которые возникали по мере усложнения приложений Solana. При этом сохранялась обратная совместимость, чтобы старые форматы продолжали работать.

Все три формата сосуществуют в сети. Разработчики могут использовать тот, который лучше всего подходит для создаваемой транзакции.

Legacy-транзакции

Исходный формат называют Legacy, поскольку он появился до версионирования транзакций и не содержит идентификатора версии.

Максимальный размер в 1 232 байта связан с исходной сетевой архитектурой Solana: размер транзакций рассчитывался так, чтобы они помещались в минимальный MTU IPv6 в 1 280 байт. После учета сетевых накладных расходов оставалось 1 232 байта.

Для небольших транзакций этого хватало, но по мере развития приложений ограничение становилось все более существенным. Каждый адрес аккаунта, непосредственно включенный в транзакцию, занимает 32 байта, а каждая подпись Ed25519 — еще 64 байта.

Поэтому на практике транзакции с большим числом аккаунтов могли исчерпать лимит байтов задолго до достижения лимита блокировок аккаунтов в среде выполнения.

Транзакции v0

Первой попыткой ослабить это ограничение стали транзакции v0, запущенные в mainnet-beta в октябре 2022 года. Вместо увеличения лимита в 1 232 байта формат v0 представил таблицы поиска адресов (Address Lookup Tables, ALT).

ALT хранит адреса аккаунтов ончейн. Благодаря этому транзакция v0 может ссылаться на них с помощью однобайтовых индексов, а не повторять каждый 32-байтовый публичный ключ. Это позволяет транзакциям достигать лимита среды выполнения в 64 аккаунта, не выходя за существующее ограничение размера пакета.

v0 стал последовательным расширением формата Legacy: он добавил префикс версии 0x80 и раздел поиска адресов, сохранив базовую кодировку сообщений и инструкций.

Появление версионирования также создало основу, при которой новые форматы транзакций могли сосуществовать с Legacy-транзакциями, а не заменять их.

ALT решили непосредственную проблему с размером списка аккаунтов, но создали новые сложности. Приложения должны создавать и обслуживать таблицы поиска ончейн, валидаторы — разрешать их записи перед выполнением, а RPC-сервисы и индексаторы должны получать разрешенные адреса для восстановления полной транзакции.

Историческое декодирование также значительно усложняется, если таблица поиска, на которую ссылается необработанная транзакция, впоследствии была закрыта. Таким образом, v0 эффективно сжимал список аккаунтов, но добавлял в представление транзакции при передаче внешнюю ончейн-зависимость.

Разработчики Solana стали активно использовать ALT. Исследование, проведенное незадолго до появления транзакций v1, показало, что около 62% транзакций v0 ссылаются хотя бы на одну ALT.

Добавление приоритетных комиссий

Приоритетные комиссии также появились в Solana в 2022 году, до активации транзакций v0 в основной сети, хотя к тому моменту сам формат v0 уже был разработан. Вместо переработки одного из форматов транзакций Solana добавила настройку комиссий через существующую Compute Budget Program. Транзакции могли включать такие инструкции, как SetComputeUnitLimit и SetComputeUnitPrice. Это позволяло пользователям запрашивать вычислительный бюджет и добавлять комиссию за приоритет при планировании. Решение одинаково хорошо работало для Legacy- и v0-транзакций и не требовало отдельного механизма комиссий для каждого формата.

Это было практичное решение с обратной совместимостью, но не самое элегантное. Приоритетные комиссии и лимиты вычислений фактически являются метаданными уровня транзакции. Однако в Legacy и v0 для них не было отдельных полей, поэтому их добавили в поток инструкций в виде вызовов программы. В результате транзакция должна ссылаться на Compute Budget Program, конфигурация занимает байты инструкций, а валидаторам приходится проверять эти инструкции при приеме транзакции, чтобы получить настройки комиссий и ресурсов.

Таким образом, v0 не был масштабной переработкой формата транзакций Solana. Его основная цель заключалась в устранении узкого места, связанного с адресами аккаунтов, с помощью Address Lookup Tables. При этом большая часть структуры сообщений Legacy осталась неизменной. Поскольку инструкции Compute Budget уже обеспечивали совместимый способ поддержки приоритетных комиссий в обоих форматах, расширять область применения v0 не было необходимости.

Увеличенный размер транзакций

Со временем Solana перевела прием транзакций с UDP на QUIC, потоки которого больше не ограничены одной полезной нагрузкой размером с MTU. Поэтому исходный предел в 1 232 байта перестал быть транспортным требованием. В 2025 году были предложены два SIMD для внедрения нового формата v1. SIMD-0296 увеличил максимальный размер транзакции v1 до 4 096 байт — примерно в 3,3 раза больше прежнего лимита. SIMD-0385 определил полностью новый формат передачи данных, рассчитанный на дополнительное пространство и более эффективный прием транзакций валидаторами.

Дополнительное пространство позволяет v1 полностью отказаться от ALT. Для лимита в 64 аккаунта с 32-байтовыми адресами требуется не более 2 048 байт, поэтому полный список аккаунтов можно передавать непосредственно в транзакции.

Анализ Solana Foundation показывает, что при переводе большинства существующих транзакций v0 на новый формат увеличение размера из-за непосредственного включения всех адресов будет умеренным: 50% транзакций вырастут менее чем на 420 байт, а 90% — менее чем на 1 400 байт. Даже у транзакций, активно использующих ALT, останется значительный запас в пределах лимита v1 в 4 096 байт.

Что еще важнее, v1 — это не просто увеличенная транзакция v0. Формат передачи данных существенно реорганизован: подписи перемещены в конец, конфигурация ресурсов вынесена из инструкций Compute Budget в раздел конфигурации транзакции, а полезные нагрузки инструкций переменной длины отделены от заголовков фиксированной длины. Благодаря этим изменениям валидаторы могут быстрее и проще анализировать транзакции и определять их приоритет.

Увеличенный лимит в 4 096 байт также открывает возможности для нагрузок, которым не помогло бы одно лишь сжатие адресов. Доказательства с нулевым разглашением, вложенные мультиподписи, необрезанные подписи Winternitz, подписи BLS и другие криптографические операции могут требовать сотни или тысячи байтов данных инструкций. Например, конфиденциальные балансы Token-2022 теперь можно реализовать в виде одной атомарной транзакции v1, а не разделять между несколькими транзакциями.

Важно отметить, что первоначальный формат v1 не повышает лимиты Solana на вычисления, подписи, количество инструкций или 64 аккаунта. Он прежде всего устраняет ограничение размера и меняет представление транзакции при передаче.

SIMD-0596, предложенный Anza, увеличит лимит блокировок аккаунтов для v1 с 64 до 96. Он будет охватывать все аккаунты, на которые ссылается транзакция, включая подписантов, ID программ, а также доступные для записи и только для чтения аккаунты. На момент написания это предложение все еще рассматривается. Для транзакций Legacy и v0 сохранится лимит в 64 аккаунта.

Спецификации и сравнение форматов

ОграничениеLegacyv0v1
Максимальный размер1 232 байта1 232 байта4 096 байт
Адреса аккаунтов~32, ограничены размером64, через таблицы поиска64, непосредственно в транзакции
Таблицы поиска адресовНе поддерживаютсяПоддерживаютсяНе поддерживаются
Повторяющиеся адресаразрешеныразрешеныотклоняются
ПрефиксНет0x800x81
Приоритетная комиссияИнструкция SetComputeUnitPrice, микролампорты за CUИнструкция SetComputeUnitPrice, микролампорты за CUconfig.priorityFeeLamports, общее количество лампортов
Лимит вычислительных единицИнструкция SetComputeUnitLimitИнструкция SetComputeUnitLimitconfig.computeUnitLimit
Размер кучиИнструкция RequestHeapFrameИнструкция RequestHeapFrameconfig.heapSize
Лимит загруженных аккаунтовИнструкция SetLoadedAccountsDataSizeLimitИнструкция SetLoadedAccountsDataSizeLimitconfig.loadedAccountsDataSizeLimit

Спецификация Legacy-транзакции

Сериализованная Legacy-транзакция начинается с количества подписей в формате compact-u16, за которым следуют 64-байтовые подписи Ed25519.

Далее идет сообщение, содержащее трехбайтовый заголовок, список аккаунтов с префиксом компактной длины, 32-байтовый недавний хеш блока и массив скомпилированных инструкций с префиксом компактной длины.

У Legacy-транзакций нет префикса версии.

Код
NumSignatures (compact-u16)

Signatures [[u8; 64]]
  -- Length = NumSignatures

MessageHeader (u8, u8, u8)
  -- (NumRequiredSignatures,
      NumReadonlySignedAccounts,
      NumReadonlyUnsignedAccounts)

NumAccountKeys (compact-u16)

AccountKeys [[u8; 32]]
  -- Length = NumAccountKeys

RecentBlockhash [u8; 32]

NumInstructions (compact-u16)

Instructions [CompiledInstruction]
  -- Length = NumInstructions

CompiledInstruction:
  ProgramIdIndex (u8)

  NumInstructionAccounts (compact-u16)

  InstructionAccountIndexes [u8]
    -- Length = NumInstructionAccounts

  InstructionDataLength (compact-u16)

  InstructionData [u8]
    -- Length = InstructionDataLength

Ключевая особенность заключается в том, что каждая CompiledInstruction полностью сериализуется до начала следующей инструкции.

Массивы индексов аккаунтов и данных имеют переменную длину, которая задается префиксами compact-u16.

Спецификация транзакции v0

Транзакция v0 сохраняет почти весь формат передачи данных Legacy. Транзакция по-прежнему начинается с количества подписей и самих подписей, но сообщение начинается с префикса версии 0x80.

Затем в сообщении используются те же трехбайтовый заголовок, статический список аккаунтов, хеш блока и формат скомпилированных инструкций, что и в Legacy. После них добавляется раздел Address Lookup Table.

Это позволяет транзакциям v0 загружать дополнительные аккаунты через ALT и при этом не превышать лимит транзакции в 1 232 байта.

Код
NumSignatures (compact-u16)

Signatures [[u8; 64]]
  -- Length = NumSignatures

VersionByte (u8)
  -- 0x80

MessageHeader (u8, u8, u8)

NumStaticAccountKeys (compact-u16)

StaticAccountKeys [[u8; 32]]
  -- Length = NumStaticAccountKeys

RecentBlockhash [u8; 32]

NumInstructions (compact-u16)

Instructions [CompiledInstruction]
  -- Same encoding as legacy

NumAddressTableLookups (compact-u16)

AddressTableLookups [MessageAddressTableLookup]
  -- Length = NumAddressTableLookups

MessageAddressTableLookup:
  AccountKey [u8; 32]
    -- Address of the lookup table account

  NumWritableIndexes (compact-u16)

  WritableIndexes [u8]
    -- Indices into the lookup table

  NumReadonlyIndexes (compact-u16)

  ReadonlyIndexes [u8]
    -- Indices into the lookup table

Различие между статическими ключами аккаунтов и загруженными адресами имеет большое значение. Непосредственно в сообщение сериализуются только статические ключи. Адреса, на которые есть ссылки через ALT, разрешаются во время выполнения и добавляются в итоговый список аккаунтов.

Для транзакции v0, использующей ALT, валидатор должен сначала загрузить каждую указанную таблицу поиска из Bank и AccountsDB, проверить, что аккаунт является допустимой Address Lookup Table, десериализовать ее состояние, преобразовать запрошенные индексы в полные 32-байтовые адреса, а затем объединить эти адреса со статическими ключами аккаунтов транзакции. Только после этого валидатор получает полный список аккаунтов, необходимый для определения блокировок чтения и записи и конфликтов с другими транзакциями.

Спецификация транзакции v1

Сериализованная транзакция v1 начинается с байта версии 0x81. За ним следуют трехбайтовый заголовок сообщения в стиле Legacy, 32-битная маска конфигурации транзакции, 32-байтовый спецификатор срока действия, количество инструкций и адресов, полный массив 32-байтовых адресов, значения конфигурации, заголовки инструкций фиксированного размера, непрерывные полезные нагрузки инструкций и, наконец, подписи.

Код
VersionByte (u8)
  -- 0x81

LegacyHeader (u8, u8, u8)

TransactionConfigMask (u32)
  -- Bitmask describing which configuration values are present

LifetimeSpecifier [u8; 32]

NumInstructions (u8)

NumAddresses (u8)

Addresses [[u8; 32]]
  -- Length = NumAddresses

ConfigValues [[u8; 4]]
  -- Length = popcount(TransactionConfigMask)
  -- Multi-word values, such as priority fee, consume multiple entries

InstructionHeaders [(u8, u8, u16)]
  -- Length = NumInstructions
  -- (ProgramAccountIndex,
      NumInstructionAccounts,
      NumInstructionDataBytes)

InstructionPayloads [InstructionPayload]
  -- Length = NumInstructions

InstructionPayload:
  InstructionAccountIndexes [u8]
    -- Length = NumInstructionAccounts

  InstructionData [u8]
    -- Length = NumInstructionDataBytes

Signatures [[u8; 64]]
  -- Length = LegacyHeader.NumRequiredSignatures

Таким образом, v1 принципиально отличается от предыдущих форматов по нескольким параметрам. Идентификатор версии находится в нулевом байте, подписи перемещены в конец и больше не требуют собственного префикса длины, количество аккаунтов и инструкций представлено значениями u8 фиксированной ширины, конфигурация ресурсов кодируется непосредственно в транзакции, а заголовки инструкций фиксированного размера отделены от полезных нагрузок переменной длины. В отличие от Legacy и v0, v1 не использует Address Lookup Tables.

Транзакция v1 заменяет инструкции конфигурации Compute Budget Program полями в заголовке транзакции. Исходная TransactionConfigMask может задавать следующие параметры транзакции:

  • общая приоритетная комиссия в лампортах
  • лимит вычислительных единиц
  • лимит размера данных загруженных аккаунтов
  • запрошенный размер кучи

Каждый установленный бит указывает на сопутствующее четырехбайтовое значение конфигурации, при этом 64-битная приоритетная комиссия занимает две позиции маски. Маску можно расширять в будущих версиях транзакций.

Пример транзакции

Чтобы сравнить различные форматы транзакций Solana, рассмотрим простейший полезный пример: перевод SOL с одного адреса на другой.

В нашей тестовой транзакции есть один подписант, то есть отправитель. Она один раз вызывает System Program, чтобы перевести получателю 1 000 лампортов. Транзакция ссылается на три адреса: отправителя, получателя и System Program.

Транзакции Legacy и v0

Транзакции Legacy и v0 используют почти одинаковую структуру верхнего уровня. Обе начинаются с количества подписей, сразу после которого идут сами подписи. Затем следует сообщение транзакции. Для перевода с одним подписантом первый байт — 01. Он указывает на одну подпись, после чего идет 64-байтовая подпись Ed25519 отправителя.

Сообщение содержит трехбайтовый заголовок, адреса аккаунтов, недавний хеш блока — спецификатор срока действия — и скомпилированные инструкции.

Отправитель имеет адрес 0, получатель — адрес 1, а System Program — адрес 2. Инструкция перевода ссылается на программу по индексу 2 и передает ей индексы аккаунтов 00 01.

Форматы Legacy и v0 различаются лишь незначительно:

  • Сообщение Legacy начинается непосредственно с трехбайтового заголовка, а сообщение v0 — с байта версии 0x80, за которым следует заголовок.
  • v0 также добавляет раздел Address Lookup Table после инструкций. В нашем простом примере таблица поиска не используется, поэтому этот раздел состоит из одного байта 00, который указывает на отсутствие поисков.

В результате размер нашего примера транзакции перевода SOL составляет 215 байт в формате Legacy и 217 байт в формате v0. В v0 добавляется 1 байт префикса версии и 1 байт пустого массива таблиц поиска. Остальная часть транзакции идентична.

Отправитель подписывает только сообщение. В нашем примере Legacy подпись охватывает байты 65–214, а в v0 — байты 65–216, начиная с префикса версии сообщения 0x80.

Ниже приведена таблица с подробной побайтовой структурой нашего примера перевода SOL между двумя адресами в формате транзакции v0.

СмещениеРазмерПолеПример значенияОписание
01 БКоличество подписей01Одна подпись; compact-u16
1–6464 БПодпись 0<Ed25519 signature>Подпись отправителя
651 БПрефикс версии80Версионированное сообщение, версия 0
66–683 БЗаголовок сообщения01 00 011 обязательный подписант, 0 подписанных только для чтения, 1 неподписанный только для чтения
691 БКоличество статических аккаунтов03Три непосредственно включенных аккаунта
70–10132 БАккаунт 0<sender pubkey>Отправитель/плательщик комиссии; подписант с правом записи
102–13332 БАккаунт 1<recipient pubkey>Получатель; неподписанный с правом записи
134–16532 БАккаунт 211111111111111111111111111111111System Program; неподписанный только для чтения
166–19732 БНедавний хеш блока<recent blockhash>Срок действия транзакции
1981 БКоличество инструкций01Одна инструкция
1991 БИндекс ID программы02System Program
2001 БКоличество аккаунтов инструкции02Два аккаунта инструкции
201–2022 БИндексы аккаунтов00 01Отправитель, получатель
2031 БДлина данных0C12 байт
204–2074 БДискриминатор перевода02 00 00 00SystemInstruction::Transfer
208–2158 БЛампортыE8 03 00 00 00 00 00 001 000 лампортов
2161 БКоличество обращений к таблицам адресов00Нет обращений к ALT
Итого217 Б

Конфигурации ресурсов

В транзакциях Legacy и v0 конфигурации ресурсов задаются в виде инструкций для Compute Budget Program. Среди распространенных — SetComputeUnitLimit и SetComputeUnitPrice. При необходимости также используются SetLoadedAccountsDataSizeLimit и RequestHeapFrame.

В нашем минимальном примере транзакции эти инструкции отсутствуют. Вместо них среда выполнения применяет значения по умолчанию.

Отсутствие цены вычислительной единицы означает отсутствие приоритетной комиссии, а лимит данных загруженных аккаунтов по умолчанию равен максимуму среды выполнения.

Необходимость сканировать список инструкций в поисках инструкций Compute Budget при приеме транзакций снижает эффективность валидаторов. Это одна из причин появления обновленного формата v1, где эта информация перемещена в TransactionConfigMask и ConfigValues.

Кроме того, само представление конфигурации уровня транзакции в виде инструкций создает накладные расходы. В Legacy и v0 не было отдельных полей для запрошенных вычислительных ресурсов или приоритетных комиссий, поэтому эти настройки добавили через Compute Budget Program. Транзакция должна ссылаться на ID этой программы, каждая настройка занимает место в списке инструкций, а сам вызов программы не выполняет прикладной работы, но все равно расходует вычислительные ресурсы.

В v1 эти значения получили собственное место в формате передачи данных. Это устраняет накладные расходы на дополнительные инструкции и упрощает валидаторам проверку конфигурации ресурсов.

Транзакция v1

Вместо количества подписей и самих подписей транзакция v1 начинается непосредственно с байта версии 0x81.

Далее следуют трехбайтовый заголовок, новая четырехбайтовая TransactionConfigMask, спецификатор срока действия — обычно хеш блока, но также возможен nonce, — количество инструкций и адресов, адреса аккаунтов, значения конфигурации, инструкции и, наконец, подписи.

СмещениеРазмерПолеПример значенияОписание
01 ББайт версии81Транзакция v1
1–33 БЗаголовок Legacy01 00 011 обязательная подпись, 0 подписанных аккаунтов только для чтения, 1 неподписанный аккаунт только для чтения
4–74 БМаска конфигурации транзакции0C 00 00 000x0000000C: установлены биты 2 и 3, задающие два четырехбайтовых значения конфигурации
8–3932 БСпецификатор срока действия<recent blockhash>Недавний хеш блока или nonce
401 БКоличество инструкций011 инструкция System Program
411 БКоличество адресов03Отправитель, получатель, System Program
42–7332 БАдрес 0<sender pubkey>Отправитель, плательщик комиссии, подписант с правом записи
74–10532 БАдрес 1<recipient pubkey>Получатель, неподписанный аккаунт с правом записи
106–13732 БАдрес 211111111111111111111111111111111System Program, только для чтения, без подписи
138–1414 БЗначение конфигурации: лимит вычислительных единиц10 27 00 0010 000 CU в виде u32 с порядком байтов от младшего к старшему (соответствует биту 2 маски)
142–1454 БЗначение конфигурации: лимит размера данных загруженных аккаунтов00 00 01 0065 536 байт / 64 КиБ в виде u32 с порядком байтов от младшего к старшему (соответствует биту 3 маски)
146–1494 БИнструкция: заголовок02 02 0C 00Индекс программы 2, 2 аккаунта, 12 байт данных
150–1512 БИнструкция: индексы аккаунтов00 01Адрес 0 = отправитель, адрес 1 = получатель
152–1554 БИнструкция: дискриминатор перевода02 00 00 00SystemInstruction::Transfer
156–1638 БИнструкция: лампортынапример, E8 03 00 00 00 00 00 001 000 лампортов в виде u64 с порядком байтов от младшего к старшему
164–22764 БПодпись 0<Ed25519 signature>Подпись отправителя для байтов 0–155
Итого228 Б

Проверка подписей

Проверка подписей — одна из первых операций, выполняемых при поступлении транзакции валидатору. Транзакции с недействительными подписями необходимо отфильтровать и отбросить до их передачи планировщику. Может показаться, что размещение подписей после сообщения переменной длины усложняет доступ к ним, но на практике это не так.

Перед ресурсоемкой проверкой Ed25519 валидатору нужно лишь определить, где начинается и заканчивается каждая часть транзакции. Формат v1 делает это быстро и детерминированно.

Первый байт, 0x81, сразу определяет транзакцию как v1. Следующий заголовок содержит num_required_signatures, поэтому валидатор с самого начала знает, сколько 64-байтовых подписей нужно найти.

Затем парсер TransactionView в Agave последовательно проходит по транзакции и записывает смещения. Он считывает поля фиксированного размера и использует NumAddresses, чтобы пропустить массив адресов.

Парсер использует маску конфигурации для определения размера раздела конфигурации и считывает каждый четырехбайтовый заголовок инструкции, чтобы узнать размер соответствующей полезной нагрузки.

Когда парсер проходит последнюю полезную нагрузку инструкции, его текущая позиция записывается как смещение подписей. Начиная с этой позиции Agave ожидает ровно num_required_signatures × 64 байта.

Реализация хранит SignatureFrame, содержащий количество подписей и байтовое смещение первой подписи в пакете. Подписанное сообщение транзакции представляет собой диапазон байтов от начала сообщения v1 до записанного смещения подписи. Поэтому валидатор может выполнить ресурсоемкую проверку Ed25519, не выполняя транзакцию и не загружая аккаунты.

v1 также запрещает дополнительные байты после массива подписей. Когда парсер доходит до подписей, размер оставшихся байтов однозначно определяется количеством подписей. SIMD-0385 требует ровно одну 64-байтовую подпись для каждого обязательного подписанта и отсутствие данных после последней подписи.

Улучшенный разбор инструкций

Структура транзакции v1 упрощает разбор инструкций. Чтобы найти более позднюю инструкцию в транзакциях Legacy и v0, парсер должен пройти по предыдущим инструкциям, декодировать их длину и пропустить каждую полезную нагрузку переменной длины.

v1 отделяет заголовки инструкций фиксированной ширины от полезных нагрузок переменной длины. Каждая инструкция сначала добавляет четырехбайтовый заголовок, содержащий индекс аккаунта программы, количество аккаунтов инструкции и длину данных инструкции. Эти заголовки группируются перед индексами аккаунтов и полезными нагрузками данных. Так парсер сразу получает компактное описание каждой инструкции. Это снижает затраты на определение границ и пропуск раздела инструкций, а также помогает определить смещение массива подписей в конце без разбора данных инструкций.

Маска конфигурации транзакции

Другое важное дополнение формата v1 — четырехбайтовая TransactionConfigMask.

Транзакции Legacy и v0 настраивают ресурсы с помощью инструкций для Compute Budget Program. Например, транзакция может содержать инструкции SetComputeUnitLimit, SetComputeUnitPrice или SetLoadedAccountsDataSizeLimit. Валидатор, которому нужны требования транзакции к ресурсам или ее приоритет, должен найти и интерпретировать эти инструкции. Транзакция v1 выносит эту информацию из потока инструкций непосредственно в формат транзакции.

Маска представляет собой 32-битное битовое поле с порядком байтов от младшего к старшему. Каждый установленный бит соответствует четырехбайтовому слову в разделе ConfigValues, расположенном далее в транзакции:

  • Биты 0 и 1: общая приоритетная комиссия в лампортах (кодируется как 8-байтовое u64 с порядком байтов от младшего к старшему)
  • Бит 2: лимит вычислительных единиц (4-байтовое u32)
  • Бит 3: лимит размера данных загруженных аккаунтов (4-байтовое u32)
  • Бит 4: запрошенный размер кучи (4-байтовое u32)

Примечание. В первоначальной спецификации v1 значения присвоены только битам 0–4. Остальные биты пока не назначены, что оставляет место для будущих полей конфигурации уровня транзакции.

Маска действует как компактная схема, сообщающая парсеру, какие поля присутствуют и сколько байтов следует ожидать. Например, для нашего простого перевода SOL нужны лимит вычислительных единиц и лимит размера данных загруженных аккаунтов, но не требуются приоритетная комиссия или нестандартный размер кучи.

Поскольку эти два бита установлены, после массива адресов транзакции идут ровно два четырехбайтовых значения конфигурации. В нашем случае они запрашивают лимит в 20 000 CU и лимит данных загруженных аккаунтов в 64 КиБ.

Маска сообщает валидатору, что первое четырехбайтовое значение конфигурации относится к биту 2 — лимиту вычислительных единиц, а второе — к биту 3, то есть лимиту данных загруженных аккаунтов.

Если в транзакциях Legacy и v0 отсутствует инструкция лимита вычислительных единиц, транзакция получает неявный вычислительный бюджет. v1 не использует те же значения по умолчанию. Неустановленный лимит вычислительных единиц принимает нулевое значение, как и неустановленный лимит размера данных загруженных аккаунтов. Только для кучи сохраняется значение по умолчанию в 32 КиБ. Поэтому транзакция v1 должна явно запрашивать необходимые ресурсы.

Перенос этих настроек в четко определенную область конфигурации предоставляет валидаторам прямой доступ к нужной информации при приеме транзакции. Им больше не требуется искать ее в инструкциях. Это также означает, что инструкции Compute Budget Program больше не настраивают транзакции v1. Если они включены, то игнорируются и обрабатываются как инструкции без операций, но по-прежнему расходуют вычислительные единицы.

Это также экономит место. При добавлении инструкций Compute Budget в транзакции Legacy/v0 обычно требуется включить в список аккаунтов 32-байтовый адрес Compute Budget Program, а также сами сериализованные инструкции.

Заключение

Три формата транзакций Solana отражают эволюцию сети. Legacy заложил исходную модель, v0 расширил ее с помощью ALT для поддержки большего числа аккаунтов в пределах лимита в 1 232 байта, а v1 фундаментально переосмысливает формат передачи данных с учетом более крупных транзакций, упрощенного разбора, непосредственного включения адресов и нативной конфигурации ресурсов.

Все три формата остаются действительными, но каждый отражает отдельный этап развития Solana. Вместе они показывают, как формат транзакций адаптировался по мере развития сетевых приложений, рынков комиссий и требований валидаторов.

Дополнительные материалы

Подпишитесь на Helius

Следите за новостями разработки на Solana и получайте уведомления о наших публикациях

Увеличенное изображение