В Solana смарт-контракт называется программой. Программа — это статeless аккаунт, который содержит исполняемый код. Этот код организован в функции, называемые инструкциями. Пользователи взаимодействуют с программой, отправляя транзакцию, содержащую одну или несколько инструкций. Одна транзакция может включать инструкции из нескольких программ.
Когда программа развёртывается, Solana использует LLVM для компиляции её в исполняемый и компонуемый формат (ELF). ELF-файл содержит бинарный код программы в формате байткода Solana (sBPF) и сохраняется в сети на исполняемом аккаунте.
sBPF — это собственная версия байткода eBPF для Solana.
Написание программ
Большинство программ пишутся на Rust с использованием двух основных подходов к разработке:
- Anchor: Anchor — это фреймворк, созданный для быстрой и простой разработки на Solana. Он использует макросы Rust для сокращения шаблонного кода, что делает его отличным выбором для новичков.
- Чистый Rust: Написание программ на Rust без использования фреймворков. Такой подход даёт больше гибкости, но требует большего опыта и усложняет разработку.
Обновление программ
Чтобы
изменить
существующую программу, аккаунт должен быть назначен
управляющим обновлением.
(Обычно это тот же аккаунт, который изначально
развёртывал программу.) Если права управляющего
обновлением отозваны и установлены в None, программа больше не может быть
обновлена.
Верификация программ
Solana поддерживает проверяемые сборки, которые позволяют пользователям убедиться, что код программы в сети соответствует её открытому исходному коду. Фреймворк Anchor предоставляет встроенную поддержку для создания проверяемых сборок.
Чтобы проверить, верифицирована ли существующая программа, найдите её идентификатор программы на Solana Explorer. Также вы можете воспользоваться CLI-инструментом Ellipsis Labs Solana Verifiable Build CLI, чтобы самостоятельно верифицировать программы в блокчейне.
Встроенные программы
System Program
System Program — единственный аккаунт, который может создавать новые аккаунты. По умолчанию все новые аккаунты принадлежат System Program, хотя при создании многим из них назначается новый владелец. System Program выполняет следующие ключевые функции:
| Функция | Описание |
|---|---|
| Создание нового аккаунта | Только System Program может создавать новые аккаунты. |
| Выделение пространства | Устанавливает объём байтов для поля данных каждого аккаунта. |
| Назначение владельца программы | После создания аккаунта System Program может переназначить владельца программы на другой program account. Так кастомные программы получают владение новыми аккаунтами, созданными System Program. |
| Перевод SOL | Переводит лампорты (SOL) с аккаунтов System Program на другие аккаунты. |
Адрес System Program: 11111111111111111111111111111111.
Загрузочные программы
Каждая программа принадлежит другой — своему загрузчику (loader). Загрузчики используются для деплоя, повторного деплоя, обновления или закрытия программ. Также они применяются для финализации программы и передачи полномочий.
В настоящее время существует пять загрузочных программ, приведённых в таблице ниже.
| Загрузчик | Program ID | Примечания | Ссылка на инструкции |
|---|---|---|---|
| native | NativeLoader1111111111111111111111111111111 | Является владельцем остальных четырёх загрузчиков | — |
| v1 | BPFLoader1111111111111111111111111111111111 | Инструкции управления отключены, но программы продолжают выполняться | — |
| v2 | BPFLoader2111111111111111111111111111111111 | Инструкции управления отключены, но программы продолжают выполняться | Инструкции |
| v3 | BPFLoaderUpgradeab1e11111111111111111111111 | Программы можно обновлять после деплоя. Исполняемый файл программы хранится в отдельном аккаунте program data | Инструкции |
| v4 | LoaderV411111111111111111111111111111111111 | В разработке (не выпущен) | Инструкции |
Программы, развернутые с помощью loader-v3 или loader-v4, могут быть изменяемыми после развертывания, если это разрешено их полномочиями на обновление.
При развертывании новой программы по умолчанию будет использоваться последняя версия загрузчика.
Предкомпилированные программы
В дополнение к программам-загрузчикам Solana предоставляет следующие предкомпилированные программы.
Проверка подписи ed25519
Программа ed25519 используется для проверки одной или нескольких подписей ed25519.
| Программа | ID программы | Описание | Инструкции |
|---|---|---|---|
| Программа Ed25519 | Ed25519SigVerify111111111111111111111111111 | Проверяет подписи ed25519. Если какая-либо подпись не проходит проверку, возвращается ошибка. | Инструкции |
Программа ed25519 обрабатывает инструкцию. Первый u8 инструкции содержит
количество подписей, которые необходимо проверить, за которым следует один байт
для выравнивания. После этого для каждой подписи сериализуется следующая
структура.
struct Ed25519SignatureOffsets {signature_offset: u16, // offset to ed25519 signature of 64 bytessignature_instruction_index: u16, // instruction index to find signaturepublic_key_offset: u16, // offset to public key of 32 bytespublic_key_instruction_index: u16, // instruction index to find public keymessage_data_offset: u16, // offset to start of message datamessage_data_size: u16, // size of message datamessage_instruction_index: u16, // index of instruction data to get message data}
process_instruction() {for i in 0..count {// i'th index values referenced:instructions = &transaction.message().instructionsinstruction_index = ed25519_signature_instruction_index != u16::MAX ? ed25519_signature_instruction_index : current_instruction;signature = instructions[instruction_index].data[ed25519_signature_offset..ed25519_signature_offset + 64]instruction_index = ed25519_pubkey_instruction_index != u16::MAX ? ed25519_pubkey_instruction_index : current_instruction;pubkey = instructions[instruction_index].data[ed25519_pubkey_offset..ed25519_pubkey_offset + 32]instruction_index = ed25519_message_instruction_index != u16::MAX ? ed25519_message_instruction_index : current_instruction;message = instructions[instruction_index].data[ed25519_message_data_offset..ed25519_message_data_offset + ed25519_message_data_size]if pubkey.verify(signature, message) != Success {return Error}}return Success}
Проверка восстановления secp256k1
Программа secp256k1 используется для проверки операций восстановления открытого ключа secp256k1.
| Программа | ID программы | Описание | Инструкции |
|---|---|---|---|
| Программа Secp256k1 | KeccakSecp256k11111111111111111111111111111 | Проверяет операции восстановления открытого ключа secp256k1 (ecrecover). | Инструкции |
Программа secp256k1 обрабатывает инструкцию. Первый байт инструкции содержит количество открытых ключей, которые необходимо проверить. После этого для каждого открытого ключа создаётся следующая структура, затем сериализуется и добавляется в instruction data.
struct Secp256k1SignatureOffsets {secp_signature_offset: u16, // offset to [signature,recovery_id] of 64+1 bytessecp_signature_instruction_index: u8, // instruction index to find signaturesecp_pubkey_offset: u16, // offset to ethereum_address pubkey of 20 bytessecp_pubkey_instruction_index: u8, // instruction index to find pubkeysecp_message_data_offset: u16, // offset to start of message datasecp_message_data_size: u16, // size of message datasecp_message_instruction_index: u8, // instruction index to find message data}
process_instruction() {for i in 0..count {// i'th index values referenced:instructions = &transaction.message().instructionssignature = instructions[secp_signature_instruction_index].data[secp_signature_offset..secp_signature_offset + 64]recovery_id = instructions[secp_signature_instruction_index].data[secp_signature_offset + 64]ref_eth_pubkey = instructions[secp_pubkey_instruction_index].data[secp_pubkey_offset..secp_pubkey_offset + 20]message_hash = keccak256(instructions[secp_message_instruction_index].data[secp_message_data_offset..secp_message_data_offset + secp_message_data_size])pubkey = ecrecover(signature, recovery_id, message_hash)eth_pubkey = keccak256(pubkey[1..])[12..]if eth_pubkey != ref_eth_pubkey {return Error}}return Success}
Это позволяет пользователю указывать любые instruction data в транзакции для подписи и данных сообщения. Указав специальную системную переменную инструкций, можно также получать данные непосредственно из самой транзакции.
Стоимость транзакции рассчитывается как количество подписей для проверки, умноженное на коэффициент стоимости проверки подписи.
Программа secp256r1 используется для проверки до 8 подписей secp256r1.
| Программа | ID программы | Описание | Инструкции |
|---|---|---|---|
| Программа Secp256r1 | Secp256r1SigVerify1111111111111111111111111 | Проверяет до 8 подписей secp256r1. Принимает подпись, открытый ключ и сообщение. Возвращает ошибку при любой ошибке. | Инструкции |
Программа secp256r1 обрабатывает инструкцию. Первый u8 инструкции — это
количество подписей, которые необходимо проверить, за которым следует один байт
для выравнивания. Затем для каждой подписи создаётся следующая структура,
сериализуется и добавляется в instruction data.
struct Secp256r1SignatureOffsets {signature_offset: u16, // offset to compact secp256r1 signature of 64 bytessignature_instruction_index: u16, // instruction index to find signaturepublic_key_offset: u16, // offset to compressed public key of 33 bytespublic_key_instruction_index: u16, // instruction index to find public keymessage_data_offset: u16, // offset to start of message datamessage_data_size: u16, // size of message datamessage_instruction_index: u16, // index of instruction data to get message data}
Для всех подписей применяется требование низких значений S, чтобы избежать случайной изменяемости подписи.
process_instruction() {if data.len() < SIGNATURE_OFFSETS_START {return Error}num_signatures = data[0] as usizeif num_signatures == 0 || num_signatures > 8 {return Error}expected_data_size = num_signatures * SIGNATURE_OFFSETS_SERIALIZED_SIZE + SIGNATURE_OFFSETS_STARTif data.len() < expected_data_size {return Error}for i in 0..num_signatures {offsets = parse_signature_offsets(data, i)signature = get_data_slice(data, instruction_datas, offsets.signature_instruction_index, offsets.signature_offset, SIGNATURE_SERIALIZED_SIZE)if s > half_curve_order {return Error}pubkey = get_data_slice(data, instruction_datas, offsets.public_key_instruction_index, offsets.public_key_offset, COMPRESSED_PUBKEY_SERIALIZED_SIZE)message = get_data_slice(data, instruction_datas, offsets.message_instruction_index, offsets.message_data_offset, offsets.message_data_size)if !verify_signature(signature, pubkey, message) {return Error}}return Success}
Основные программы
Программы в списке ниже обеспечивают основную функциональность сети.
| Программа | ID программы | Описание | Инструкции |
|---|---|---|---|
| System | 11111111111111111111111111111111 | Создание новых аккаунтов, выделение данных аккаунта, назначение аккаунтов программам-владельцам, перевод лампортов с аккаунтов, принадлежащих системной программе, и оплата комиссий за транзакции | SystemInstruction |
| Vote | Vote111111111111111111111111111111111111111 | Создание и управление аккаунтами, отслеживающими состояние голосования валидаторов и вознаграждения | VoteInstruction |
| Stake | Stake11111111111111111111111111111111111111 | Создание и управление аккаунтами, представляющими стейк и вознаграждения за делегирование валидаторам | StakeInstruction |
| Config | Config1111111111111111111111111111111111111 | Добавление конфигурационных данных в цепочку, а также списка открытых ключей, которым разрешено их изменять. В отличие от других программ, программа Config не определяет отдельных инструкций. В ней есть только одна неявная инструкция: "store". Её instruction data — это набор ключей, ограничивающих доступ к аккаунту и данным внутри него | ConfigInstruction |
| Compute Budget | ComputeBudget111111111111111111111111111111 | Установка лимитов и цен на вычислительные ресурсы для транзакций, позволяя пользователям управлять вычислительными ресурсами и приоритетными комиссиями | ComputeBudgetInstruction |
| Address Lookup Table | AddressLookupTab1e1111111111111111111111111 | Управление таблицами поиска адресов, которые позволяют транзакциям ссылаться на большее количество аккаунтов, чем обычно помещается в списке аккаунтов транзакции | ProgramInstruction |
| ZK ElGamal Proof | ZkE1Gama1Proof11111111111111111111111111111 | Предоставляет проверку доказательств с нулевым разглашением для данных, зашифрованных с помощью ElGamal | — |
Is this page helpful?