У Solana смарт-контракт називається програмою. Програма — це stateless акаунт, що містить виконуваний код. Цей код організовано у функції, які називаються інструкціями. Користувачі взаємодіють з програмою, надсилаючи транзакцію, що містить одну або кілька інструкцій. Транзакція може включати інструкції з кількох програм.
Коли програму розгортають, Solana використовує LLVM для компіляції її у виконуваний формат з можливістю компонування (ELF). ELF-файл містить бінарний код програми у форматі Solana Bytecode Format (sBPF) і зберігається он-чейн у виконуваному акаунті.
sBPF — це кастомна версія байткоду eBPF від Solana.
Написання програм
Більшість програм написані на Rust, з двома поширеними підходами до розробки:
- Anchor: Anchor — це фреймворк, призначений для швидкої та легкої розробки на Solana. Він використовує макроси Rust для зменшення шаблонного коду — що робить його чудовим для початківців.
- Нативний Rust: Написання програм на Rust без використання будь-яких фреймворків. Цей підхід пропонує більше гнучкості, але супроводжується підвищеною складністю.
Оновлення програм
Щоб
модифікувати
існуючу програму, акаунт має бути призначений як
upgrade authority.
(Зазвичай той самий акаунт, який спочатку
розгорнув програму.) Якщо upgrade authority
відкликано і встановлено в None, програму більше не можна оновити.
Верифікація програм
Solana підтримує верифіковані білди, які дозволяють користувачам перевірити, чи відповідає он-чейн код програми її публічному вихідному коду. Фреймворк Anchor надає вбудовану підтримку для створення верифікованого білду.
Щоб перевірити, чи існуюча програма верифікована, знайдіть її ідентифікатор програми в Solana Explorer. Альтернативно, ви можете використати Solana Verifiable Build CLI від Ellipsis Labs для незалежної верифікації он-чейн програм.
Вбудовані програми
System Program
System Program — це єдиний акаунт, який може створювати нові акаунти. За замовчуванням усі нові акаунти належать System Program, хоча багато з них отримують нового власника при створенні. System Program виконує такі ключові функції:
| Функція | Опис |
|---|---|
| Створення нового акаунта | Тільки System Program може створювати нові акаунти. |
| Виділення простору | Встановлює ємність у байтах для поля даних кожного акаунта. |
| Призначення власника програми | Після того, як System Program створює акаунт, вона може переназначити визначеного власника програми на інший program account. Саме так кастомні програми отримують право власності на нові акаунти, створені System Program. |
| Переказ SOL | Переказує лампорти (SOL) з системних акаунтів на інші акаунти. |
Адреса системної програми — 11111111111111111111111111111111.
Програми-завантажувачі
Кожна програма належить іншій — її завантажувачу. Завантажувачі використовуються для розгортання, повторного розгортання, оновлення або закриття програм. Вони також використовуються для фіналізації програми та передачі повноважень програми.
Наразі існує п'ять програм-завантажувачів, як показано в таблиці нижче.
| Завантажувач | Ідентифікатор програми | Примітки | Посилання на інструкції |
|---|---|---|---|
| native | NativeLoader1111111111111111111111111111111 | Володіє іншими чотирма завантажувачами | — |
| v1 | BPFLoader1111111111111111111111111111111111 | Інструкції керування вимкнено, але програми все ще виконуються | — |
| v2 | BPFLoader2111111111111111111111111111111111 | Інструкції керування вимкнено, але програми все ще виконуються | Інструкції |
| v3 | BPFLoaderUpgradeab1e11111111111111111111111 | Програми можна оновлювати після розгортання. Виконуваний код програми зберігається в окремому program data account | Інструкції |
| 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 обробляє інструкцію. Перший байт інструкції містить кількість відкритих ключів, які потрібно перевірити. Після цього, наступна структура створюється один раз для кожного відкритого ключа, потім серіалізується та додається до даних інструкції.
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}
Це дозволяє користувачеві вказати будь-які дані інструкції в транзакції для даних підпису та повідомлення. Вказавши спеціальний sysvar інструкцій, можна також отримувати дані з самої транзакції.
Вартість транзакції буде враховувати кількість підписів для перевірки, помножену на множник вартості перевірки підпису.
Програма secp256r1 використовується для перевірки до 8 підписів secp256r1.
| Програма | ID програми | Опис | Інструкції |
|---|---|---|---|
| Програма Secp256r1 | Secp256r1SigVerify1111111111111111111111111 | Перевіряє до 8 підписів secp256r1. Приймає підпис, відкритий ключ та повідомлення. Повертає помилку, якщо будь-який не пройде перевірку. | Інструкції |
Програма secp256r1 обробляє інструкцію. Перший u8 інструкції містить кількість
підписів, які потрібно перевірити, за яким слідує один байт заповнення. Після
цього, наступна структура створюється для кожного підпису, потім серіалізується
та додається до даних інструкції.
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 | Створення та управління обліковими записами, які відстежують стан голосування validator та винагороди | VoteInstruction |
| Stake | Stake11111111111111111111111111111111111111 | Створення та управління обліковими записами, що представляють ставку та винагороди за делегування validator | StakeInstruction |
| Config | Config1111111111111111111111111111111111111 | Додавання конфігураційних даних до ланцюга, за якими слідує список відкритих ключів, яким дозволено їх змінювати. На відміну від інших програм, програма Config не визначає окремих інструкцій. Вона має лише одну неявну інструкцію: "store". Її дані інструкції — це набір ключів, які контролюють доступ до облікового запису та даних, що зберігаються в ньому | ConfigInstruction |
| Compute Budget | ComputeBudget111111111111111111111111111111 | Встановлення лімітів обчислювальних одиниць та цін для транзакцій, що дозволяє користувачам контролювати обчислювальні ресурси та комісії за пріоритет | ComputeBudgetInstruction |
| Address Lookup Table | AddressLookupTab1e1111111111111111111111111 | Управління таблицями пошуку адрес, які дозволяють транзакціям посилатися на більше облікових записів, ніж могло б вміститися у списку облікових записів транзакції | ProgramInstruction |
| ZK ElGamal Proof | ZkE1Gama1Proof11111111111111111111111111111 | Забезпечує перевірку доказів з нульовим розголошенням для даних, зашифрованих за допомогою ElGamal | — |
Is this page helpful?